精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

使用 Argo CD 進(jìn)行 GitOps 流水線改造

云計(jì)算 云原生
Argo CD 是通過 Kubernetes 控制器來實(shí)現(xiàn)的,它持續(xù) watch 正在運(yùn)行的應(yīng)用程序并將當(dāng)前的實(shí)時(shí)狀態(tài)與所需的目標(biāo)狀態(tài)( Git 存儲(chǔ)庫中指定的)進(jìn)行比較。已經(jīng)部署的應(yīng)用程序的實(shí)際狀態(tài)與目標(biāo)狀態(tài)有差異,則被認(rèn)為是 OutOfSync 狀態(tài),Argo CD 會(huì)報(bào)告顯示這些差異,同時(shí)提供工具來自動(dòng)或手動(dòng)將狀態(tài)同步到期望的目標(biāo)狀態(tài)。

Argo CD 是一個(gè)為 Kubernetes 而生的,遵循聲明式 GitOps 理念的持續(xù)部署工具。Argo CD 可在 Git 存儲(chǔ)庫更改時(shí)自動(dòng)同步和部署應(yīng)用程序。

Argo CD 遵循 GitOps 模式,使用 Git 倉庫作為定義所需應(yīng)用程序狀態(tài)的真實(shí)來源,Argo CD 支持多種 Kubernetes 清單:

  • kustomize
  • helm charts
  • ksonnet applications
  • jsonnet files
  • Plain directory of YAML/json manifests
  • Any custom config management tool configured as a config management plugin

Argo CD 可在指定的目標(biāo)環(huán)境中自動(dòng)部署所需的應(yīng)用程序狀態(tài),應(yīng)用程序部署可以在 Git 提交時(shí)跟蹤對(duì)分支、標(biāo)簽的更新,或固定到清單的指定版本。

架構(gòu)

ArgoCD架構(gòu)

Argo CD 是通過 Kubernetes 控制器來實(shí)現(xiàn)的,它持續(xù) watch 正在運(yùn)行的應(yīng)用程序并將當(dāng)前的實(shí)時(shí)狀態(tài)與所需的目標(biāo)狀態(tài)( Git 存儲(chǔ)庫中指定的)進(jìn)行比較。已經(jīng)部署的應(yīng)用程序的實(shí)際狀態(tài)與目標(biāo)狀態(tài)有差異,則被認(rèn)為是 OutOfSync 狀態(tài),Argo CD 會(huì)報(bào)告顯示這些差異,同時(shí)提供工具來自動(dòng)或手動(dòng)將狀態(tài)同步到期望的目標(biāo)狀態(tài)。在 Git 倉庫中對(duì)期望目標(biāo)狀態(tài)所做的任何修改都可以自動(dòng)應(yīng)用反饋到指定的目標(biāo)環(huán)境中去。

下面簡單介紹下 Argo CD 中的幾個(gè)主要組件:

API 服務(wù):API 服務(wù)是一個(gè) gRPC/REST 服務(wù),它暴露了 Web UI、CLI 和 CI/CD 系統(tǒng)使用的接口,主要有以下幾個(gè)功能:

  • 應(yīng)用程序管理和狀態(tài)報(bào)告
  • 執(zhí)行應(yīng)用程序操作(例如同步、回滾、用戶定義的操作)
  • 存儲(chǔ)倉庫和集群憑據(jù)管理(存儲(chǔ)為 K8s Secrets 對(duì)象)
  • 認(rèn)證和授權(quán)給外部身份提供者
  • RBAC
  • Git webhook 事件的偵聽器/轉(zhuǎn)發(fā)器

倉庫服務(wù):存儲(chǔ)倉庫服務(wù)是一個(gè)內(nèi)部服務(wù),負(fù)責(zé)維護(hù)保存應(yīng)用程序清單 Git 倉庫的本地緩存。當(dāng)提供以下輸入時(shí),它負(fù)責(zé)生成并返回 Kubernetes 清單:

  • 存儲(chǔ) URL
  • revision 版本(commit、tag、branch)
  • 應(yīng)用路徑
  • 模板配置:參數(shù)、ksonnet 環(huán)境、helm values.yaml 等

應(yīng)用控制器:應(yīng)用控制器是一個(gè) Kubernetes 控制器,它持續(xù) watch 正在運(yùn)行的應(yīng)用程序并將當(dāng)前的實(shí)時(shí)狀態(tài)與所期望的目標(biāo)狀態(tài)(repo 中指定的)進(jìn)行比較。它檢測(cè)應(yīng)用程序的 OutOfSync 狀態(tài),并采取一些措施來同步狀態(tài),它負(fù)責(zé)調(diào)用任何用戶定義的生命周期事件的鉤子(PreSync、Sync、PostSync)。

安裝

當(dāng)然前提是需要有一個(gè) kubectl 可訪問的 Kubernetes 的集群,直接使用下面的命令即可,這里我們安裝最新的 v2.8.4 版本:

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

如果你要用在生產(chǎn)環(huán)境,則可以使用下面的命令部署一個(gè) HA 高可用的版本:

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

這將創(chuàng)建一個(gè)新的命名空間 argocd,Argo CD 的服務(wù)和應(yīng)用資源都將部署到該命名空間。

$ kubectl get pods -n argocd
NAME                                                READY   STATUS    RESTARTS   AGE
argocd-application-controller-0                     1/1     Running   0          103s
argocd-applicationset-controller-68b9bdbd8b-jzcpf   1/1     Running   0          103s
argocd-dex-server-6b7745757-6mxwk                   1/1     Running   0          103s
argocd-notifications-controller-5b56f6f7bb-jqpng    1/1     Running   0          103s
argocd-redis-f4cdbff57-dr8jc                        1/1     Running   0          103s
argocd-repo-server-c4f79b4d6-7nh6n                  1/1     Running   0          103s
argocd-server-895675597-fr42g                       1/1     Running   0          103s

如果你對(duì) UI、SSO、多集群管理這些特性不感興趣,只想把應(yīng)用變更同步到集群中,那么可以直接安裝核心組件即可:kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/v2.8.4/manifests/core-install.yaml。

然后我們可以在本地(選擇對(duì)應(yīng)的版本)安裝 CLI 工具方便操作 Argo CD:

$ curl -sSL -o /usr/local/bin/argocd https://github.com/argoproj/argo-cd/releases/download/v2.8.4/argocd-linux-amd64

為 argocd CLI 賦予可執(zhí)行權(quán)限:

$ chmod +x /usr/local/bin/argocd

現(xiàn)在我們就可以使用 argocd 命令了。如果你是 Mac,則可以直接使用 brew install argocd 進(jìn)行安裝。

Argo CD 會(huì)運(yùn)行一個(gè) gRPC 服務(wù)(由 CLI 使用)和 HTTP/HTTPS 服務(wù)(由 UI 使用),這兩種協(xié)議都由 argocd-server 服務(wù)在以下端口進(jìn)行暴露:

  • 443 - gRPC/HTTPS
  • 80 - HTTP(重定向到 HTTPS)

我們可以通過配置 Ingress 的方式來對(duì)外暴露服務(wù),其他 Ingress 控制器的配置可以參考官方文檔 https://argo-cd.readthedocs.io/en/stable/operator-manual/ingress/ 進(jìn)行配置。

Argo CD 在同一端口 (443) 上提供多個(gè)協(xié)議 (gRPC/HTTPS),所以當(dāng)我們?yōu)?argocd 服務(wù)定義單個(gè) nginx ingress 對(duì)象和規(guī)則的時(shí)候有點(diǎn)麻煩,因?yàn)?nbsp;nginx.ingress.kubernetes.io/backend-protocol 這個(gè) annotation 只能接受一個(gè)后端協(xié)議(例如 HTTP、HTTPS、GRPC、GRPCS)。

為了使用單個(gè) ingress 規(guī)則和主機(jī)名來暴露 Argo CD APIServer,必須使用 nginx.ingress.kubernetes.io/ssl-passthrough 這個(gè) annotation 來傳遞 TLS 連接并校驗(yàn) Argo CD APIServer 上的 TLS。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: argocd-server-ingress
  namespace: argocd
  annotations:
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
    nginx.ingress.kubernetes.io/ssl-passthrough: "true"
spec:
  ingressClassName: nginx
  rules:
    - host: argocd.k8s.local
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: argocd-server
                port:
                  name: https

上述規(guī)則在 Argo CD APIServer 上校驗(yàn) TLS,該服務(wù)器檢測(cè)到正在使用的協(xié)議,并做出適當(dāng)?shù)捻憫?yīng)。請(qǐng)注意,nginx.ingress.kubernetes.io/ssl-passthrough 注解要求將 --enable-ssl-passthrough 標(biāo)志添加到 nginx-ingress-controller 的命令行參數(shù)中。

由于 ingress-nginx 的每個(gè) Ingress 對(duì)象僅支持一個(gè)協(xié)議,因此另一種方法是定義兩個(gè) Ingress 對(duì)象。一個(gè)用于 HTTP/HTTPS,另一個(gè)用于 gRPC。

如下所示為 HTTP/HTTPS 的 Ingress 對(duì)象:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: argocd-server-http-ingress
  namespace: argocd
  annotations:
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
    nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
spec:
  ingressClassName: nginx
  rules:
    - http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: argocd-server
                port:
                  name: http
      host: argocd.k8s.local
  tls:
    - hosts:
        - argocd.k8s.local
      secretName: argocd-secret # do not change, this is provided by Argo CD

gRPC 協(xié)議對(duì)應(yīng)的 Ingress 對(duì)象如下所示:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: argocd-server-grpc-ingress
  namespace: argocd
  annotations:
    nginx.ingress.kubernetes.io/backend-protocol: "GRPC"
spec:
  ingressClassName: nginx
  rules:
    - http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: argocd-server
                port:
                  name: https
      host: grpc.argocd.k8s.local
  tls:
    - hosts:
        - grpc.argocd.k8s.local
      secretName: argocd-secret # do not change, this is provided by Argo CD

然后我們需要在禁用 TLS 的情況下運(yùn)行 APIServer。編輯 argocd-server 這個(gè) Deployment 以將 --insecure 標(biāo)志添加到 argocd-server 命令,或者簡單地在 argocd-cmd-params-cm ConfigMap 中設(shè)置 server.insecure: "true" 即可。

創(chuàng)建完成后,我們就可以通過 argocd.k8s.local 來訪問 Argo CD 服務(wù)了,不過需要注意我們這里配置的證書是自簽名的,所以在第一次訪問的時(shí)候會(huì)提示不安全,強(qiáng)制跳轉(zhuǎn)即可。

默認(rèn)情況下 admin 帳號(hào)的初始密碼是自動(dòng)生成的,會(huì)以明文的形式存儲(chǔ)在 Argo CD 安裝的命名空間中名為 argocd-initial-admin-secret 的 Secret 對(duì)象下的 password 字段下,我們可以用下面的命令來獲?。?/p>

$ kubectl -n argocd get secret argocd-initial-admin-secret -o jsnotallow="{.data.password}" | base64 -d && echo

使用用戶名 admin 和上面輸出的密碼即可登錄 Dashboard。

argocd ui

同樣我們也可以通過 ArgoCD CLI 命令行工具進(jìn)行登錄:

$ argocd login grpc.argocd.k8s.local
WARNING: server certificate had error: tls: failed to verify certificate: x509: certificate signed by unknown authority. Proceed insecurely (y/n)? y
Username: admin
Password:
'admin:login' logged in successfully
Context 'grpc.argocd.k8s.local' updated

需要注意的是這里登錄的地址為 gRPC 暴露的服務(wù)地址。

CLI 登錄成功后,可以使用如下所示命令更改密碼:

$ argocd account update-password
*** Enter current password:
*** Enter new password:
*** Confirm new password:
Password updated
Context 'argocd.k8s.local' updated
$ argocd version
argocd: v2.8.4+c279299
  BuildDate: 2023-09-13T19:43:37Z
  GitCommit: c27929928104dc37b937764baf65f38b78930e59
  GitTreeState: clean
  GoVersion: go1.20.7
  Compiler: gc
  Platform: darwin/arm64
argocd-server: v2.8.4+c279299
  BuildDate: 2023-09-13T19:12:09Z
  GitCommit: c27929928104dc37b937764baf65f38b78930e59
  GitTreeState: clean
  GoVersion: go1.20.6
  Compiler: gc
  Platform: linux/amd64
  Kustomize Version: v5.1.0 2023-06-19T16:58:18Z
  Helm Version: v3.12.1+gf32a527
  Kubectl Version: v0.24.2
  Jsonnet Version: v0.20.0

配置集群

由于 Argo CD 支持部署應(yīng)用到多集群,所以如果你要將應(yīng)用部署到外部集群的時(shí)候,需要先將外部集群的認(rèn)證信息注冊(cè)到 Argo CD 中,如果是在內(nèi)部部署(運(yùn)行 Argo CD 的同一個(gè)集群,默認(rèn)不需要配置),直接使用 https://kubernetes.default.svc 作為應(yīng)用的 K8S APIServer 地址即可。

首先列出當(dāng)前 kubeconfig 中的所有集群上下文:

$ kubectl config get-contexts -o name
kubernetes-admin@kubernetes
orbstack

從列表中選擇一個(gè)上下文名稱并將其提供給 argocd cluster add CONTEXTNAME,比如對(duì)于 orbstack 上下文,運(yùn)行:

$ argocd cluster add orbstack

創(chuàng)建應(yīng)用

Git 倉庫 https://github.com/argoproj/argocd-example-apps.git 是一個(gè)包含留言簿應(yīng)用程序的示例庫,我們可以用該應(yīng)用來演示 Argo CD 的工作原理。

通過 CLI 創(chuàng)建應(yīng)用

我們可以通過 argocd app create xxx 命令來創(chuàng)建一個(gè)應(yīng)用:

$ argocd app create --help
Create an application

Usage:
  argocd app create APPNAME [flags]

Examples:

        # Create a directory app
        argocd app create guestbook --repo https://github.com/argoproj/argocd-example-apps.git --path guestbook --dest-namespace default --dest-server https://kubernetes.default.svc --directory-recurse

        # Create a Jsonnet app
        argocd app create jsonnet-guestbook --repo https://github.com/argoproj/argocd-example-apps.git --path jsonnet-guestbook --dest-namespace default --dest-server https://kubernetes.default.svc --jsonnet-ext-str replicas=2

        # Create a Helm app
        argocd app create helm-guestbook --repo https://github.com/argoproj/argocd-example-apps.git --path helm-guestbook --dest-namespace default --dest-server https://kubernetes.default.svc --helm-set replicaCount=2

        # Create a Helm app from a Helm repo
        argocd app create nginx-ingress --repo https://charts.helm.sh/stable --helm-chart nginx-ingress --revision 1.24.3 --dest-namespace default --dest-server https://kubernetes.default.svc

        # Create a Kustomize app
        argocd app create kustomize-guestbook --repo https://github.com/argoproj/argocd-example-apps.git --path kustomize-guestbook --dest-namespace default --dest-server https://kubernetes.default.svc --kustomize-image gcr.io/heptio-images/ks-guestbook-demo:0.1

        # Create a app using a custom tool:
        argocd app create kasane --repo https://github.com/argoproj/argocd-example-apps.git --path plugins/kasane --dest-namespace default --dest-server https://kubernetes.default.svc --config-management-plugin kasane


Flags:
......

直接執(zhí)行如下所示命令即可:

$ argocd app create guestbook --repo https://github.com/argoproj/argocd-example-apps.git --path guestbook --dest-server https://kubernetes.default.svc --dest-namespace default
application 'guestbook' created

