记录日常工作关于系统运维,虚拟化云计算,数据库,网络安全等各方面问题。

ArgoCD简介

Argo CD是用于Kubernetes的声明性GitOps持续交付工具,应用程序定义,配置和环境应为声明性的,并应受版本控制,应用程序部署和生命周期管理应该是自动化、可审核且易于理解。

Argo CD遵循GitOps模式,该模式使用Git仓库作为定义所需应用程序状态的真实来源。

Argo CD可在指定的目标环境中自动部署所需的应用程序状态,应用程序部署可以在Git提交时跟踪对分支,标签的更新,或固定到清单的特定版本。

官网:https://argoproj.github.io/

ArgoCD架构图:
在这里插入图片描述

Argo CD被实现为kubernetes控制器,该控制器持续监视正在运行的应用程序,并将当前的活动状态与所需的目标状态(在Git存储库中指定)进行比较。

当已部署应用程序的运行状态偏离目标状态时将被argoCD视为OutOfSync。

Argo CD报告并可视化差异,同时提供了自动或手动将实时状态同步回所需目标状态的功能。在Git存储库中对所需目标状态所做的任何修改都可以自动应用并同步到指定的目标环境中。

ArgoCD支持的Kubernetes 配置清单包括helm charts、kustomize或纯YAML/json文件等。

本篇文章涉及内容:

  • 使用kubesphere devops实现CI部分, CD部分由argoCD完成;
  • ArgoCD持续监测git仓库某个目录下yaml文件变动,自动将yaml文件部署到k8s集群;
  • ArgoCD持续监测harbor镜像仓库某个镜像tag变动,自动将最新镜像部署到k8s集群。

基本原理图:
在这里插入图片描述

准备git代码仓库

准备2个git仓库,一个源码仓库,一个yaml文件仓库,源码和yaml文件分离。
在这里插入图片描述

源码仓库可参考以下链接,离线环境原因,这里选择第二个示例spring-demo:
https://github.com/kubesphere/devops-java-sample
https://github.com/willzhang/spring-demo

yaml文件仓库可参考以下链接,这里命名为argocd-gitops:
https://github.com/argoproj/argocd-example-apps

yaml仓库下创建javademo目录,并创建2个简单的yaml文件:

[root@jenkins git]# tree argocd-gitops/
argocd-gitops/
├── javademo
│   ├── javademo-deployment.yaml
│   └── javademo-svc.yaml

javademo-deployment.yaml示例,当前镜像tag可随意指定,执行CI时会实时替换该参数:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: javademo
spec:
  replicas: 1
  revisionHistoryLimit: 3
  selector:
    matchLabels:
      app: javademo
  template:
    metadata:
      labels:
        app: javademo
    spec:
      containers:
      - image: 10.39.140.196:8081/apps/javademo:replace
        name: javademo
        ports:
        - containerPort: 8080

javademo-svc.yaml

apiVersion: v1	
kind: Service	
metadata:	
  name: javademo
spec:
  type: NodePort
  ports:	
  - port: 8012 
    targetPort: 8080 
  selector:	
    app: javademo

部署ArgoCD

argocd有多种部署方式,可以直接部署yaml文件

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

这里使用helm方式部署,可直接指定argocd server service类型nodePort:

helm repo add argo https://argoproj.github.io/argo-helm

helm install argocd \
  --namespace=argocd --create-namespace \
  --set server.service.type=NodePort \
  argo/argo-cd

查看运行的pod

[root@master ~]# kubectl -n argocd get pods
NAME                                             READY   STATUS    RESTARTS   AGE
argocd-application-controller-5db8c6f8f9-qnmtr   1/1     Running   0          8h
argocd-dex-server-84b5cbfbc9-fc7rf               1/1     Running   0          8h
argocd-redis-7c7c79dcd9-hjhgr                    1/1     Running   0          8h
argocd-repo-server-5fb9cbb945-9xmc7              1/1     Running   0          8h
argocd-server-8d8cb6488-pjwt4                    1/1     Running   0          8h

如果使用kubesphere部署argocd,首先需要配置argocd helm仓库,进入企业空间,选择应用模板上传离线helm chart包,或在应用仓库配置公网helm repo地址。

完成后进入项目,点击部署新应用,选择argocd helm chart进行部署即可:
在这里插入图片描述

安装ArgoCD CLI

要与ArgoCD API Server进行交互,我们需要安装CLI命令:

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

