
# 使用Argo CD实现持续交付
#### 应用现状
[ArgoCD](https://github.com/argoproj/argo-cd)是用于Kubernetes的声明型GitOps持续交付（CD）工具。ArgoCD以Git为核心，支持声明式定义各类对象，通过ArgoCD可以实现应用快速发布到Kubernetes中，并且能够根据版本标识快速跟踪和多集群部署功能，实现多个集群之间同一应用部署问题。
图1Argo CD工作流程   
![](https://support.huaweicloud.com/bestpractice-cce/zh-cn_image_0000001383776562.png "点击放大")
本文介绍在ArgoCD中对接CCE执行持续部署的过程，并通过一个具体的示例演示该过程。
#### 准备工作
1. 创建一个CCE集群，且需要给节点绑定一个EIP，用于安装Argo CD服务时下载镜像。
2. 创建一台ECS服务器，且需要绑定一个EIP，下载并配置kubectl连接集群，具体操作步骤请参见[通过kubectl连接集群](https://support.huaweicloud.com/usermanual-cce/cce_10_0107.html)。
3. 在Git仓库中准备一个应用，本文使用<https://gitlab.com/c8147/examples.git>仓库下nginx示例应用。
 
#### 安装Argo CD
1. 在集群中安装Argo CD服务端，本文使用[v2.4.0版本](https://raw.githubusercontent.com/argoproj/argo-cd/v2.4.0/manifests/install.yaml)。
   
   ```
   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
   ```
   
   
2. 执行如下命令，将名为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
   ```
   
   
3. 通过argocd-server Service访问Argo CD，直接使用**节点IP:端口号** 访问即可。例如本示例中，端口号为**31221** 。
   
   ![](https://support.huaweicloud.com/bestpractice-cce/zh-cn_image_0000001433386221.png "点击放大")
   登录用户名为admin，密码可使用如下命令获取。
   ```
   kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d;echo
   ```
   
   
4. 在ECS服务器上安装Argo CD客户端，本文使用[2.4.0版本](https://github.com/argoproj/argo-cd/releases/download/v2.4.0/argocd-linux-amd64)。
   
   ```
   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>
      ```
      回显示例如下：
      ```
      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
      ```
      上面命令中，***internal*** 是[1.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界面，可以看到添加成功。
      ![](https://support.huaweicloud.com/bestpractice-cce/zh-cn_image_0000001383477362.png "点击放大")
      
   
   
   
   
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界面，可以看到添加成功。
   ![](https://support.huaweicloud.com/bestpractice-cce/zh-cn_image_0000001433400237.png "点击放大")
   
   
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界面，可以看到添加成功。
   ![](https://support.huaweicloud.com/bestpractice-cce/zh-cn_image_0000001433726093.png "点击放大")
   
   
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
   ```
   
   
5. 在CCE集群中可以查看到部署了一个Nginx工作负载和一个Service。 
   1. 查看工作负载：
      ```
      kubectl get deployment
      ```
      回显如下：
      ```
      NAME    READY   UP-TO-DATE   AVAILABLE   AGE
      nginx   1/1     1            1           2m47s
      ```
      
   
   2. 查看Service：
      ```
      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
      ```
      
   
   
   
   
6. 登录Argo CD界面，可以看到应用状态变为sync。 
   ![](https://support.huaweicloud.com/bestpractice-cce/zh-cn_image_0000001433607089.png "点击放大")
   
   
 
#### 使用Argo Rollouts实现灰度发布
[Argo Rollouts](https://github.com/argoproj/argo-rollouts)是一个Kubernetes控制器，可实现高级发布功能，例如蓝绿发布、灰度（金丝雀）发布、渐进式交付等功能。
1. 在集群中安装argo-rollouts服务端，本文使用[v1.2.2版本](https://github.com/argoproj/argo-rollouts/releases/download/v1.2.2/install.yaml)。
   
   ```
   kubectl create namespace argo-rollouts
   kubectl apply -f https://github.com/argoproj/argo-rollouts/releases/download/v1.2.2/install.yaml -n argo-rollouts
   ```
   ![](https://support.huaweicloud.com/bestpractice-cce/public_sys-resources/note_3.0-zh-cn.png)
   如果应用部署在多个集群，需要在每个目标集群都安装Argo Rollouts服务端。
   
   
2. 在ECS服务器上安装argo-rollouts的kubectl插件，本文使用[v1.2.2版本](https://github.com/argoproj/argo-rollouts/releases/download/v1.2.2/kubectl-argo-rollouts-linux-amd64)。
   
   ```
   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镜像仓库，具体操作步骤请参见[客户端上传镜像](https://support.huaweicloud.com/usermanual-swr/swr_01_0011.html)。其中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
   ```
   ![](https://support.huaweicloud.com/bestpractice-cce/public_sys-resources/note_3.0-zh-cn.png)
   Rollout在初始创建时不会触发版本升级，设置的发布策略不会生效，副本数会立即扩展到100%。
   
   
5. Argo Rollouts提供了Rollout以及相关资源对象的可视化，并展示实时状态变化，可以通过插件的 **get rollout --watch** 命令观察部署过程，比如：
   
   ```
   kubectl argo rollouts get rollout rollout-canary --watch
   ```
   其中*rollout-canary*为自定义的Rollout名称。
   ![](https://support.huaweicloud.com/bestpractice-cce/zh-cn_image_0000001505217617.png "点击放大")
   
   
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%的权重。
   ![](https://support.huaweicloud.com/bestpractice-cce/zh-cn_image_0000001455777146.png "点击放大")
   如果执行以下命令进行多次访问，响应结果中大概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
   ```
   ![](https://support.huaweicloud.com/bestpractice-cce/zh-cn_image_0000001455937370.png "点击放大")
   
   
9. 如需使用更多Argo Rollouts功能，例如终止发布、回滚发布等，您可使用以下命令查询： 
   ```
   kubectl argo rollouts --help
   ```
   
   
 
