乐趣区

关于云计算:KubeSphere-Argo-CD实现真正的-GitOps

来自社区用户 willqy 的分享

Argo CD 简介

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

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

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

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

Argo CD 架构图:

Argo CD 被实现为 Kubernetes 控制器,该控制器继续监督正在运行的应用程序,并将以后的活动状态与所需的指标状态(在 Git 存储库中指定)进行比拟。当已部署应用程序的运行状态偏离指标状态时将被 Argo CD 视为 OutOfSync。

Argo CD 报告并可视化差别,同时提供了主动或手动将实时状态同步回所需指标状态的性能。在 Git 存储库中对所需指标状态所做的任何批改都能够主动利用并同步到指定的指标环境中。

Argo CD 反对的 Kubernetes 配置清单包含 helm charts、kustomize 或纯 YAML/json 文件等。

本篇文章波及内容:

  • 应用 KubeSphere DevOps 实现 CI 局部, CD 局部由 Argo CD 实现;
  • Argo CD 继续监测 Git 仓库某个目录下 yaml 文件变动,主动将 yaml 文件部署到 K8s 集群;
  • Argo CD 继续监测 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

部署 Argo CD

Argo CD 有多种部署形式,能够间接部署 yaml 文件.

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

这里应用 helm 形式部署,可间接指定 Argo CD server service 类型 nodePort:

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

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

查看运行的 Pod:

[root@master ~]# kubectl -n Argo CD 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 部署 Argo CD,首先须要配置 Argo CD helm 仓库,进入企业空间,抉择利用模板上传离线 helm chart 包,或在利用仓库配置公网 helm repo 地址。

实现后进入我的项目,点击部署新利用,抉择 Argo CD helm chart 进行部署即可:

装置 Argo CD CLI

要与 Argo CD 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/Argo CD
chmod +x /usr/local/bin/Argo CD

Argo CD version

如果下面 Argo CD 应用 yaml 形式部署,批改 serivce 类型为 nodeport,以便拜访 Argo CD API Server

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

查看 Argo CD server service,记录 nodeport 信息:

[root@master ~]# kubectl -n Argo CD 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

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

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

应用 Argo CD CLI 登录,以 nodeIP 和 nodePort 作为 Argo CD server 登录地址:

Argo CD login 10.39.140.248:31195 --username admin --password $podName

批改默认明码:

Argo CD account update-password \
  --current-password $podName \
  --new-password Argo CD@123

浏览器登录 Argo CD UI:

https://10.39.140.248:31195

部署 Argo CD 利用

登陆 Argo CD UI 后,抉择 NEW APP 创立 application,抉择 EDIT AS AYML:

粘贴以下内容,SAVE 后点击左上 CREATE,当然也能够间接应用 kubectl apply 命令执行以下内容,成果雷同。

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: javademo
  namespace: Argo CD
  finalizers:
    - resources-finalizer.Argo CD.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 字段:指定了利用名称,命名空间必须指定 Argo CD,增加 finalizers 字段可在删除利用时级联删除相干 k8s 资源;
  • source 字段:指定了 yaml 文件所在 git 仓库 URL,及要监测的 yaml 文件寄存目录,该目录下文件有任何变更 Argo CD 都会主动将其更新部署到 k8s 集群;
  • destination 字段:指定监测的 yaml 文件要部署到哪个 k8s 集群及哪个命名空间下;
  • syncPolicy 字段:指定主动同步策略和频率,不配置时须要手动触发同步。

另外如果应用公有 Git 仓库,须要创立凭证,这里的凭证是 Argo CD 拜访 yaml 文件 Git 仓库的凭证:

等效的 Argo CD cli 命令:

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

创立后 Argo CD 会主动将 Git 仓库 javademo 目录下的 yaml 文件部署到 K8s 集群,此时利用无奈失常启动,因为 yaml 文件中的镜像 tag 还不存在,拉取镜像会失败:

也能够应用 Argo CD CLI 查看部署的利用:

[root@master ~]# Argo CD 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 字段。

因为此时 Argo CD 继续监测 yaml 仓库配置文件变动,当 CI 局部执行 git push 时便会触发 Argo CD 更新 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@Argo CD.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 仓库的镜像:

Argo CD 监测到 yaml 文件变更后更新至 K8s 集群:

Argo CD UI 查看应用的镜像:

登录 KubeSphere UI 查看利用状态为运行中:

在 Git 仓库间接批改 yaml 文件配置, 同样可能触发 Argo CD 同步,例如将 service 类型改为 nodePort:

期待 Argo CD 主动同步配置更新到 K8s 集群,浏览器以 nodeport 形式拜访 java web 利用:

部署 Argo CD Image Updater

下面演示了基于 Git 仓库变更作为利用部署的事实起源,上面演示另一种形式,以镜像 tag 变更作为利用部署的事实起源。Argo CD 提供了 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 Argo CD edit cm argocd-cm
data:
  accounts.image-updater: apiKey

为用户创立拜访令牌,将令牌的值复制到某个中央,稍后将须要它。

Argo CD account generate-token --account image-updater --id image-updater

2、在 Argo CD 中授予 RBAC 权限

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

# kubectl -n Argo CD 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:
  Argo CD.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 将从名为 Argo CD_TOKEN 的环境变量中读取拜访 Argo CD API 所需的令牌,该环境变量是从名为 Argo CD.token 的 secret 字段中设置的argocd-image-updater-secret

Argo CD.token 的值应设置为您下面生成的拜访令牌的 base64 编码值。作为一种捷径,您能够应用 kubectl 生成密钥,并将其利用于现有资源:

YOUR_TOKEN=xxx
kubectl create secret generic argocd-image-updater-secret \
  --from-literal Argo CD.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

登录 Argo CD UI 新建一个 Argo CD 利用,和之前相比减少了 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: Argo CD
  finalizers:
    - resources-finalizer.Argo CD.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 更新,Argo CD image updater 主动将最新 tag 更新到 K8s 集群。

查看镜像 tag:

当前每次 Harbor 仓库生成最新镜像,Argo CD 都会主动将其更新到 K8s 集群。

本文由博客一文多发平台 OpenWrite 公布!

退出移动版