微服务是一种以业务功能为主的服务设计概念,每一个服务都具有自主运行的业务功能,对外开放不受语言限制的 API,应用程序则是由一个或多个微服务组成。
在微服务架构中,不可变的基础设施和容器的自包含环境,使发布变得更加简单快捷,不用再考虑如何根据不同项目区分 Runner 环境;可以随时拉起一个 Pod 来运行我们的 Job,运行完成后立即销毁,不仅能实现动态运行节省资源,而且不用担心多项目多任务并发构建问题。
本文分享如何应用极狐 GitLab CI 将应用发布进 K8s,适用于以下场景和人群:
本文以构建一个 Java 软件项目并将其部署到阿里云容器服务 K8s 集群中为例,说明如何使用极狐 GitLab CI 在阿里云 K8s 服务上运行极狐 GitLab Runner、配置 K8s 类型的 Executor,并执行 Pipeline。
如上图为一个简单的极狐 GitLab CI 部署进 K8s 流程图,同之前我们讲到的 CI 集成一致,只需要项目中存在 .gitlab-ci.yml 文件即可。
与之前的差异是,在集成 Kubernetes 时,gitlab-runner 运行在 K8s 内,其为一个 Pod 形式运行,控制着后续的 Pipeline 中各 Stage 执行。
可以看到,当一个 Pipeline 有多个 Stage,每个 Stage 都有一个单独的 Pod 去执行,这个 Pod 使用的镜像在 CI 的.gitlab-ci.yml 的每个 Stage 的 Image 中定义,如下所示为部署 Java 项目的流程:
流程中有一些注意事项:
通过上面的极狐 GitLab CI 流程,我们能够看到将极狐 GitLab Runner 运行在 K8s 集群中,每个 Job 启动单独的 Pod 运行操作,此种方式完全凸显了 K8s 的优点:
如果您的业务目前运行环境为 K8s,那么极狐 GitLab CI 完全契合您的业务场景,您只需要自定义 gitlab-ci.yml 中的各个需求的 Stage 即可,配合 GitOps 将配置托管在项目内,跟随项目一起维护管理,实现端到端的 CI 工作流,使得运维工作也可通过 Git 追溯,提高工作效能,敏捷开发上线部署。
通过上文内容,我们了解来极狐 GitLab CI 与 K8s 的集成及其优点,接着,就让我们通过实战来更具体的了解其流程。
登录极狐 GitLab 服务器,记录极狐 GitLab 的 URL 和注册令牌。
在部署进 K8s 的极狐 GitLab Runnner 的配置中需要填写该信息,运行在 K8s 中的 Pod 就利用此信息在极狐 GitLab 服务器进行注册。
由于单独部署极狐 GitLab Runner 进 K8s 中,自己去写资源清单文件难度较大且容易出错,我们在此利用官方 Chart 镜像通过 Helm 来进行部署,仅需修改其中我们关心的字段即可。
首先登录 K8s 集群,进行极狐 GitLab Runner 的 Helm Repo 的添加;之后将 Chart 下载到本地,解压文件并修改其中的 values.yml 文件。
[root@master common-service]# helm repo add gitlab https://charts.gitlab.io
"gitlab" has been added to your repositories
[root@master common-service]# helm repo update
Hang tight while we grab the latest from your chart repositories...
...Skip local chart repository
...Successfully got an update from the "aliyun" chart repository
...Successfully got an update from the "apphub" chart repository
...Successfully got an update from the "gitlab" chart repository
...Successfully got an update from the "stable" chart repository
Update Complete.
[root@master common-service]# helm search gitlab-runner
NAME CHART VERSION APP VERSION DESCRIPTION
gitlab/gitlab-runner 0.14.0 12.8.0 GitLab Runner
可以看到极狐 GitLab Runner 的 Chart,其是 Helm 中描述相关的一组 K8s 资源文件集合,包含了一个 value.yaml 配置文件和一系列模板(deployment.yaml、svc.yaml 等)。
极狐 GitLab Runner 在运行时,需要访问 K8s 的 API。我们在此为其创建 ServiceAccount 并为其进行 RBAC 授权。
首先创建一个极狐 GitLab Runner 的名称空间,并创建 Role,将 ServiceAccount 与 Role 进行绑定。
[root@master gitlab-runner]# cat > rbac-runner-config.yaml <<EOF
apiVersion: v1
kind: ServiceAccount # 在gitlab-runners名称空间下创建名为gitlab的serviceaccount
metadata:
name: gitlab
namespace: gitlab-runners
---
kind: Role # 创建gitlab角色,
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: gitlab-runners
name: gitlab
rules:
- apiGroups: [""] #"" indicates the core API group
resources: ["*"]
verbs: ["*"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["*"]
- apiGroups: ["extensions"]
resources: ["deployments"]
verbs: ["*"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: gitlab # 将sa与角色进行绑定
namespace: gitlab-runners
subjects:
- kind: ServiceAccount
name: gitlab # Name is case sensitive
apiGroup: ""
roleRef:
kind: Role #this must be Role or ClusterRole
name: gitlab # this must match the name of the Role or ClusterRole you wish to bind to
apiGroup: rbac.authorization.k8s.io
EOF
# 创建资源清单
[root@master gitlab-runner]# kubectl create -f rbac-runner-config.yaml
serviceaccount/gitlab created
role.rbac.authorization.k8s.io/gitlab created
rolebinding.rbac.authorization.k8s.io/gitlab created
[root@master gitlab-runner]# helm fetch gitlab/gitlab-runner
[root@master gitlab-runner]# tar xf gitlab-runner-0.14.0.tgz
[root@master gitlab-runner]# vim gitlab-runner/values.yaml
Helm 为我们提供了一个配置文件,可以在安装 Runner 时,为其注册一个默认 Runner。我们可以去 gitlab-runner 的项目源码中获取到 values.yaml
这个配置文件。
由于在极狐 GitLab Runner 中需要执行 docker build
命令,需要 Docker 服务端,我们可以绑定 K8s Node 节点的 docker.sock 来实现,编辑 Chart 下的 Template 目录中的 configmap.yaml,在大约 42 行修改。
# add volume and bind docker.sock
cat >>/home/gitlab-runner/.gitlab-runner/config.toml <<EOF
[[runners.kubernetes.volumes.pvc]]
name = "{{.Values.maven.cache.pvcName}}"
mount_path = "{{.Values.maven.cache.mountPath}}"
[[runners.kubernetes.volumes.host_path]]
name = "docker"
mount_path = "/var/run/docker.sock"
EOF
在流程详解中,能够看到生成的 war/jar 包制品需要存储在一个地方,这个地方就需要挂载一块外置的存储设备,在 k8s 中,我们需要为其提供 PVC,如果你可以用 NFS 存储或者分布式 Ceph 制成的存储类。
在此,我们机器中使用的为 Storageclass,演示利用存储类来声明 PVC,在 Pod 中进行挂载。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: gitlab-runner-pvc # 创建名称为gitlab-runner-pvc的pvc
namespace: gitlab-runners
spec:
accessModes:
- ReadWriteMany # 访问模式
storageClassName: rbd # 存储类名称
resources:
requests:
storage: 2Gi # 存储大小
[root@master gitlab-runner]# kubectl apply -f gitlab-runner-pvc.yaml
persistentvolumeclaim/gitlab-runner-pvc created
[root@master gitlab-runner]# kubectl get pvc -n gitlab-runners
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
gitlab-runner-pvc Bound pvc-a620cd43-f396-4626-8599-c973c19cddd3 2Gi RWO rbd 4s
查看已经在极狐 GitLab Runner 名称空间下已经创建好了 PVC。
在上面,我们配置绑定宿主机 Docker 进程时,已经将 PVC 配置进去了,我们还需要在 Charts 的 values.yaml 下,新添加配置 Volume 信息,并在 values.yaml 配置相应变量。
# 添加在values.yaml 的最后即可
maven:
cache:
pvcName: gitlab-runner-pvc
mountPath: /home/cache/maven
配置文件比较长,可以根据需要自行配置,下面是本文示例需要配置的地方。
[root@master gitlab-runner]# egrep "^$|^#|^[[:space:]]+#" -v values.yaml
imagePullPolicy: IfNotPresent
gitlabUrl: https://jihulab.com/ # gitlab url
runnerRegistrationToken: "nnxxxxxxxxxxxxxxxS" # gitlab token
unregisterRunners: true
terminationGracePeriodSeconds: 3600
concurrent: 10
checkInterval: 30
rbac:
create: true
clusterWideAccess: false
serviceAccountName: gitlab # rbac的sa
metrics:
enabled: true
runners:
image: ubuntu:16.04 # 使用的镜像
tags: "gitlab-runner"
privileged: true
imagePullPolicy: "if-not-present" # 如果执行具体job的runner不存在则拉取
pollTimeout: 180
outputLimit: 4096
cache: {}
builds: {}
services: {}
helpers: {}
serviceAccountName: gitlab # serviceaccount
nodeSelector: {}
securityContext:
fsGroup: 65533
runAsUser: 100
resources: {}
affinity: {}
nodeSelector: {}
tolerations: []
hostAliases: []
podAnnotations: {}
podLabels: {}
maven: # 配置maven缓存信息
cache:
pvcName: gitlab-runner-pvc # pvc信息
mountPath: /home/cache/maven # 挂载点
在配置完成 values.yaml 相关字段后,我们利用 Helm 来进行安装。后期如果有变动,直接修改 value.yml ,进行更新即可 helm upgrade gitlab-rujner gitlab-runner/
[root@master gitlab-runner]# helm install --name gitlab-runner -f gitlab-runner/values.yaml --namespace gitlab-runners gitlab-runner/
NAME: gitlab-runner
LAST DEPLOYED: Sun Feb 23 22:45:37 2020
NAMESPACE: gitlab-runners
STATUS: DEPLOYED
RESOURCES:
==> v1/ConfigMap
NAME DATA AGE
gitlab-runner-gitlab-runner 5 1s
==> v1/Deployment
NAME READY UP-TO-DATE AVAILABLE AGE
gitlab-runner-gitlab-runner 0/1 1 0 1s
==> v1/Pod(related)
NAME READY STATUS RESTARTS AGE
gitlab-runner-gitlab-runner-6745dd4cd6-r9z28 0/1 Pending 0 0s
==> v1/Secret
NAME TYPE DATA AGE
gitlab-runner-gitlab-runner Opaque 2 1s
复制代码
查看已经成功运行的相关 Pod 资源,极狐 GitLab Runner 的配置是通过 Configmap 挂载进去,如有新的配置可以修改,并删除之前的极狐 GitLab Runner 的 Pod,其 Deployment 控制器会为 Pod 挂载新的配置文件。
➤ 查看 Pod 运行状态
[root@master ~]# kubectl get po -n gitlab-runners
NAME READY STATUS RESTARTS AGE
gitlab-runner-gitlab-runner-6745dd4cd6-r9z28 1/1 Running 0 21h
此时,可以进入 Pod 查看 Runner 的配置文件(/home/gitlab-runner/.gitlab-runner/config.toml
)。这个文件就是根据之前配置的 values.yaml 自动生成的。
[root@master ~]# kubectl get cm -n gitlab-runners gitlab-runner-gitlab-runner
NAME DATA AGE
gitlab-runner-gitlab-runner 5 21h
[root@master gitlab-runner]# kubectl exec -it -n gitlab-runners gitlab-runner-gitlab-runner-6c7dfd859c-62dv5 -- cat /home/gitlab-runner/.gitlab-runner/config.toml
listen_address = "[::]:9252"
concurrent = 10
check_interval = 30
log_level = "info"
[session_server]
session_timeout = 1800
[[runners]]
name = "gitlab-runner-gitlab-runner-6c7dfd859c-62dv5"
output_limit = 4096
request_concurrency = 1
url = "https://jihulab.com/" # 注册的url
token = "eRxxxxxb63q" # gitlab注册的token
executor = "kubernetes" # executor为kubernetes
[runners.custom_build_dir]
[runners.cache]
[runners.cache.s3]
[runners.cache.gcs]
[runners.kubernetes]
host = ""
bearer_token_overwrite_allowed = false
image = "ubuntu:16.04" # 使用的镜像为ubuntu
namespace = "gitlab-runners" # 使用的namespace为gitlab-runners
namespace_overwrite_allowed = ""
privileged = true
poll_timeout = 180
service_account = "gitlab" # serviceaccont 为gitlab
service_account_overwrite_allowed = ""
pod_annotations_overwrite_allowed = ""
[runners.kubernetes.pod_security_context]
[runners.kubernetes.volumes]
[[runners.kubernetes.volumes.pvc]]
name = "gitlab-runner-pvc" # 挂载的pvc名称
mount_path = "/home/cache/maven" # 挂载在pod下的缓存目录
[[runners.kubernetes.volumes.host_path]]
name = "docker"
mount_path = "/var/run/docker.sock" # 绑定宿主机的docker.sock
至此,我们已经将极狐 GitLab Runner 在 K8s 集群中运行起来。
接下来,让我们来集成 CI。
由于使用的 Executor 不同,所以. gitlab-ci.yml 和之前服务器也有些不同,不如 Image,默认如果每个 Stage 中没有指定某个 Image,则使用该 Image。
image: docker:latest
variables:
DOCKER_DRIVER: overlay2
# k8s 挂载本地卷作为 maven 的缓存
MAVEN_OPTS: "-Dmaven.repo.local=/home/cache/maven"
stages:
- package # 源码打包阶段
- docker_build # 镜像构建和打包推送阶段
- deploy_k8s # 应用部署阶段
before_script:
- export APP_TAG="${CI_COMMIT_TAG:-${CI_COMMIT_SHA::8}}" # 定义制作好的镜像tag
maven-package:
#image: maven:3.5-jdk-8-alpine
image: registry.cn-beijing.aliyuncs.com/codepipeline/public-blueocean-codepipeline-slave-java:0.1-63b99a20 # maven镜像进行java源码的build
tags:
- gitlab-runner # 指定使用gitlab-runner来追寻
stage: package
script:
- mvn clean package -Dmaven.test.skip=true
artifacts: # 将生成的war包上传到pvc挂载目录中
paths:
- target/*.war
docker-build:
tags:
- gitlab-runner
stage: build
script:
- echo "Building Dockerfile-based application..."
- docker build -t ${REGISTRY}/${QHUB_NAMESPACE}/${APP_NAME}:${APP_TAG} . # 构建镜像
- docker login --username=${DOCKER_USERNAME} ${REGISTRY} -p ${DOCKER_PASSWORD} # 登录镜像仓
- docker push ${REGISTRY}/${QHUB_NAMESPACE}/${APP_NAME}:${APP_TAG} # push镜像
only:
- master
k8s-deploy:
image: bitnami/kubectl:latest # 使用kubectl镜像来进行最终的部署
tags:
- gitlab-runner
stage: deploy
script:
- echo "deploy to k8s cluster..."
- sed -i "s@$(grep -E "^[[:space:]]+image:" deployment.yaml | awk '{print $2}' |head -1)@${REGISTRY}/${QHUB_NAMESPACE}/${APP_NAME}:${APP_TAG}@g" deployment.yaml # 替换deployment中的镜像
- kubectl apply -f deployment.yaml # 应用资源清单文件
only:
- master
可以看到 CI 文件中,我们定义了三个 Stage:
由于在 CI 文件中有一些敏感信息,例如镜像仓库的登录信息、后期可以更改的镜像名称等,可利用环境注入方式,使得 CI 文件脱敏而且更具灵活性和适用性。
添加极狐 GitLab Runner 可用的环境变量,本示例添加变量如下:
在配置好了 CI 文件后,让我们来运行测试,提交代码,或者手动运行。
在项目 CI/CD 右上角有运行流水线按钮。
在图中,我们可以看到可以并行运行多个 Pipeline,互不影响。
登录 K8s 集群,查看此时运行的 Pod:
至此我们就完成了极狐 GitLab CI + K8s 示例。让我们尽情享受 K8s +极狐 GitLab CI 为我们带来畅快淋漓的发布体验吧。
通过本文极狐 GitLab CI 实战总结,笔者再次安利大家去了解极狐 GitLab 的此项特性。如果您的公司困于多套系统维护的复杂性,不妨尝试下极狐 GitLab CI 简单集成。
在云原生时代,将工具或中间件下沉到基础设施中,用户只需要专注于自身业务开发,在敏捷高效的文化中协作、快速试错、快速反馈、持续改进、不断迭代,以 Git 为契机打破研发与运维的壁垒隔阂,实现产品更快、更频繁、更稳定的交付。