文档首页/ 云容器引擎 CCE/ 最佳实践/ DevOps/ 使用Argo CD实现持续交付
更新时间:2024-11-25 GMT+08:00

使用Argo CD实现持续交付

应用现状

ArgoCD是用于Kubernetes的声明型GitOps持续交付(CD)工具。ArgoCD以Git为核心,支持声明式定义各类对象,通过ArgoCD可以实现应用快速发布到Kubernetes中,并且能够根据版本标识快速跟踪和多集群部署功能,实现多个集群之间同一应用部署问题。

图1 Argo CD工作流程

本文介绍在ArgoCD中对接CCE执行持续部署的过程,并通过一个具体的示例演示该过程。

准备工作

  1. 创建一个CCE集群,且需要给节点绑定一个EIP,用于安装Argo CD服务时下载镜像。
  2. 创建一台ECS服务器,且需要绑定一个EIP,下载并配置kubectl连接集群,具体操作步骤请参见通过kubectl连接集群
  3. 在Git仓库中准备一个应用,本文使用https://gitlab.com/c8147/examples.git仓库下nginx示例应用。

安装Argo CD

  1. 在集群中安装Argo CD服务端。

    # kubectl create namespace argocd
    # kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/v2.4.0/manifests/install.yaml

    查看安装是否成功,当argocd命名空间下Pod状态都为Running时表示安装成功。

    # kubectl get pod -A
    NAMESPACE     NAME                                                READY   STATUS    RESTARTS   AGE
    argocd        argocd-application-controller-0                     1/1     Running   0          8m32s
    argocd        argocd-applicationset-controller-789457b498-6n6l5   1/1     Running   0          8m32s
    argocd        argocd-dex-server-748bddb496-bxj2c                  1/1     Running   0          8m32s
    argocd        argocd-notifications-controller-8668ffdd75-q7wdb    1/1     Running   0          8m32s
    argocd        argocd-redis-55d64cd8bf-g85np                       1/1     Running   0          8m32s
    argocd        argocd-repo-server-778d695657-skprm                 1/1     Running   0          8m32s
    argocd        argocd-server-59c9ccff4c-vd9ww                      1/1     Running   0          8m32s

    执行如下命令,将名为argocd-server的Service类型修改为NodePort。

    # kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "NodePort"}}'
    service/argocd-server patched

    查看修改结果。

    # kubectl -n argocd get svc
    NAME                                      TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
    argocd-applicationset-controller          ClusterIP   10.247.237.53    <none>        7000/TCP,8080/TCP            18m
    argocd-dex-server                         ClusterIP   10.247.164.111   <none>        5556/TCP,5557/TCP,5558/TCP   18m
    argocd-metrics                            ClusterIP   10.247.138.98    <none>        8082/TCP                     18m
    argocd-notifications-controller-metrics   ClusterIP   10.247.239.85    <none>        9001/TCP                     18m
    argocd-redis                              ClusterIP   10.247.220.90    <none>        6379/TCP                     18m
    argocd-repo-server                        ClusterIP   10.247.1.142     <none>        8081/TCP,8084/TCP            18m
    argocd-server                             NodePort    10.247.57.16     <none>        80:30118/TCP,443:31221/TCP   18m
    argocd-server-metrics                     ClusterIP   10.247.206.190   <none>        8083/TCP                     18m

    通过argocd-server Service访问Argo CD,直接使用节点IP:端口号访问即可。例如本示例中,端口号为31221

    登录用户名为admin,密码可使用如下命令获取。

    # kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d;echo

  2. 在ECS服务器上安装Argo CD客户端。

    # wget https://github.com/argoproj/argo-cd/releases/download/v2.4.0/argocd-linux-amd64
    # cp argocd-linux-amd64 /usr/local/bin/argocd
    # chmod +x /usr/local/bin/argocd

    执行如下命令,如果显示如下则说明安装正确。

    # argocd version
    argocd: v2.4.0+91aefab
      BuildDate: 2022-06-10T17:44:14Z
      GitCommit: 91aefabc5b213a258ddcfe04b8e69bb4a2dd2566
      GitTreeState: clean
      GoVersion: go1.18.3
      Compiler: gc
      Platform: linux/amd64
    FATA[0000] Argo CD server address unspecified

