docker-compose部署多环境apollo

2,950 阅读5分钟

一、 暴露端口的方式

1. 前言

基于以下几点,写下了本文:

  1. apollo官网docker部署介绍比较模糊
  2. 网上其他人部署也大多是抄袭,不得精算
  3. 本人捣鼓这个有两个礼拜了,虽然ureaka上还是有点问题,但是多环境使用已无问题。

2. 部署说明

  1. 版本:apollo-1.2.0

  2. 部署方式:基于源码+docker-compose构建镜像部署,看本文默认你会了docker-compose

  3. 环境介绍:

物理机centos7机器一台,IP地址为:192.168.64.201

centos7物理机上部署四套环境 dev,fat,uat,pro

3. 部署步骤

3.1 下载源码,创建数据库

  1. 源码地址:
https://github.com/ctripcorp/apollo/tree/v1.2.0
  1. 创建数据库

apollo 要部署三个模块:apollo-configservice,apollo-adminservice,apollo-portal

其中apollo-configservice,apollo-adminservice要分环境部署,各个环境下apollo-configservice,apollo-adminservice公用一个数据库(参考官网),apollo-portal独用一个数据库

共五个个数据库,apollo-configservice,apollo-adminservice分别在dev,fat,uat,pro一个数据库,apollo-portal一个数据库,如下图所示:

数据库修改ServerConfig表中的记录:

huayun_ApolloConfigDB_DEV

http://192.168.64.201:8080/eureka/

huayun_ApolloConfigDB_FAT

http://192.168.64.201:8081/eureka/

huayun_ApolloConfigDB_UAT

http://192.168.64.201:8082/eureka/

huayun_ApolloConfigDB_PRO

http://192.168.64.201:8083/eureka/

huayun_ApolloPortalDB

apollo-portal 的修改有所不同,同样是ServerConfig表,但是不是配置URL而是配置启用的环境,如下

dev,fat,uat,pro

3.2 编译源码

官网下载对应的版本的源码,导入idea,如下图,我这里标记了几个重要的模块以及目录

直接使用maven打包(不用apollo自带的build.sh,这种方式要改配置),直接打包后,取到config、admin、portal对应的zip包以及对应的Dockerfile文件,以及创建.env文件、docker-compose.yml、apollo-env.properties文件,最终文件目录结构如下:

3.3 编写docker-compose.yml

.env文件

该文件用于定义docker-compose.yml文件中使用的变量,主要是暴露的端口定义,数据库连接串信息

VERSION=1.2.0

LOG_BASE_DIR=/data/apollo
BUILD_BASE_DIR=/data/docker-image


IP_ADDRESS=192.168.64.201

CONFIG_PORT_DEV=8080
CONFIG_PORT_FAT=8081
CONFIG_PORT_UAT=8082
CONFIG_PORT_PRO=8083

ADMIN_PORT_DEV=8090
ADMIN_PORT_FAT=8091
ADMIN_PORT_UAT=8092
ADMIN_PORT_PRO=8093

DATASOURCE_URL_DEV=jdbc:mysql://192.168.64.201:13306/huayun_ApolloConfigDB_DEV?characterEncoding=utf8
DATASOURCE_URL_FAT=jdbc:mysql://192.168.64.201:13306/huayun_ApolloConfigDB_FAT?characterEncoding=utf8
DATASOURCE_URL_UAT=jdbc:mysql://192.168.64.201:13306/huayun_ApolloConfigDB_UAT?characterEncoding=utf8
DATASOURCE_URL_PRO=jdbc:mysql://192.168.64.201:13306/huayun_ApolloConfigDB_PRO?characterEncoding=utf8

PORTAL_DATASOURCE_URL=jdbc:mysql://192.168.64.201:13306/huayun_ApolloPortalDB?characterEncoding=utf8

DATASOURCE_USERNAME=root
DATASOURCE_PASSWORD=root

apollo-env.properties

dev.meta=http://192.168.64.201:8080
fat.meta=http://192.168.64.201:8081
uat.meta=http://192.168.64.201:8082
pro.meta=http://192.168.64.201:8083

