本文来自:极狐 GitLab 开发者社区
作者:KaliArch
微服务是一种以业务性能为主的服务设计概念,每一个服务都具备自主运行的业务性能,对外开放不受语言限度的 API,应用程序则是由一个或多个微服务组成。
在微服务架构中,不可变的基础设施和容器的自蕴含环境,使公布变得更加简略快捷,不必再思考如何依据不同我的项目辨别 Runner 环境;能够随时拉起一个 Pod 来运行咱们的 Job,运行实现后立刻销毁,不仅能实现动静运行节俭资源,而且不必放心多我的项目多任务并发构建问题。
本文分享如何利用极狐 GitLab CI 将利用公布进 K8s,实用于以下场景和人群:
- 业务容器微服务化,或半微服务化;
- 有明确流程标准,上线部署标准及明确可循的规范;
- 谋求极致继续集成 / 继续交付体验的 GitOps 追崇者;
- 具备 K8s 运维能力的运维人员。
极狐 GitLab CI + K8s 架构解析
本文以构建一个 Java 软件我的项目并将其部署到阿里云容器服务 K8s 集群中为例,阐明如何应用极狐 GitLab CI 在阿里云 K8s 服务上运行极狐 GitLab Runner、配置 K8s 类型的 Executor,并执行 Pipeline。
极狐 GitLab CI 流程图
流程详解
如上图为一个简略的极狐 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 我的项目的流程:
- 开发者或我的项目维护者 Merge Request 到特定分支,该分支存在 CI 文件,开始进行 CI;
-
CI 工作由曾经注册在 gitlab-server 运行在 K8s 集群内的 gitlab-runner 进行下发:
- 第一个为 Package,对 Java 我的项目利用 Maven 镜像进行打包,生成 War 包制品到缓存目录中;
- 利用 Docker 镜像,依据我的项目中的 Dockerfile 对缓存中的制品进行镜像构建,构建实现后登录镜像仓库进行镜像推送;
- 在此,将部署文件托管在我的项目内,也体现了 GitOps 思维,将之前构建推送胜利的镜像地址信息在 deployment.yaml 文件进行批改,之后 Apply 进 k8s 中,Java 我的项目构建的镜像就运行在 K8s 集群内了,实现公布。
流程中有一些注意事项:
- 可在 Stage 中增加本人业务需要的内容,例如单元测试、代码扫描等;
- 在部署文件中,能够将整个我的项目制作成 Helm 的 Chart,替换其中的镜像,利用 Helm 来进行利用部署;
- 利用部署中,单个 Stage 利用的是不同的 Image,在各个 Stage 中传递曾经生成的制品例如 war/jar 包,须要应用内部存储来缓存制品。
极狐 GitLab CI + K8s 架构长处
通过下面的极狐 GitLab CI 流程,咱们可能看到将极狐 GitLab Runner 运行在 K8s 集群中,每个 Job 启动独自的 Pod 运行操作,此种形式齐全凸显了 K8s 的长处:
- 高可用:当某个节点呈现故障时,K8s 会主动创立一个新的极狐 GitLab Runner 容器,并挂载同样的 Runner 配置,使服务达到高可用;
- 弹性伸缩:触发式工作,正当应用资源,每次运行脚本工作时,极狐 GitLab Runner 会主动创立一个或多个新的长期 Runner 来运行 Job;
- 资源最大化利用:动态创建 Pod 运行 Job,资源主动开释,而且 K8s 会依据每个节点资源的应用状况,动态分配长期 Runner 到闲暇节点上,升高呈现因某节点资源利用率高,还排队期待在该节点的状况;
- 扩展性好:当 K8s 集群的资源严重不足而导致长期 Runner 排队期待时,能够很容易地增加一个 K8s Node 到集群中,从而实现横向扩大。
如果您的业务目前运行环境为 K8s,那么极狐 GitLab CI 齐全符合您的业务场景,您只须要自定义 gitlab-ci.yml 中的各个需要的 Stage 即可,配合 GitOps 将配置托管在我的项目内,追随我的项目一起保护治理,实现端到端的 CI 工作流,使得运维工作也可通过 Git 追溯,进步工作效力,麻利开发上线部署。
开启极狐 GitLab CI + K8s 实战
通过上文内容,咱们理解来极狐 GitLab CI 与 K8s 的集成及其长处,接着,就让咱们通过实战来更具体的理解其流程。
环境筹备
- 极狐 GitLab 服务器:能够是部署在物理服务器上,也能够部署在 K8s 集群外部;
- K8s 集群:能够是私有云的容器编排引擎,例如阿里云的 ACK、腾讯云的 TKE、华为云的 CCE 等都实用;
- 本次示例中应用 Helm 来装置,Helm 版本为 v2.14.3,有能力的搭档,能够本人编写资源清单部署。
记录注册信息
登录极狐 GitLab 服务器,记录极狐 GitLab 的 URL 和注册令牌。
在部署进 K8s 的极狐 GitLab Runnner 的配置中须要填写该信息,运行在 K8s 中的 Pod 就利用此信息在极狐 GitLab 服务器进行注册。
获取极狐 GitLab Runner
因为独自部署极狐 GitLab Runner 进 K8s 中,本人去写资源清单文件难度较大且容易出错,咱们在此利用官网 Chart 镜像通过 Helm 来进行部署,仅需批改其中咱们关怀的字段即可。
首先登录 K8s 集群,进行极狐 GitLab Runner 的 Helm Repo 的增加;之后将 Chart 下载到本地,解压文件并批改其中的 values.yml 文件。
➤ 增加 Repo 获取 Charts
[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
➤ 获取 Charts 文件,并进行配置
[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
这个配置文件。
绑定 docker.sock
因为在极狐 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 中进行挂载。
➤ 创立 PVC 申明文件 gitlab-runner-pvc.yaml
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 # 存储大小
➤ 创立 PVC
[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。
➤ 配置 Values
在下面,咱们配置绑定宿主机 Docker 过程时, 曾经将 PVC 配置进去了,咱们还须要在 Charts 的 values.yaml 下,新增加配置 Volume 信息,并在 values.yaml 配置相应变量。
# 增加在 values.yaml 的最初即可
maven:
cache:
pvcName: gitlab-runner-pvc
mountPath: /home/cache/maven
装置极狐 GitLab Runner
配置文件比拟长,能够依据须要自行配置,上面是本文示例须要配置的中央。
[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 # 挂载点
➤ 装置极狐 GitLab Runner
在配置实现 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
➤ 查看 Configmap 及 Pod 中挂载的配置
此时,能够进入 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
➤ 登录极狐 GitLab 控制台查看目前极狐 GitLab Runner 曾经注册上了
➤ 当 Pod 运行起来后,查看残缺配置
[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。
集成 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:
- 利用 Maven 镜像进行打包,生成 war 包制品到缓存目录中;
- 利用 Docker 镜像,依据我的项目中的 Dockerfile 对缓存中的制品进行镜像构建,构建实现后,登录镜像仓库进行镜像推送;
- 利用 Kubectl 镜像先对原有 Deployment 文件进行镜像替换,之后将资源清单更新至 K8s 集群中;
- 在为镜像打 Tag 时,能够自行设置,也能够利用 Commit 来对照 Git 版本。
注意事项
- 因为在镜像构建的 Stage 中,须要应用 Docker 命令进行相干操作,因而须要绑定本地 Docker 守护过程;
- Maven 仓库缓存,在须要生产制品并保留的构建中,须要内部存储来寄存制品;
- 在 Stage 中援用的镜像最好能当时 Pull 到各个 Node 节点上,不然第一次运行 CI,如果网络有稳定或带宽小,可能会因为镜像下载超时导致 CI 失败。
配置变量
因为在 CI 文件中有一些敏感信息,例如镜像仓库的登录信息、前期能够更改的镜像名称等,可利用环境注入形式,使得 CI 文件脱敏而且更具灵活性和适用性。
增加极狐 GitLab Runner 可用的环境变量,本示例增加变量如下:
- APP_NAME:制作实现后镜像的名称;
- DOCKER_USERNAME:镜像仓库用户名;
- DOCKER_PASSWORD 镜像仓库明码;
- QHUB_NAMESPACE:镜像仓库名称空间。在该我的项目中,咱们应用腾讯云的镜像仓库,当然能够自建 Harbor 或应用其余私有云提供的镜像仓库或者 Dockerhub 等;
- REGISTRY:镜像仓库的地址。
运行测试
在配置好了 CI 文件后,让咱们来运行测试,提交代码,或者手动运行。
运行 Pipeline
在我的项目 CI/CD 右上角有运行流水线按钮。
在图中,咱们能够看到能够并行运行多个 Pipeline,互不影响。
查看运行 Pod
登录 K8s 集群,查看此时运行的 Pod:
查看 Job
➤ 打包镜像
➤ 镜像构建
➤ 部署进 K8s
查看构建状况
➤ 查看 Pipeline
➤ 查看构建利用
至此咱们就实现了极狐 GitLab CI + K8s 示例。让咱们纵情享受 K8s + 极狐 GitLab CI 为咱们带来畅快淋漓的公布体验吧。
注意事项
- 实战中的资源清单文件只写了 Deployment,读者能够依据本人我的项目调整,能够将 Service/Configmap/HPA 等资源清单文件也放在我的项目中托管,当然也能够制作成 Helm 利用,每次公布利用 Helm 来更新利用;
- 在极狐 GitLab CI 中,留神将敏感信息例如镜像仓库的登录形式等进行脱敏,将有变动的字段设置为变量,使得 CI 更扩展性及灵活性;
- 在此节中,局部内容须要读者具备肯定的 K8s 教训,例如其中的 Helm 及相干的资源清单文件,如当时理解业务微服务后,看本章节内容更为适合;
- 留神在写 RBAC 与 PVC 资源清单的名称空间为你想部署的业务名称空间,即例如你想把资源清单部署在 Common 名称空间下,就须要把 PVC 和 RBAC 创立在 Common 名称空间下,将 极狐 GitLab Runner 注册在 Common 名称空间下。
总结思考
通过本文极狐 GitLab CI 实战总结,笔者再次安利大家去理解极狐 GitLab 的此项个性。如果您的公司困于多套系统维护的复杂性,无妨尝试下极狐 GitLab CI 简略集成。
在云原生时代,将工具或中间件下沉到基础设施中,用户只须要专一于本身业务开发,在麻利高效的文化中合作、疾速试错、疾速反馈、继续改良、一直迭代,以 Git 为契机突破研发与运维的壁垒隔膜,实现产品更快、更频繁、更稳固的交付。