<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Gitlab+Jenkins+k8s+Helm 的自動(dòng)化部署實(shí)踐

          共 11245字,需瀏覽 23分鐘

           ·

          2021-11-05 15:44

          來(lái)源:https://segmentfault.com/a/1190000022637144

          本文從實(shí)踐角度介紹如何結(jié)合我們常用的 Gitlab 與 Jenkins,通過(guò) K8s 來(lái)實(shí)現(xiàn)項(xiàng)目的自動(dòng)化部署,示例將包括基于 SpringBoot 的服務(wù)端項(xiàng)目與基于 Vue.js 的 Web 項(xiàng)目。

          本文涉及到的工具與技術(shù)包括:
          • Gitlab —— 常用的源代碼管理系統(tǒng)
          • Jenkins,Jenkins Pipeline —— 常用的自動(dòng)化構(gòu)建、部署工具,Pipeline 以流水線的方式將構(gòu)建、部署的各個(gè)步驟組織起來(lái)
          • Docker,Dockerfile —— 容器引擎,所有應(yīng)用最終都要以 Docker 容器運(yùn)行,Dockerfile 是 Docker 鏡像定義文件
          • Kubernetes —— Google 開源的容器編排管理系統(tǒng)
          • Helm —— Kubernetes 的包管理工具,類似 Linux 的 yum,apt,或 Node 的 npm 等包管理工具,能將 Kubernetes 中的應(yīng)用及相關(guān)依賴服務(wù)以包(Chart)的形式組織管理
          環(huán)境背景:
          1. 已使用 Gitlab 做源碼管理,源碼按不同的環(huán)境建立了 develop(對(duì)應(yīng)開發(fā)環(huán)境),pre-release(對(duì)應(yīng)測(cè)試環(huán)境),master(對(duì)應(yīng)生產(chǎn)環(huán)境)分支
          2. 已搭建了 Jenkins 服務(wù)
          3. 已有 Docker Registry 服務(wù),用于 Docker 鏡像存儲(chǔ)(基于 Docker Registry 或Harbor 自建,或使用云服務(wù),本文使用阿里云容器鏡像服務(wù))
          4. 已搭建了 K8s 集群

          預(yù)期效果:

          1. 分環(huán)境部署應(yīng)用,開發(fā)環(huán)境、測(cè)試環(huán)境、生產(chǎn)環(huán)境分開來(lái),部署在同一集群的不同namespace,或不同集群中(比如開發(fā)測(cè)試部署在本地集群的不同 namespace中,生產(chǎn)環(huán)境部署在云端集群)

          2. 配置盡可能通用化,只需要通過(guò)修改少量配置文件的少量配置屬性,就能完成新項(xiàng)目的自動(dòng)化部署配置

          3. 開發(fā)測(cè)試環(huán)境在push代碼時(shí)自動(dòng)觸發(fā)構(gòu)建與部署,生產(chǎn)環(huán)境在 master 分支上添加版本 tag 并且 push tag 后觸發(fā)自動(dòng)部署

          4. 整體交互流程如下圖

          項(xiàng)目配置文件

          首先我們需要在項(xiàng)目的根路徑中添加一些必要的配置文件,如下圖所示


          包括:

          1. Dockerfile 文件,用于構(gòu)建 Docker 鏡像的文件(參考 Docker筆記(十一):

            Dockerfile 詳解與最佳實(shí)踐)

          2. Helm 相關(guān)配置文件,Helm 是 Kubernetes 的包管理工具,可以將應(yīng)用部署相關(guān)的Deployment,Service,Ingress 等打包進(jìn)行發(fā)布與管理(Helm 的具體介紹我們后面再補(bǔ)充)

          3. Jenkinsfile 文件,Jenkins 的 pipeline 定義文件,定義了各個(gè)階段需執(zhí)行的任務(wù)

          Dockerfile

          在項(xiàng)目根目錄中添加一個(gè) Dockerfile 文件(文件名就叫 Dockerfile),定義如何構(gòu)建Docker 鏡像,以 Spring Boot 項(xiàng)目為例,
          FROM frolvlad/alpine-java:jdk8-slim#在build鏡像時(shí)可以通過(guò) --build-args profile=xxx 進(jìn)行修改ARG profileENV SPRING_PROFILES_ACTIVE=${profile}#項(xiàng)目的端口EXPOSE 8000 WORKDIR /mnt
          #修改時(shí)區(qū)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 ./target/your-project-name-1.0-SNAPSHOT.jar ./app.jarENTRYPOINT ["java", "-jar", "/mnt/app.jar"]

          將 SPRING_PROFILES_ACTIVE 通過(guò)參數(shù) profile 暴露出來(lái),在構(gòu)建的時(shí)候可以通過(guò) —build-args profile=xxx 來(lái)進(jìn)行動(dòng)態(tài)設(shè)定,以滿足不同環(huán)境的鏡像構(gòu)建要求。

          SPRING_PROFILES_ACTIVE 本可以在 Docker 容器啟動(dòng)時(shí)通過(guò) docker run -e SPRING_PROFILES_ACTIVE=xxx 來(lái)設(shè)定,因這里使用 Helm 進(jìn)行部署不直接通過(guò)docker run 運(yùn)行,因此通過(guò) ARG 在鏡像構(gòu)建時(shí)指定

          Helm 配置文件

          Helm 是 Kubernetes 的包管理工具,將應(yīng)用部署相關(guān)的 Deployment,Service,Ingress 等打包進(jìn)行發(fā)布與管理(可以像 Docker 鏡像一樣存儲(chǔ)于倉(cāng)庫(kù)中)。如上圖中Helm 的配置文件包括:

          helm                                    - chart包的目錄名├── templates                           - k8s配置模版目錄│   ├── deployment.yaml                 - Deployment配置模板,定義如何部署Pod│   ├── _helpers.tpl                    - 以下劃線開頭的文件,helm視為公共庫(kù)定義文件,用于定義通用的子模版、函數(shù)、變量等│   ├── ingress.yaml                    - Ingress配置模板,定義外部如何訪問(wèn)Pod提供的服務(wù),類似于Nginx的域名路徑配置│   ├── NOTES.txt                       - chart包的幫助信息文件,執(zhí)行helm install命令成功后會(huì)輸出這個(gè)文件的內(nèi)容│   └── service.yaml                    - Service配置模板,配置訪問(wèn)Pod的服務(wù)抽象,有NodePort與ClusterIp等|── values.yaml                         - chart包的參數(shù)配置文件,各模版文件可以引用這里的參數(shù)├── Chart.yaml                          - chart定義,可以定義chart的名字,版本號(hào)等信息├── charts                              - 依賴的子包目錄,里面可以包含多個(gè)依賴的chart包,一般不存在依賴,我這里將其刪除了
          我們可以在 Chart.yaml 中定義每個(gè)項(xiàng)目的 chart 名稱(類似安裝包名),如
          apiVersion: v2name: your-chart-namedescription: A Helm chart for Kubernetes
          type: applicationversion: 1.0.0appVersion: 1.16.0

          在 values.yaml 中定義模板文件中需要用到的變量,如

          #部署Pod的副本數(shù),即運(yùn)行多少個(gè)容器replicaCount: 1#容器鏡像配置image:  repository: registry.cn-hangzhou.aliyuncs.com/demo/demo  pullPolicy: Always  # Overrides the image tag whose default is the chart version.  tag: "dev"#鏡像倉(cāng)庫(kù)訪問(wèn)憑證imagePullSecrets:  - name: aliyun-registry-secret#覆蓋啟動(dòng)容器名稱nameOverride: ""fullnameOverride: ""#容器的端口暴露及環(huán)境變量配置container:  port: 8000  env: []#ServiceAccount,默認(rèn)不創(chuàng)建serviceAccount:  # Specifies whether a service account should be created  create: false  # Annotations to add to the service account  annotations: {}  name: ""
          podAnnotations: {}
          podSecurityContext: {} # fsGroup: 2000
          securityContext: {} # capabilities: # drop: # - ALL # readOnlyRootFilesystem: true # runAsNonRoot: true # runAsUser: 1000#使用NodePort的service,默認(rèn)為ClusterIpservice: type: NodePort port: 8000#外部訪問(wèn)Ingress配置,需要配置hosts部分ingress: enabled: true annotations: {} # kubernetes.io/ingress.class: nginx # kubernetes.io/tls-acme: "true" hosts: - host: demo.com paths: ["/demo"] tls: [] # - secretName: chart-example-tls # hosts: # - chart-example.local
          #.... 省略了其它默認(rèn)參數(shù)配置

          這里在默認(rèn)生成的基礎(chǔ)上添加了 container 部分,可以在這里指定容器的端口號(hào)而不用去改模板文件(讓模板文件在各個(gè)項(xiàng)目通用,通常不需要做更改),同時(shí)添加env的配置,可以在helm部署時(shí)往容器里傳入環(huán)境變量。將Service type從默認(rèn)的ClusterIp改為了NodePort。部署同類型的不同項(xiàng)目時(shí),只需要根據(jù)項(xiàng)目情況配置Chart.yaml與values.yaml兩個(gè)文件的少量配置項(xiàng),templates目錄下的模板文件可直接復(fù)用。

          部署時(shí)需要在K8s環(huán)境中從 Docker 鏡像倉(cāng)庫(kù)拉取鏡像,因此需要在K8s中創(chuàng)建鏡像倉(cāng)庫(kù)訪問(wèn)憑證(imagePullSecrets)
          # 登錄Docker Registry生成/root/.docker/config.json文件sudo docker login --username=your-username registry.cn-shenzhen.aliyuncs.com# 創(chuàng)建 namespace develop(我這里是根據(jù)項(xiàng)目的環(huán)境分支名稱建立namespacekubectl create namespace develop# 在 namespace develop中創(chuàng)建一個(gè)secretkubectl create secret generic aliyun-registry-secret --from-file=.dockerconfigjson=/root/.docker/config.json  --type=kubernetes.io/dockerconfigjson --namespace=develop

          Jenkinsfile

          Jenkinsfile 是 Jenkins pipeline 配置文件,遵循 Groovy 語(yǔ)法,對(duì)于 Spring Boot 項(xiàng)目的構(gòu)建部署, 編寫 Jenkinsfile 腳本文件如下,
          image_tag = "default"  //定一個(gè)全局變量,存儲(chǔ)Docker鏡像的tag(版本)pipeline {    agent any    environment {        GIT_REPO = "${env.gitlabSourceRepoName}"  //從Jenkins Gitlab插件中獲取Git項(xiàng)目的名稱        GIT_BRANCH = "${env.gitlabTargetBranch}"  //項(xiàng)目的分支        GIT_TAG = sh(returnStdout: true,script: 'git describe --tags --always').trim()  //commit id或tag名稱        DOCKER_REGISTER_CREDS = credentials('aliyun-docker-repo-creds') //docker registry憑證        KUBE_CONFIG_LOCAL = credentials('local-k8s-kube-config')  //開發(fā)測(cè)試環(huán)境的kube憑證        KUBE_CONFIG_PROD = "" //credentials('prod-k8s-kube-config') //生產(chǎn)環(huán)境的kube憑證
          DOCKER_REGISTRY = "registry.cn-hangzhou.aliyuncs.com" //Docker倉(cāng)庫(kù)地址 DOCKER_NAMESPACE = "your-namespace" //命名空間 DOCKER_IMAGE = "${DOCKER_REGISTRY}/${DOCKER_NAMESPACE}/${GIT_REPO}" //Docker鏡像地址
          INGRESS_HOST_DEV = "dev.your-site.com" //開發(fā)環(huán)境的域名 INGRESS_HOST_TEST = "test.your-site.com" //測(cè)試環(huán)境的域名 INGRESS_HOST_PROD = "prod.your-site.com" //生產(chǎn)環(huán)境的域名 } parameters { string(name: 'ingress_path', defaultValue: '/your-path', description: '服務(wù)上下文路徑') string(name: 'replica_count', defaultValue: '1', description: '容器副本數(shù)量') }
          stages { stage('Code Analyze') { agent any steps { echo "1. 代碼靜態(tài)檢查" } } stage('Maven Build') { agent { docker { image 'maven:3-jdk-8-alpine' args '-v $HOME/.m2:/root/.m2' } } steps { echo "2. 代碼編譯打包" sh 'mvn clean package -Dfile.encoding=UTF-8 -DskipTests=true' } } stage('Docker Build') { agent any steps { echo "3. 構(gòu)建Docker鏡像" echo "鏡像地址:${DOCKER_IMAGE}" //登錄Docker倉(cāng)庫(kù) sh "sudo docker login -u ${DOCKER_REGISTER_CREDS_USR} -p ${DOCKER_REGISTER_CREDS_PSW} ${DOCKER_REGISTRY}" script { def profile = "dev" if (env.gitlabTargetBranch == "develop") { image_tag = "dev." + env.GIT_TAG } 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" } //通過(guò)--build-arg將profile進(jìn)行設(shè)置,以區(qū)分不同環(huán)境進(jìn)行鏡像構(gòu)建 sh "docker build --build-arg profile=${profile} -t ${DOCKER_IMAGE}:${image_tag} ." sh "sudo docker push ${DOCKER_IMAGE}:${image_tag}" sh "docker rmi ${DOCKER_IMAGE}:${image_tag}" } } } stage('Helm Deploy') { agent { docker { image 'lwolf/helm-kubectl-docker' args '-u root:root' } } steps { echo "4. 部署到K8s" sh "mkdir -p /root/.kube" script { def kube_config = env.KUBE_CONFIG_LOCAL def ingress_host = env.INGRESS_HOST_DEV if (env.gitlabTargetBranch == "pre-release") { ingress_host = env.INGRESS_HOST_TEST } else if (env.gitlabTargetBranch == "master"){ ingress_host = env.INGRESS_HOST_PROD kube_config = env.KUBE_CONFIG_PROD } sh "echo ${kube_config} | base64 -d > /root/.kube/config" //根據(jù)不同環(huán)境將服務(wù)部署到不同的namespace下,這里使用分支名稱 sh "helm upgrade -i --namespace=${env.gitlabTargetBranch} --set replicaCount=${params.replica_count} --set image.repository=${DOCKER_IMAGE} --set image.tag=${image_tag} --set nameOverride=${GIT_REPO} --set ingress.hosts[0].host=${ingress_host} --set ingress.hosts[0].paths={${params.ingress_path}} ${GIT_REPO} ./helm/" } } } }}
          Jenkinsfile定義了整個(gè)自動(dòng)化構(gòu)建部署的流程:
          1. Code Analyze,可以使用 SonarQube 之類的靜態(tài)代碼分析工具完成代碼檢查,這里先忽略
          2. Maven Build,啟動(dòng)一個(gè) Maven 的 Docker 容器來(lái)完成項(xiàng)目的 maven 構(gòu)建打包,掛載 maven 本地倉(cāng)庫(kù)目錄到宿主機(jī),避免每次都需要重新下載依賴包
          3. Docker Build,構(gòu)建 Docker 鏡像,并推送到鏡像倉(cāng)庫(kù),不同環(huán)境的鏡像通過(guò)tag區(qū)分,開發(fā)環(huán)境使用 dev.commitId 的形式,如 dev.88f5822,測(cè)試環(huán)境使用 test.commitId,生產(chǎn)環(huán)境可以將 webhook 事件設(shè)置為 tag push event,直接使用 tag名稱
          4. Helm Deploy,使用helm完成新項(xiàng)目的部署,或已有項(xiàng)目的升級(jí),不同環(huán)境使用不同的參數(shù)配置,如訪問(wèn)域名,K8s 集群的訪問(wèn)憑證kube_config等

          Jenkins 配置

          Jenkins 任務(wù)配置

          在 Jenkins 中創(chuàng)建一個(gè) pipeline 的任務(wù),如圖

          配置構(gòu)建觸發(fā)器,將目標(biāo)分支設(shè)置為 develop 分支,生成一個(gè) token,如圖

          記下這里的“GitLab webhook URL”及token值,在Gitlab配置中使用。

          配置流水線,選擇“Pipeline script from SCM”從項(xiàng)目源碼中獲取pipeline腳本文件,配置項(xiàng)目Git地址,拉取源碼憑證等,如圖

          保存即完成了項(xiàng)目開發(fā)環(huán)境的Jenkins配置。測(cè)試環(huán)境只需將對(duì)應(yīng)的分支修改為pre-release 即可

          Jenkins 憑據(jù)配置

          在 Jenkinsfile 文件中,我們使用到了兩個(gè)訪問(wèn)憑證——Docker Registry憑證與本地K8s的kube憑證,
          DOCKER_REGISTER_CREDS = credentials('aliyun-docker-repo-creds') //docker registry憑證KUBE_CONFIG_LOCAL = credentials('local-k8s-kube-config')  //開發(fā)測(cè)試環(huán)境的kube憑證
          這兩個(gè)憑證需要在 Jenkins 中創(chuàng)建。
          添加 Docker Registry 登錄憑證,在 Jenkins 憑據(jù)頁(yè)面,添加一個(gè)用戶名密碼類型的憑據(jù),如圖


          添加 K8s 集群的訪問(wèn)憑證,在 master 節(jié)點(diǎn)上將 /root/.kube/config 文件內(nèi)容進(jìn)行 base64 編碼,

          base64 /root/.kube/config > kube-config-base64.txtcat kube-config-base64.txt

          使用編碼后的內(nèi)容在 Jenkins 中創(chuàng)建一個(gè) Secret text 類型的憑據(jù),如圖

          在 Secret 文本框中輸入 base64 編碼后的內(nèi)容。

          Gitlab 配置

          在 Gitlab 項(xiàng)目的 Settings - Integrations 頁(yè)面配置一個(gè) webhook,在 URL 與 Secret Token 中填入前面 Jenkins 觸發(fā)器部分的“GitLab webhook URL”及token值,選中“Push events”作為觸發(fā)事件,如圖

          開發(fā)、測(cè)試環(huán)境選擇“Push events”則在開發(fā)人員push代碼,或merge代碼到develop,pre-release分支時(shí),就會(huì)觸發(fā)開發(fā)或測(cè)試環(huán)境的Jenkins pipeline任務(wù)完成自動(dòng)化構(gòu)建;生產(chǎn)環(huán)境選擇“Tag push events”,在往master分支push tag時(shí)觸發(fā)自動(dòng)化構(gòu)建。如圖為pipeline構(gòu)建視圖

          總結(jié)

          本文介紹使用 Gitlab+Jenkins Pipeline+Docker+Kubernetes+Helm 來(lái)實(shí)現(xiàn) Spring Boot項(xiàng)目的自動(dòng)化部署,只要稍加修改即可應(yīng)用于其它基于Spring Boot的項(xiàng)目(具體修改的地方在源碼的 Readme 文件中說(shuō)明)。

          - END -

          ?推薦閱讀?

          Kubernetes 企業(yè)容器云平臺(tái)運(yùn)維實(shí)戰(zhàn)?
          面試官:你都監(jiān)控 Redis 哪些指標(biāo)?
          Linux運(yùn)維工程師的 6 類好習(xí)慣和 23 個(gè)教訓(xùn)
          一名運(yùn)維小哥對(duì)運(yùn)維規(guī)則的10個(gè)總結(jié),收藏起來(lái)
          終于明白了 DevOps 與 SRE 的區(qū)別!
          Kubernetes上生產(chǎn)環(huán)境后,99%都會(huì)遇到這2個(gè)故障
          如何用 Kubernetes 實(shí)現(xiàn) CI/CD 發(fā)布流程?| 漫畫
          K8s kubectl 常用命令總結(jié)(建議收藏)
          Kubernetes 的這些核心資源原理,你一定要了解
          我在創(chuàng)業(yè)公司的 “云原生” 之旅
          基于Nginx實(shí)現(xiàn)灰度發(fā)布與AB測(cè)試
          編寫 Dockerfile 最佳實(shí)踐
          12年資深運(yùn)維老司機(jī)的成長(zhǎng)感悟
          搭建一套完整的企業(yè)級(jí)高可用 K8s 集群(kubeadm方式)



          點(diǎn)亮,服務(wù)器三年不宕機(jī)

          瀏覽 86
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  逼逼逼逼五月情 | 天天射一射 | 婷婷射亚洲 | 黄色影视在线观看 | 大鸡吧网站在现看 |