3

使用 GitLab CI 与 Argo CD 进行 GitOps 实践

 2 years ago
source link: https://www.qikqiak.com/post/gitlab-ci-argo-cd-gitops/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

使用 GitLab CI 与 Argo CD 进行 GitOps 实践-阳明的博客|Kubernetes|Istio|Prometheus|Python|Golang|云原生

https://unsplash.com/photos/0YL3UFYjR_g

在现在的云原生世界里面 GitOps 不断的被提及,这种持续交付的模式越来越受到了大家的青睐,我们前面也有文章详细讲解了 GitOps 的相关概念,在网上也可以找到很多关于它的资源,但是关于 GitOps 相关的工作流实践的示例却并不多见,我们这里就将详细介绍一个使用示例,希望对大家实践 GitOps 有所帮助。

GitOps WorkflowGitOps Workflow

上图是当前示例中的 GitOps 工作流程。GitLab 和 Argo CD 是两个主要的核心组件:

Argo CD 是一个声明式、GitOps 持续交付的 Kubernetes 工具,它的配置和使用分非常简单,并且自带一个简单一用的 Dashboard 页面,更重要的是 Argo CD 支持 kustomzie、helm、ksonnet 等多种工具。应用程序可以通过 Argo CD 提供的 CRD 资源对象进行配置,可以在指定的目标环境中自动部署所需的应用程序。关于 Argo CD 更多的信息可以查看官方文档了解更多。

GitLab CI 是 GitLab 的持续集成和持续交付的工具,也是非常流行的 CI/CD 工具,相比 Jenkins 更加轻量级,更重要的是和 GitLab 天然集成在一起的,所以非常方便。

Argo CD 安装

当前前提条件是有一个可用的 Kubernetes 集群,通过 kubectl 可以正常访问集群,为了访问 Argo CD 的 Dashboard 页面,我们可以通过 Ingress 来暴露服务,为此需要在 Kubernetes 中安装一个 Ingress Controller,我这里已经提前安装了 ingress-nginx,接下来我们将 Helm3 来安装 Argo CD,关于 Helm 以及 ingress-nginx 的使用我们前面的文章中已经多次提到,这里就不再详细介绍他们的使用了。

首先创建一个 argocd 的命名空间:

$ kubectl create ns argocd

然后添加 argocd 的 chart 仓库地址:

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

接下来我们就可以使用 Helm 安装 Argo CD 了:

$ helm install argocd -n argocd argo/argo-cd --values values.yaml

其中 values.yaml 文件如下所示,用来定制安装的 Argo CD:

server:
  ingress:
    enabled: true
    annotations: 
      kubernetes.io/ingress.class: "nginx"
      nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
      nginx.ingress.kubernetes.io/ssl-passthrough: "true"
      nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
    hosts:
    - argocd.k8s.local

执行上面的安装命令后,Argo CD 就会被安装在 argocd 命名空间之下,可以在本地 /etc/hosts 中添加一个映射,将 argocd.k8s.local 映射到 ingress-nginx 所在的节点即可:

$ helm ls -n argocd
NAME    NAMESPACE       REVISION        UPDATED                                 STATUS    CHART            APP VERSION
argocd  argocd          2               2020-07-10 15:26:38.259258 +0800 CST    deployed  argo-cd-2.5.0    1.6.1
$ kubectl get pods -n argocd
NAME                                             READY   STATUS    RESTARTS   AGE
argocd-application-controller-85c4788ffc-p2m4c   1/1     Running   0          49m
argocd-dex-server-cc65c7546-x78bj                1/1     Running   0          49m
argocd-redis-5f45875bc7-mnx8b                    1/1     Running   0          49m
argocd-repo-server-7bcf647588-h8gtq              1/1     Running   0          49m
argocd-server-7877ff8889-zp7tq                   1/1     Running   0          49m

当所有 Pod 变成 Running 状态后,我们就可以通过浏览器访问 Argo CD 的 Dashboard 页面了:

20200710161259.png

默认的用户名为 admin,密码为 server Pod 的名称,可以通过如下所示的命令来获取:

$ kubectl get pods -n argocd -l app.kubernetes.io/name=argocd-server -o name | cut -d'/' -f 2
argocd-server-7877ff8889-zp7tq

用上面的用户名和密码即可登录成功,接下来我们在 GitLab 中来创建示例项目。

20200710161420.png

GitLab 项目配置

我们这里使用的示例项目是一个 Golang 程序,在页面上显示一个文本信息和 Pod 名称,代码地址:https://github.com/cnych/gitops-webapp-demo。我们可以将该项目代码上传到我们自己的 GitLab 上面去,我这里的 GitLab 安装在 Kubernetes 之上,通过配置域名 git.k8s.local 进行访问,调整过后我们本地的代码仓库地址为:http://git.k8s.local/course/gitops-webapp