通過 UI 創(chuàng)建應(yīng)用

除了可以通過 CLI 工具來創(chuàng)建應(yīng)用,我們也可以通過 UI 界面來創(chuàng)建,定位到 argocd.k8s.local 頁面,登錄后,點(diǎn)擊 +New App 新建應(yīng)用按鈕,如下圖:

New App

將應(yīng)用命名為 guestbook,使用 default project,并將同步策略設(shè)置為 Manual:

配置應(yīng)用

然后在下面配置 Repository URL 為 https://github.com/argoproj/argocd-example-apps.git,由于某些原因我們這里使用的是 Gitee 倉庫地址 https://gitee.com/cnych/argocd-example-apps,將 Revision 設(shè)置為 HEAD,并將路徑設(shè)置為 guestbook。然后下面的 Destination 部分,將 cluster 設(shè)置為 inCluster 和 namespace 為 default:

配置集群

填寫完以上信息后,點(diǎn)擊頁面上方的 Create 安裝,即可創(chuàng)建 guestbook 應(yīng)用,創(chuàng)建完成后可以看到當(dāng)前應(yīng)用的處于 OutOfSync 狀態(tài):

guestbook application

Argo CD 默認(rèn)情況下每 3 分鐘會(huì)檢測(cè) Git 倉庫一次,用于判斷應(yīng)用實(shí)際狀態(tài)是否和 Git 中聲明的期望狀態(tài)一致,如果不一致,狀態(tài)就轉(zhuǎn)換為 OutOfSync。默認(rèn)情況下并不會(huì)觸發(fā)更新,除非通過 syncPolicy 配置了自動(dòng)同步。

通過 CRD 創(chuàng)建

除了可以通過 CLI 和 Dashboard 可以創(chuàng)建 Application 之外,其實(shí)也可以直接通過聲明一個(gè) Application 的資源對(duì)象來創(chuàng)建一個(gè)應(yīng)用,如下所示:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: guestbook
spec:
  destination:
    namespace: default
    server: "https://kubernetes.default.svc"
  source:
    path: guestbook
    repoURL: "https://github.com/cnych/argocd-example-apps"
    targetRevision: HEAD
  project: default
  syncPolicy:
    automated: null

部署應(yīng)用

由于上面我們?cè)趧?chuàng)建應(yīng)用的時(shí)候使用的同步策略為 Manual,所以應(yīng)用創(chuàng)建完成后沒有自動(dòng)部署,需要我們手動(dòng)去部署應(yīng)用。同樣可以通過 CLI 和 UI 界面兩種同步方式。

使用 CLI 同步

應(yīng)用創(chuàng)建完成后,我們可以通過如下所示命令查看其狀態(tài):

$ argocd app get argocd/guestbook
Name:               argocd/guestbook
Project:            default
Server:             https://kubernetes.default.svc
Namespace:          default
URL:                https://grpc.argocd.k8s.local/applications/guestbook
Repo:               https://gitee.com/cnych/argocd-example-apps
Target:             HEAD
Path:               guestbook
SyncWindow:         Sync Allowed
Sync Policy:        <none>
Sync Status:        OutOfSync from HEAD (f3736e6)
Health Status:      Missing

GROUP  KIND        NAMESPACE  NAME          STATUS     HEALTH   HOOK  MESSAGE
       Service     default    guestbook-ui  OutOfSync  Missing
apps   Deployment  default    guestbook-ui  OutOfSync  Missing

應(yīng)用程序狀態(tài)為初始 OutOfSync 狀態(tài),因?yàn)閼?yīng)用程序尚未部署,并且尚未創(chuàng)建任何 Kubernetes 資源。要同步(部署)應(yīng)用程序,可以執(zhí)行如下所示命令:

$ argocd app sync argocd/guestbook

此命令從 Git 倉庫中檢索資源清單并執(zhí)行 kubectl apply 部署應(yīng)用,執(zhí)行上面命令后 guestbook 應(yīng)用便會(huì)運(yùn)行在集群中了,現(xiàn)在我們就可以查看其資源組件、日志、事件和評(píng)估其健康狀態(tài)了。

通過 UI 同步

直接添加 UI 界面上應(yīng)用的 Sync 按鈕即可開始同步:

sync 操作

同步完成后可以看到我們的資源狀態(tài),甚至還可以直接查看應(yīng)用的日志信息:

Sync 完成

也可以通過 kubectl 查看到我們部署的資源:

$ kubectl get pods
NAME                                 READY   STATUS      RESTARTS       AGE
guestbook-ui-6c96fb4bdc-bdwh9        1/1     Running     0              3m3s
?  ~ kubectl get svc
NAME                 TYPE           CLUSTER-IP       EXTERNAL-IP    PORT(S)                      AGE
guestbook-ui         ClusterIP      10.100.170.117   <none>         80/TCP                       3m16s
kubernetes           ClusterIP      10.96.0.1        <none>         443/TCP                      42d

和我們從 Git 倉庫中同步 guestbook 目錄下面的資源狀態(tài)也是同步的,證明同步成功了。

流水線改造

前面我們通過 Jenkins Pipeline 已經(jīng)成功的將應(yīng)用部署到了集群中了,但是我們使用的是傳統(tǒng)的主動(dòng) push 方式,接下來我們需要將這個(gè)流程改造成為一個(gè) GitOps 的流水線,這樣我們就可以通過 Git 來管理應(yīng)用的部署了。

使用到的代碼倉庫位于 https://github.com/cnych/drone-k8s-demo,然后遷移到內(nèi)部的 gitlab 環(huán)境上實(shí)驗(yàn)。

前面 Jenkins Pipeline 中我們?cè)诎l(fā)布應(yīng)用的時(shí)候是通過 helm 方式來部署的,現(xiàn)在我們只需要將流水線的 CD 部分進(jìn)行改造,比如將鏡像構(gòu)建后推送到鏡像倉庫,然后去修改 git 倉庫中的 values 文件,Argo CD 來同步部署應(yīng)用即可。

首先我們將應(yīng)用的部署資源清單單獨(dú)放一個(gè) config 的倉庫下面 http://gitlab.k8s.local/cnych/k8s-devops-demo-config.git,將前面應(yīng)用的 helm 目錄上傳到該倉庫中。這樣方便和 Argo CD 進(jìn)行對(duì)接,整個(gè)項(xiàng)目下面只有用于應(yīng)用部署的 Helm Chart 模板。

config repo

如果有多個(gè)團(tuán)隊(duì),每個(gè)團(tuán)隊(duì)都要維護(hù)大量的應(yīng)用,就需要用到 Argo CD 的另一個(gè)概念:項(xiàng)目(Project)。Argo CD 中的項(xiàng)目(Project)可以用來對(duì) Application 進(jìn)行分組,不同的團(tuán)隊(duì)使用不同的項(xiàng)目,這樣就實(shí)現(xiàn)了多租戶環(huán)境。項(xiàng)目還支持更細(xì)粒度的訪問權(quán)限控制:

  • 限制部署內(nèi)容(受信任的 Git 倉庫);
  • 限制目標(biāo)部署環(huán)境(目標(biāo)集群和 namespace);
  • 限制部署的資源類型(例如 RBAC、CRD、DaemonSets、NetworkPolicy 等);
  • 定義項(xiàng)目角色,為 Application 提供 RBAC(例如 OIDC group 或者 JWT 令牌綁定)。

比如我們這里創(chuàng)建一個(gè)名為 demo 的項(xiàng)目,將該應(yīng)用創(chuàng)建到該項(xiàng)目下,只需創(chuàng)建一個(gè)如下所示的 AppProject 對(duì)象即可:

apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  # 項(xiàng)目名
  name: demo
  namespace: argocd
