kubernetes 搭建 Apollo 配置中心

众所周知,携程的 Apollo 已经成为行业里非常流行的配置中心了,这个轮子的原理其实并不复杂,但是如果重新开发一套又需要考虑很多边界条件,Apollo 本身也是开源的,所以有问题的话热心的网友一定会很早就帮我们解决掉了。

前面也有考虑过直接使用 k8s 里面的 configMap,但是 configMap 只有在创建 pods 的时候会拉取,后面如果修改了 configMap ,其实是不会同步到 pods 中,如果手动去拉取 configMap 中的内容,这又和 Apollo 有什么区别呢,Apollo 还有审计还有灰度,还有历史变更记录,还有一套权限系统,所以不如直接使用 Apollo 了。

Apollo配置中心设计

基础模型

基础模型

软件架构图

架构图

kubernetes 部署

Apollo 是由 java 语言编写,使用了 spring 框架,以及 Eureka 服务发现,如果使用 k8s 环境的话,当然是使用 k8s 自带的服务发现最佳,提升系统可读性,可维护性和稳定性。wiki 上已经有详细的文档,这里说一下重点步骤:

添加数据库配置文件

首先下载 https://github.com/ctripcorp/apollo/tree/master/scripts/sql 两个 sql 文件,然后倒入到自己各个环境的数据库中。

apolloconfigdb.sql 是各个环境都需要配置的 service 服务需要的数据库,apolloportaldb.sql 是 portal 管理端服务需要的数据库,如果暂时搞不清楚,两个文件可以都导入,后面再去理解原理。

下面的描述中提到的 service 均指 configservice 和 adminservice 。

helm 添加 Apollo 的源

1
2
3
4
5
6
$ helm repo add apollo http://ctripcorp.github.io/apollo/charts
$ helm search repo apollo

NAME CHART VERSION APP VERSION DESCRIPTION
apollo/apollo-portal 0.1.1 1.7.1 A Helm chart for Apollo Portal
apollo/apollo-service 0.1.1 1.7.1 A Helm chart for Apollo Config Service and Apol...

拉取模板文件

这里拉取文件是为了可以详细的看下作者是如何设计这个 chart,已经可以拿到一封完整的 values.xml 文件。基于 k8s 的思想,配置都要留在文件里,helm 如果使用命令行的方式,可以测试使用,但是如果是线上环境那终究没有里面存档,命令行的参数过长也会造成阅读不遍。

如果相信作者的话也可以直接使用下面我粘贴的 apollo-portal-values.yamlapollo-service-values.yaml 文件

1
2
3
4
5
6
7
$ helm pull apollo/apollo-portal
$ helm pull apollo/apollo-service
$ ls -l

total 16
-rw-r--r-- 1 jake staff 3568 Sep 16 17:01 apollo-portal-0.1.1.tgz
-rw-r--r-- 1 jake staff 3478 Sep 16 17:00 apollo-service-0.1.1.tgz

两个压缩文件,mac 中就点击下就可以直接解压了,然后两个 chart 根目录中的 values.yaml 文件可以复制出来,重命名一下备用。

apollo-portal-values.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
name: apollo-portal
fullNameOverride: ""
replicaCount: 2
containerPort: 8070
image:
repository: apolloconfig/apollo-portal
pullPolicy: IfNotPresent
imagePullSecrets: []
service:
fullNameOverride: ""
port: 8070
targetPort: 8070
type: ClusterIP
sessionAffinity: ClientIP
ingress:
enabled: false
annotations: {}
hosts:
- host: ""
paths: []
tls: []
liveness:
initialDelaySeconds: 100
periodSeconds: 10
readiness:
initialDelaySeconds: 30
periodSeconds: 5
# environment variables passed to the container, e.g. JAVA_OPTS
env: {}
strategy: {}
resources: {}
nodeSelector: {}
tolerations: []
affinity: {}

config:
# spring profiles to activate
profiles: "github,auth"
# specify the env names, e.g. dev,pro
envs: ""
# specify the meta servers, e.g.
# dev: http://apollo-configservice-dev:8080
# pro: http://apollo-configservice-pro:8080
metaServers: {}
# specify the context path, e.g. /apollo
contextPath: ""
# extra config files for apollo-portal, e.g. application-ldap.yml
files: {}

portaldb:
name: apollo-portaldb
# apolloportaldb host
host:
port: 3306
dbName: ApolloPortalDB
# apolloportaldb user name
userName:
# apolloportaldb password
password:
connectionStringProperties: characterEncoding=utf8
service:
# whether to create a Service for this host or not
enabled: false
fullNameOverride: ""
port: 3306
type: ClusterIP

apollo-service-values.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
configdb:
name: apollo-configdb
# apolloconfigdb host
host: ""
port: 3306
dbName: ApolloConfigDB
# apolloconfigdb user name
userName: ""
# apolloconfigdb password
password: ""
connectionStringProperties: characterEncoding=utf8
service:
# whether to create a Service for this host or not
enabled: false
fullNameOverride: ""
port: 3306
type: ClusterIP

