自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

使用 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í)跟蹤對分支、標(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 倉庫中對期望目標(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 對象)
  • 認(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)行比較。它檢測應(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

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

然后我們可以在本地(選擇對應(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 的方式來對外暴露服務(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 對象和規(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ù)器檢測到正在使用的協(xié)議,并做出適當(dāng)?shù)捻憫?yīng)。請注意,nginx.ingress.kubernetes.io/ssl-passthrough 注解要求將 --enable-ssl-passthrough 標(biāo)志添加到 nginx-ingress-controller 的命令行參數(shù)中。

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

如下所示為 HTTP/HTTPS 的 Ingress 對象:

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é)議對應(yīng)的 Ingress 對象如下所示:

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 對象下的 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)證信息注冊到 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,比如對于 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ì)檢測 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 的資源對象來創(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)用

由于上面我們在創(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)在我們就可以查看其資源組件、日志、事件和評估其健康狀態(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 中我們在發(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)行對接,整個(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)可以用來對 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 對象即可:

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

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

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

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

$ 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)境中刪除對應(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('單元測試') {
      echo "測試階段"
    }
    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"
            }
        }
    }

  }
}

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

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

默認(rèn)情況下 Argo CD 每三分鐘輪詢一次 Git 存儲(chǔ)庫,以檢測清單的更改。為了消除輪詢延遲,可以將 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ì)對你的工作負(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 對象,對應(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è)新的資源對象中,我們添加了一些注釋,這些注釋用于配置 Argo CD Image Updater。這些配置用于指定自動(dòng)更新容器鏡像的策略、參數(shù)和相關(guān)信息。以下是對這些注釋的詳細(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('單元測試') {
      echo "測試階段"
    }
    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-09-11 09:25:00

2021-01-05 08:39:51

容器前端流水線

2024-05-22 08:03:15

2019-11-07 09:00:39

Jenkins流水線開源

2021-07-09 06:40:59

TektonArgo CD GitOps

2017-03-02 14:12:13

流水線代碼Clojure

2021-07-04 07:24:48

GitOps 工具 Argo CD

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

2022-07-18 06:05:28

Gitlab流水線

2017-02-28 16:00:45

DevOpsMarkdownreST

2023-05-10 15:08:00

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

2013-06-06 09:31:52

2017-02-28 15:40:30

Docker流水線Azure

2021-11-08 07:41:16

Go流水線編程

2024-01-07 12:47:35

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

2021-06-24 07:20:21

Linked GitOps Argo CD

2017-02-14 21:00:33

大數(shù)據(jù)機(jī)器學(xué)習(xí)廣告檢測
點(diǎn)贊
收藏

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