argocd version

如果上面argocd使用yaml方式部署,修改serivce类型为nodeport,以便访问Argo CD API Server

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

查看argocd server service,记录nodeport信息:

[root@master ~ ]# kubectl -n argocd get svc
NAME                    TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
argocd-dex-server       ClusterIP   10.99.232.27     <none>        5556/TCP,5557/TCP,5558/TCP   5d
argocd-metrics          ClusterIP   10.107.37.4      <none>        8082/TCP                     5d
argocd-redis            ClusterIP   10.106.160.6     <none>        6379/TCP                     5d
argocd-repo-server      ClusterIP   10.100.101.100   <none>        8081/TCP,8084/TCP            5d
argocd-server           NodePort    10.106.141.243   <none>        80:31195/TCP,443:32079/TCP   5d
argocd-server-metrics   ClusterIP   10.109.81.234    <none>        8083/TCP                     5d

argocd默认登录用户为admin,初始密码为argocd-server pod名称,获取pod名称

podName=`kubectl get pods -n argocd -l app.kubernetes.io/name=argocd-server -o name | cut -d'/' -f 2`

使用argocd CLI登录,以nodeIP和nodePort作为argocd server登录地址:

argocd login 10.39.140.248:31195 --username admin --password $podName

修改默认密码

argocd account update-password \
  --current-password $podName \
  --new-password argocd@123

浏览器登录argocd UI

https://10.39.140.248:31195

部署ArgoCD应用

登陆Argocd UI后,选择NEW APP创建application,选择EDIT AS AYML
在这里插入图片描述
粘贴以下内容,SAVE后点击左上CREATE,当然也可以直接使用kubectl apply命令执行以下内容,效果相同。

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: javademo
  namespace: argocd
  finalizers:
    - resources-finalizer.argocd.argoproj.io
spec:
  project: default
  source:
    path: javademo
    repoURL: http://10.39.140.196:10080/gogs/argocd-gitops.git
    targetRevision: HEAD
  destination:
    namespace: apps
    server: https://kubernetes.default.svc	
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
      allowEmpty: false
    syncOptions:
    - Validate=false
    - CreateNamespace=true
    retry:
      limit: 5
      backoff:
        duration: 5s
        factor: 2
        maxDuration: 3m

参数说明:

  • metadata字段:指定了应用名称,命名空间必须指定argocd,添加finalizers字段可在删除应用时级联删除相关k8s资源;
  • source字段:指定了yaml文件所在git仓库URL,及要监测的yaml文件存放目录,该目录下文件有任何变更argocd都会自动将其更新部署到k8s集群;
  • destination字段:指定监测的yaml文件要部署到哪个k8s集群及哪个命名空间下;
  • syncPolicy字段:指定自动同步策略和频率,不配置时需要手动触发同步。

另外如果使用私有git仓库,需要创建凭证,这里的凭证是argocd访问yaml文件git仓库的凭证:
在这里插入图片描述
等效的argocd cli命令:

argocd repo add http://10.39.140.196:10080/gogs/argocd-gitops --username gogs --password xxxxxx

创建后argocd会自动将git仓库javademo目录下的yaml文件部署到k8s集群,此时应用无法正常启动,因为yaml文件中的镜像tag还不存在,拉取镜像会失败:
在这里插入图片描述
也可以使用argocd CLI查看部署的应用

[root@master ~]# argocd app get javademo
Name:               javademo
Project:            default
Server:             https://kubernetes.default.svc
Namespace:          apps
URL:                https://10.39.140.248:31195/applications/javademo
Repo:               http://10.39.140.196:10080/gogs/argocd-gitops.git
Target:             HEAD
Path:               javademo
SyncWindow:         Sync Allowed
Sync Policy:        Automated (Prune)
Sync Status:        Synced to HEAD (1b96380)
Health Status:      Progressing

GROUP  KIND        NAMESPACE  NAME      STATUS  HEALTH       HOOK  MESSAGE
       Service     apps       javademo  Synced  Healthy            service/javademo unchanged
apps   Deployment  apps       javademo  Synced  Progressing        deployment.apps/javademo unchanged

在kubesphere UI查看pod状态,一直在重试拉取镜像:
在这里插入图片描述

使用kubectl命令查看,状态为ImagePullBackOff :