configService:
name: apollo-configservice
fullNameOverride: ""
replicaCount: 2
containerPort: 8080
image:
repository: apolloconfig/apollo-configservice
pullPolicy: IfNotPresent
imagePullSecrets: []
service:
fullNameOverride: ""
port: 8080
targetPort: 8080
type: ClusterIP
liveness:
initialDelaySeconds: 100
periodSeconds: 10
readiness:
initialDelaySeconds: 30
periodSeconds: 5
config:
# spring profiles to activate
profiles: "github,kubernetes"
# override apollo.config-service.url: config service url to be accessed by apollo-client
configServiceUrlOverride: ""
# override apollo.admin-service.url: admin service url to be accessed by apollo-portal
adminServiceUrlOverride: ""
# environment variables passed to the container, e.g. JAVA_OPTS
env: {}
strategy: {}
resources: {}
nodeSelector: {}
tolerations: []
affinity: {}

adminService:
name: apollo-adminservice
fullNameOverride: ""
replicaCount: 2
containerPort: 8090
image:
repository: apolloconfig/apollo-adminservice
pullPolicy: IfNotPresent
imagePullSecrets: []
service:
fullNameOverride: ""
port: 8090
targetPort: 8090
type: ClusterIP
liveness:
initialDelaySeconds: 100
periodSeconds: 10
readiness:
initialDelaySeconds: 30
periodSeconds: 5
config:
# spring profiles to activate
profiles: "github,kubernetes"
# environment variables passed to the container, e.g. JAVA_OPTS
env: {}
strategy: {}
resources: {}
nodeSelector: {}
tolerations: []
affinity: {}

部署核心文件

由于 Apollo 的设计原则,可以一个 portal 管理多个 service,我们可以在各个环境(DEV,PRO)都部署一套 service,然后用 portal 单独去管理。

配置 service

我们的各个环境应该都有自己的一套数据库,Apollo 唯一的依赖也是 mysql,所以只需要修改 configdb 中的数据库字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
configdb:
name: apollo-configdb
# apolloconfigdb host
host: "mysql8" # 修改为自己的数据库地址
port: 3306 # 修改为自己的数据库端口
dbName: apolloconfigdb # 修改为自己的数据库名字
# apolloconfigdb user name
userName: "root" # 修改为自己的数据库用户
# apolloconfigdb password
password: "1" # 修改为自己的数据库用户密码
connectionStringProperties: characterEncoding=utf8
service:
# whether to create a Service for this host or not
enabled: false
fullNameOverride: ""
port: 3306
type: ClusterIP

可以将 apollo-service-values.yaml 中的其他内容都删除只保留一个 configdb, 其他属性会走默认的配置字段,如果有特殊需求就自行编辑。

1
2
3
4
5
6
7
$ helm install -f apollo-service-values.yaml apollo-service apollo/apollo-service -n sv-dev

...
NOTES:
Get meta service url for current release by running these commands:
echo http://apollo-service-apollo-configservice.sv-dev:8080
...

我这里的 namespace 是 sv-dev, 核心的一段是 http://apollo-service-apollo-configservice.sv-dev:8080,需要暂时存储一下。

然后替换 configdb 中的数据库信息,将 apollo-service 配置到各个环境中去。

配置 protal

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
replicaCount: 1 # **切记切记**,这里一定要写 1,如果有多个 protal ,使用的 session 之间不共享内存,导致我需要反复登录

config:
# spring profiles to activate
profiles: "github,auth"
# specify the env names, e.g. dev,pro
envs: "dev,pro" # 如果是部署了多个环境,这里写多个环境以逗号隔开
# specify the meta servers, e.g.
# dev: http://apollo-configservice-dev:8080
# pro: http://apollo-configservice-pro:8080
metaServers:
dev: "http://apollo-service-apollo-configservice.sv-dev:8080" # 这里填写上面 helm 部署成功得到的地址
pro: "http://apollo-service-apollo-configservice.sv-pro:8080" # 这里填写上面 helm 部署成功得到的地址
# specify the context path, e.g. /apollo
contextPath: ""
# extra config files for apollo-portal, e.g. application-ldap.yml
files: {}

portaldb:
name: apollo-portaldb
# apolloportaldb host
host: "" # 修改为自己的数据库地址
port: 3306 # 修改为自己的数据库端口
dbName: ApolloPortalDB # 修改为自己的数据库名字
# apolloportaldb user name
userName: "" # 修改为自己的数据库用户
# apolloportaldb password
password: "" # 修改为自己的数据库用户密码
connectionStringProperties: characterEncoding=utf8
service:
# whether to create a Service for this host or not
enabled: false
fullNameOverride: ""
port: 3306
type: ClusterIP

ingress:
enabled: true
annotations: {}
hosts:
- host: "apollo.xxxx.com" # 选一个自己喜欢的域名,绑定一下
paths:
- "/"
tls: []

无关的配置默认就好,我们可以直接删除掉,只保留核心的需要修改配置。

1
$ helm install -f apollo-portal-values.yaml apollo-portal apollo/apollo-portal -n apollo

这里我将 apollo-portal 部署到单独的一个 namespace 中。

访问服务

打开 apollo.xxxx.com 就可以打开管理页面
image.png

默认账户密码是 apolloadmin,登录进去就可以享受配置中心带来的便利了,到此搭建结束。

参考文档

坚持原创技术分享,您的支持将鼓励我继续创作!