用GitHub Actions、ArgoCD、Helm和Kubernetes建立自动化CI/CD管道

1,040 阅读8分钟

在这个例子中,我们将为我们的一个应用程序实现一个完整的CI/CD管道。对于CI(持续集成),我们将使用GitHub Actions,对于CD(持续部署/交付),我们将使用ArgoCD。为了使一些步骤动态化,减少重复性,我们将使用Helm图表,而不是普通的Kubernetes清单*(不过没有什么能阻止你抛弃Helm,坚持使用普通的K8S清单*)。最后,应用程序将被部署到几个不同的Kubernetes集群,并有不同的命名空间。虽然这是为多版本应用程序设计的,但你也可以很容易地将其适用于单版本。我必须说,在把Helm图表移到配置仓库并对其他配置进行一些小调整后,它将非常好地适用于monorepo。

我们将创建两个GitHub仓库。一个是应用程序的仓库,用于存放应用程序代码和Helm图表*(我会解释为什么!)。另一个是ArgoCD的声明性配置文件,因为我们不想在每次有新的应用程序出现时都使用用户界面来手动创建许多资源(我们将使用argocd 命令*)。

在我开始之前,我应该明确指出,每个人都会有不同的要求和期望,所以你可以自由地走自己的路。不要觉得你必须按照我在这个例子中的方式做。你可以让所有阶段完全自动化*(GitFlow的分支会对此有很大帮助*)或手动,或者像我这样,部分自动化/手动。如果你愿意花更多的钱,你也可以为每个环境创建一个Kubernetes集群 :)所有选项都有优点和缺点。

Kubernetes设置

如果你愿意,你可以添加更多的集群或命名空间。

CLUSTER     NAMESPACE   DESCRIPTION         DEPLOYMENT STRATEGY            IMAGE TAG

CI/CD策略

这里我解释一下我们的整个设置将如何在每个ArgoCD应用程序条目中表现。dev ,总是在GitHub仓库的HEAD/master变化后自动部署。sbox ,只有在创建新版本和图像标签被添加到Helm Chart文件时才会自动部署。prod ,即使创建新版本或图像标签被添加到Helm Chart文件,也不会自动部署。默认情况下,自动部署是每三分钟进行一次,这是ArgoCD的默认情况。顺便说一下,当我在下面说到 "流程 "时,我指的是ArgoCD用户界面中的 "应用程序 "条目,它代表一个特定的应用程序及其环境。

设计

启用ArgoCD的 "自动同步 "以实现自动部署。ArgoCD 观察对 GitHub 仓库中的 HEAD/master 所做的更改。如果发现有变化,而且DockerHub中的latest 图像标签的摘要与ArgoCD所知道的不同,就开始自动部署。整个CI/CD是自动化的,所以工程师不需要为部署做任何手工操作。

Kubernetes "强制推出 "是启用的,因为我们使用的图像标签总是latest ,否则Pod重新启动不会拉出最新的图像,因为它已经在那里了。反正你也不想在每次推出新功能的时候都创建一个新的独特的图像标签。

在GitHub上创建一个新的版本并不影响这个流程。

sbox

启用ArgoCD的 "自动同步 "来进行自动部署。ArgoCD 观察着对 GitHub 仓库中的 HEAD/master 所做的修改。如果一个新的版本被创建,并且.infra/helm/Chart.yaml:appVersion 与ArgoCD所知道的不同,自动部署就会开始。这个CD流程是部分自动化的,所以工程师需要创建一个拉动请求,将新的发布标签添加到提到的文件中。一旦完成,自动部署就启动了。

Kubernetes的 "强制推出 "功能被禁用,因为它观察的图像标签是一个语义图像标签版本,任何变化都会触发图像拉动。

为这个流程工作所做的一切也将触发dev 流程,因为GitHub仓库的HEAD/master以及DockerHub中的latest 图像标签的摘要都发生了变化。prod 流程将进入 "不同步 "状态,因为ArgoCD知道的语义图像标签现在已经过时。

进展

ArgoCD的 "自动同步 "在自动部署中被禁用。然而,如果创建了一个新的版本,并且.infra/helm/Chart.yaml:appVersion 与ArgoCD所知道的不同,这个流程就会进入 "不同步 "状态,这时工程师可以点击 "SYNC "图标来触发部署。正如你所看到的,这个CD流程是完全手动的,所以工程师需要创建一个拉动请求,将新的发布标签添加到文件中,然后点击 "SYNC "图标。

Kubernetes的 "强制推出 "是禁用的,因为它观察的图像标签是一个语义图像标签版本,任何变化都会触发图像拉动。

这个流程不会影响到dev 流程,因为sbox 流程在进入这个阶段之前已经管理了它。

回滚

如果你为任何环境回滚一个流程,即使有人在任何地方引入了新的变化,它也会保持原样。自动同步选项不会恢复你的回滚,即使HEAD/master commit hash发生变化,创建了一个新的版本或更新了Helm Chart文件。你必须先手动同步流程以解锁它,这是一件好事,因为你不希望你的回滚被过早地恢复了。

将舵手图保留在应用程序库中

