GitOps: K8S 通过 FluxCD 自动从 GitLab 部署应用
FluxCD
FluxCD 是一组 K8S 控制器,用于构建 GitOps,可以监控代码库,并进行自动部署
GitLab 和 GitHub
GitLab 和 GitHub 非常相似,都是代码托管平台,都基于 Git,都提供了命令行和 Web 界面,都支持问题跟踪、代码审查和团队协作等功能
GitLab 和 GitHub 也有不同
GitHub 主要面向开源社区,例如非盈利性组织、开源项目、个人开发者等
GitLab 更适合企业内部或私有项目管理,主要针对商业用户,提供了更多功能,比如 CI/CD
GitHub 本身不开源
GitLab 是开源的
GitHub 只能用官方平台
GitLab 既可以用官方平台,也可以自己部署服务器,能自定义配置和扩展,更灵活,能更好的控制和保护代码
GitHub 开发者和项目更多
GitLab 规模相对较小,更多是企业用户在用
都有免费和付费版本,付费版本提供了更高级的功能,如 CI/CD 集成和高级安全特性
开源项目协作可以放 GitHub
企业项目可以用 GitLab,提供了许多额外功能,如持续集成、部署管道和自动化测试,能够更高效地协作和交付项目
如果考虑安全和保护代码,可以自己搭建 GitLab 服务器
此外托管代码也可以用 BitBucket
配置 GitLab
可以创建免费账号做测试用
登录后可以建自己的项目 https://gitlab.com/<group>/<project>,比如 https://gitlab.com/my-test-group/hello-world
或者 https://gitlab.com/<user>/<project>
这里的 <group> 或 <user> 就是 owner,一个 <group> 可以有多个 <user>
为了访问 GitLab API,需要设置个人访问令牌 (PAT) 使得 FluxCD 能访问 GitLab
在 GitLab 的 Settings -> Access Tokens -> Add new token,选择 api 权限,创建 token,其 role 是 owner
记下 Token 的值比如 glpat-98rjF7hMxfJR1Sz5s-Rb
安装 Flux 命令行工具
curl -s https://fluxcd.io/install.sh | sudo bash
成功后运行一下
$ flux --version
flux version 2.2.1
正常返回说明安装成功
在 K8S 安装 Flux 控制器
Flux CLI 提供了一个 bootstrap 命令在 Kubernetes 集群上部署 Flux 控制器,配置控制器从 Git 存储库同步状态,并将 Flux 清单推送到 Git 存储库,并将 Flux 配置为从 Git 进行自我更新
export GITLAB_TOKEN=glpat-98rjF7hMxfJR1Sz5s-Rb
sudo flux bootstrap gitlab \
--deploy-token-auth \
--hostname=gitlab.com \
--owner=my-test-group \
--repository=hello-world \
--branch=main \
--path=flux/K8S \
--personal
可能会要求输入 Token,这里 --owner 填 <group> 或 <user>,而 --path 填的是 Flux 清单要推到 hello-world 这个 project 下的哪个目录
export GITLAB_TOKEN=glpat-98rjF7hMxfJR1Sz5s-Rb
$ sudo flux bootstrap gitlab \
> --deploy-token-auth \
> --hostname=gitlab.com \
> --owner=my-test-group \
> --repository=hello-world \
> --branch=main \
> --path=flux/K8S \
> --personal
Please enter your GitLab personal access token (PAT):
► connecting to https://gitlab.com
► cloning branch "main" from Git repository "https://gitlab.com/my-test-group/hello-world.git"
✔ cloned repository
► generating component manifests
✔ generated component manifests
✔ committed component manifests to "main" ("ac1caf868a910367fa9fa2b8d22db829a112ff5d")
► pushing component manifests to "https://gitlab.com/my-test-group/hello-world.git"
► installing components in "flux-system" namespace
✔ installed components
✔ reconciled components
► checking to reconcile deploy token for source secret
✔ configured deploy token "flux-system-main-flux-system-./flux/K8S" for "https://gitlab.com/my-test-group/hello-world"
► determining if source secret "flux-system/flux-system" exists
► generating source secret
► applying source secret "flux-system/flux-system"
✔ reconciled source secret
► generating sync manifests
✔ generated sync manifests
✔ committed sync manifests to "main" ("e7ab061ee089de66d4ba59a23fe2f9e1be74493c")
► pushing sync manifests to "https://gitlab.com/my-test-group/hello-world.git"
► applying sync manifests
✔ reconciled sync configuration
◎ waiting for GitRepository "flux-system/flux-system" to be reconciled
✔ GitRepsoitory reconciled successfully
◎ waiting for Kustomization "flux-system/flux-system" to be reconciled
✔ Kustomization reconciled successfully
► confirming components are healthy
✔ helm-controller: deployment ready
✔ kustomize-controller: deployment ready
✔ notification-controller: deployment ready
✔ source-controller: deployment ready
✔ all components are healthy
这里安装的几个 controller 的作用
source-controller:监听 Git Repo 的变化,当代码或配置发生变化时,同步相关资源配置
kustomize-controller:当监控的 Kustomize 配置变化时,更新相应的 K8S 资源
helm-controller:当监控的 Helm Chart 变化时,跟新相应的 Helm release
notification-controller:当事件发生时,比如同步成功或失败,可以通知外部系统,支持 webhooks,自定义脚本等
可以通过 --components 参数来指定要安装的组件,但是需要注意最小安装需要 source-controller 和 kustomize-controller
查看 K8S 的 namespace 可以看到新建了一个 flux-system
flux-system Active 13m
查看这个 namespace 下面的 pods
$ sudo kubectl get pods -n flux-system
NAME READY STATUS RESTARTS AGE
helm-controller-5584c79984-ncx2t 1/1 Running 0 13m
kustomize-controller-689c96979f-mhpc4 1/1 Running 0 13m
notification-controller-7c6d7dd557-xkrcb 1/1 Running 0 13m
source-controller-68858c9b59-hlhq5 1/1 Running 0 13m
还有 secret 被创建
$ sudo kubectl get secrets -n flux-system
NAME TYPE DATA AGE
default-token-qxzjm kubernetes.io/service-account-token 3 14m
flux-system Opaque 2 14m
helm-controller-token-crpbn kubernetes.io/service-account-token 3 14m
kustomize-controller-token-hqwgm kubernetes.io/service-account-token 3 14m
notification-controller-token-f9jl2 kubernetes.io/service-account-token 3 14m
source-controller-token-fxm7g kubernetes.io/service-account-token 3 14m
到 GitLab 上可以看到多了个 flux/K8S/flux-system 目录
https://gitlab.com/my-test-group/hello-world/-/tree/main/flux/K8S/flux-system?ref_type=heads
下面有三个新建的文件
gotk-components.yaml
gotk-sync.yaml
kustomization.yaml
改变这些文件可以触发 K8S 的 FluxCD 自我更新
这些 controller 还提供了一些 CRD (Custom Resource Definition)
$ sudo kubectl get crd | grep fluxcd
NAME CREATED AT
alerts.notification.toolkit.fluxcd.io 2023-12-19T09:25:59Z
buckets.source.toolkit.fluxcd.io 2023-12-19T09:25:59Z
gitrepositories.source.toolkit.fluxcd.io 2023-12-19T09:25:59Z
helmcharts.source.toolkit.fluxcd.io 2023-12-19T09:25:59Z
helmreleases.helm.toolkit.fluxcd.io 2023-12-19T09:25:59Z
helmrepositories.source.toolkit.fluxcd.io 2023-12-19T09:25:59Z
kustomizations.kustomize.toolkit.fluxcd.io 2023-12-19T09:25:59Z
ocirepositories.source.toolkit.fluxcd.io 2023-12-19T09:25:59Z
providers.notification.toolkit.fluxcd.io 2023-12-19T09:25:59Z
receivers.notification.toolkit.fluxcd.io 2023-12-19T09:25:59Z
提供了一些 kind 给 K8S 的 manifest yaml 文件使用
创建 GitRepository
以部署 spark 为例子,假设 spark namespace 和 spark operator 都已经部署了
建一个 spark-git-repo.yaml 文件
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: spark-git-repo
namespace: spark
spec:
url: https://gitlab.com/my-test-group/hello-world.git
timeout: 60s
interval: 30s
ref:
branch: main
secretRef:
name: spark-git-repo
---
apiVersion: v1
kind: Secret
type: Opaque
metadata:
name: spark-git-repo
namespace: spark
stringData:
username: <GitLab user or email>
password: <GitLab password>
这里的 interval: 30s 表示 30s 检查一次 GitLab 看代码库有没有更新
还配置了一个 secret 用于登录 GitLab
部署
$ sudo kubectl apply -f spark-git-repo.yaml -n spark
gitrepository.source.toolkit.fluxcd.io/spark-git-repo created
secret/spark-git-repo created
查看 GitRepository 资源
$ sudo kubectl get GitRepository -n spark
NAME URL AGE READY STATUS
spark-git-repo https://gitlab.com/my-test-group/hello-world.git 42s True stored artifact for revision 'main@sha1:e7ab061ee089de66d4ba59a23fe2f9e1be74493c'
这里 e7ab061ee089de66d4ba59a23fe2f9e1be74493c 是 hello-world.git 最新的 commit id
describe 一下可以看到这个 GitRepository 什么时候做的同步
$ sudo kubectl describe GitRepository spark-git-repo -n spark
......
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal NewArtifact 4m17s source-controller stored artifact for commit 'Add Flux sync manifests'
Normal GitOperationSucceeded 9s (x8 over 3m46s) source-controller no changes since last reconcilation: observed revision 'main@sha1:e7ab061ee089de66d4ba59a23fe2f9e1be74493c'
如果 hello-world.git 有变化,就会自动同步,并更新 commit id
提交 app 代码到 GitLab
创建文件 spark-app.yaml 并提交到 hello-world.git 的 /test/spark 路径
apiVersion: "sparkoperator.k8s.io/v1beta2"
kind: SparkApplication
metadata:
name: spark-pi
namespace: spark
spec:
type: Scala
mode: cluster
image: "apache/spark:v3.1.3"
imagePullPolicy: IfNotPresent
mainClass: org.apache.spark.examples.SparkPi
mainApplicationFile: "local:///opt/spark/examples/jars/spark-examples_2.12-3.1.3.jar"
sparkVersion: "3.1.3"
restartPolicy:
type: Never
volumes:
- name: "volume"
hostPath:
path: "/tmp"
type: Directory
driver:
cores: 1
coreLimit: "1200m"
memory: "512m"
labels:
version: 3.1.3
serviceAccount: spark
volumeMounts:
- name: "volume"
mountPath: "/tmp"
executor:
cores: 1
instances: 1
memory: "512m"
labels:
version: 3.1.3
volumeMounts:
- name: "volume"
mountPath: "/tmp"
等一会就可以看到 GitRepository 的 commit id 变了
$ sudo kubectl get GitRepository -n spark
NAME URL AGE READY STATUS
spark-git-repo https://gitlab.com/my-test-group/hello-world.git 14m True stored artifact for revision 'main@sha1:18ccc9a220188d3199acbf4028a696ee3567b37a'
describe 可以看到新的 event
$ sudo kubectl describe GitRepository spark-git-repo -n spark
......
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal NewArtifact 16m source-controller stored artifact for commit 'Add Flux sync manifests'
Normal GitOperationSucceeded 3m48s (x24 over 15m) source-controller no changes since last reconcilation: observed revision 'main@sha1:e7ab061ee089de66d4ba59a23fe2f9e1be74493c'
Normal NewArtifact 3m15s source-controller stored artifact for commit 'spark-app.yaml'
Normal GarbageCollectionSucceeded 2m44s source-controller garbage collected 1 artifacts
Normal GitOperationSucceeded 42s (x5 over 2m43s) source-controller no changes since last reconcilation: observed revision 'main@sha1:18ccc9a220188d3199acbf4028a696ee3567b37a'
可以看到新的 commit id 和 commit message
创建 Kustomization
现在 GitRepository spark-git-repo 会自动同步 GitLab 上 hello-world.git 的 /test/spark 代码,但还不会自动部署
自动部署还需要创建 Kustomization 或 HelmRelease
这里以 Kustomization 为例,建一个 spark-kustomization.yaml 文件
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
name: spark-kustomization
namespace: spark
spec:
interval: 1m
path: "./test/spark"
prune: true
timeout: 2m
sourceRef:
kind: GitRepository
name: spark-git-repo
sourceRef 设置从 spark-git-repo 这个 GitRepository 获取代码
path 表示检查的是这个 GitRepository (前面配置为 https://gitlab.com/my-test-group/hello-world.git) 的 ./test/spark 目录
interval: 1m 表示每分钟检查一次,看 ./test/spark 目录下的代码有没有变化
部署 Kustomization
$ sudo kubectl apply -f spark-kustomization.yaml -n spark
Warning: v1beta2 Kustomization is deprecated, upgrade to v1
kustomization.kustomize.toolkit.fluxcd.io/spark-kustomization created
查看 Kustomization
$ sudo kubectl get Kustomization -n spark
NAME AGE READY STATUS
spark-kustomization 35s True Applied revision: main@sha1:18ccc9a220188d3199acbf4028a696ee3567b37a
describe Kustomization
$ sudo kubectl describe Kustomization spark-kustomization -n spark
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Progressing 57s kustomize-controller SparkApplication/spark/spark-pi created
Normal ReconciliationSucceeded 57s kustomize-controller Reconciliation finished in 50.650416ms, next run in 1m0s
因为前面提交了 spark-app.yaml 到 hello-world.git 的 /test/spark 目录,所以 Kustomization 检查到后就 apply 了这个文件
查看 spark 这个 namespace,这个 app 确实被执行了
$ sudo kubectl get pods -n spark
NAME READY STATUS RESTARTS AGE
my-release-spark-operator-6f5bbf76f6-zcnln 1/1 Running 0 6h46m
spark-pi-driver 0/1 Completed 0 3m10s
再 describe Kustomization
$ sudo kubectl describe Kustomization spark-kustomization -n spark
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Progressing 2m18s kustomize-controller SparkApplication/spark/spark-pi created
Normal ReconciliationSucceeded 2m18s kustomize-controller Reconciliation finished in 50.650416ms, next run in 1m0s
Normal ReconciliationSucceeded 76s kustomize-controller Reconciliation finished in 59.993991ms, next run in 1m0s
可以看到约 1 分钟后又检查了一次,但因为代码没变化,所以没操作
如果提交代码更新了 GitLab 上的 spark-app.yaml 文件,spark-kustomization 又会检查到并重新部署
通常提交的是 kustomization.yaml 文件,这样就可以自动部署很多应用和配置了
tenant namespace
前面的简单测试,flux-cd 和 spark-app 代码都放到了 hello-world 这个 project
实际应用应该放在不同 project 比较合适
同时前面把 GitRepository 和 Kustomization 还有 spark-app 都放到了 spark 这个 namespace 下面,实际应用中可以创建一个名为 tenants 的 namespace 统一放所有的 GitRepository 和 Kustomization,然后不同类型或模块的 app 再放在各自的 namespace 比如 spark namespace、flink namespace