本文首發於個人我的博客,Gitlab CI 集成 Kubernetes 集羣部署 Spring Boot 項目 ,歡迎訪問!html
在上一篇博客中,咱們成功將 Gitlab CI 部署到了 Docker 中去,成功建立了 Gitlab CI Pipline 來執行 CI/CD 任務。那麼這篇文章咱們更進一步,將它集成到 K8s 集羣中去。這個纔是咱們最終的目標。衆所周知,k8s 是目前最火的容器編排項目,不少公司都使用它來構建和管理本身容器集羣,能夠用來作機器學習訓練以及 DevOps 等一系列的事情。java
在這裏,咱們聚焦 CI/CD,針對於 Spring Boot 項目,藉助 Gitlab CI 完成流水線的任務配置,最終部署到 K8s 上去。本文會詳細講解如何一步步操做,完成這樣的一條流水線。node
軟件的核心版本以下:git
k8s 集羣信息:github
[root@master01 ~]# kubectl get nodes NAME STATUS ROLES AGE VERSION 172.17.11.62 Ready <none> 37d v1.16.0-rc.2 172.17.13.120 Ready <none> 91d v1.16.0-rc.2 172.17.13.121 Ready <none> 91d v1.15.1 172.17.13.122 Ready <none> 91d v1.16.0-rc.2 172.17.13.123 Ready <none> 92d v1.16.0-rc.2
在上一篇博客《Docker Gitlab CI 部署 Spring Boot 項目》中咱們已經實現了在 Docker 中部署這一套流水線,可是單節點的 Docker 只適合本地調試,若是真正搭建起來用於公司的 CI/CD 工做,仍是會把它放到集羣環境下,所以如今咱們將流水線部署到 k8s 上。web
其實部署到 k8s 上包含兩種,一個是把 Gitlab 部署上去,另外一個是把 CI 這部分部署上去(也就是 Gitlab Runner)。其實 Gitlab 自己就是一個服務,部署在哪裏均可以,能夠選擇 Docker 部署,也能夠找一臺服務器單獨部署,做爲代碼倉庫。最關鍵的實際上是後者,CI/CD 的流程複雜且消耗資源多,部署在集羣上就能自動調度,達到資源利用最大化。那麼下面着重講 Gitlab Runner 的 k8s 部署,想了解前者的能夠看官方文檔,經過 helm 安裝。GitLab cloud native Helm Chartspring
假設 Gitlab 都已經部署成功了,那麼下面開始安裝 Gitlab Runner。具體的就是把 Runner 安裝到某個節點的 pod 的上,在處理具體的 CI 任務時,Runner 會啓動新的 pod 來執行任務,由 k8s 進行節點間的調度。docker
通常來講,咱們會使用 Helm 來進行安裝,Helm 是相似 CentOS 裏的 yum,是一種軟件管理工具,能夠幫咱們快速安裝軟件到 k8s 上。咱們須要在其中一個主節點上安裝好 Helm 的 client 和 server。具體可參考:ubuntu
顯示以下,證實安裝成功。api
[root@master01 ~]# helm version Client: &version.Version{SemVer:"v2.14.3", GitCommit:"0e7f3b6637f7af8fcfddb3d2941fcc7cbebb0085", GitTreeState:"clean"} Server: &version.Version{SemVer:"v2.14.3", GitCommit:"0e7f3b6637f7af8fcfddb3d2941fcc7cbebb0085", GitTreeState:"clean"}
添加 gitlab 源並更新。
[root@master01 ~]# helm repo add gitlab https://charts.gitlab.io [root@master01 ~]# helm repo update Hang tight while we grab the latest from your chart repositories... ...Skip local chart repository ...Successfully got an update from the "gitlab" chart repository ...Successfully got an update from the "stable" chart repository Update Complete. [root@master01 ~]# helm search gitlab-runner NAME CHART VERSION APP VERSION DESCRIPTION gitlab/gitlab-runner 0.10.0-rc1 12.4.0-rc1 GitLab Runner
這裏看到有兩個版本,一個是 chart version 一個是 app version。 chart 是 helm 中描述相關的一組 Kubernetes 資源的文件集合,裏面包含了一個 value.yaml 配置文件和一系列模板(deployment.yaml、svc.yaml 等),而具體的 app 是經過須要單獨去 Docker Hub 上拉取的。這兩個字段分別就是描述了這兩個版本號。
安裝前先建立一個 gitlab 的 namespace,併爲其配置相應的權限。
[root@master01 ~]# kubectl create namespace gitlab-runners
建立一個 rbac-runner-config.yaml
apiVersion: v1 kind: ServiceAccount metadata: name: gitlab namespace: gitlab-runners --- kind: Role 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: ["*"] --- kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: gitlab 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
而後執行如下。
[root@master01 ~]# kubectl create -f rbac-runner-config.yaml
接下來配置 runner 的註冊信息。上一篇博客中,咱們是先安裝 gitlab runner 而後進入容器執行 gitlab-runner register 來進行註冊的。在 k8s 可支持這麼操做,可是同時 helm 也提供了一個配置文件能夠在安裝 runner 的時候爲其註冊一個默認的 runner。咱們能夠去 gitlab-runner 的項目源碼 中獲取到 values.yaml
這個配置文件。配置文件比較長,能夠根據須要本身去配置,下面就貼下本文中須要配置的地方。
## 拉取策略, 先取本地鏡像 imagePullPolicy: IfNotPresent ## 配置 gitlab 的 url 和註冊令牌 ## 能夠在 gitlab 項目中設置 --CI/CD--Runner-- 手動設置 specific Runner 中查詢 gitlabUrl: http://172.17.193.109:7780/ runnerRegistrationToken: "qzxposxDst_Nnq5MMnPf" ## 和以前配置的 rbac name 對應 rbac: serviceAccountName: gitlab ## 指定關聯 runner 的標籤 tags: "maven,docker,k8s" privileged: true serviceAccountName: gitlab
而後經過 helm install 安裝 runner 就能夠了。token 和 url 不知道如何獲取的,見我上一篇博客。
[root@master01 ~]# helm install --name gitlab-runner gitlab/gitlab-runner -f values.yaml --namespace gitlab-runners NAME: gitlab-runner LAST DEPLOYED: Fri Oct 25 10:08:40 2019 NAMESPACE: default STATUS: DEPLOYED RESOURCES: ==> v1/ConfigMap NAME DATA AGE gitlab-runner-gitlab-runner 5 <invalid> ==> v1/Deployment NAME READY UP-TO-DATE AVAILABLE AGE gitlab-runner-gitlab-runner 0/1 0 0 <invalid> ==> v1/Secret NAME TYPE DATA AGE gitlab-runner-gitlab-runner Opaque 2 <invalid> NOTES: Your GitLab Runner should now be registered against the GitLab instance reachable at: "http://172.17.193.109:7780/"
等待一段時間後就能夠在 k8s 的 dashboard 上看到啓動成功的 runner 的 pod 了。
這個時候能夠進入 pod 看一下 runner 的配置文件(/home/gitlab-runner/.gitlab-runner/config.toml
)了。這個文件就是根據以前配置的 values.yaml 自動生成的。
listen_address = "[::]:9252" concurrent = 10 check_interval = 30 log_level = "info" [session_server] session_timeout = 1800 [[runners]] name = "gitlab-runner-gitlab-runner-6767fdcb6-pjvbz" request_concurrency = 1 url = "http://172.17.193.109:7780/" token = "Soxf6HEQVj4wr25zsGUS" 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" namespace = "gitlab-runners" namespace_overwrite_allowed = "" privileged = true service_account = "gitlab" service_account_overwrite_allowed = "" pod_annotations_overwrite_allowed = "" [runners.kubernetes.pod_security_context] [runners.kubernetes.volumes]
註冊成功後就能夠在 gitlab 的 web UI 上看到對應 token 的 runner 了。
這邊沒啥好說的,直接新建一個 spring boot 的 hello world 項目,並添加一個 dockerfile。
FROM openjdk:8-jdk-alpine VOLUME /tmp COPY /target/demo-0.0.1-SNAPSHOT.jar app.jar ENV PORT 5000 EXPOSE $PORT ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-Dserver.port=${PORT}","-jar","/app.jar"]
因爲使用的 executor 不一樣,因此. gitlab-ci.yml 和以前也有些不一樣。好比 k8s 貌似不支持緩存,volume 掛載方式的不一樣,以及權限問題等。先看完整的配置文件。
image: docker:latest variables: DOCKER_DRIVER: overlay2 # k8s 掛載本地卷做爲 maven 的緩存 MAVEN_OPTS: "-Dmaven.repo.local=/home/cache/maven" REGISTRY: "registry.cn-hangzhou.aliyuncs.com" TAG: "tmp-images/hello-spring" TEST_POD: "hello-spring" TEST_POD_CONTAINER: "spring-boot" stages: - package - build - deploy - release maven-package: image: maven:3.5-jdk-8-alpine tags: - maven stage: package script: - mvn clean package -Dmaven.test.skip=true artifacts: paths: - target/*.jar docker-build: tags: - docker stage: build script: - echo "Building Dockerfile-based application..." - docker login --username=maoqyhz@outlook.com registry.cn-hangzhou.aliyuncs.com -p [your pwd] - docker build -t $REGISTRY/$TAG:$CI_COMMIT_SHORT_SHA . - docker push $REGISTRY/$TAG only: - master k8s-deploy: image: bitnami/kubectl:latest tags: - k8s stage: deploy script: - echo "deploy to k8s cluster..." - kubectl version - kubectl set image deployment/$TEST_POD $TEST_POD_CONTAINER=$REGISTRY/$TAG:$CI_COMMIT_SHORT_SHA --namespace gitlab-runners only: - master # when: manual release: stage: release script: - echo "release to prod env..." when: manual
須要特別指出的地方有 3 點:
綁定本地 Docker 守護進程。
k8s 測試鏡像的部署。
Docker 環境下咱們使用了一個 docker:dind 的服務用於執行 docker build 到本地鏡像倉庫。在 k8s 中,發現用了這個東西會出現 runner 連不到 Gitlab 服務器上,報了一個 host xxx is unreachable
的錯誤。因此最終採用 volume 綁定的形式把本地 docker.sock
經過 host_path 的方式掛載到 runner 中去。
# /home/gitlab-runner/.gitlab-runner/config.toml [[runners.kubernetes.volumes.host_path]] name = "docker" mount_path = "/var/run/docker.sock"
在以前的 Docker 環境下,volume 的掛載是一件很容易的事情,咱們直接能夠把本地的 maven 倉庫掛載。或者經過 cache 節點進行緩存的配置。可是在 k8s 環境下,我折騰了好久也沒找到 cache 節點的配置方法。生產環境下應該能夠配置 aws 或者 minio 做爲緩存。目前最終測試出來本地可行的方案是經過掛載 nfs pvc。
首先咱們須要建立一個 PersistentVolume 和 PersistentVolumeClaim。
apiVersion: v1 kind: PersistentVolume metadata: name: gitlab-runner-maven-repo spec: accessModes: - ReadWriteMany capacity: storage: 5Gi mountOptions: - nolock nfs: path: /opt/maven-cache/ server: 172.17.13.120 persistentVolumeReclaimPolicy: Recycle --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: gitlab-runner-maven-repo-claim namespace: gitlab-runners spec: accessModes: - ReadWriteMany resources: requests: storage: 5Gi volumeName: gitlab-runner-maven-repo status: accessModes: - ReadWriteMany capacity: storage: 5Gi
在 runner 的配置中綁定。
# /home/gitlab-runner/.gitlab-runner/config.toml [[runners.kubernetes.volumes.pvc]] name = "gitlab-runner-maven-repo-claim" mount_path = "/home/cache/maven"
而後配置 MAVEN_OPTS
到掛載的路徑,就能夠實現 maven 倉庫的緩存了。
在 Docker 中,build 以後的鏡像直接能夠經過 docker run 啓動。在 k8s 下相對比較複雜,須要經過配置 deployment.yaml 來進行啓動,若是須要外部訪問,還須要配置 services 等組件。這裏僅僅是爲了演示流水線的執行過程,就預先啓動一個 pod 做爲測試。每次觸發新的構建任務時,直接經過命令 kubectl set image
替換掉舊鏡像就能夠了。
git push & commit 代碼後,流水線會自動建立執行。完成後可在以前配置的 services 端口看到部署的結果。
第一次實操過程當中,坑仍是不少的,在這裏記錄一下。
k8s 迭代的速度較快,使用最新版可是周邊生態沒有跟上腳步同步更新的話很容易產生問題。在 1.16 中 API versions 就有了比較大的變化,因此致使 helm 的模板沒及時更新出錯了。
Error: validation failed: unable to recognize "": no matches for kind"Deployment"in version"extensions/v1beta1"
以往 helm 的服務端安裝直接調用 helm init 就能夠了。因爲 apiVersion 的問題須要經過如下命令才能裝上。完整的安裝的命令以下:
# 添加權限控制帳戶 [root@master01 ~]# kubectl create serviceaccount --namespace kube-system tiller [root@master01 ~]# kubectl create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller # 經過此命令修改 apiVersion 由 extensions/v1beta1 變爲 apps/v1,並使用國內鏡像。 [root@master01 ~]# helm init --upgrade -i registry.cn-hangzhou.aliyuncs.com/google_containers/tiller:v2.14.3 --service-account tiller --override spec.selector.matchLabels.'name'='tiller',spec.selector.matchLabels.'app'='helm' --output yaml | sed 's@apiVersion: extensions/v1beta1@apiVersion: apps/v1@' | kubectl apply -f - [root@master01 ~]# [root@master01 ~]# helm repo remove stable [root@master01 ~]# helm repo add stable https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts
一樣的,上文咱們是經過手動安裝的 helm server 和 gitlab runner。而實際上 Gitlab CE 支持免費綁定 1 個 k8s 集羣,而且提供一鍵式的安裝。可是因爲版本號的問題,我這裏安裝不上。你們能夠用低版本的 k8s 測試一下。具體在 Gitlab WebUI 中 root 帳戶登陸,管理中心 -- Kubernetes 或者項目管理界面下,運維 --Kubernetes 進行集羣的綁定。
綁定後會託管到 Gitlab,建立一個 namespace 來進行程序的安裝。
以前在配置 runner 的 volume 的時候是直接進入 pod 內部修改 config.toml 這個配置文件的。這樣會存在一個問題,若是集羣重啓了,修改過的數據就全沒了,由於重啓後會從新起一個 pod。以往在 Docker 中,咱們會 commit 成一個新的鏡像保存,但這樣保存的鏡像顯然沒有廣泛性,而且每次還須要修改 deployment.yaml 中的鏡像,所以最好的方法是修改 helm 的 chart 中的模板,把全部的配置信息都寫入 yaml 文件中,而非直接修改 pod 自己中的配置。
所以爲了可以高度的配置咱們本身的 runner,就不直接從 helm 官方的源鏡像安裝了。
[root@master01 ~]# helm fetch gitlab/gitlab-runner
helm fetch 能夠將 chart 下載到本地,能夠看到是. tgz 格式的,解壓後的文件夾內包含的就是描述資源的一些模板文件。
gitlab-runner-v0.10.0-rc1 ├── CHANGELOG.md ├── Chart.yaml ├── CONTRIBUTING.md ├── LICENSE ├── NOTICE ├── README.md ├── scripts │ ├── changelog2releasepost │ └── prepare-changelog-entries.rb ├── templates │ ├── _cache.tpl │ ├── configmap.yaml │ ├── deployment.yaml │ ├── _env_vars.tpl │ ├── _helpers.tpl │ ├── hpa.yaml │ ├── NOTES.txt │ ├── role-binding.yaml │ ├── role.yaml │ ├── secrets.yaml │ └── service-account.yaml └── values.yaml
以前提取的 values.yaml 和這裏是同樣的,用於設置一些可配置的變量。具體的模板在 templates 目錄下。這裏咱們能夠仔細看下 values.yaml、deployment.yaml 和 configmap.yaml,會發現 runner 的 config.toml 文件中的大部分信息都是根據這三個配置文件中的信息自動生成的。那麼咱們只須要額外配置一下須要的 volume 就能夠了。
這裏咱們須要修改 vaules.yaml 和 configmap.yaml。
## configmap.yaml if ! sh /scripts/register-the-runner; then exit 1 fi # add volume config 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 # Start the runner exec /entrypoint run --user=gitlab-runner \ --working-directory=/home/gitlab-runner
在 register 和 start 之間添加配置 volume 的信息,並在 values.yaml 配置相應的變量。
## my config # maven cache maven: cache: pvcName: gitlab-runner-maven-repo-claim mountPath: /home/cache/maven
配置完成後,執行 helm upgrade gitlab-runner gitlab-runner-v0.10.0-rc1/
。
以後不管重啓 pod 仍是集羣,runner 的配置信息都能被正確加載了。
gcr.io 沒法訪問,Docker Hub 訪問速度慢,這個你們都懂的。
阿里雲通用鏡像服務器: https://registry.cn-hangzhou.aliyuncs.com
helm chart 鏡像
本文主要描述了在 k8s 上部署流水線的整個過程,因爲對 k8s 不太熟悉,遇到了很多的坑,國內相關的博客也較少,因此就記錄一下整個配置的過程。對於整個流程不熟悉的讀者能夠先閱讀上一篇博客《Docker Gitlab CI 部署 Spring Boot 項目》。下一步的工做就是要將流水線對接到實際的項目中去了。
未完待續...