使用Argo CD部署应用

  1. 在Argo CD中添加CCE集群。

    1. 登录ECS服务器。
    2. 查看kubectl上下文配置。
      # kubectl config get-contexts
      CURRENT   NAME       CLUSTER           AUTHINFO   NAMESPACE
      *         internal   internalCluster   user 
    3. 登录Argo服务端,用户名为admin,服务端地址及密码可从1中获取。如果ECS服务器与集群处于同一VPC下,此处节点IP可使用私网IP。
      argocd login <节点IP:端口号> --username admin --password <password>

      回显示例如下:

      # argocd login 192.168.0.52:31221 --username admin --password ******
      WARNING: server certificate had error: x509: cannot validate certificate for 192.168.0.52 because it doesn't contain any IP SANs. Proceed insecurely (y/n)? y
      'admin:login' logged in successfully
      Context '192.168.0.52:31221' updated
    4. 添加CCE集群。
      # argocd cluster add internal --kubeconfig /root/.kube/config --name argocd-01

      上面命令中,internal1.b中查出来的上下文名称,/root/.kube/config是kubectl配置文件所在路径,argocd-01是集群在Argo CD中定义的名称。

      回显如下。

      WARNING: This will create a service account `argocd-manager` on the cluster referenced by context `internal` with full cluster level privileges. Do you want to continue [y/N]? y
      INFO[0002] ServiceAccount "argocd-manager" already exists in namespace "kube-system" 
      INFO[0002] ClusterRole "argocd-manager-role" updated    
      INFO[0002] ClusterRoleBinding "argocd-manager-role-binding" updated 
      Cluster "https://192.168.0.113:5443"" added

      登录Argo CD界面,可以看到添加成功。

  2. 连接Git仓库。

    # argocd repo add https://gitlab.com/c8147/examples.git --username <username>  --password <password>

    https://gitlab.com/c8147/examples.git 为仓库地址,<username><password>为仓库登录名和密码,请替换为实际取值。

    回显如下。

    Repository 'https://gitlab.com/c8147/cidemo.git' added

    登录Argo CD界面,可以看到添加成功。

  3. 在Argo CD中添加应用。

    # argocd app create nginx --repo https://gitlab.com/c8147/examples.git  --path nginx --dest-server https://192.168.0.113:5443 --dest-namespace default

    https://gitlab.com/c8147/examples.git 为仓库地址,nginx 为仓库路径,https://192.168.0.113:5443 为要部署集群的地址,default 为命名空间。

    本例中,gitlab仓库下nginx目录下为nginx应用的YAML文件,包含一个Deployment和一个Service。

    创建后可以查看应用。

    # argocd app list
    NAME   CLUSTER                     NAMESPACE  PROJECT  STATUS     HEALTH   SYNCPOLICY  CONDITIONS  REPO                                   PATH   TARGET
    nginx  https://192.168.0.113:5443  default    default  OutOfSync  Missing  <none>      <none>      https://gitlab.com/c8147/examples.git  nginx  

    登录Argo CD界面,可以看到添加成功。

  4. 同步应用。

    同步应用及将应用部署到指定集群。执行如下命令。

    # argocd app sync nginx
    TIMESTAMP                  GROUP        KIND   NAMESPACE                  NAME    STATUS    HEALTH        HOOK  MESSAGE
    2022-10-24T12:15:10+08:00            Service     default                 nginx  OutOfSync  Missing              
    2022-10-24T12:15:10+08:00   apps  Deployment     default                 nginx  OutOfSync  Missing              
    2022-10-24T12:15:10+08:00            Service     default                 nginx    Synced  Healthy              
    2022-10-24T12:15:10+08:00            Service     default                 nginx    Synced   Healthy              service/nginx created
    2022-10-24T12:15:10+08:00   apps  Deployment     default                 nginx  OutOfSync  Missing              deployment.apps/nginx created
    2022-10-24T12:15:10+08:00   apps  Deployment     default                 nginx    Synced  Progressing              deployment.apps/nginx created
    
    Name:               nginx
    Project:            default
    Server:             https://192.168.0.113:5443
    Namespace:          default
    URL:                https://192.168.0.178:32459/applications/nginx
    Repo:               https://gitlab.com/c8147/examples.git
    Target:             
    Path:               nginx
    SyncWindow:         Sync Allowed
    Sync Policy:        <none>
    Sync Status:        Synced to  (dd15906)
    Health Status:      Progressing
    
    Operation:          Sync
    Sync Revision:      dd1590679856bd9288036847bdc4a5556c169267
    Phase:              Succeeded
    Start:              2022-10-24 12:15:10 +0800 CST
    Finished:           2022-10-24 12:15:10 +0800 CST
    Duration:           0s
    Message:            successfully synced (all tasks run)
    
    GROUP  KIND        NAMESPACE  NAME   STATUS  HEALTH       HOOK  MESSAGE
           Service     default    nginx  Synced  Healthy            service/nginx created
    apps   Deployment  default    nginx  Synced  Progressing        deployment.apps/nginx created

    在CCE集群中可以查看到部署了一个nginx工作负载和一个service。

    # kubectl get deployment
    NAME    READY   UP-TO-DATE   AVAILABLE   AGE
    nginx   1/1     1            1           2m47s
    # kubectl get svc
    NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
    kubernetes   ClusterIP   10.247.0.1      <none>        443/TCP   5h12m
    nginx        ClusterIP   10.247.177.24   <none>        80/TCP    2m52s

    登录Argo CD界面,可以看到应用状态变为sync。