[root@master ~]# kubectl -n apps get pods
NAME                       READY   STATUS             RESTARTS   AGE
javademo-64d46bff8-6dgjn   0/1     ImagePullBackOff   0          13m

[root@master ~]# kubectl -n apps get svc
NAME       TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
javademo   ClusterIP   10.111.56.180   <none>        8012/TCP   33m

kubesphere创建流水线

创建CI流水线,使用kubesphere devops完成源码编译、镜像构建并推送到harbor仓库,最后以git commit方式更新yaml仓库中image字段。

由于此时argoCD持续监测yaml仓库配置文件变动,当CI部分执行git push时便会触发argoCD更新yaml文件到k8s集群。

在kubesphere devops工程下创建一条空流水线,命名为javademo,进入流水线,选择编辑Jenkinsfile,复制以下内容:

pipeline {
   

    environment {
   
        GIT_URL='http://10.39.140.196:10080/gogs/spring-demo.git'
        GIT_CREDENTIAL_ID = 'git-id'
        GIT_BRANCH = 'master'
        REGISTRY = '10.39.140.196:8081/apps/javademo'
        REGISTRY_CREDENTIAL_ID = 'harbor-id'
    }

    agent {
   
        node {
   
            label 'maven'
        }
    }

    stages {
   
        
        stage('SCM Checkout') {
   
            steps {
   
                git branch: "${GIT_BRANCH}", credentialsId: "${GIT_CREDENTIAL_ID}", url: "${GIT_URL}"
            }
        }
        
        stage('source build') {
   
            steps {
   
                container('maven') {
   
                    sh 'mvn clean package'
                
                }
            }
        }

        stage('docker build & push') {
   
            steps {
   
                script {
   
                    env.COMMIT_ID = sh(returnStdout: true, script: "git log -n 1 --pretty=format:'%h'").trim()
                    env.TIMESTRAP = sh(returnStdout: true, script: 'date +%Y%m%d%H%M%S').trim()
                    env.DOCKER_TAG = "dev_${TIMESTRAP}_${COMMIT_ID}_${BUILD_NUMBER}"
                }
                container('maven') {
   
                    withCredentials([usernamePassword(passwordVariable : 'DOCKER_PASSWORD' ,usernameVariable : 'DOCKER_USERNAME' ,credentialsId : "$REGISTRY_CREDENTIAL_ID" ,)]) {
   
                        sh 'docker build -t $REGISTRY:$DOCKER_TAG .'
                        sh 'echo "$DOCKER_PASSWORD" | docker login $REGISTRY -u "$DOCKER_USERNAME" --password-stdin'
                        sh 'docker push $REGISTRY:$DOCKER_TAG'
                    }
                }
            }
        }

        stage('update docker tag') {
   
            environment {
   
                BUILD_USER = 'admin'
                BUILD_USER_EMAIL = 'admin@argocd.com'
                YAML_REPO_URL='http://${username}:${password}@10.39.140.196:10080/gogs/argocd-gitops.git'
            }

            steps {
   
                withCredentials([usernamePassword(passwordVariable : 'password' ,usernameVariable : 'username' ,credentialsId : "$GIT_CREDENTIAL_ID" ,)]) {
   
                    sh """ git config --global user.name "$BUILD_USER" git config --global user.email "$BUILD_USER_EMAIL" git clone ${YAML_REPO_URL} && cd argocd-gitops sed -i "s#$REGISTRY.*#${REGISTRY}:${DOCKER_TAG}#g" javademo/javademo-deployment.yaml git add -A && git commit -m "update tag: ${DOCKER_TAG}" && git push ${YAML_REPO_URL} """
                }
            }
        }
    }
}

注意修改相关参数,流水线中引用了2个凭证:

  • GIT_CREDENTIAL_ID为内网gogs git仓库账号密码
  • REGISTRY_CREDENTIAL_ID为harbor仓库账号密码

运行流水线前需要在devops工程下提前创建好相关凭证,后续需要在jenkinsfile中引用。
在这里插入图片描述
最终流水线如下,点击运行,等待流水线执行完成,查看状态为成功:
在这里插入图片描述
查看流水线构建日志,可以看到执行了以下过程,其中最后update docker tag步骤,执行了2个关键操作,sed命令替换镜像tag,然后执行git push更新yaml仓库。
在这里插入图片描述
查看推送到harbor仓库的镜像:
在这里插入图片描述