docker-compose.yml

version: '3'
services:
  # 开发环境  configservice
  apollo-configservice-dev:
    container_name: apollo-configservice-dev
    build: apollo-configservice/
    image: apollo-configservice
    restart: always
    environment:
      SPRING_DATASOURCE_URL: ${DATASOURCE_URL_DEV}
      SPRING_DATASOURCE_USERNAME: ${DATASOURCE_USERNAME}
      SPRING_DATASOURCE_PASSWORD: ${DATASOURCE_PASSWORD}
      EUREKA_INSTANCE_IP_ADDRESS: ${IP_ADDRESS}
      EUREKA_INSTANCE_HOME_PAGE_URL: http://${IP_ADDRESS}:${CONFIG_PORT_DEV}
    volumes:
      - ${LOG_BASE_DIR}/apollo-configservice-dev/logs:/opt/logs
    ports:
      - "${CONFIG_PORT_DEV}:8080"

  # 开发环境  adminservice
  apollo-adminservice-dev:
    container_name: apollo-adminservice-dev
    build: apollo-adminservice/
    image: apollo-adminservice
    restart: always
    depends_on:
      - apollo-configservice-dev
    environment:
      SPRING_DATASOURCE_URL: ${DATASOURCE_URL_DEV}
      SPRING_DATASOURCE_USERNAME: ${DATASOURCE_USERNAME}
      SPRING_DATASOURCE_PASSWORD: ${DATASOURCE_PASSWORD}
      EUREKA_INSTANCE_IP_ADDRESS: ${IP_ADDRESS}
      EUREKA_INSTANCE_HOME_PAGE_URL: http://${IP_ADDRESS}:${ADMIN_PORT_DEV}
    volumes:
      - ${LOG_BASE_DIR}/apollo-adminservice-dev/logs:/opt/logs
    ports:
      - "${ADMIN_PORT_DEV}:8090"

  # fat  configservice
  apollo-configservice-fat:
    container_name: apollo-configservice-fat
    build: apollo-configservice/
    image: apollo-configservice
    restart: always
    environment:
      SPRING_DATASOURCE_URL: ${DATASOURCE_URL_FAT}
      SPRING_DATASOURCE_USERNAME: ${DATASOURCE_USERNAME}
      SPRING_DATASOURCE_PASSWORD: ${DATASOURCE_PASSWORD}
      EUREKA_INSTANCE_IP_ADDRESS: ${IP_ADDRESS}
      EUREKA_INSTANCE_HOME_PAGE_URL: http://${IP_ADDRESS}:${CONFIG_PORT_FAT}
    volumes:
      - ${LOG_BASE_DIR}/apollo-configservice-fat/logs:/opt/logs
    ports:
      - "${CONFIG_PORT_FAT}:8080"

  # fat  adminservice
  apollo-adminservice-fat:
    container_name: apollo-adminservice-fat
    build: apollo-adminservice/
    image: apollo-adminservice
    restart: always
    depends_on:
      - apollo-configservice-fat
    environment:
      SPRING_DATASOURCE_URL: ${DATASOURCE_URL_FAT}
      SPRING_DATASOURCE_USERNAME: ${DATASOURCE_USERNAME}
      SPRING_DATASOURCE_PASSWORD: ${DATASOURCE_PASSWORD}
      EUREKA_INSTANCE_IP_ADDRESS: ${IP_ADDRESS}
      EUREKA_INSTANCE_HOME_PAGE_URL: http://${IP_ADDRESS}:${ADMIN_PORT_FAT}
    volumes:
      - ${LOG_BASE_DIR}/apollo-adminservice-fat/logs:/opt/logs
    ports:
      - "${ADMIN_PORT_FAT}:8090"

  # uat  configservice
  apollo-configservice-uat:
    container_name: apollo-configservice-uat
    build: apollo-configservice/
    image: apollo-configservice
    restart: always
    environment:
      SPRING_DATASOURCE_URL: ${DATASOURCE_URL_UAT}
      SPRING_DATASOURCE_USERNAME: ${DATASOURCE_USERNAME}
      SPRING_DATASOURCE_PASSWORD: ${DATASOURCE_PASSWORD}
      EUREKA_INSTANCE_IP_ADDRESS: ${IP_ADDRESS}
      EUREKA_INSTANCE_HOME_PAGE_URL: http://${IP_ADDRESS}:${CONFIG_PORT_UAT}
    volumes:
      - ${LOG_BASE_DIR}/apollo-configservice-uat/logs:/opt/logs
    ports:
      - "${CONFIG_PORT_UAT}:8080"

  # uat  adminservice
  apollo-adminservice-uat:
    container_name: apollo-adminservice-uat
    build: apollo-adminservice/
    image: apollo-adminservice
    restart: always
    depends_on:
      - apollo-configservice-uat
    environment:
      SPRING_DATASOURCE_URL: ${DATASOURCE_URL_UAT}
      SPRING_DATASOURCE_USERNAME: ${DATASOURCE_USERNAME}
      SPRING_DATASOURCE_PASSWORD: ${DATASOURCE_PASSWORD}
      EUREKA_INSTANCE_IP_ADDRESS: ${IP_ADDRESS}
      EUREKA_INSTANCE_HOME_PAGE_URL: http://${IP_ADDRESS}:${ADMIN_PORT_UAT}
    volumes:
      - ${LOG_BASE_DIR}/apollo-adminservice-uat/logs:/opt/logs
    ports:
      - "${ADMIN_PORT_UAT}:8090"


  # pro  configservice
  apollo-configservice-pro:
    container_name: apollo-configservice-pro
    build: apollo-configservice/
    image: apollo-configservice
    restart: always
    environment:
      SPRING_DATASOURCE_URL: ${DATASOURCE_URL_PRO}
      SPRING_DATASOURCE_USERNAME: ${DATASOURCE_USERNAME}
      SPRING_DATASOURCE_PASSWORD: ${DATASOURCE_PASSWORD}
      EUREKA_INSTANCE_IP_ADDRESS: ${IP_ADDRESS}
      EUREKA_INSTANCE_HOME_PAGE_URL: http://${IP_ADDRESS}:${CONFIG_PORT_PRO}
    volumes:
      - ${LOG_BASE_DIR}/apollo-configservice-pro/logs:/opt/logs
    ports:
      - "${CONFIG_PORT_PRO}:8080"

  # pro  adminservice
  apollo-adminservice-pro:
    container_name: apollo-adminservice-pro
    build: apollo-adminservice/
    image: apollo-adminservice
    restart: always
    depends_on:
      - apollo-configservice-pro
    environment:
      SPRING_DATASOURCE_URL: ${DATASOURCE_URL_PRO}
      SPRING_DATASOURCE_USERNAME: ${DATASOURCE_USERNAME}
      SPRING_DATASOURCE_PASSWORD: ${DATASOURCE_PASSWORD}
      EUREKA_INSTANCE_IP_ADDRESS: ${IP_ADDRESS}
      EUREKA_INSTANCE_HOME_PAGE_URL: http://${IP_ADDRESS}:${ADMIN_PORT_PRO}
    volumes:
      - ${LOG_BASE_DIR}/apollo-adminservice-pro/logs:/opt/logs
    ports:
      - "${ADMIN_PORT_PRO}:8090"

  # portal
  apollo-portal:
    container_name: apollo-portal
    build: apollo-portal/
    image: apollo-portal
    restart: always
    depends_on:
      - apollo-adminservice-dev
      - apollo-adminservice-fat
      - apollo-adminservice-uat
      - apollo-adminservice-pro
    environment:
      SPRING_DATASOURCE_URL: ${PORTAL_DATASOURCE_URL}
      SPRING_DATASOURCE_USERNAME: ${DATASOURCE_USERNAME}
      SPRING_DATASOURCE_PASSWORD: ${DATASOURCE_PASSWORD}
      APOLLO_PROFILE: github,auth
    volumes:
      - ${LOG_BASE_DIR}/apollo-portal/logs:/opt/logs
      - ${BUILD_BASE_DIR}/docker-compose-huayun/apollo-env.properties:/apollo-portal/config/apollo-env.properties
    ports:
      - "8070:8070"