使用Argo Rollouts实现灰度发布

Argo Rollouts是一个Kubernetes控制器,可实现高级发布功能,例如蓝绿发布、灰度(金丝雀)发布、渐进式交付等功能。

  1. 在集群中安装argo-rollouts服务端。

    # kubectl create namespace argo-rollouts
    # kubectl apply -f https://github.com/argoproj/argo-rollouts/releases/download/v1.2.2/install.yaml -n argo-rollouts

    如果应用部署在多个集群,需要在每个目标集群都安装Argo Rollouts服务端。

  2. 在ECS服务器上安装argo-rollouts的kubectl插件。

    # curl -LO https://github.com/argoproj/argo-rollouts/releases/download/v1.2.2/kubectl-argo-rollouts-linux-amd64
    # chmod +x ./kubectl-argo-rollouts-linux-amd64
    # sudo mv ./kubectl-argo-rollouts-linux-amd64 /usr/local/bin/kubectl-argo-rollouts

    执行以下命令来验证插件是否安装成功:

    # kubectl argo rollouts version
    kubectl-argo-rollouts: v1.2.2+22aff27
      BuildDate: 2022-07-26T17:24:43Z
      GitCommit: 22aff273bf95646e0cd02555fbe7d2da0f903316
      GitTreeState: clean
      GoVersion: go1.17.6
      Compiler: gc
      Platform: linux/amd64

  3. 准备两个示例nginx应用镜像,版本分别为v1和v2,欢迎页分别显示为nginx:v1!nginx:v2!

    创建一个Dockerfile文件,其中v1版本的Dockerfile内容如下,v2版本将nginx:v1!替换为nginx:v2!即可。
    FROM nginx:latest
    RUN echo '<h1>nginx:v1!</h1>' > /usr/share/nginx/html/index.html

    制作v1版本镜像:

    docker build -t nginx:v1 .

    登录SWR,并将镜像上传至SWR镜像仓库,具体操作步骤请参见客户端上传镜像。其中container为SWR中的组织名,请根据实际填写。

    docker login -u {region}@xxx -p xxx swr.{region}.myhuaweicloud.com
    docker tag nginx:v1 swr.cn-east-3.myhuaweicloud.com/container/nginx:v1
    docker push swr.cn-east-3.myhuaweicloud.com/container/nginx:v1

    使用相同的方法制作v2版本镜像并上传至镜像仓库。

  4. 部署一个Rollout,本文中的示例会先将20%的流量发送到新版本实例上,然后手动继续更新,最后在升级的剩余时间内逐渐自动增大流量。

    创建一个rollout-canary.yaml文件,示例如下:

    apiVersion: argoproj.io/v1alpha1
    kind: Rollout
    metadata:
      name: rollout-canary  # 自定义的Rollout名称
    spec:
      replicas: 5  # 定义5个副本
      strategy:  # 定义升级策略
        canary:   # 灰度(金丝雀)发布
          steps:  # 发布的节奏(每个阶段可以设置持续时间)
          - setWeight: 20 #流量权重
          - pause: {}  # 不填写暂停时间会一直暂停
          - setWeight: 40
          - pause: {duration: 10}  # 暂停时间,单位默认秒
          - setWeight: 60
          - pause: {duration: 10}
          - setWeight: 80
          - pause: {duration: 10}
      revisionHistoryLimit: 2  
      selector:
        matchLabels:
          app: rollout-canary
      template:
        metadata:
          labels:
            app: rollout-canary
        spec:
          containers:
          - name: rollout-canary
            image: swr.cn-east-3.myhuaweicloud.com/container/nginx:v1  #SWR中提前上传的镜像,版本号为v1
            ports:
            - name: http
              containerPort: 80
              protocol: TCP
            resources:
              requests:
                memory: 32Mi
                cpu: 5m
          imagePullSecrets:
            - name: default-secret
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: rollout-canary
    spec:
      type: NodePort
      ports:
      - port: 80
        targetPort: 80
        nodePort: 31270  #自定义节点端口号
      selector:
        app: rollout-canary

    创建上面的两个资源对象:

    kubectl apply -f rollout-canary.yaml

    Rollout在初始创建时不会触发版本升级,设置的发布策略不会生效,副本数会立即扩展到100%。

  5. Argo Rollouts提供了Rollout以及相关资源对象的可视化,并展示实时状态变化,可以通过插件的 get rollout --watch 命令观察部署过程,比如:

    kubectl argo rollouts get rollout rollout-canary --watch

    其中rollout-canary为自定义的Rollout名称。

  6. 创建完成后,可通过节点EIP:端口号访问nginx应用,其中端口号在rollout-canary.yaml文件中的Service资源中指定,本例中端口号为31270。
  7. 执行版本更新,使用v2版本的镜像更新上面的应用:

    kubectl argo rollouts set image rollout-canary rollout-canary=swr.cn-east-3.myhuaweicloud.com/container/nginx:v2

    在版本更新期间,控制器将通过更新策略中定义的步骤进行。本示例中在发布的第一步中设置了20%的流量权重,并一直暂停,直到用户取消或继续发布。可通过以下命令查看详细过程,该发布正处于暂停状态。

    kubectl argo rollouts get rollout rollout-canary --watch

    可查看5个副本中有1个运行新版本,其余4个仍然运行旧版本,即setWeight: 20中所定义的20%的权重。

    如果执行以下命令进行多次访问,响应结果中大概20%为v2版本的响应。

    for i in {1..10}; do curl <节点EIP:端口号>; done;

    验证结果如下:

    <h1>nginx:v2!</h1>
    <h1>nginx:v1!</h1>
    <h1>nginx:v1!</h1>
    <h1>nginx:v1!</h1>
    <h1>nginx:v1!</h1>
    <h1>nginx:v1!</h1>
    <h1>nginx:v1!</h1>
    <h1>nginx:v1!</h1>
    <h1>nginx:v2!</h1>
    <h1>nginx:v1!</h1>

  8. 手动继续执行版本更新。

    kubectl argo rollouts promote rollout-canary

    本示例中,剩余的步骤是完全自动化的,直到完全过渡到新版本。通过以下命令查看详细过程,该Rollout会逐渐完成全部流量切换。

    kubectl argo rollouts get rollout rollout-canary --watch

  9. 如需使用更多Argo Rollouts功能,例如终止发布、回滚发布等,您可使用以下命令查询:

    kubectl argo rollouts --help