ArgoCD监测到yaml文件变更后更新至k8s集群:
在这里插入图片描述

ArgoCD UI查看使用的镜像:
在这里插入图片描述

登录kubesphere UI查看应用状态为运行中:
在这里插入图片描述
在git仓库直接修改yaml文件配置,同样能够触发argocd同步,例如将service类型改为nodePort:
在这里插入图片描述
等待argoCD自动同步配置更新到k8s集群,浏览器以nodeport方式访问java web应用:
在这里插入图片描述

部署Argo CD Image Updater

上面演示了基于git仓库变更作为应用部署的事实来源,下面演示另一种方式,以镜像tag变更作为应用部署的事实来源。argocd提供了Argo CD Image Updater小工具,用于实现该操作。

argo cd image updater是一种自动更新由Argo CD管理的Kubernetes工作负载容器镜像的工具。

该工具目前还在开发中,并且有以下特性和局限性:

  • 只能更新由Argo CD管理并由HelmKustomize工具生成的应用程序的镜像;
  • 对广泛使用的容器仓库的默认支持:dockerhub、harbor私有镜像仓库等;
  • 能够使用匹配器功能过滤镜像仓库返回的标签列表;
  • 镜像拉取secrets必须存在于Argo CD Image Updater在其中运行(或可以访问)的同一Kubernetes群集中。当前不可能从其他集群中获取这些secrets。
  • 在当前版本中,Argo CD Image Updater不会将任何更改写回到Git存储库。

官方文档:
https://argocd-image-updater.readthedocs.io/en/stable/

Argo CD Image Updater部署略显繁琐,部署操作如下:

1、在argo cd中创建本地用户

创建Argo CD镜像更新程序需要访问Argo CD API Server的凭据,使用一个image-updater具有适当API权限的帐户,将以下用户定义添加到argocd-cm:

# kubectl -n argocd edit cm argocd-cm
data:
  accounts.image-updater: apiKey

为用户创建访问令牌,将令牌的值复制到某个地方,稍后将需要它。

argocd account generate-token --account image-updater --id image-updater

2、在Argo CD中授予RBAC权限

image-updater用户配置适当的RBAC权限,Argo CD Image Updater需要应用程序的updateget权限。

# kubectl -n argocd edit cm argocd-rbac-cm 
data:
  policy.default: role:readonly
  policy.csv: | p, role:image-updater, applications, get, */*, allow p, role:image-updater, applications, update, */*, allow g, image-updater, role:image-updater

3、 安装Argo CD Image Updater

yaml文件下载:https://github.com/argoproj-labs/argocd-image-updater/tree/master/manifests

kubectl create ns argocd-image-updater
kubectl apply -n argocd-image-updater -f manifests/install.yaml

4、 配置镜像仓库

即使您不打算使用私有镜像仓库,您也需要至少配置一个empty registries.conf

# kubectl -n argocd-image-updater edit cm argocd-image-updater-config 
data:
  registries.conf: ""

没有此条目argocd-image-updater pod将无法启动。

如果使用私有镜像仓库可参考以下配置,以harbor镜像仓库为例:

data:
  argocd.insecure: "true"
  log.level: debug
  registries.conf: | registries: - name: harbor api_url: http://10.39.140.196:8081 prefix: 10.39.140.196:8081 ping: yes insecure: yes

5、 配置API访问令牌密钥

当从清单安装到Kubernetes集群时,Argo CD Image Updater将从名为ARGOCD_TOKEN的环境变量中读取访问Argo CD API所需的令牌,

该环境变量是从名为argocd.token的secret字段中设置的argocd-image-updater-secret

argocd.token的值应设置为您上面生成的访问令牌的base64编码值。作为一种捷径,您可以使用kubectl生成密钥,并将其应用于现有资源:

YOUR_TOKEN=xxx
kubectl create secret generic argocd-image-updater-secret \
  --from-literal argocd.token=$YOUR_TOKEN --dry-run -o yaml |
  kubectl -n argocd-image-updater apply -f -

更改后,必须重新启动 argocd-image-updater Pod,即运行

kubectl -n argocd-image-updater rollout restart deployment argocd-image-updater

新建yaml仓库Kustomize文件

由于image updater仅支持helm或Kustomize类型yaml,这里新建一个基于Kustomize的yaml目录,修改yaml中的参数不要与之前的冲突即可:

[root@jenkins git]# tree argocd-gitops/kustomize-javademo/
argocd-gitops/kustomize-javademo/
├── javademo-deployment.yaml
├── javademo-svc.yaml
└── kustomization.yaml

javademo-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: javademo-tag
spec:
  replicas: 1
  revisionHistoryLimit: 3
  selector:
    matchLabels:
      app: javademo-tag
  template:
    metadata:
      labels:
        app: javademo-tag
    spec:
      containers:
      - image: 10.39.140.196:8081/apps/javademo:replace
        name: javademo-tag
        ports:
        - containerPort: 8080

javademo-svc.yaml

apiVersion: v1	
kind: Service	
metadata:	
  name: javademo-tag
spec:	
  ports:	
  - port: 8012 
    targetPort: 8080 
  selector:	
    app: javademo-tag

kustomization.yaml

amePrefix: kustomize-

resources:
- javademo-deployment.yaml
- javademo-svc.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

登录argocd UI新建一个argocd应用,和之前相比增加了annotations参数,指定要监测的镜像地址,更新策略为latest,另外修改了source path

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  annotations:
    argocd-image-updater.argoproj.io/image-list: javademo=10.39.140.196:8081/apps/javademo
    argocd-image-updater.argoproj.io/javademo.update-strategy: latest
  name: javademo-tag
  namespace: argocd
  finalizers:
    - resources-finalizer.argocd.argoproj.io
spec:
  destination:
    namespace: apps
    server: https://kubernetes.default.svc
  project: default
  source:
    path: kustomize-javademo
    repoURL: http://10.39.140.196:10080/gogs/argocd-gitops.git
    targetRevision: HEAD
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
      allowEmpty: false
    syncOptions:
    - Validate=false
    - CreateNamespace=true
    retry:
      limit: 5
      backoff:
        duration: 5s
        factor: 2
        maxDuration: 3m

登录kubesphere UI重新创建一条ci流水线,删除update docker tag 步骤即可,已经不需要基于git push来触发应用部署了:

pipeline {
   

    environment {
   
        GIT_URL='http://10.39.140.196:10080/gogs/spring-demo.git'
        GIT_CREDENTIAL_ID = 'git-id'
        GIT_BRANCH = 'master'
        REGISTRY = '10.39.140.196:8081/apps/javademo'
        REGISTRY_CREDENTIAL_ID = 'harbor-id'
    }

    agent {
   
        node {
   
            label 'maven'
        }
    }

    stages {
   
        
        stage('SCM Checkout') {
   
            steps {
   
                git branch: "${GIT_BRANCH}", credentialsId: "${GIT_CREDENTIAL_ID}", url: "${GIT_URL}"
            }
        }
        
        stage('source build') {
   
            steps {
   
                container('maven') {
   
                    sh 'mvn clean package'
                
                }
            }
        }

        stage('docker build & push') {
   
            steps {
   
                script {
   
                    env.COMMIT_ID = sh(returnStdout: true, script: "git log -n 1 --pretty=format:'%h'").trim()
                    env.TIMESTRAP = sh(returnStdout: true, script: 'date +%Y%m%d%H%M%S').trim()
                    env.DOCKER_TAG = "dev_${TIMESTRAP}_${COMMIT_ID}_${BUILD_NUMBER}"
                }
                container('maven') {
   
                    withCredentials([usernamePassword(passwordVariable : 'DOCKER_PASSWORD' ,usernameVariable : 'DOCKER_USERNAME' ,credentialsId : "$REGISTRY_CREDENTIAL_ID" ,)]) {
   
                        sh 'docker build -t $REGISTRY:$DOCKER_TAG .'
                        sh 'echo "$DOCKER_PASSWORD" | docker login $REGISTRY -u "$DOCKER_USERNAME" --password-stdin'
                        sh 'docker push $REGISTRY:$DOCKER_TAG'
                    }
                }
            }
        }
    }
}

查看流水线日志,镜像成功推送到harbor仓库:
在这里插入图片描述

harbor仓库镜像tag更新,argocd image updater自动将最新tag更新到k8s集群。

在这里插入图片描述
查看镜像tag
在这里插入图片描述
以后每次harbor仓库生成最新镜像,ArgoCD都会自动将其更新到k8s集群。



转载请标明出处【k8s的GitOps持续交付工具ArgoCD】。

《www.micoder.cc》 虚拟化云计算,系统运维,安全技术服务.

网站已经关闭评论