spec:
  # 目標(biāo)
  destinations:
    # 此項(xiàng)目的服務(wù)允許部署的 namespace,這里為全部
    - namespace: "*"
      # 此項(xiàng)目允許部署的集群,這里為默認(rèn)集群,即為Argo CD部署的當(dāng)前集群
      server: https://kubernetes.default.svc
  # 允許的數(shù)據(jù)源
  sourceRepos:
    - http://gitlab.k8s.local/cnych/k8s-devops-demo-config.git

該對(duì)象中有幾個(gè)核心的屬性:

  • sourceRepos:項(xiàng)目中的應(yīng)用程序可以從中獲取清單的倉庫引用。
  • destinations:項(xiàng)目中的應(yīng)用可以部署到的集群和命名空間。
  • roles:項(xiàng)目內(nèi)資源訪問定義的角色。

直接創(chuàng)建該對(duì)象即可:

$ kubectl get appproject -n argocd
NAME      AGE
default   47h
demo      6s

然后前往 Argo CD 的 Settings 頁面點(diǎn)擊 + CONNECT REPO 添加倉庫:

connect repo

需要注意的是這里的密碼需要使用 AccessToken,我們可以前往 GitLab 的頁面 http://gitlab.k8s.local/-/profile/personal_access_tokens 創(chuàng)建。

gitlab token

更多配置信息可以前往文檔 https://argo-cd.readthedocs.io/en/stable/operator-manual/declarative-setup/ 查看,項(xiàng)目創(chuàng)建完成后,在該項(xiàng)目下創(chuàng)建一個(gè) Application,代表環(huán)境中部署的應(yīng)用程序?qū)嵗?/p>

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: devops-demo
  namespace: argocd
spec:
  destination:
    namespace: default
    server: "https://kubernetes.default.svc"
  project: demo
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
  source:
    path: helm # 從 Helm 存儲(chǔ)庫創(chuàng)建應(yīng)用程序時(shí),chart 必須指定 path
    repoURL: "http://gitlab.k8s.local/cnych/k8s-devops-demo-config.git"
    targetRevision: HEAD
    helm:
      parameters:
        - name: replicaCount
          value: "2"
      valueFiles:
        - my-values.yaml

這里我們定義了一個(gè)名為 devops-demo 的應(yīng)用,應(yīng)用源來自于 helm 路徑,使用的是 my-values.yaml 文件,此外還可以通過 source.helm.parameters 來配置參數(shù)。

同步策略可以選擇使用自動(dòng)的方式,該策略下面還有兩個(gè)屬性可以配置:

  • PRUNE RESOURCES:開啟后 Git Repo 中刪除資源會(huì)自動(dòng)在環(huán)境中刪除對(duì)應(yīng)的資源。

刪除資源

  • SELF HEAL:自動(dòng)痊愈,強(qiáng)制以 Git Repo 狀態(tài)為準(zhǔn),手動(dòng)在環(huán)境中修改不會(huì)生效。

自動(dòng)痊愈

正常創(chuàng)建后這個(gè)應(yīng)用會(huì)出現(xiàn) Degraded 的錯(cuò)誤,這是因?yàn)槲覀?Values 中的鏡像默認(rèn)為 latest,而我們沒有將鏡像推送到鏡像倉庫,所以會(huì)出現(xiàn)錯(cuò)誤。

app status

接下來我們?nèi)バ薷?Jenkins Pipeline 的流水線,將 CD 部分進(jìn)行修改。

podTemplate(cloud: "Kubernetes", nodeSelector: "kubernetes.io/hostname=node2", containers: [
  containerTemplate(name: 'golang', image: 'golang:1.18.3-alpine3.16', command: 'cat', ttyEnabled: true),
  containerTemplate(name: 'docker', image: 'docker:latest', command: 'cat', ttyEnabled: true),
  containerTemplate(name: 'kubectl', image: 'cnych/kubectl', command: 'cat', ttyEnabled: true),
  containerTemplate(name: 'helm', image: 'cnych/helm', command: 'cat', ttyEnabled: true),
  containerTemplate(name: 'yq', image: 'cnych/yq-jq:git', command: 'cat', ttyEnabled: true)
], serviceAccount: 'jenkins', envVars: [
  envVar(key: 'DOCKER_HOST', value: 'tcp://docker-dind:2375')  // 環(huán)境變量
]) {
  node(POD_LABEL) {
    def myRepo = checkout scm
    def gitConfigRepo = "gitlab.k8s.local/cnych/k8s-devops-demo-config.git"
    def gitCommit = myRepo.GIT_COMMIT
    def gitBranch = myRepo.GIT_BRANCH

    // 獲取 git commit id 作為鏡像標(biāo)簽
    def imageTag = sh(script: "git rev-parse --short HEAD", returnStdout: true).trim()
    // 倉庫地址
    def registryUrl = "harbor.k8s.local"
    def imageEndpoint = "course/devops-demo"
    // 鏡像
    def image = "${registryUrl}/${imageEndpoint}:${imageTag}"

    stage('單元測(cè)試') {
      echo "測(cè)試階段"
    }
    stage('代碼編譯打包') {
        try {
            container('golang') {
            echo "2.代碼編譯打包階段"
            sh """
                export GOPROXY=https://goproxy.io
                GOOS=linux GOARCH=amd64 go build -v -o demo-app
                """
            }
        } catch (exc) {
            println "構(gòu)建失敗 - ${currentBuild.fullDisplayName}"
            throw(exc)
        }
    }
    stage('構(gòu)建 Docker 鏡像') {
        withCredentials([[$class: 'UsernamePasswordMultiBinding',
            credentialsId: 'docker-auth',
            usernameVariable: 'DOCKER_USER',
            passwordVariable: 'DOCKER_PASSWORD']]) {
            container('docker') {
                echo "3. 構(gòu)建 Docker 鏡像階段"
                sh """
                docker login ${registryUrl} -u ${DOCKER_USER} -p ${DOCKER_PASSWORD}
                docker build -t ${image} .
                docker push ${image}
                """
            }
        }
    }
    stage('修改 Config Repo') {
        withCredentials([[$class: 'UsernamePasswordMultiBinding',
            credentialsId: 'gitlab-auth',
            usernameVariable: 'GIT_USER',
            passwordVariable: 'GIT_PASSWORD']]) {
                container('yq') {
                    echo "3. 修改 Config Repo 倉庫 Values"
                    // Bed6gAYq
                    sh """
                    git clone http://${GIT_USER}:${GIT_PASSWORD}@${gitConfigRepo}
                    cd k8s-devops-demo-config
                    yq write -i -y helm/my-values.yaml image.tag "${imageTag}"

                    git add helm/my-values.yaml

                    git config --global user.name "cnych"
                    git config --global user.email "cnych@youdianzhishi.com"

                    git commit -m "update image tag to ${imageTag}"

                    git push http://${GIT_USER}:${GIT_PASSWORD}@${gitConfigRepo}
                    """
                }
        }

    }
    stage('運(yùn)行 Kubectl') {
        withCredentials([file(credentialsId: 'kubeconfig', variable: 'KUBECONFIG')]) {
            container('kubectl') {
                sh "mkdir -p ~/.kube && cp ${KUBECONFIG} ~/.kube/config"
                echo "5.查看應(yīng)用"
                sh "kubectl get all -n kube-ops -l app=devops-demo"
            }
        }
    }

  }
}

上面的流水線中我們?cè)趹?yīng)用構(gòu)建成鏡像后,直接去修改了 Config Repo 倉庫中的 values 文件,然后提交到倉庫中,這樣 Argo CD 就會(huì)自動(dòng)同步部署應(yīng)用了。

由于 Argo CD 默認(rèn)并不是實(shí)時(shí)去監(jiān)測(cè) Config Repo 的變化的,如果要更快的檢測(cè)到變化我們可以使用 Git Webhook 的方式。