各个环境下的apollo-configservice和apollo-adminservice中有两个参数解释一下:

EUREKA_INSTANCE_IP_ADDRESS 指定服务想eureaka注册时使用物理机器IP地址

EUREKA_INSTANCE_HOME_PAGE_URL 该参数配置当前服务的注册全路径,如果不配置,Java应用客户端无法连接apollo服务端

3.4 启动容器

将修改后的docker-compose-huayun文件夹打包,上传到centos主机的/data/docker-image目录下(你可以更改,记得更改.env中的配置的BUILD_BASE_DIR对应的值为你的目录即可),解压,如下:

进入docker-compose-huayun目录

启动容器

docker-compose up -d

观察各个服务启动的日志(我这里的日志挂在在了物理机的/data/apollo目录下),服务一开始会有报错,因为注册中心启动需要一定的时间

3.5 apollo后台多环境验证,以及后台功能验证

  1. 确认服务启动

查看日志,看到portal有如下日志,则服务都已启动

或查看注册中心注册的服务信息,地址分别是:

http://192.168.64.201:8080/
http://192.168.64.201:8081/
http://192.168.64.201:8082/
http://192.168.64.201:8083/

看到服务注册成功即可。

访问apollo后台

http://192.168.64.201:8070/

登录用户名密码:apollo/admin

