精品欧美一区二区三区在线观看 _久久久久国色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)

182在线视频| 日本黄大片在线观看| 亚洲天堂网在线观看视频| 国产精品精品| 亚洲成人精品在线| 最近免费中文字幕中文高清百度| 黄色动漫在线| 2021国产精品久久精品| 国产精品激情av电影在线观看 | 欧美国产激情一区二区三区蜜月| 国产综合在线观看视频| av黄色在线看| 自拍偷拍欧美| 一本色道久久88综合亚洲精品ⅰ| 欧美一级大片免费看| 青青热久免费精品视频在线18| 亚洲精品日产精品乱码不卡| 免费看污久久久| 国产高清视频免费观看| 日韩精品一卡二卡三卡四卡无卡| 欧美国产日韩视频| 免费看一级黄色| 亚洲婷婷丁香| 亚洲成人av资源网| 天天色天天干天天色| 日本综合视频| 欧美三级xxx| 日韩a级在线观看| 成人无遮挡免费网站视频在线观看| 久久青草欧美一区二区三区| 成人高清在线观看| 中文字幕乱码中文字幕| 久久激情久久| 欧美最猛性xxxxx亚洲精品| 久久久久亚洲av片无码下载蜜桃| 99欧美视频| 中文字幕精品一区久久久久| 精品人妻少妇嫩草av无码| ccyy激情综合| 日韩欧美国产三级| 久久精品国产99久久99久久久| 欧美在线va视频| 色婷婷狠狠综合| 国产肥臀一区二区福利视频| 91豆花视频在线播放| 亚洲综合久久av| 久久精品在线免费视频| 91麻豆国产福利在线观看宅福利| 国产精品久久久久久户外露出| 日韩欧美视频一区二区| 国产福利片在线| 国产婷婷色一区二区三区四区| 老牛影视免费一区二区| 欧美香蕉爽爽人人爽| 91免费小视频| 欧美日韩国产精品一卡| 可以在线观看的黄色| 久久丝袜美腿综合| 日本高清一区| 91精品大全| 中文字幕综合网| 先锋影音男人资源| 欧美巨大xxxx做受沙滩| 亚洲高清免费观看| 国产老熟妇精品观看| 涩涩视频在线播放| 日本韩国一区二区三区视频| 簧片在线免费看| 日韩av黄色| 欧美一区二区人人喊爽| 在线看黄色的网站| 免费成人结看片| 日韩中文字幕免费| 欧美国产在线看| 99成人免费视频| 国产激情视频一区| 国产乱淫av免费| 成人黄色小视频在线观看| 免费精品视频一区二区三区| av中文字幕在线| 亚洲免费在线看| 亚洲熟妇国产熟妇肥婆| 香蕉久久免费电影| 制服.丝袜.亚洲.另类.中文| 99久久久无码国产精品性波多| 亚洲图区在线| 欧美成人免费小视频| 国产成人亚洲精品自产在线| 日韩福利电影在线| 亚洲最大福利视频| 人成免费电影一二三区在线观看| 国产精品午夜在线观看| 日韩精品在线中文字幕| 韩国成人在线| 精品伦理精品一区| 人妻av无码一区二区三区| 牛牛国产精品| 国产精品高潮呻吟久久av无限 | 香蕉精品视频在线| 波多野结衣在线播放| 91久久精品日日躁夜夜躁欧美| 欧美专区第二页| 国产aⅴ精品一区二区三区久久| 久久久精品一区| 中文在线第一页| 国产成人在线视频免费播放| 日韩中文一区二区三区| 免费影视亚洲| 69久久99精品久久久久婷婷| 中文幕无线码中文字蜜桃| 欧美黄色精品| 国产精品女人久久久久久| 手机看片1024日韩| 最新国产成人在线观看| 熟女人妇 成熟妇女系列视频| 亚洲欧美在线人成swag| 国产视频在线观看一区二区| 男女免费视频网站| 国产真实精品久久二三区| 区一区二区三区中文字幕| 韩国成人免费视频| 51精品国自产在线| 中文字幕免费在线看线人动作大片| 亚洲一级一区| 亚洲在线免费视频| 日韩伦理在线观看| 91成人免费网站| 久久久久久九九九九九| 亚洲少妇在线| 高清免费日韩| 日韩三级电影视频| 91精品国产综合久久香蕉麻豆| 卡一卡二卡三在线观看| 久久久久国产精品一区二区| 蜜桃免费一区二区三区| 77thz桃花论族在线观看| 日韩精品在线网站| 欧美精品乱码视频一二专区| 国产精品66部| 91传媒免费视频| 国产精品国产亚洲精品| 日韩中文在线观看| 91麻豆成人精品国产| 国产精品久久久久久久久久久免费看| 国产又粗又长又大的视频| 欧美中文一区二区| 国产精品日韩在线一区| 一区二区高清不卡| 欧美日韩高清影院| 亚洲欧美卡通动漫| 韩国女主播成人在线观看| 中文字幕久久综合| 日韩精品视频中文字幕| 欧美猛交免费看| 乱色精品无码一区二区国产盗| 洋洋av久久久久久久一区| 中文字幕永久免费| 国产一区成人| 日本一区免费在线观看| 欧美黄色三级| 在线日韩精品视频| 亚洲一区二区视频在线播放| 亚洲人亚洲人成电影网站色| 久久发布国产伦子伦精品| 激情成人亚洲| 日本一区视频在线播放| 日本一区二区中文字幕| 欧美激情在线观看视频| 天堂av在线免费| 日韩欧美福利视频| 久久一级免费视频| 成人午夜视频福利| 欧美 日韩精品| 99久久亚洲精品蜜臀| www.久久草| 色综合一本到久久亚洲91| 精品国产一区二区三区四区在线观看 | 伊人精品影院| 亚洲精品福利资源站| 波多野结衣爱爱| 亚洲精选视频在线| 大黑人交xxx极品hd| 免费高清不卡av| 欧美黄网在线观看| 曰本一区二区三区视频| 成人做爽爽免费视频| 黄色在线网站噜噜噜| 一区国产精品视频| www.com欧美| 在线欧美一区二区| 国产亚洲欧美久久久久 | 日日骚一区二区三区| 99久久综合精品| 欧美视频国产视频| 国产亚洲福利| 91视频 - 88av| 国产影视一区| 国产精品久久国产精品| 黑人巨大精品| 久久久女女女女999久久| www.成人.com| 日韩黄在线观看| 国产成人a人亚洲精品无码| 91福利在线导航| 日本学生初尝黑人巨免费视频| 中文无字幕一区二区三区 | 成人免费视频国产| 欧美日韩高清一区二区不卡| www.毛片.com| 亚洲综合免费观看高清完整版在线 | 久久久久亚洲精品国产| 日本中文在线观看| 国产亚洲精品一区二555| 狠狠综合久久av一区二区| 欧美日韩国产欧美日美国产精品| 四虎精品永久在线| 一卡二卡三卡日韩欧美| 日韩精品123区| 中文字幕第一区综合| 成人午夜福利一区二区| 成人avav影音| 国产精品99久久久精品无码| 精东粉嫩av免费一区二区三区| 国内外免费激情视频| 亚洲人成高清| 久久手机在线视频| 欧美日本精品| 99精品一区二区三区的区别| 91麻豆国产自产在线观看亚洲| 日韩精品欧美专区| 欧美**字幕| 久久久久久久久一区二区| 国产伦精品一区二区三区在线播放| 亚洲一区二区在线| 国产美女亚洲精品7777| 亚洲一区二区中文| 欧美电影在线观看一区| 99re6热在线精品视频播放速度| 欧美黑粗硬大| 国产免费一区二区三区香蕉精| 91在线成人| 国产精品三级久久久久久电影| 欧美日韩视频网站| 国产精品99久久99久久久二8| 成人av观看| 国产精品69久久久久| 亚洲精品.com| 国产噜噜噜噜噜久久久久久久久| 国产三级一区| 成人免费网站在线| 日韩欧美中文字幕在线视频 | 天天干在线观看| 亚洲国产免费av| 奇米影视888狠狠狠777不卡| 亚洲精品视频中文字幕| 蜜桃视频在线观看网站| 中文字幕成人精品久久不卡| 99青草视频在线播放视| 久久精品99久久久香蕉| 中文字幕中文字幕在线中高清免费版| 欧美成aaa人片免费看| 国精一区二区三区| 欧美最猛黑人xxxx黑人猛叫黄| 成人自拍av| 国产日韩精品入口| 成人资源在线播放| 久久精品国产综合精品| 日韩欧美网站| 久久久久久久久久伊人| 亚洲在线黄色| 久久国产精品国产精品| 国产黄色成人av| 菠萝菠萝蜜网站| 国产精品日韩精品欧美在线| 午夜免费激情视频| 欧美日在线观看| 国产精品主播一区二区| 亚洲精品福利资源站| 一本一道波多野毛片中文在线 | 国产精品亚洲综合在线观看| 国产精品污www一区二区三区| 国产精品手机在线播放| 福利网在线观看| 亚洲影视综合| 无套白嫩进入乌克兰美女| 久久综合久色欧美综合狠狠| 亚洲aaa视频| 婷婷成人综合网| 国产精品视频在线观看免费| 亚洲国产一区二区三区四区 | 国产69精品久久久| 少妇精品视频一区二区免费看| 999日本视频| 欧美一级精品| av在线播放亚洲| 国产在线视频一区二区| 粉嫩av蜜桃av蜜臀av| 亚洲美女视频在线观看| 波多野结衣爱爱| 亚洲电影免费观看高清| 免费在线观看黄| 清纯唯美日韩制服另类| 综合激情网...| 亚洲欧洲一区二区福利| 亚洲欧美日韩精品一区二区 | 亚洲人成小说网站色在线| 亚洲影院在线播放| 亚洲第一视频网| 2024短剧网剧在线观看| 国产精品中文在线| 亚洲+变态+欧美+另类+精品| 男人的天堂视频在线| 日本色护士高潮视频在线观看| 成人福利视频在线看| 国产视频一区二区三区四区| 天天做天天爱天天爽综合网| 国内性生活视频| 国产成人精品免费看| av资源在线免费观看| 91成人免费电影| 亚洲欧洲精品视频| 欧美激情伊人电影| 欧美a级大片在线| 中文字幕制服丝袜在线| 日产欧产美韩系列久久99| 亚洲精品乱码久久久久久不卡| 亚洲一区二区三区国产| 国产三级三级在线观看| 最新亚洲国产精品| 一呦二呦三呦精品国产| 久久久精品动漫| 国产亚洲成人一区| 菠萝菠萝蜜网站| 欧美日韩在线看| 日本高清中文字幕二区在线| 51视频国产精品一区二区| 日韩精品福利一区二区三区| 欧美精品一区二区三区三州| 成人高清视频免费观看| 国产91av视频| 日韩欧美一区在线观看| 91国内在线| 超碰97在线资源| 精品9999| 欧美 日本 国产| 色综合久久综合网97色综合| 免费在线性爱视频| 国产精品草莓在线免费观看| 欧美日韩久久精品| 牛夜精品久久久久久久| 国产精品乱码久久久久久| 国产一区二区在线不卡| 免费成人高清视频| 一区二区三区亚洲变态调教大结局 | 午夜欧美在线一二页| 无码国产精品一区二区色情男同| 欧美在线观看网站| 精品精品久久| 午夜免费福利视频在线观看| 亚洲天堂2014| 丰满肥臀噗嗤啊x99av| 91po在线观看91精品国产性色| 中日韩免视频上线全都免费| 亚洲人辣妹窥探嘘嘘| 中文字幕综合网| 欧美自拍第一页| 日韩av电影国产| 国产精品99一区二区三| 在线播放av网址| 欧美性猛交xxxx免费看漫画| 成a人片在线观看www视频| 91精品中文在线| 亚洲欧洲一区| 国产成人免费观看网站| 91精品国产91久久久久久最新毛片| 成人性生交大片免费看网站| 欧美日韩精品免费看| 黄色资源网久久资源365| 国产亚洲精品久久久久久无几年桃| 日韩精品在线看| vam成人资源在线观看| 国产96在线 | 亚洲| 国产精品久久久久久妇女6080| 丰满熟妇乱又伦| 国产精品久久久久久av福利软件| 成人性生活毛片| 欧美美女喷水视频| 91超碰在线免费| 亚洲自拍偷拍二区| 成人激情午夜影院| 中文字幕在线观看你懂的| 欧美激情图片区| 欧美限制电影| 亚洲婷婷在线观看| 欧美日韩一区二区三区四区五区| 好吊日av在线| 9999在线观看| 久久精品欧美日韩| 亚洲精品免费在线观看视频| 国产97在线视频|