默認(rèn)情況下 Argo CD 每三分鐘輪詢一次 Git 存儲(chǔ)庫,以檢測(cè)清單的更改。為了消除輪詢延遲,可以將 API 服務(wù)器配置為接收 Webhook 事件。Argo CD 支持來自 GitHub、GitLab、Bitbucket、Bitbucket Server 和 Gogs 的 Git webhook 通知。

同樣方式我們可以在 k8s-devops-demo-config 倉庫下面創(chuàng)建一個(gè) Webhook,Git 提供程序中配置的有效負(fù)載 URL 應(yīng)使用 Argo CD 實(shí)例的 /api/webhook 端點(diǎn)(例如 https://argocd.example.com/api/webhook)。

gitlab webhook

然后在 argocd-secret 這個(gè) Kubernetes Secret 中,使用上面配置的 Git 提供商的 Webhook 密鑰配置以下密鑰之一。

gitlab token

$ kubectl edit secret argocd-secret -n argocd
apiVersion: v1
kind: Secret
metadata:
  name: argocd-secret
  namespace: argocd
type: Opaque
data:
...

stringData:
  # github webhook secret
  webhook.github.secret: shhhh! it's a GitHub secret

  # gitlab webhook secret
  webhook.gitlab.secret: shhhh! it's a GitLab secret

  # bitbucket webhook secret
  webhook.bitbucket.uuid: your-bitbucket-uuid

  # bitbucket server webhook secret
  webhook.bitbucketserver.secret: shhhh! it's a Bitbucket server secret

  # gogs server webhook secret
  webhook.gogs.secret: shhhh! it's a gogs server secret

可以直接使用 stringData 來配置 secret,這樣就不用去手動(dòng)編碼了。

devops demo

因?yàn)?GitOps 的核心是 Git,所以我們一定要將部署到集群中的資源清單文件全都托管到 Git 倉庫中,這樣才能實(shí)現(xiàn) GitOps 的自動(dòng)同步部署。上面我們是在 CI 流水線中去修改 Git 倉庫中的資源清單文件,其實(shí)我們也可以通過其他方式去修改,比如 Argo CD 也提供了一個(gè)新的工具 Argo CD Image Updater。

Argo CD Image Updater

Argo CD Image Updater 是一種自動(dòng)更新由 Argo CD 管理的 Kubernetes 工作負(fù)載的容器鏡像的工具。 該工具可以檢查與 Kubernetes 工作負(fù)載一起部署的容器鏡像的新版本,并使用 Argo CD 自動(dòng)將其更新到允許的最新版本。它通過為 Argo CD 應(yīng)用程序設(shè)置適當(dāng)?shù)膽?yīng)用程序參數(shù)來工作,類似于 argocd app set --helm-set image.tag=v1.0.1,但以完全自動(dòng)化的方式。

Argo CD Image Updater 會(huì)定期輪詢 Argo CD 中配置的應(yīng)用程序,并查詢相應(yīng)的鏡像倉庫以獲取可能的新版本。如果在倉庫中找到新版本的鏡像,并且滿足版本約束,Argo CD 鏡像更新程序?qū)⒅甘?Argo CD 使用新版本的鏡像更新應(yīng)用程序。

根據(jù)您的應(yīng)用程序自動(dòng)同步策略,Argo CD 將自動(dòng)部署新的鏡像版本或?qū)?yīng)用程序標(biāo)記為不同步,您可以通過同步應(yīng)用程序來手動(dòng)觸發(fā)鏡像更新。

特征

  • 更新由 Argo CD 管理且由 Helm 或 Kustomize 工具生成的應(yīng)用程序鏡像。
  • 根據(jù)不同的更新策略更新應(yīng)用鏡像。
  • semver:根據(jù)給定的鏡像約束更新到允許的最高版本。
  • latest:更新到最近創(chuàng)建的鏡像標(biāo)簽。
  • name:更新到按字母順序排序的列表中的最后一個(gè)標(biāo)簽。
  • digest:更新到可變標(biāo)簽的最新推送版本。
  • 支持廣泛使用的容器鏡像倉庫。
  • 通過配置支持私有容器鏡像倉庫。
  • 可以將更改寫回 Git。
  • 能夠使用匹配器函數(shù)過濾鏡像倉庫返回的標(biāo)簽列表。
  • 在 Kubernetes 集群中運(yùn)行,或者可以從命令行獨(dú)立使用。
  • 能夠執(zhí)行應(yīng)用程序的并行更新。

另外需要注意的是使用該工具目前有幾個(gè)限制:

  • 想要更新容器鏡像的應(yīng)用程序必須使用 Argo CD 進(jìn)行管理。不支持未使用 Argo CD 管理的工作負(fù)載。
  • Argo CD 鏡像更新程序只能更新其清單使用 Kustomize 或 Helm 呈現(xiàn)的應(yīng)用程序的容器鏡像,特別是在 Helm 的情況下,模板需要支持使用參數(shù)(即image.tag)。
  • 鏡像拉取密鑰必須存在于 Argo CD Image Updater 運(yùn)行(或有權(quán)訪問)的同一 Kubernetes 集群中。目前無法從其他集群獲取這些機(jī)密信息。

安裝

建議在運(yùn)行 Argo CD 的同一個(gè) Kubernetes 命名空間集群中運(yùn)行 Argo CD Image Updater,但這不是必需的。事實(shí)上,甚至不需要在 Kubernetes 集群中運(yùn)行 Argo CD Image Updater 或根本不需要訪問任何 Kubernetes 集群。但如果不訪問 Kubernetes,某些功能可能無法使用,所以強(qiáng)烈建議使用第一種安裝方法。

運(yùn)行鏡像更新程序的最直接方法是將其作為 Kubernetes 工作負(fù)載安裝到運(yùn)行 Argo CD 的命名空間中。這樣就不需要任何配置,也不會(huì)對(duì)你的工作負(fù)載產(chǎn)生任何影響。

kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj-labs/argocd-image-updater/stable/manifests/install.yaml

Argo CD Image Updater 安裝完成后我們就可以直接去監(jiān)聽鏡像是否發(fā)生了變化,而不需要在 CI 流水線中去手動(dòng)提交修改資源清單到代碼倉庫了。

現(xiàn)在我們可以先去刪除前面的 app:

$ argocd app delete devops-demo --cascade
Are you sure you want to delete 'devops-demo' and all its resources? [y/n] y
application 'devops-demo' deleted

然后接下來創(chuàng)建一個(gè)新的 Application 對(duì)象,對(duì)應(yīng)的資源清單如下所示:

# demo-app2.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: devops-demo2
  annotations:
    argocd-image-updater.argoproj.io/image-list: myalias=cnych/devops-demo # Write repository name
    argocd-image-updater.argoproj.io/myalias.allow-tags: regexp:^.*$
    argocd-image-updater.argoproj.io/myalias.pull-secret: pullsecret:argocd/dockerhub-secret
    argocd-image-updater.argoproj.io/myalias.update-strategy: latest # There are several ways to update the image, but I'm using digest.
    argocd-image-updater.argoproj.io/write-back-method: git
    argocd-image-updater.argoproj.io/git-branch: main
    argocd-image-updater.argoproj.io/myalias.force-update: "true"
  namespace: argocd
spec:
  destination:
    namespace: argocd
    server: https://kubernetes.default.svc
  project: demo
  source:
    path: helm # 從 Helm 存儲(chǔ)庫創(chuàng)建應(yīng)用程序時(shí),chart 必須指定 path
    repoURL: http://gitlab.k8s.local/cnych/k8s-devops-demo-config.git
    targetRevision: main
    helm:
      parameters:
        - name: replicaCount
          value: "2"
      valueFiles:
        - my-values.yaml
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true