登录后验证创建用户,看是不是会报错,能创建用户成功就OK了。

3.6 apollo客户端(Java应用)接入测试

新建一个springboot2的web项目,整合apollo客户端,项目结构如下:

pom.xml,加入apollo客户端依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.huayun</groupId>
    <artifactId>huayun-apollo-test</artifactId>
    <version>1.0-SNAPSHOT</version>


    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.8</version>
        </dependency>
        <dependency>
            <artifactId>apollo-client</artifactId>
            <groupId>com.ctrip.framework.apollo</groupId>
            <version>1.5.0</version>
        </dependency>
    </dependencies>


</project>

启动类App.java,加@EnableApolloConfig开启apollo

package com.huayun.apollo;

import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author amyzhang
 * @history 2020/12/20 新建
 * @since JDK1.7
 */
@EnableApolloConfig
@SpringBootApplication
public class App {

    public static void main(String[] args) {
        SpringApplication.run(App.class,args);
    }
}

application.yml定义服务端口

server:
  port: 8001

apollo-env.properties定义apollo服务的meta信息

dev.meta=http://192.168.64.201:8080
fat.meta=http://192.168.64.201:8081
uat.meta=http://192.168.64.201:8082
pro.meta=http://192.168.64.201:8083

app.properties定义appid,与apollo服务端appId对应

app.id=huayun-apollo-test

测试controller ApolloController.java,就是简单的获取apollo中配置的aaa的值,并返回

package com.huayun.apollo.controller;

import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author 张咪
 * @history 2020/12/20 新建
 * @since JDK1.7
 */
@RestController
public class ApolloController {

//    @ApolloConfig
//    private Config config;

//    @RequestMapping(value = "/test",method = RequestMethod.GET)
//    public Object test(){
//        return config.getIntProperty("aaa",-1);
//    }
    @RequestMapping(value = "/test",method = RequestMethod.GET)
    public Object test(){
        Config config = ConfigService.getAppConfig(); //config instance is singleton for each namespace and is never null
        String someKey = "aaa";
        int someDefaultValue = -1;
        int value = config.getIntProperty(someKey, someDefaultValue);
        return value;
    }
}

apollo服务端配置aaa在各个环境不同的值

为测试项目配置App的启动参数 -Denv=dev

分别为env配置不同的环境,测试获取到的aaa的值,aaa的值为对应的环境的值,那么就成功了。

二、基于traefik反向代理的方式(apollo服务本身不暴露任何端口)