ArgoCD建议最好将所有清单或配置文件保存在一个单独的资源库中(例如config ),这有很多好的理由。然而,它有一个问题,打败了全自动部署管道的整个目的。例如,如果你想提供一个完全自动化的CD,就像我为dev 流所做的那样,你将不得不手动更新配置库中的一些东西,这样ArgoCD就会接收到它并触发部署。这是因为,你的配置被设置为监视配置库,而不再是应用程序库。这对工程师来说并不友好,因为正如我所说的,每次你在应用库中引入一些东西时,你也必须在配置中做一些事情。太麻烦了!说了这么多,有些人提出了一个解决方案来避免这种手动操作。这就是在CI步骤中向配置库推送一个提交。我觉得这有点不靠谱。如果 CI 步骤因为冲突而中断怎么办?我也不喜欢在CI管道中拉出一个不同的仓库并推送一个提交给它的想法,因为那是针对不同的仓库。我只是不喜欢这个解决方案的声音。如果你还想要,这里有我的一个例子。

如果你的应用程序仓库被设置为单库,采用ArgoCD的建议会非常有用,因为你可能有数百个服务在里面。在这种情况下,你经常想部署特定的服务,而不是在应用仓库的每一个变化后部署所有的服务。这就太疯狂了。所以简而言之,看看你有什么,做什么是最好的。

GitHub 动作的责任

有三个行动,但其中只有两个直接影响ArgoCD,即 "合并 "和 "发布"。你可以阅读下面实际文件中的详细注释。

merge "动作使用 "最新 "标签推送了一个新的docker镜像。这是为dev CD流程准备的。release "动作推送一个新的docker镜像,使用你刚刚创建的语义镜像标签版本。这适用于sboxprod CD流程。

应用程序仓库

├── .github

文件

merge.yaml
# Trigger the workflow only when:
pull_request.yaml
# Trigger the workflow only when:
release.yaml
# Trigger the workflow only when:
Dockerfile
FROM golang:1.17.5-alpine3.15 as build
Chart.yaml
apiVersion: v2
dev.yaml
namespace: dev
prod.yaml
namespace: default
sbox.yaml
namespace: sbox
configmap.yaml
apiVersion: v1
部署.yaml
apiVersion: apps/v1
service.yaml
apiVersion: v1
.dockerignore
.dockerignore
main.go
package main
main_test.go
package main

配置资源库

这只是为了保留ArgoCD的声明性配置,目前是这样。

└── infra

文件

dev.yaml
apiVersion: argoproj.io/v1alpha1
prod.yaml
apiVersion: argoproj.io/v1alpha1
sbox.yaml
apiVersion: argoproj.io/v1alpha1
project.yaml
apiVersion: argoproj.io/v1alpha1

准备好GitHub

在应用程序仓库中添加DOCKERHUB_USERDOCKERHUB_TOKEN 秘密。你需要先在DockerHub中创建一个令牌,用于DOCKERHUB_TOKEN 。例如:86b2f4b8-816d-4d96-9666-ac0a8066e737 同时创建一个GitHub令牌,称为ARGOCD ,并勾选repo 范围。例如:ghp_816dac0a8066e737966686b2f4b84d96

准备好Kubernetes

创建集群

$ minikube start -p argocd --vm-driver=virtualbox --memory=2000

验证

$ kubectl config get-contexts
$ kubectl config view

安装Helm

头部Helm的Helm CLI安装。我们用它来创建、刷新和调试我们的图表。你可以用它的命令来对付我添加到这个例子中的图表。正如我之前所说,Helm并不是必需的。你可以只使用Kubernetes清单,并做一些小改动。然而,Helm使许多事情变得令人愉快。

ArgoCD的安装

大多数例子都将ArgoCD安装到应用集群中,但我将为ArgoCD准备一个专门的集群,因为我喜欢把事情分开。然后ArgoCD将把应用程序部署到其他集群。查看这里有更多的安装选项。

$ kubectl config current-context

如果你想卸载它,你可以使用下面的命令。

$ kubectl delete -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
$ kubectl get all

让我们把它暴露出来,这样我们就可以用浏览器访问它。顺便说一下,你可以把ArgoCD安装成LoadBalancer,避免端口转发。

$ kubectl port-forward svc/argd-server 8443:443

使用下面的命令提取登录密码。

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

现在你可以把https://localhost:8443/ ,用admin:gYzYfJ5kxzJsdZGK 来登录。

使用下面的命令来安装argocd 命令。这将有助于我们避免在用户界面中手动创建ArgoCD资源。

$ brew tap argoproj/tap && brew install argoproj/tap/argocd
$ argocd version

创建资源

首先我们需要登录。

$ argocd --insecure login 127.0.0.1:8443

添加群集。这仅是CLI。

$ argocd cluster add nonprod

添加应用资源库。

$ argocd repo add https://github.com/you/pacman \

创建项目。如你所见,我们正在从配置库中读取。

$ argocd proj create --file ~/config/infra/argocd/pacman/project.yaml

创建应用程序。如你所见,我们正从应用程序库中读取信息。

$ argocd app create --file ~/pacman/.infra/helm/dev.yaml && \

屏幕截图

集群

存储库

项目

应用程序