這個(gè)新的資源對(duì)象中,我們添加了一些注釋,這些注釋用于配置 Argo CD Image Updater。這些配置用于指定自動(dòng)更新容器鏡像的策略、參數(shù)和相關(guān)信息。以下是對(duì)這些注釋的詳細(xì)解釋:

  • argocd-image-updater.argoproj.io/image-list: 這個(gè)注解定義了應(yīng)用中使用的鏡像列表。
  • argocd-image-updater.argoproj.io/allow-tags: 這個(gè)注解指定了允許更新的鏡像標(biāo)簽,可以使用正則表達(dá)式的方式。-
  • argocd-image-updater.argoproj.io/<alias>.pull-secret: 這個(gè)注解指定了用于拉取鏡像的 Secret。
  • argocd-image-updater.argoproj.io/update-strategy: 這個(gè)注解定義了鏡像更新策略。這里的值是 latest,表示使用最新的鏡像標(biāo)簽進(jìn)行更新,還可以指定的值包括:digest、name、semver。
  • argocd-image-updater.argoproj.io/write-back-method: 這個(gè)注解定義了更新后的配置寫回方法。git 表示將更新后的配置寫回到 Git 倉庫。
  • argocd-image-updater.argoproj.io/git-branch:這個(gè)注解定義了更新后的配置寫回到 Git 倉庫的分支。

注意上面我們配置了一個(gè) pull-secret 的注解,如果使用的是 docker hub,需要在個(gè)人中心去創(chuàng)建一個(gè) access token:

docker access token

然后使用如下命令創(chuàng)建一個(gè) secret:

kubectl create -n argocd secret docker-registry dockerhub-secret \
  --docker-username xxxx \
  --docker-password xxxx \
  --docker-server "https://registry-1.docker.io"

然后我們就可以創(chuàng)建這個(gè)應(yīng)用了:

$ kubectl apply -f demo-app2.yaml

創(chuàng)建后正常第一次會(huì)去同步部署應(yīng)用。然后接下來我們可以去修改 Jenkins Pipeline 的流水線,只需要保留到鏡像構(gòu)建的部分即可,其他的部分都可以去掉了。