接下来需要添加一些在 GitLab CI 流水线中用到的环境变量(Settings → CI/CD → Variables):

  • CI_REGISTRY - 镜像仓库地址,值为:https://index.docker.io/v1/
  • CI_REGISTRY_IMAGE - 镜像名称,值为:cnych/gitops-webapp
  • CI_REGISTRY_USER - Docker Hub 仓库用户名,值为 cnych
  • CI_REGISTRY_PASSWORD - Docker Hub 仓库密码
  • CI_PASSWORD - Git 仓库访问密码
  • CI_USERNAME - Git 仓库访问用户名

20200710184849.png

Argo CD 配置

现在我们可以开始使用 GitOps 来配置我们的 Kubernetes 中的应用了。Argo CD 自带了一套 CRD 对象,可以用来进行声明式配置,这当然也是推荐的方式,把我们的基础设施作为代码来进行托管,下面是我们为开发和生产两套环境配置的资源清单:

# gitops-demo-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: web-app-dev
  namespace: argocd
spec:
  project: default
  source: 
    repoURL: http://git.k8s.local/course/gitops-webapp.git
    targetRevision: HEAD
    path: deployment/dev
  destination:
    server: https://kubernetes.default.svc
    namespace: dev
  syncPolicy:
    automated:
      prune: true
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: web-app-prod
  namespace: argocd
spec:
  project: default
  source: 
    repoURL: http://git.k8s.local/course/gitops-webapp.git
    targetRevision: HEAD
    path: deployment/prod
  destination:
    server: https://kubernetes.default.svc
    namespace: prod
  syncPolicy:
    automated:
      prune: true

上面定义的 Application 这个资源,就是 Argo CD 用于描述应用的 CRD 对象:

  • name:Argo CD 应用程序的名称
  • project:应用程序将被配置的项目名称,这是在 Argo CD 中应用程序的一种组织方式
  • repoURL:源代码的仓库地址
  • targetRevision:想要使用的 git 分支
  • path:Kubernetes 资源清单在仓库中的路径
  • destination:Kubernetes 集群中的目标

然后同样使用 kubectl 工具直接部署上面的资源对象即可,将会创建两个 Application 类型的对象:

$ kubectl apply -f gitops-demo-app.yaml
application.argoproj.io/web-app-dev created
application.argoproj.io/web-app-prod created
$ kubectl get application -n argocd
NAME           AGE
web-app-dev    25s
web-app-prod   24s

此时我们再去 Argo CD 的 Dashboard 首页同样将会看到两个 Application 的信息:

20200710161727.png

点击其中一个就可以看到关于应用的详细信息,我们可以在 gitops-webapp 代码仓库的 deployment/<env> 目录里面找到资源对象。我们可以看到,在每个文件夹下面都有一个 kustomization.yaml 文件,Argo CD 可以识别它,不需要任何其他的设置就可以使用。

由于我们这里的代码仓库是私有的 GitLab,所以我们还需要配置对应的仓库地址,在页面上 Settings → Repositories,点击 Connect Repo using HTTPS 按钮:

20200710162651.png

添加我们的代码仓库认证信息:

20200710162935.png

需要注意的是这里默认使用的是 HTTPS,所以我们需要勾选下方的 Skip server verification,然后点击上方的 CONNECT 按钮添加即可。然后重新同步上面的两个 Application,就可以看到正常的状态了。

GitLab CI 流水线

接下来我们需要为应用程序创建流水线,自动构建我们的应用程序,推送到镜像仓库,然后更新 Kubernetes 的资源清单文件。

下面的示例并不是一个多么完美的流水线,但是基本上可以展示整个 GitOps 的工作流。开发人员在自己的分支上开发代码,他们分支的每一次提交都会触发一个阶段性的构建,当他们将自己的修改和主分支合并时,完整的流水线就被触发。将构建应用程序,打包成 Docker 镜像,将镜推送到 Docker 仓库,并自动更新 Kubernetes 资源清单,此外,一般情况下将应用部署到生产环境需要手动操作。

GitLab CI 中的流水线默认定义在代码仓库根目录下的 .gitlab-ci.yml 文件中,在改文件的最上面定义了一些构建阶段和环境变量、镜像以及一些前置脚本:

stages:
- build
- publish
- deploy-dev
- deploy-prod

接下来是阶段的定义和所需的任务声明。我们这里的构建过程比较简单,只需要在一个 golang 镜像中执行一个构建命令即可,然后将编译好的二进制文件保存到下一个阶段处理,这一个阶段适合分支的任何变更:

build:
  stage: build
  image:
    name: golang:1.13.1
  script:
    - go build -o main main.go
  artifacts:
    paths:
      - main
  variables:
    CGO_ENABLED: 0

