K8S部署N个微服务,每个微服务都有很多配置,需要一个配置中心来集中管理这些配置。于是采用apollo来作为配置中心。本文介绍如何使用ArgoCD在K8S集群中部署Apollo配置中心。
一、环境
- 已经搭建了多个K8S集群,一个集群对应一个环境
- 集群中安装了ArgoCD
- 一个mysql数据库(apollo是需要用到mysql数据库的,所以必须要有一个mysql数据库)
二、初始化mysql数据库
初始化脚本直接使用官方的脚本: github.com/apolloconfi…
apolloconfigdb.sql 初始化的是config的database --- ApolloConfigDB
apolloportaldb.sql 初始化的是portal的database --- ApolloPortalDB
三、apollo在K8S集群中部署
请参考官方文档: www.apolloconfig.com/#/zh/deploy…
Apollo 1.7.0版本增加了基于Kubernetes原生服务发现的部署模式,由于不再使用内置的Eureka,所以在整体部署上有很大简化,同时也提供了Helm Charts,便于部署。支持Helm Charts,那用argoCD部署也太方便了。
直接下载代码,放到你ArgoCD配置仓下,然后修改mysql的信息,最后定义argoCD的Application就行了。
下载代码
git clone https://github.com/apolloconfig/apollo-helm-chart
修改mysql对接配置
- apollo-portal对接mysql配置
- apollo-service对接mysql配置
部署apollo-portal
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: apollo-portal
namespace: argocd
spec:
destination:
namespace: apollo
server: https://kubernetes.default.svc
project: ops-prod
source:
path: apollo-helm-chart/apollo-portal/
repoURL: https://xxxxxxxxx.git
targetRevision: HEAD
syncPolicy:
syncOptions:
- CreateNamespace=true
automated:
selfHeal: false
prune: false
- 在project: ops-prod中对命名空间apollo的支持
- 安装到命名空间namespace: apollo中
- path: apollo-helm-chart/apollo-portal/ 是你下载的代码路径
- repoURL: xxxxxxxxx.git 是配置仓的地址
部署测试环境apollo-portal
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: apollo-service-dev
namespace: argocd
spec:
destination:
namespace: apollo
server: https://kubernetes.default.svc
project: ops-prod
source:
helm:
valueFiles:
- values-dev.yaml
path: apollo-helm-chart/apollo-service/
repoURL: https://xxxxxx.git
targetRevision: HEAD
syncPolicy:
syncOptions:
- CreateNamespace=true
automated:
selfHeal: false
prune: false
-
path 换成了apollo-service
-
为了支持多个环境,我在apollo-service下拷贝了多个value,对应多个环境的配置。
在Application中通过valueFiles来指定。
source:
helm:
valueFiles:
- values-dev.yaml
App指定helm使用不同的valueFiles请参考官方样例:
github.com/argoproj/ar…
部署生产环境apollo-portal
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: apollo-service-prod
namespace: argocd
spec:
destination:
namespace: apollo
server: https://kubernetes.default.svc
project: ops-prod
source:
helm:
valueFiles:
- values-prod.yaml
path: apollo-helm-chart-main/apollo-service/
repoURL: https://xxxxxx.git
targetRevision: HEAD
syncPolicy:
syncOptions:
- CreateNamespace=true
automated:
selfHeal: false
prune: false
四、对接Apollo
本地对接Apollo
官方文档说 Config Service部署在公有云上,注册到Meta Server的是内网地址,本地开发环境无法直接连接。
按照上文,我们在本地启动需要在启动参数中添加 -Dapollo.configService=http://xxxxxx
http://xxxxxxx 是configService暴露的LB地址。
集群业务容器对接Apollo
业务容器的deployment文件中
command: ["/bin/sh"]
args: ["-c", "set -e && java -Dapollo.configService=http://xxxxxx/ -jar app.jar"]
五、apollo使用
TODO
六、新增环境
如果不是全新部署的Apollo配置中心,比如已经使用了一段时间,这时在Apollo配置中心已经创建了不少项目以及namespace等,那么在新环境中的ApolloConfigDB中需要从其它正常运行的环境中导入必要的项目数据。
2.1.2.4 从别的环境导入ApolloConfigDB的项目数据
envs添加环境test后
argocd上同步后,apollo系统信息中并没有多出一套环境
数据serverconfig-configView.memberOnly.envs中并没有添加test
强制同步apollo-portal这个deployment
报错
ALTER TABLE apolloportaldb.serverconfig ADD DeletedAt BIGINT(20) DEFAULT 0 NOT NULL COMMENT 'Delete timestamp based on milliseconds';
七、对接LDAP
参考官网: github.com/apolloconfi…
问题1: apollo对接ldap之后,默认的项目管理员账户(apollo)就登录不了了。用ldap账户登录又管理不了项目,这个问题请问怎么办?
修改super admin的配置
superAdmin超级管理员拥有所有权限,需要谨慎设置。
如果没有接入自己公司的SSO系统的话,可以先暂时使用默认值apollo(默认用户)。等接入后,修改为实际使用的账号,多个账号以英文逗号分隔(,)。
直接在数据库中如下位置添加超级管理员
问题2:发现ldap用户能登录,但是授权的时候发现无法选择用户(即数据库 user表除了apollo用户没有其他用户)
github.com/apolloconfi… 接入 ldap 后无论是登录还是选择用户都是从 ldap 中查询的,可以看下 memberof 的配置是否正确,或者尝试先把 memberof 去掉看看
spring:
ldap:
base: "dc=example,dc=com"
username: "admin" # 配置管理员账号,用于搜索、匹配用户
password: "password"
searchFilter: "(sAMAccountName={0})" # 用户过滤器,登录的时候用这个过滤器来搜索用户
urls:
- "ldap://1.1.1.1:389"
ldap:
mapping: # 配置 ldap 属性
objectClass: "user" # ldap 用户 objectClass 配置
loginId: "sAMAccountName" # ldap 用户惟一 id,用来作为登录的 id
userDisplayName: "cn" # ldap 用户名,用来作为显示名
email: "userPrincipalName" # ldap 邮箱属性
按照官方样列,只适配了username、password、urls,就ok了!
八、长轮询报错
2022-06-20 04:48:46.730 [TID: N/A] [APP:application] [172.16.0.41] [EXT:] [Apollo-RemoteConfigLongPollService-1] WARN c.c.f.apollo.internals.RemoteConfigLongPollService - Long polling failed, will retry in 120 seconds. appId: xxxxxx-common, cluster: default, namespaces: application, long polling url: http://apollo-config-test.yyyyyy.com/notifications/v2?cluster=default&appId=xxxxxx-common&ip=172.17.5.41¬ifications=%5B%7B%22namespaceName%22%3A%22application%22%2C%22notificationId%22%3A51%7D%5D, reason: Could not complete get operation [Cause: Read timed out]
先了解下apollo的长轮询机制; cloud.tencent.com/developer/a… www.lixin.help/2021/07/16/…
Apollo客户端和服务端保持了一个长连接,从而能第一时间获得配置更新的推送. 长连接实际上是通过Http Long Polling实现的,具体做法如下:
客户端发起一个Http请求到服务端 服务端会保持住(Hold)这个连接60秒. 如果在60秒内有客户端关心的配置变化,被保持住的客户端请求会立即返回,并告知客户端有配置变化的namespace信息,客户端会据此拉取对应namespace的最新配置(注意:推只是事件,底层还是要靠拉取),为什么这样设计?因为,如果client太多,要推送的内容以及次数太多,会消耗服务器资源. 如果在60秒内没有客户端关心的配置变化,那么会返回Http状态码304给客户端. 客户端在收到服务端请求后会立即重新发起连接,回到第一步
在github上搜索源码,我们也的得到了这个长轮询超时配置DEFAULT_LONG_POLLING_TIMEOUT
我的apollo访问的路径是apollo-config-test.yyyyyy.com ---> 集群内nginx ingress controller ---> apollo-config的pod
登陆nginx ingress controller的容器, cat nginx.conf | grep ado-apollo-config-test.yyyyyyy.com -A 100 我们可以看到nginx的默认代理发送和读取的超时时间都是60S
proxy_connect_timeout 5s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
这下就知道了,nginx的60s超时肯定在apollo-hold超时之前,那么回给客户端的错误就会是
reason: Could not complete get operation [Cause: Read timed out]
那我们有两种改动方法,一个是改nginx的超时时间大于60S,一个是改apollo的"long.polling.timeout"配置小于60S。
nginx改动方法:
Ingress上添加注解
nginx.ingress.kubernetes.io/proxy-send-timeout=70
nginx.ingress.kubernetes.io/proxy-read-timeout=70
apollo改动方法:
apollo-helm-chart-main/apollo-service/values.yaml的config下添加
longPullingTimeout: 50
apollo-helm-chart-main/apollo-service/templates/deployment-configservice.yaml
{{- if .Values.configService.config.longPullingTimeout }}
long.polling.timeout = {{ .Values.configService.config.longPullingTimeout }}
{{- end }}