podTemplate(cloud: "Kubernetes", containers: [
  containerTemplate(name: 'golang', image: 'golang:1.18.3-alpine3.16', command: 'cat', ttyEnabled: true),
  containerTemplate(name: 'docker', image: 'docker:latest', command: 'cat', ttyEnabled: true),
  containerTemplate(name: 'kubectl', image: 'cnych/kubectl', command: 'cat', ttyEnabled: true)
], serviceAccount: 'jenkins', envVars: [
  envVar(key: 'DOCKER_HOST', value: 'tcp://docker-dind:2375')  // 環(huán)境變量
]) {
  node(POD_LABEL) {
    def myRepo = checkout scm
    def gitCommit = myRepo.GIT_COMMIT
    def gitBranch = myRepo.GIT_BRANCH

    // 獲取 git commit id 作為鏡像標(biāo)簽
    def imageTag = sh(script: "git rev-parse --short HEAD", returnStdout: true).trim()
    // 倉庫地址
    def registryUrl = "docker.io"
    def imageEndpoint = "cnych/devops-demo"
    // 鏡像
    def image = "${registryUrl}/${imageEndpoint}:${imageTag}"

    stage('單元測(cè)試') {
      echo "測(cè)試階段"
    }
    stage('代碼編譯打包') {
        try {
            container('golang') {
            echo "2.代碼編譯打包階段"
            sh """
                export GOPROXY=https://goproxy.io
                GOOS=linux GOARCH=amd64 go build -v -o demo-app
                """
            }
        } catch (exc) {
            println "構(gòu)建失敗 - ${currentBuild.fullDisplayName}"
            throw(exc)
        }
    }
    stage('構(gòu)建 Docker 鏡像') {
        withCredentials([[$class: 'UsernamePasswordMultiBinding',
            credentialsId: 'docker-auth',
            usernameVariable: 'DOCKER_USER',
            passwordVariable: 'DOCKER_PASSWORD']]) {
            container('docker') {
                echo "3. 構(gòu)建 Docker 鏡像階段"
                sh """
                docker login ${registryUrl} -u ${DOCKER_USER} -p ${DOCKER_PASSWORD}
                docker build -t ${image} .
                docker push ${image}
                """
            }
        }
    }
}

重新提交上面的流水線過后,最終我們會(huì)將應(yīng)用鏡像推送到鏡像倉庫中去。

然后 Argo CD Image Updater 將會(huì)每 2 分鐘從鏡像倉庫去檢索鏡像版本變化,一旦發(fā)現(xiàn)有新的鏡像版本,它將自動(dòng)使用新版本來更新集群內(nèi)工作負(fù)載的鏡像,并將鏡像版本回寫到 Git 倉庫重去。我們可以去查看 Argo CD Image Updater 的日志變化:

$ kubectl logs -f argocd-image-updater-56d94c674d-npgqp -n argocd
# ......
time="2023-09-19T06:39:12Z" level=info msg="Starting image update cycle, considering 1 annotated application(s) for update"
time="2023-09-19T06:39:16Z" level=info msg="Setting new image to cnych/devops-demo:a6268b3" alias=myalias applicatinotallow=devops-demo2 image_name=cnych/devops-demo image_tag=739a588 registry=
time="2023-09-19T06:39:16Z" level=info msg="Successfully updated image 'cnych/devops-demo:739a588' to 'cnych/devops-demo:a6268b3', but pending spec update (dry run=false)" alias=myalias applicatinotallow=devops-demo2 image_name=cnych/devops-demo image_tag=739a588 registry=
time="2023-09-19T06:39:16Z" level=info msg="Committing 1 parameter update(s) for application devops-demo2" applicatinotallow=devops-demo2
time="2023-09-19T06:39:16Z" level=info msg="Starting configmap/secret informers"
time="2023-09-19T06:39:17Z" level=info msg="Configmap/secret informer synced"
time="2023-09-19T06:39:17Z" level=info msg="Initializing http://gitlab.k8s.local/cnych/k8s-demo-config.git to /tmp/git-devops-demo23205764981"
time="2023-09-19T06:39:17Z" level=info msg="rm -rf /tmp/git-devops-demo23205764981" dir= execID=14972
time="2023-09-19T06:39:17Z" level=info msg="secrets informer cancelled"
time="2023-09-19T06:39:17Z" level=info msg="configmap informer cancelled"
time="2023-09-19T06:39:17Z" level=info msg=Trace args="[rm -rf /tmp/git-devops-demo23205764981]" dir= operation_name="exec rm" time_ms=4.474982
time="2023-09-19T06:39:17Z" level=info msg="git fetch origin --tags --force" dir=/tmp/git-devops-demo23205764981 execID=08213
time="2023-09-19T06:39:17Z" level=info msg=Trace args="[git fetch origin --tags --force]" dir=/tmp/git-devops-demo23205764981 operation_name="exec git" time_ms=492.78976600000004
time="2023-09-19T06:39:17Z" level=info msg="git config user.name argocd-image-updater" dir=/tmp/git-devops-demo23205764981 execID=35e12
time="2023-09-19T06:39:17Z" level=info msg=Trace args="[git config user.name argocd-image-updater]" dir=/tmp/git-devops-demo23205764981 operation_name="exec git" time_ms=1.4469750000000001
time="2023-09-19T06:39:17Z" level=info msg="git config user.email noreply@argoproj.io" dir=/tmp/git-devops-demo23205764981 execID=6515c
time="2023-09-19T06:39:17Z" level=info msg=Trace args="[git config user.email noreply@argoproj.io]" dir=/tmp/git-devops-demo23205764981 operation_name="exec git" time_ms=1.593801
time="2023-09-19T06:39:17Z" level=info msg="git checkout --force main" dir=/tmp/git-devops-demo23205764981 execID=e5492
time="2023-09-19T06:39:17Z" level=info msg=Trace args="[git checkout --force main]" dir=/tmp/git-devops-demo23205764981 operation_name="exec git" time_ms=5.05169
time="2023-09-19T06:39:17Z" level=info msg="git clean -fdx" dir=/tmp/git-devops-demo23205764981 execID=5cca4
time="2023-09-19T06:39:17Z" level=info msg=Trace args="[git clean -fdx]" dir=/tmp/git-devops-demo23205764981 operation_name="exec git" time_ms=1.8230989999999998
time="2023-09-19T06:39:17Z" level=info msg="git commit -a -F /tmp/image-updater-commit-msg2911699728" dir=/tmp/git-devops-demo23205764981 execID=ac1b3
time="2023-09-19T06:39:17Z" level=info msg=Trace args="[git commit -a -F /tmp/image-updater-commit-msg2911699728]" dir=/tmp/git-devops-demo23205764981 operation_name="exec git" time_ms=7.143674
time="2023-09-19T06:39:17Z" level=info msg="git push origin main" dir=/tmp/git-devops-demo23205764981 execID=136ad
time="2023-09-19T06:39:18Z" level=info msg=Trace args="[git push origin main]" dir=/tmp/git-devops-demo23205764981 operation_name="exec git" time_ms=874.7453360000001
time="2023-09-19T06:39:18Z" level=info msg="Successfully updated the live application spec" applicatinotallow=devops-demo2
time="2023-09-19T06:39:18Z" level=info msg="Processing results: applicatinotallow=1 images_cnotallow=1 images_skipped=0 images_updated=1 errors=0"
time="2023-09-19T06:41:18Z" level=info msg="Starting image update cycle, considering 1 annotated application(s) for update"
time="2023-09-19T06:41:21Z" level=info msg="Processing results: applicatinotallow=1 images_cnotallow=1 images_skipped=0 images_updated=0 errors=0"
time="2023-09-19T06:43:21Z" level=info msg="Starting image update cycle, considering 1 annotated application(s) for update"
# ......

另外需要注意的是在回寫時(shí),ArgoCD Image Updater 并不會(huì)直接修改倉庫的 values.yaml 文件,而是會(huì)創(chuàng)建一個(gè)專門用于覆蓋 Helm Chart values.yaml 的 .argocd-source-devops-demo2.yaml 文件。

config repo

自動(dòng)提交變更后,Argo CD 就會(huì)自動(dòng)同步部署應(yīng)用了。

責(zé)任編輯:姜華 來源: k8s技術(shù)圈
相關(guān)推薦

2022-08-16 22:39:01

Argo CDKubernetes

2024-05-22 08:03:15

2024-09-11 09:25:00

2021-07-09 06:40:59

TektonArgo CD GitOps

2021-01-05 08:39:51

容器前端流水線

2019-11-07 09:00:39

Jenkins流水線開源

2021-07-04 07:24:48

GitOps 工具 Argo CD

2017-03-02 14:12:13

流水線代碼Clojure

2022-08-18 17:07:00

sopsGitOps

2021-04-09 09:45:33

GitOps環(huán)境應(yīng)用程序

2021-06-28 06:32:46

Tekton Kubernetes Clone

2021-06-24 07:20:21

Linked GitOps Argo CD

2017-02-28 15:40:30

Docker流水線Azure

2021-11-08 07:41:16

Go流水線編程

2024-01-07 12:47:35

Golang流水線設(shè)計(jì)模式

2013-06-06 09:31:52

2017-02-28 16:00:45

DevOpsMarkdownreST

2023-05-10 15:08:00

Pipeline設(shè)計(jì)模式

2022-07-18 06:05:28

Gitlab流水線

2021-12-08 12:20:55

KubernetesGitOpsLinux
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

久久99国产精品自在自在app| 亚洲在线视频免费观看| 国产精品亚发布| 国产乱国产乱老熟300| 日本免费一区二区视频| 亚洲一区二区三区美女| 欧美亚洲另类久久综合| 国产一区二区三区视频免费观看| 欧美久久成人| 亚洲毛片在线免费观看| 亚洲黄色片免费看| 国产精品原创| 中文字幕亚洲电影| 国产欧美一区二区视频| 中文字幕在线观看免费| 亚洲高清av| 在线观看精品自拍私拍| 永久免费未满蜜桃| av在线成人| 欧美小视频在线| 亚洲精品少妇一区二区| 91gao视频| 男人的天堂免费| 99久久综合国产精品二区| 一区二区三区四区在线免费观看 | 久久久精品区| 日本高清不卡一区| 可以在线看的av网站| 久草中文在线| 欧美国产日本视频| 麻豆av一区二区三区| 亚洲av无码国产精品永久一区 | 手机看片1024日韩| 国产在线播放一区二区三区| 国产日韩一区二区三区在线| 中文字幕视频一区二区在线有码| 亚洲色图14p| 日韩欧美另类中文字幕| 欧美日韩国产精选| 人人干人人视频| 亚洲精品成人图区| 天天综合天天做天天综合| 日韩黄色片在线| 国产色在线观看| 国产精品视频一区二区三区不卡| 久久亚洲国产精品日日av夜夜| 亚洲av无码一区二区乱子伦| 狠狠色丁香久久婷婷综合丁香| 国产精品视频99| 亚洲天堂视频在线播放| 久久精品一区二区国产| 欧美夜福利tv在线| 国产原创视频在线| 亚洲欧美大片| 国产va免费精品高清在线观看 | 亚洲精选成人| 97久久久免费福利网址| 男人天堂中文字幕| 国产欧美二区| 日本韩国欧美精品大片卡二| 9i精品福利一区二区三区| 久久黄色网页| 国产精品美女无圣光视频| 中文字幕男人天堂| 久久国产精品无码网站| 亚洲伊人久久大香线蕉av| 99久久精品国产成人一区二区| 国产乱码一区二区三区| 国产不卡一区二区在线观看| 天堂在线精品视频| 日韩欧美在线观看免费| 亚洲女人av| 国产精品日韩在线观看| 亚洲在线免费观看视频| 韩国视频一区二区| 成人看片在线| 日韩精品一二| 中文字幕免费不卡在线| a级网站在线观看| 成人福利电影| 在线视频中文字幕一区二区| 性欧美1819| 无码国模国产在线观看| 日韩电影网在线| 谁有免费的黄色网址| 围产精品久久久久久久| 韩国欧美亚洲国产| 亚洲成人第一网站| 国产一区二区三区综合| 精品日产一区2区三区黄免费 | 成人午夜看片网址| 欧美日本亚洲| 超碰人人在线| 欧美性jizz18性欧美| 污污的网站免费| 国产精品nxnn| 在线观看亚洲区| 久久亚洲成人av| 奇米色777欧美一区二区| 999热视频| 国模吧精品人体gogo| 亚洲视频一区在线| 看av免费毛片手机播放| av在线国产精品| 亚洲欧美精品一区| 艳妇荡乳欲伦69影片| 亚洲永久免费| 999视频在线免费观看| 日韩欧美亚洲系列| 亚洲综合自拍偷拍| 无限资源日本好片| 人妖一区二区三区| 久久激情视频久久| 日本黄色片视频| 国产精品88888| 亚洲国产一区在线| 成人欧美大片| 精品不卡在线视频| 欧美大片xxxx| 日本va欧美va瓶| 久久久久久久久一区| 欧美精品videosex| 91麻豆精品国产91久久久使用方法 | 成人毛片老司机大片| 正在播放国产精品| 在线一区视频观看| 亚洲精品永久免费| 青青操免费在线视频| 国产精品一二三四区| 亚洲最大免费| 国产亚洲精彩久久| 亚洲午夜国产成人av电影男同| 国产视频91在线| 丁香啪啪综合成人亚洲小说| 一区二区三区日韩视频| 久久久久黄色| 正在播放欧美一区| 嫩草影院一区二区三区| 久久久精品一品道一区| 国产乱子伦农村叉叉叉| 国产香蕉精品| 国内精品久久久久久久久| 性猛交xxxx乱大交孕妇印度| 亚洲三级电影网站| 奇米777在线| 欧美aa国产视频| 亚洲自拍小视频| 综合久久2o19| 欧美va在线播放| 久草福利资源在线观看| 高清不卡一二三区| 毛片av在线播放| 91九色鹿精品国产综合久久香蕉| 色噜噜久久综合伊人一本| 性高潮视频在线观看| 五月综合久久| 国产精品女同互慰在线看| 丰满少妇大力进入| 卡一精品卡二卡三网站乱码| 97成人精品区在线播放| 免费在线观看污视频| 日本国产一区二区| 中文字幕第69页| 国模一区二区三区白浆| 日韩专区第三页| 国产精品对白| 日本免费久久高清视频| caoporn国产精品免费视频| 欧美日韩国产天堂| 欧美人与禽zozzo禽性配| 国产98色在线|日韩| 国产精品国产亚洲精品看不卡| 色先锋久久影院av| 国产精品入口福利| 尤物视频在线看| 日韩成人在线观看| 中文无码av一区二区三区| 亚洲色图视频网| 亚洲av成人无码一二三在线观看| 亚洲伊人观看| 午夜探花在线观看| 精品亚洲自拍| 国产日韩欧美91| h片在线观看| 中文字幕国内精品| 精品国产av一区二区三区| 精品美女国产在线| 四季av中文字幕| 成人一区二区在线观看| 不卡av免费在线| 欧美一区综合| 欧洲精品一区色| 精品一区二区三区在线观看视频| 91国产一区在线| 黄色一级大片在线免费看产| 亚洲第一综合天堂另类专| 久久精品99北条麻妃| 亚洲国产精品人人做人人爽| 综合久久五月天| 国产在线观看你懂的| 国产日韩欧美综合在线| 久久久久久国产精品日本| 久久精品123| 亚洲色欲久久久综合网东京热| 国产不卡一二三区| 国产精品国产精品| 欧美成人家庭影院| 欧美夜福利tv在线| 福利写真视频网站在线| 在线视频中文亚洲| 亚欧洲精品视频| 精品剧情在线观看| 国产又大又黄又爽| 欧洲国产伦久久久久久久| 日本在线观看中文字幕| 亚洲欧美激情插| 久久精品三级视频| 久久综合色鬼综合色| 亚洲av午夜精品一区二区三区| 麻豆精品久久久| 99久久激情视频| 亚洲视频大全| av免费观看大全| 夜间精品视频| 在线日韩av永久免费观看| 国产成人精品免费视| 激情视频一区二区| 日韩一区二区三区色| 91久久精品视频| 一区二区三区无毛| 国产日韩综合一区二区性色av| 午夜精品久久久久久久久久蜜桃| 97激碰免费视频| av伦理在线| 欧美激情中文网| gogo高清在线播放免费| 欧美xxxx做受欧美| 超碰在线caoporn| 久久中文字幕一区| av观看在线| 欧美成人免费大片| 神马午夜伦理不卡 | 黄页在线观看免费| 欧美黑人国产人伦爽爽爽| 91最新在线视频| 欧美裸身视频免费观看| 污片视频在线免费观看| 99国产精品免费视频观看| 欧美日韩一区二区三区在线视频| 亚洲妇女av| 欧美精品一区二区三区在线看午夜| 日韩高清一级| 日韩av电影在线观看| 日韩精品一卡| 中文字幕一区二区三区四区五区人| 亚洲澳门在线| 国产亚洲精品久久久久久久| 精品电影一区| 日日鲁鲁鲁夜夜爽爽狠狠视频97| 久久av在线| 69久久久久久| 国产精品影视在线| 北京富婆泄欲对白| 久久久三级国产网站| 国产精品一区二区亚洲| 一区二区三区日本| 日本一级一片免费视频| 一本到不卡免费一区二区| 中文字幕人妻一区二区在线视频 | 亚洲一区二区三区四区的| 日本一本高清视频| 一道本成人在线| 91亚洲视频在线观看| 精品国产伦一区二区三区免费 | 国产成人精品亚洲线观看| 精品卡一卡二| 日韩极品一区| 中文精品无码中文字幕无码专区 | 亚洲狠狠爱一区二区三区| 五月天婷婷综合网| 欧美日韩精品一区视频| 亚洲第九十九页| 亚洲一品av免费观看| av网站大全在线| 欧美一级淫片播放口| 四虎影视精品永久在线观看| 国产精品久久久久久久免费大片 | jazzjazz国产精品麻豆| 欧美少妇一区| 日本中文字幕有码| 国产剧情在线观看一区二区| 艳妇乳肉亭妇荡乳av| 国产精品伦理一区二区| 久久免费在线观看视频| 欧美视频一区二区在线观看| www.日日夜夜| 中文字幕一精品亚洲无线一区| 激情图片在线观看高清国产| 国产精品欧美日韩| 乱中年女人伦av一区二区| 成年人免费观看的视频| 亚洲一区欧美二区| 曰本三级日本三级日本三级| 国产午夜久久久久| 日韩大片免费在线观看| 91精品国产一区二区三区蜜臀| 青草久久伊人| 国语自产精品视频在线看| 成人国产精品| 乱一区二区三区在线播放| 欧美人成网站| www.cao超碰| 国产日韩欧美精品一区| 日韩xxx高潮hd| 精品欧美一区二区三区精品久久 | 欧美精品久久久久久久| 欧美亚洲黄色| 欧美日韩高清在线一区| 亚洲日本视频| jjzz黄色片| 亚洲精品视频在线观看网站| 国产乱码在线观看| 亚洲免费视频在线观看| 久久影院午夜精品| 成人看片视频| 欧美黄污视频| 999热精品视频| 亚洲色图在线播放| 91精品人妻一区二区三区果冻| 亚洲人免费视频| 卡通欧美亚洲| 欧美精品七区| 麻豆精品网站| 亚洲永久精品ww.7491进入| 亚洲国产精品久久久久婷婷884| 成人h动漫精品一区二区无码 | 日韩精品99| 蜜桃免费一区二区三区| 亚洲综合国产| www.中文字幕av | 超碰在线观看99| 欧美高清视频在线| 成人av综合网| 青草视频在线观看视频| 成人国产精品免费观看| 日本系列第一页| 精品视频久久久久久| 欧美一级大黄| 亚洲国产精品视频一区| 久久精品国产亚洲a| 天海翼在线视频| 日韩午夜电影在线观看| 免费男女羞羞的视频网站在线观看| 91久久精品国产91久久性色tv| 欧美日韩mv| 粉嫩av懂色av蜜臀av分享| 午夜精品视频一区| 免费av在线电影| 国产精品久久久久久久午夜| 91久久夜色精品国产按摩| www.午夜av| 亚洲一区二区三区四区五区黄| 亚洲人成色777777精品音频| 国产ts人妖一区二区三区 | 中文字幕av一区| 国产精品毛片无码| 日韩a级在线观看| 久久免费精品国产久精品久久久久| www.日韩一区| 久久精品国产亚洲7777| 国产欧美三级电影| 白嫩少妇丰满一区二区| 亚洲伦理在线精品| 精品黑人一区二区三区国语馆| 国模视频一区二区三区| 国产一区二区三区天码| 天天爽夜夜爽视频| 欧美日韩激情视频| 欧美另类极品| 精品久久久久久一区| 免费不卡在线视频| 久久亚洲AV无码| 在线日韩日本国产亚洲| 在线观看视频一区二区三区| 国产精品97在线| 亚洲欧美视频一区| 久久久久久久影视| 91传媒视频免费| 日韩综合在线视频| 久久免费视频播放| 色妞在线综合亚洲欧美| 欧美国产不卡| 国产精品嫩草影院8vv8| 欧美午夜无遮挡| 日韩成人伦理| 亚洲天堂电影网| 91论坛在线播放| 亚洲综合网在线观看| 精品一区免费av| 手机看片久久久|