使用Argo CD实现持续交付
应用现状
ArgoCD是用于Kubernetes的声明型GitOps持续交付(CD)工具。ArgoCD以Git为核心,支持声明式定义各类对象,通过ArgoCD可以实现应用快速发布到Kubernetes中,并且能够根据版本标识快速跟踪和多集群部署功能,实现多个集群之间同一应用部署问题。
本文介绍在ArgoCD中对接CCE执行持续部署的过程,并通过一个具体的示例演示该过程。
准备工作
- 创建一个CCE集群,且需要给节点绑定一个EIP,用于安装Argo CD服务时下载镜像。
- 创建一台ECS服务器,且需要绑定一个EIP,下载并配置kubectl连接集群,具体操作步骤请参见通过kubectl连接集群。
- 在Git仓库中准备一个应用,本文使用https://gitlab.com/c8147/examples.git仓库下nginx示例应用。
安装Argo CD
- 在集群中安装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
- 在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部署应用
- 在Argo CD中添加CCE集群。
- 登录ECS服务器。
- 查看kubectl上下文配置。
# kubectl config get-contexts CURRENT NAME CLUSTER AUTHINFO NAMESPACE * internal internalCluster user
- 登录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
- 添加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界面,可以看到添加成功。
- 连接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界面,可以看到添加成功。
- 在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界面,可以看到添加成功。
- 同步应用。
同步应用及将应用部署到指定集群。执行如下命令。
# 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控制器,可实现高级发布功能,例如蓝绿发布、灰度(金丝雀)发布、渐进式交付等功能。
- 在集群中安装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服务端。
- 在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
- 准备两个示例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版本镜像并上传至镜像仓库。
- 部署一个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%。
- Argo Rollouts提供了Rollout以及相关资源对象的可视化,并展示实时状态变化,可以通过插件的 get rollout --watch 命令观察部署过程,比如:
kubectl argo rollouts get rollout rollout-canary --watch
其中rollout-canary为自定义的Rollout名称。
- 创建完成后,可通过节点EIP:端口号访问nginx应用,其中端口号在rollout-canary.yaml文件中的Service资源中指定,本例中端口号为31270。
- 执行版本更新,使用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>
- 手动继续执行版本更新。
kubectl argo rollouts promote rollout-canary
本示例中,剩余的步骤是完全自动化的,直到完全过渡到新版本。通过以下命令查看详细过程,该Rollout会逐渐完成全部流量切换。
kubectl argo rollouts get rollout rollout-canary --watch
- 如需使用更多Argo Rollouts功能,例如终止发布、回滚发布等,您可使用以下命令查询:
kubectl argo rollouts --help