然后就是构建镜像并推送到镜像仓库,这里我们使用 Kaniko,当然也可以使用 DinD 模式进行构建,只是安全性不高,这里我们可以使用 GIT 提交的 commit 哈希值作为镜像 tag,关于 Docker 镜像仓库的认证和镜像地址信息可以通过项目的参数来进行传递,不过这个阶段只在主分支发生变化时才会触发:

publish:
  stage: publish
  image:
    name: cnych/kaniko-executor:v0.22.0
    entrypoint: [""]
  script:
    - echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json
    - /kaniko/executor --context $CI_PROJECT_DIR --dockerfile ./Dockerfile --destination $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
  dependencies:
    - build  
  only:
    - master

下一个阶段就是将应用程序部署到开发环境中,在 GitOps 中就意味着需要更新 Kubernetes 的资源清单,这样 Argo CD 就可以拉取更新的版本来部署应用。这里我们使用了为项目定义的环境变量,包括用户名和 TOKEN,此外在提交消息里面增加 [skip ci] 这样的关键字,这样流水线就不会被触发:

deploy-dev:
  stage: deploy-dev
  image: cnych/kustomize:v1.0
  before_script:
    - git remote set-url origin http://${CI_USERNAME}:${CI_PASSWORD}@git.k8s.local/course/gitops-webapp.git
    - git config --global user.email "[email protected]"
    - git config --global user.name "GitLab CI/CD"
  script:
    - git checkout -B master
    - cd deployment/dev
    - kustomize edit set image $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
    - cat kustomization.yaml
    - git commit -am '[skip ci] DEV image update'
    - git push origin master
  only:
    - master

最后添加一个部署到 prod 环境的阶段,和前面非常类似,只是添加了一个手动操作的流程:

deploy-prod:
  stage: deploy-prod
  image: cnych/kustomize:v1.0
  before_script:
    - git remote set-url origin http://${CI_USERNAME}:${CI_PASSWORD}@git.k8s.local/course/gitops-webapp.git
    - git config --global user.email "[email protected]"
    - git config --global user.name "GitLab CI/CD"
  script:
    - git checkout -B master
    - git pull origin master
    - cd deployment/prod
    - kustomize edit set image $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
    - cat kustomization.yaml
    - git commit -am '[skip ci] PROD image update'
    - git push origin master
  only:
    - master
  when: manual

这样我们就完成了整个流水线的定义。

接下来我们来看看它们是如何一起工作的。我们将开发和线上两个环境的应用分别部署在了 dev 和 prod 命名空间之下,通过 Ingress 暴露服务,同样需要将两个应用的域名 http://webapp.dev.k8s.local/http://webapp.prod.k8s.local/ 在本地 /etc/hosts 中添加映射。

如果一切正常的话现在我们可以在浏览器中来查看我们部署的 web 应用程序了。

Dev web appDev web app

然后我们来尝试修改下代码,编辑 main.go 文件,将变量 welcome 中的 GITOPS 修改为 GITOPS-K8S:

func main() {
   welcome := Welcome{"GITOPS-K8S", time.Now().Format(time.Stamp), os.Getenv("HOSTNAME")
	  ......
}

然后提交代码到 master 分支,然后进入 GitLab 项目 -> CI/CD -> Pipelines,就可以看到一个新的流水线开始构建了。

20200710191018.png

等待一会儿,正常情况下会执行到 dev 的部署阶段,然后变成 skipped 的状态,此时流水线已经将代码中的 dev 下的资源清单文件已经更新了。

GitLab CI/CD PipelineGitLab CI/CD Pipeline

然后 Argo CD 在自动同步模式下在一分钟内变会更新 Kubernetes 的资源对象,我们也可以在 Argo CD 的页面中看到进度。当 Argo CD 中同步完成后我们再去查看 DEV 环境的应用,就可以看到页面上面的信息已经变成了 GITOPS-K8S 了。

Update Dev Web APPUpdate Dev Web APP

最后如果需要部署到 prod 环境,我们只需要在 GitLab 的流水线中手动触发即可,之后,prod 中的镜像也会被更新。

GitLab CI/CD Prod deploymentGitLab CI/CD Prod deployment

下面是同步时 Argo CD 更新的页面状态变化图。

Argo CD Sync WorkflowArgo CD Sync Workflow

到这里,我们就使用 GitOps 成功的将我们的应用部署到了开发和生产环境之中了。

Kubernetes进阶训练营

微信公众号

扫描下面的二维码关注我们的微信公众帐号,在微信公众帐号中回复◉加群◉即可加入到我们的 kubernetes 讨论群里面共同学习。

wechat-account-qrcode

「真诚赞赏,手留余香」


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK