本文示例如何使用 Jenkins 自動編譯打包, 構建 Docker 鏡像, 提交到本地 Docker Registry 鏡像服務, 並經過 Helm 發佈到 K8S 集羣.java
總體的流程圖以下:
node
本文涉及到的環境:linux
服務端 ttg12
:git
應用:web
本地工做電腦spring
應用:docker
在 ttg12
上安裝好 docker, 並配置好國內鏡像.數據庫
在 ttg12
上經過 docker 安裝本地 Docker Registry (v2.6.1). 參考私有化部署極簡 Docker Registry, 並將自簽名證書複製到 /etc/docker/certs.d/<registry_domain>:<registry_port>/ca.crt
.segmentfault
準備一個 K8S 集羣或者單節點 K8S, 在 ttg12
上安裝好 kubectl 工具, 並配置好 /etc/.kube/config
.tomcat
在 ttg12
上安裝好 helm 3 客戶端. Linux 下 Helm 3 的安裝很簡單, 直接下載二進制文件下來, 解壓, 移動到/usr/local/bin/
目錄下便可.
# 這裏以 helm v3.3.0 爲例 curl https://get.helm.sh/helm-v3.3.0-rc.1-linux-amd64.tar.gz > /tmp/helm-v3.3.0-rc.1-linux-amd64.tar.gz tar zxf /tmp/helm-v3.3.0-rc.1-linux-amd64.tar.gz -C /tmp/helm-v3.3.0-rc.1-linux-amd64/helm `/usr/local/bin/helm` sudo cp /tmp/helm-v3.3.0-rc.1-linux-amd64/helm /usr/local/bin/helm sudo rm -rf /tmp/helm-v3.3.0-rc.1-linux-amd64.tar.gz /tmp/helm-v3.3.0-rc.1-linux-amd64/helm
本文使用 Docker 方式安裝 Jenkins. 具體步驟參考本文另一篇博文 Docker安裝Jenkins並支持Maven,Docker,Helm.
啓動容器後, 登陸 Jenkins, 安裝插件 Docker plugin
and Docker Pipeline
. 不然會報異常:
Obtained Jenkinsfile from git [https://gitee.com/facelessdemos/SpringBootDemo.git](https://gitee.com/facelessdemos/SpringBootDemo.git) Running in Durability level: MAX\_SURVIVABILITY org.codehaus.groovy.control.MultipleCompilationErrorsExcept.ion: startup failed: WorkflowScript: 34: Invalid agent type "docker" specified. Must be one of \[any, label, none\] @ line 34, column 17. docker { ^
參考 Gitee 官方文檔, 安裝 Gitee
插件.
在項目根目錄下新建 Dockerfile, Jenkinsfile 文件 以及 helm 目錄.
FROM frolvlad/alpine-java:jdk8-slim #在build鏡像時能夠經過 --build-args profile=xxx 進行修改 ARG profile ENV SPRING_PROFILES_ACTIVE=${profile} #項目的端口 EXPOSE 8080 WORKDIR /mnt #修改時區 RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories \ && apk add --no-cache tzdata \ && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ && echo "Asia/Shanghai" > /etc/timezone \ && apk del tzdata \ && rm -rf /var/cache/apk/* /tmp/* /var/tmp/* $HOME/.cache COPY ./web/target/web-1.0-SNAPSHOT.jar ./app.jar ENTRYPOINT ["java", "-jar", "/mnt/app.jar"]
image_tag = "1.0.0-snapshot" //定一個全局變量,存儲Docker鏡像的tag(版本) pipeline { agent any environment { //GIT_REPO = "${env.gitlabSourceRepoName}" //從Jenkins Gitlab插件中獲取Git項目的名稱 GIT_REPO = "springbootdemo" GIT_BRANCH = "${env.gitlabTargetBranch}" //項目的分支 GIT_TAG = sh(returnStdout: true,script: 'git describe --tags --always').trim() //commit id或tag名稱 KUBE_CONFIG_LOCAL = credentials('local-k8s-kube-config') //開發測試環境的kube憑證 KUBE_CONFIG_PROD = "" //credentials('prod-k8s-kube-config') //生產環境的kube憑證 DOCKER_REGISTRY = "registry.faceless.com:5443" //Docker倉庫地址 DOCKER_NAMESPACE = "facelessdemo" //命名空間 DOCKER_IMAGE = "${DOCKER_REGISTRY}/${DOCKER_NAMESPACE}/${GIT_REPO}" //Docker鏡像地址 INGRESS_HOST_DEV = "dev.springbootdemo.cn" //開發環境的域名 INGRESS_HOST_TEST = "test.springbootdemo.cn" //測試環境的域名 INGRESS_HOST_PROD = "prod.springbootdemo.cn" //生產環境的域名 K8S_NAMESPACE = "demo-dev" } parameters { string(name: 'ingress_path', defaultValue: '/', description: '服務上下文路徑') string(name: 'replica_count', defaultValue: '2', description: '容器副本數量') } stages { stage('Code Analyze') { agent any steps { echo "1. 代碼靜態檢查" } } stage('Maven Build') { agent any steps { echo "2. 代碼編譯打包" sh 'mvn clean package -Dfile.encoding=UTF-8 -Dmaven.test.skip=true' } } stage('Docker Build') { agent any steps { echo "3. 構建Docker鏡像" echo "鏡像地址: ${DOCKER_IMAGE}" script { def profile = "dev" image_tag = "dev." + env.GIT_TAG if (env.gitlabTargetBranch == "develop") { image_tag = "dev." + env.GIT_TAG profile = "dev" } else if (env.gitlabTargetBranch == "pre-release") { image_tag = "test." + env.GIT_TAG profile = "test" } else if (env.gitlabTargetBranch == "master"){ // master分支則直接使用Tag image_tag = env.GIT_TAG profile = "prod" } //經過--build-arg將profile進行設置,以區分不一樣環境進行鏡像構建 sh "docker build --build-arg profile=${profile} -t ${DOCKER_IMAGE}:${image_tag} ." sh "docker push ${DOCKER_IMAGE}:${image_tag}" sh "docker rmi ${DOCKER_IMAGE}:${image_tag}" } } } stage('Helm Deploy') { agent any steps { echo "4. 部署到K8s" sh "helm upgrade -i --namespace=${K8S_NAMESPACE} --set image.repository=${DOCKER_IMAGE} --set image.tag=${image_tag} ${GIT_REPO} ./helm/" } } } }
經過helm 客戶端建立對應版本的 chart 配置文件清單:
helm create springbootdemo
獲得相應的文件清單以下:
1) 咱們須要修改其中的 values.yaml
文件. 注意如下帶註釋的部分.
# 啓動容器副本數 replicaCount: 2 image: # 項目打包出來的 docker image 提交在本地鏡像倉庫中 repository: registry.faceless.com:5443/facelessdemo/springbootdemo pullPolicy: IfNotPresent # 默認image標籤. 需在Jenkinsfile中的 `sh helm upgrade` 命令中覆蓋. tag: "dev.latest" imagePullSecrets: [] # 項目名 nameOverride: "springbootdemo" fullnameOverride: "" # 容器的端口暴露及環境變量配置 container: port: 8080 env: [] serviceAccount: create: true annotations: {} name: "" podAnnotations: {} podSecurityContextext: {} securityContext: {} # 本示例經過Ingress提供對外服務, 因此Service使用ClusterIP模式便可 service: type: ClusterIP port: 8080 # Ingress配置域名和路徑. 測試時須要將`dev.springbootdemo.cn`域名指向k8s的任一臺worker的IP. ingress: enabled: true annotations: {} hosts: - host: dev.springbootdemo.cn paths: [/] tls: [] resources: {} autoscaling: enabled: false minReplicas: 1 maxReplicas: 4 nodeSelector: {} tolerations: [] affinity: {} # Probe延時參數 probe: livenessDelaySeconds: 120 readinessDelaySeconds: 120
2) templates/depolyment.yaml 文件. templates
文件夾下的文件是 K8S deploymnet, service, ingress 等通用配置模板, 通常狀況下無需修改. 可是對於 SrpingBoot 項目, 特別是涉及到啓動過程當中須要鏈接數據庫/消息隊列/其餘第三方服務的狀況, 默認在啓動後就進行服務探測(Probe). 而此時可能 tomcat 還沒起來, 因此容易誤報爲服務失敗, 致使無故重啓容器. 所以咱們須要修改 templates/depolyment.yaml
文件, 將其中 Probe 延時改成一個相對比較合理的時間.
咱們修改 templates/depolyment.yaml
文件, 在 .spec.template.spec.containers
節點下增長 .livenessProbe
和 .readinessProbe
兩個節點. 其餘部分沒有任何改動, 因此這裏只給出這一段代碼片斷:
containers: - name: {{ .Chart.Name }} # 省略... ports: - name: http containerPort: {{ .Values.container.port }} protocol: TCP livenessProbe: httpGet: path: / port: http initialDelaySeconds: {{ .Values.probe.livenessDelaySeconds }} readinessProbe: httpGet: path: / port: http initialDelaySeconds: {{ .Values.probe.readinessDelaySeconds }}
1) 新建一個 Item, 取一個名字 (好比: SpringBootDemo-K8S), 選擇 Pipeline 類型.
2) 進入到配置頁面, General -> Description
字段輸入項目描述.
3) 若是你的 Jenkins 能夠外網訪問, 或者跟你的 Gitlab 處於同一局域網, 能夠由 Gitee 或者 Gitlab 觸發 WebHook, 那麼在 Build Triggers
模塊進行相應的配置. 本示例由於 Gitee 沒法觸達內網部署的 Jenkins, 因此沒有配置 Build Triggers
. 後面須要手動觸發編譯流程.
4) Pipeline的定義以下圖所示 (注意, 我這裏取的是base
分支, 若是你須要取master
分支, 將下圖中的3處base
改成master
:
最後, 手動觸發編譯, Pipeline 的 Stage View 以下圖所示: