手把手带你玩转ArgoCD --- 部署 Apollo 配置中心

1,634 阅读6分钟

K8S部署N个微服务,每个微服务都有很多配置,需要一个配置中心来集中管理这些配置。于是采用apollo来作为配置中心。本文介绍如何使用ArgoCD在K8S集群中部署Apollo配置中心。

image.png

image.png

一、环境

  1. 已经搭建了多个K8S集群,一个集群对应一个环境
  2. 集群中安装了ArgoCD
  3. 一个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配置

image.png

  • apollo-service对接mysql配置

image.png

部署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,对应多个环境的配置。

image.png

在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 image.png

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后

image.png

argocd上同步后,apollo系统信息中并没有多出一套环境

image.png

数据serverconfig-configView.memberOnly.envs中并没有添加test

image.png

强制同步apollo-portal这个deployment

image.png

报错 image.png

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的配置

github.com/ctripcorp/a…

superAdmin超级管理员拥有所有权限,需要谨慎设置。

如果没有接入自己公司的SSO系统的话,可以先暂时使用默认值apollo(默认用户)。等接入后,修改为实际使用的账号,多个账号以英文逗号分隔(,)。

直接在数据库中如下位置添加超级管理员 image.png

问题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了!

八、长轮询报错

image.png

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&notifications=%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

image.png

我的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 }}

参考文章

# .NET Core + K8S + Apollo 玩转配置中心