溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

怎樣使用 Kubernetes和Jenkins創(chuàng)建一個(gè)CI/CD流水線

發(fā)布時(shí)間:2021-11-10 16:26:51 來源:億速云 閱讀:118 作者:柒染 欄目:云計(jì)算

這期內(nèi)容當(dāng)中小編將會給大家?guī)碛嘘P(guān)怎樣使用 Kubernetes和Jenkins創(chuàng)建一個(gè)CI/CD流水線,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

CI/CD 嘗試解決什么問題?

CI/CD 同 DevOps、Agile、Scrum、Kanban、自動化以及其他術(shù)語一樣,是一個(gè)一起被經(jīng)常提及的專用術(shù)語。有時(shí)候,它被當(dāng)做工作流的一部分,但是并沒有搞清楚這是什么或者為什么它會被采用。對于年輕的 DevOps 工程師來說,使用 CI/CD 理所當(dāng)然已經(jīng)成為了常態(tài),可能他們并沒有看到“傳統(tǒng)”的軟件發(fā)布流程而因此不欣賞 CI/CD。

CI/CD 表示持續(xù)集成/持續(xù)交付和/或部署。如果一個(gè)團(tuán)隊(duì)不接入 CI/CD 流程就必須要在產(chǎn)生一個(gè)新的軟件產(chǎn)品時(shí)經(jīng)歷如下的階段:

  1. 產(chǎn)品經(jīng)理(代表了客戶利益)提供了產(chǎn)品需要有的功能以及產(chǎn)品需要遵從的行為。文檔必須要越詳實(shí)越好。

  2. 具有業(yè)務(wù)分析能力的開發(fā)人員開始對應(yīng)用進(jìn)行編碼,執(zhí)行單元測試,然后將結(jié)果提交到版本控制系統(tǒng)(例如 git)。

  3. 一旦開發(fā)階段完成,項(xiàng)目移交到 QA。對產(chǎn)品進(jìn)行多輪測試,比如用戶驗(yàn)收測試,集成測試,性能測試。在此期間,直到 QA 階段完成之前都不會有任何代碼上的改動。如果有任何 bug 被發(fā)現(xiàn),需要回退給開發(fā)人員做修改,然后再將產(chǎn)品移交給 QA。

  4. 一旦 QA 完成,操作團(tuán)隊(duì)會將代碼部署到生產(chǎn)環(huán)境中。

上述工作流存在一些弊端:

  • 首先,從產(chǎn)品經(jīng)理提出需求到產(chǎn)品具備開發(fā)條件中間會消耗太多時(shí)間。

  • 對開發(fā)人員來說,從寫了一個(gè)月甚至更長時(shí)間的代碼中去定位問題真的很困難。請記住,bug 只能是在開發(fā)階段完成 QA 階段開始后被發(fā)現(xiàn)。

  • 當(dāng)有一個(gè)緊急的代碼修復(fù)比如像一個(gè)嚴(yán)重的 bug 需要熱修復(fù)時(shí),QA 階段可能會因?yàn)樾枰M快部署而被縮短。

  • 不同的團(tuán)隊(duì)之間很少會有協(xié)作,當(dāng) bug 出現(xiàn)的時(shí)候,人們就開始互相甩鍋互相指責(zé)。每個(gè)人從一開始只是關(guān)心項(xiàng)目中自己的那部分工作而忽視了共同的目標(biāo)。

CI/CD 通過引入自動化來解決上述的問題。代碼中的每次改動一旦推送至版本控制系統(tǒng),進(jìn)行測試,然后在部署到用戶使用的生產(chǎn)環(huán)境之前部署至預(yù)生產(chǎn)/UAT 環(huán)境進(jìn)行進(jìn)一步的測試。自動化確保了整體流程的快速,可信賴,可重復(fù),以及不容易出錯(cuò)。

所以,什么是 CI/CD 呢?

關(guān)于這個(gè)主題已經(jīng)有著作撰寫完畢。如何,為什么,以及什么時(shí)候在你的架構(gòu)中使用。然而,我們總是傾向于輕理論重實(shí)踐。話雖如此,下文簡單介紹了一下一旦修改的代碼被提交后會執(zhí)行哪些自動化步驟:

  1. 持續(xù)集成(CI):第一步不包括 QA。換句話說,它不關(guān)注代碼是否提供了用戶需要的功能。相反,它確保了代碼的質(zhì)量。通過單元測試,集成測試,開發(fā)人員能很快的就會發(fā)現(xiàn)代碼質(zhì)量中的缺陷。我們可以增加代碼覆蓋率的檢查以及靜態(tài)分析讓代碼質(zhì)量保證做的更加完善。

  2. 用戶驗(yàn)收測試:這是 CD 流程的第一部分。這個(gè)階段,會對代碼執(zhí)行自動化測試從而確保代碼符合用戶的期望。比如說,一個(gè) web 應(yīng)用沒有任何報(bào)錯(cuò)產(chǎn)生能正常運(yùn)行,但是客戶想讓訪問者在導(dǎo)航到主頁之前先進(jìn)入到登錄頁面。但是當(dāng)前的代碼直接讓訪問者導(dǎo)航到了主頁面,這與客戶的需求不相符。這種問題會在 UAT 測試時(shí)被指出。而在非 CD 環(huán)境,就成了人工的 QA 測試人員的工作。

  3. Deployment:這是 CD 流程的第二部分。它包括在托管應(yīng)用的服務(wù)器/ pods /容器上面執(zhí)行更改來應(yīng)用更新的版本。這會在自動化的方法下完成,最好通過一個(gè)配置管理工具來做這些事情,比如 Ansible、Chef 或者 Puppet。

什么是流水線?

流水線是一個(gè)有著簡單的概念的花哨術(shù)語;當(dāng)你有一些需要按照順序依次執(zhí)行的腳本用來實(shí)現(xiàn)一個(gè)共同的目標(biāo)時(shí),這些組合起來可以稱為“流水線”。比如說,在 Jenkins 里,一個(gè)流水線包含了一個(gè)或多個(gè)一次構(gòu)建需要成功必須全部執(zhí)行的_stages_。使用 stages 能夠可視化整個(gè)流程,能夠看到每個(gè)階段使用了多長時(shí)間,然后能夠準(zhǔn)確得出構(gòu)建過程的哪個(gè)地方是失敗的。

實(shí)驗(yàn):為一個(gè) Golang 應(yīng)用創(chuàng)建一個(gè)流水線

在這個(gè)實(shí)驗(yàn)中,我們構(gòu)建一個(gè)持續(xù)交付(CD)的流水線。我們使用一個(gè)用 Go 語言編寫的簡單的小程序。為了簡單起見,我們只對代碼運(yùn)行一種類型的測試。實(shí)驗(yàn)的前期工作如下:

  • 一個(gè)運(yùn)行的 Jenkins 實(shí)例。它可以是一個(gè)云實(shí)例,一個(gè)虛擬機(jī),一個(gè)裸機(jī)或者是一個(gè) docker 容器。必須是從互聯(lián)網(wǎng)上可獲得的,這樣倉庫才可以通過 web-hooks 連上 Jenkins。

  • 鏡像系統(tǒng):你可以使用 Docker Registry,一款基于云的產(chǎn)品它提供了ECR,GCR, 甚至一個(gè)定制的系統(tǒng)。

  • 一個(gè) GitHub 賬號。盡管我們在這個(gè)例子中使用 GitHub,程序使用其他倉庫同樣可以,例如少量修改后的 Bitbucket。

流水線可以用下圖做一個(gè)說明:

怎樣使用 Kubernetes和Jenkins創(chuàng)建一個(gè)CI/CD流水線

第一步:應(yīng)用程序文件

我們的實(shí)驗(yàn)程序會對任意的 GET 請求回復(fù) ‘Hello World’。創(chuàng)建一個(gè)名稱為 main.go 的文件然后添加如下的代碼:

package main

import (
   "log"
   "net/http"
)

type Server struct{}

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
   w.WriteHeader(http.StatusOK)
   w.Header().Set("Content-Type", "application/json")
   w.Write([]byte(`{"message": "hello world"}`))
}

func main() {
   s := &Server{}
   http.Handle("/", s)
   log.Fatal(http.ListenAndServe(":8080", nil))
}

當(dāng)我們構(gòu)建一個(gè) CD 流水線時(shí),我們應(yīng)該進(jìn)行一些測試。我們代碼是如此的簡單以至于它僅僅只需要一個(gè)測試用例;能夠確保我們在輸入根 URL 時(shí)得到正確的字符串。在同目錄下創(chuàng)建名為 main_test.go 的文件然后添加如下代碼:

package main

import (
   "log"
   "net/http"
)

type Server struct{}

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
   w.WriteHeader(http.StatusOK)
   w.Header().Set("Content-Type", "application/json")
   w.Write([]byte(`{"message": "hello world"}`))
}

func main() {
   s := &Server{}
   http.Handle("/", s)
   log.Fatal(http.ListenAndServe(":8080", nil))
}

我們同樣有一些其他用來幫助我們部署應(yīng)用程序的文件,稱為:

Dockerfile

這就是我們對我們的應(yīng)用進(jìn)行打包的地方:

FROM golang:alpine AS build-env
RUN mkdir /go/src/app && apk update && apk add git
ADD main.go /go/src/app/
WORKDIR /go/src/app
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags '-extldflags "-static"' -o app .

FROM scratch
WORKDIR /app
COPY --from=build-env /go/src/app/app .
ENTRYPOINT [ "./app" ]

Dcokerfile 是一個(gè)多階段的文件能讓鏡像保持的越小越好。它從基于 golang:alpine 構(gòu)建鏡像開始。生成的二進(jìn)制文件在第二個(gè)鏡像中使用,它僅僅是一個(gè)臨時(shí)的鏡像,這個(gè)鏡像沒有依賴或者庫文件,只有用來啟動應(yīng)用的二進(jìn)制文件。

Service

由于我們使用 Kubernetes 作為托管該應(yīng)用程序的平臺,我們需要至少一個(gè) service 和一個(gè) deployment。我們的 service.yml 長這樣:

apiVersion: v1
kind: Service
metadata:
  name: hello-svc
spec:
  selector:
    role: app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
      nodePort: 32000
  type: NodePort

這個(gè)文件的定義沒有什么特別的地方,只有一個(gè) NodePort 作為其類型的 Service。它會監(jiān)聽任何 IP 地址的集群節(jié)點(diǎn)上的 32000 端口。傳入的連接將中繼到 8080 端口上。而作為內(nèi)部通信,這個(gè)服務(wù)在 80 端口上進(jìn)行監(jiān)聽。

deployment

應(yīng)用程序本身,一旦容器化了,就可以通過一個(gè) Deployment 資源部署到 Kubernetes。deployment.yml 如下所示:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-deployment
  labels:
    role: app
spec:
  replicas: 2
  selector:
    matchLabels:
      role: app
  template:
    metadata:
      labels:
        role: app
    spec:
      containers:
      - name: app
        image: ""
        resources:
          requests:
            cpu: 10m

這個(gè)部署文件里的定義最有意思的地方就是 image 部分。不同于硬編碼鏡像名稱和標(biāo)簽的方式,我們使用了一個(gè)變量。后面的內(nèi)容,我們會看到怎樣將該變量用作 Ansible 的模板以及通過命令替換鏡像名稱(以及部署用的其他參數(shù))。

Playbook

這個(gè)實(shí)驗(yàn)中,我們使用 Ansible 作為部署工具。還有許多其他的方式用來部署 Kubernetes 資源包括Helm Charts,但是我認(rèn)為 Ansible 是一個(gè)相對簡單一些的選擇。Ansible 使用 playbooks 來組織它的操作。我們的 playbook.yml 文件如下所示:

- hosts: localhost
  tasks:
  - name: Deploy the service
    k8s:
      state: present
      definition: ""
      validate_certs: no
      namespace: default
  - name: Deploy the application
    k8s:
      state: present
      validate_certs: no
      namespace: default
      definition: ""

Ansible 已經(jīng)包括了k8s 模塊用來處理和 Kubernetes API 服務(wù)器的通信。所以我們不需要安裝kubectl但是我們需要一個(gè)有效的 kubeconfig 文件來連接到集群(后面會詳細(xì)介紹)。讓我們快速討論一下這個(gè) playbook 重要的部分:

  • 這個(gè) playbook 用來部署服務(wù)以及部署資源到集群上。

  • 當(dāng)我們需要在動態(tài)執(zhí)行的過程中向定義文件中注入數(shù)據(jù)時(shí),我們需要使用定義文件作為模板這樣變量可以應(yīng)用到外部環(huán)境。

  • 為此,Ansible 具有查找功能,你可以在其中傳遞一個(gè)有效的 YAML 文件作為模板。Ansible 支持許多將變量注入模板的方法。在這個(gè)實(shí)驗(yàn)中,我們使用命令行的方法。

學(xué)習(xí)怎樣持續(xù)優(yōu)化您的 k8s 集群

第二部:安裝 Jenkins、Ansible 和 Docker

讓我們開始安裝 Ansible 然后使用它自動部署一個(gè) Jenkins 服務(wù)器以及 Docker 運(yùn)行環(huán)境。我們同樣需要安裝 openshift Python 模塊用來將 Ansible 連接到 Kubernetes。 Ansible 的安裝非常簡單;只需要安裝 Python 然后使用 pip 安裝 Ansible:

  1. 登錄 Jenkins 實(shí)例。

  2. 安裝 Python3,Ansible,以及 openshift 模塊:

sudo apt update && sudo apt install -y python3 && sudo apt install -y python3-pip && sudo pip3 install ansible && sudo pip3 install openshift
  1. 默認(rèn)情況下,pip 會將二進(jìn)制安裝到用戶主文件夾的隱藏目錄中。我們需要添加這個(gè)路徑到 $PATH 環(huán)境變量中因此我們可以很輕松調(diào)用如下命令:

echo "export PATH=$PATH:~/.local/bin" >> ~/.bashrc && . ~/.bashrc
  1. 安裝必要的 Ansible 角色用來部署一個(gè) Jenkins 實(shí)例。

ansible-galaxy install geerlingguy.jenkins
  1. 安裝 Dcoker 角色:

ansible-galaxy install geerlingguy.docker
  1. 創(chuàng)建一個(gè) playbook.yml 添加下面的代碼:

- hosts: localhost
  become: yes
  vars:
    jenkins_hostname: 35.238.224.64
    docker_users:
    - jenkins
  roles:
    - role: geerlingguy.jenkins
    - role: geerlingguy.docker
  1. 通過下面的命令運(yùn)行這個(gè) playbook:ansible-playbook playbook.yaml。注意到我們使用實(shí)例的公共 IP 地址作為 Jenkins 的主機(jī)地址。如果你使用 DNS,你或許需要將該實(shí)例更換成 DNS 域名。另外,注意你必須在 playbook 運(yùn)行之前允許 8080 端口通過防火墻(如果有的話)。

  2. 過幾分鐘,Jenkins 應(yīng)該會被安裝完成,你可以通過這臺機(jī)器的 IP 地址(或者是 DNS 域名)還有端口8080訪問到 Jenkins:

怎樣使用 Kubernetes和Jenkins創(chuàng)建一個(gè)CI/CD流水線

  1. 點(diǎn)擊登錄鏈接使用 “admin” 作為用戶名,“admin” 作為登錄密碼。這些都是通過 Ansible 角色創(chuàng)建的默認(rèn)憑據(jù)。當(dāng) Jenkins 在生產(chǎn)環(huán)境中使用時(shí),你可以(應(yīng)該)修改這些默認(rèn)值。這個(gè)可以通過設(shè)置角色變量來進(jìn)行設(shè)置。你可以參考角色官方頁面。

  2. 你需要做的最后一件事情就是安裝下面這些我們這個(gè)實(shí)驗(yàn)中用到的插件:

  • git

  • pipeline

  • CloudBees Docker Build and Publish

  • GitHub

第三步:配置 Jenkins 用戶來連接到集群上

之前我們提到了,這個(gè)實(shí)驗(yàn)假設(shè)你已經(jīng)有一個(gè)啟動的 Kubernetes 集群。為了讓 Jenkins 連接到這個(gè)集群上,我們需要添加必要的 kubeconfig 文件。在這個(gè)特定的實(shí)驗(yàn)中,我們使用主機(jī)在 Google Cloud 的 Kubernetes 集群所以我們可以使用 gcloud command。因環(huán)境而異。但是不管什么情況,我們都必須拷貝 kubeconfig 文件到 Jenkins 的用戶目錄下,如下所示:

$ sudo cp ~/.kube/config ~jenkins/.kube/
$ sudo chown -R jenkins: ~jenkins/.kube/

需要記住的是你使用的賬號必須要有必要的權(quán)限用來創(chuàng)建管理 Deployment 和 Service。

第四步:創(chuàng)建 Jenkins 流水線任務(wù)

怎樣使用 Kubernetes和Jenkins創(chuàng)建一個(gè)CI/CD流水線

創(chuàng)建一個(gè)新的 Jenkins 任務(wù)選擇流水線類型的任務(wù)。任務(wù)的設(shè)置如下圖所示:

怎樣使用 Kubernetes和Jenkins創(chuàng)建一個(gè)CI/CD流水線

怎樣使用 Kubernetes和Jenkins創(chuàng)建一個(gè)CI/CD流水線

我們修改的配置有:

  • 我們使用 Poll SCM 作為構(gòu)建觸發(fā)器;設(shè)置這個(gè)選項(xiàng)來讓 Jenkins 定期檢查 Git 倉庫(按 * * * * 指示的每分鐘進(jìn)行檢查)。如果倉庫從上次輪詢后做了修改,任務(wù)就會被觸發(fā)。

  • 從流水線本身來說,我們指定了倉庫的 URL 以及憑據(jù)。分支是 master 分支。

  • 這個(gè)實(shí)驗(yàn)中,我們在一個(gè) Jenkinsfile 中添加了所有的任務(wù)的代碼,Jenkinsfile 跟代碼一樣存放在同一個(gè)倉庫當(dāng)中。Jenkinsfile 我們會在后面的文章中進(jìn)行討論。

第五步:配置 GitHub 和 Docker Hub 的 Jenkins 憑據(jù)

轉(zhuǎn)到/credentials/store/system/domain/_/newCredentials鏈接下然后添加目標(biāo)憑據(jù)。請確認(rèn)你每個(gè)憑據(jù)均提供一個(gè)有意義的 ID 和描述信息因?yàn)槟銜诤竺媸褂玫剿鼈儭?/p>

怎樣使用 Kubernetes和Jenkins創(chuàng)建一個(gè)CI/CD流水線

怎樣使用 Kubernetes和Jenkins創(chuàng)建一個(gè)CI/CD流水線

第六步:創(chuàng)建 Jenkinsfile

Jenkinsfile 是用來指導(dǎo) Jenkins 如何構(gòu)建,測試,容器化,發(fā)布以及交付我們的應(yīng)用程序的文件。我們的 Jenkinsfile 長這樣:

pipeline {
   agent any
   environment {
       registry = "magalixcorp/k8scicd"
       GOCACHE = "/tmp"
   }
   stages {
       stage('Build') {
           agent {
               docker {
                   image 'golang'
               }
           }
           steps {
               // Create our project directory.
               sh 'cd ${GOPATH}/src'
               sh 'mkdir -p ${GOPATH}/src/hello-world'
               // Copy all files in our Jenkins workspace to our project directory.               
               sh 'cp -r ${WORKSPACE}/* ${GOPATH}/src/hello-world'
               // Build the app.
               sh 'go build'              
           }    
       }
       stage('Test') {
           agent {
               docker {
                   image 'golang'
               }
           }
           steps {                
               // Create our project directory.
               sh 'cd ${GOPATH}/src'
               sh 'mkdir -p ${GOPATH}/src/hello-world'
               // Copy all files in our Jenkins workspace to our project directory.               
               sh 'cp -r ${WORKSPACE}/* ${GOPATH}/src/hello-world'
               // Remove cached test results.
               sh 'go clean -cache'
               // Run Unit Tests.
               sh 'go test ./... -v -short'           
           }
       }
       stage('Publish') {
           environment {
               registryCredential = 'dockerhub'
           }
           steps{
               script {
                   def appimage = docker.build registry + ":$BUILD_NUMBER"
                   docker.withRegistry( '', registryCredential ) {
                       appimage.push()
                       appimage.push('latest')
                   }
               }
           }
       }
       stage ('Deploy') {
           steps {
               script{
                   def image_id = registry + ":$BUILD_NUMBER"
                   sh "ansible-playbook  playbook.yml --extra-vars \"image_id=${image_id}\""
               }
           }
       }
   }
}

這個(gè)文件比它本身看起來要簡單的多?;旧希@個(gè)流水線包括了 4 個(gè)階段:

  1. 在哪里構(gòu)建我們的 Go 二進(jìn)制文件從而確保構(gòu)建過程中無錯(cuò)誤出現(xiàn)。

  2. 在哪里進(jìn)行一個(gè)簡單的 UAT 測試能確保應(yīng)用程序如預(yù)期運(yùn)行。

  3. 發(fā)布,在哪里構(gòu)建 Docker 鏡像然后推送到倉庫。在這之后,任何環(huán)境都可以使用它。

  4. 部署,這是流水線的最后一步, Ansible 會與 Kubernetes 通信然后應(yīng)用這些定義文件。

現(xiàn)在,讓我們討論下這個(gè) Jenkinsfile 中重要的部分:

  • 一開始的兩個(gè)階段大致差不多。它們都是使用 golang Docker 鏡像來構(gòu)建/測試應(yīng)用程序。讓階段在所有構(gòu)建和測試均已準(zhǔn)備就緒的容器中運(yùn)行始終是一個(gè)很好的實(shí)踐。另外的選擇就是安裝這些工具到 master 服務(wù)器上或者是其中一個(gè)節(jié)點(diǎn)上。當(dāng)你需要測試不同版本的工具時(shí)問題容易顯現(xiàn)出來。例如,或許你想使用 Go 1.9 構(gòu)建測試你的代碼,但是我們的應(yīng)用尚未準(zhǔn)備好支持最新版本的 Golang。所有的東西都放在鏡像中的話修改版本號或者甚至是鏡像類型會和修改字符串一樣簡單。

  • 在發(fā)布階段(從42行開始)開頭定義了一個(gè)環(huán)境變量,這個(gè)環(huán)境變量會在后面的步驟中使用到。這個(gè)變量指向的是我們先前步驟在 Jenkins 中添加的 Docker Hub 憑據(jù)。

  • 48 行:我們使用 docker 插件來構(gòu)建鏡像。它默認(rèn)使用我們 registry 中的 Dockerfile 然后添加構(gòu)建號作為鏡像的 tag。后面,當(dāng)你需要決定哪次 Jenkins 構(gòu)建作為當(dāng)前運(yùn)行容器的來源時(shí)這會非常的重要。

  • 49-51行:鏡像構(gòu)建成功后,我們使用構(gòu)建號將其推送到 Docker Hub。另外,我們在鏡像上添加了 “l(fā)atest” 的標(biāo)簽(一個(gè)第二標(biāo)簽)因此我們允許用戶不需要指定構(gòu)建號即可拉取鏡像

  • 56-60行:在部署階段,我們將部署和服務(wù)定義文件應(yīng)用到集群上。我們使用之前討論過的 Ansible 的 playbook。記住,我們傳遞 image_id 作為命令行的參數(shù)。該值將自動替換部署文件中的鏡像名稱。

了解更多關(guān)于配置模式的知識

測試我們的 CD 流水線

這部分是真正將我們的工作進(jìn)行測試的內(nèi)容。我們將會提交代碼到 GitHub 上確保我們的代碼直到到達(dá)集群之前都是經(jīng)過流水線操作的。

  1. 添加我們的文件:git add *

  2. 提交我們的改動:git commit -m “Initial commit”

  3. 推送到GitHub:git push

  4. 在 Jenkins 中,我們可以等待任務(wù)自動被觸發(fā),或者我們只需要點(diǎn)一下“立即構(gòu)建”。

  5. 如果任務(wù)成功了,我們可以使用下面的命令驗(yàn)證我們部署好的的應(yīng)用程序:

獲取節(jié)點(diǎn)的 IP 地址:

kubectl get nodes -o wide
NAME                                          STATUS   ROLES    AGE   VERSION          INTERNAL-IP   EXTERNAL-IP     OS-IMAGE                             KERNEL-VERSION   CONTAINER-RUNTIME
gke-security-lab-default-pool-46f98c95-qsdj   Ready       7d    v1.13.11-gke.9   10.128.0.59   35.193.211.74   Container-Optimized OS from Google   4.14.145+        docker://18.9.7

現(xiàn)在讓我們向應(yīng)用程序發(fā)起一個(gè) HTTP 請求:

$ curl 35.193.211.74:32000
{"message": "hello world"}

OK,我們可以看到應(yīng)用程序工作正常。讓我們在代碼中故意制造一個(gè)錯(cuò)誤以確保流水線不會將錯(cuò)誤的代碼應(yīng)用到目標(biāo)環(huán)境中:

將應(yīng)顯示的信息修改為“Hello World!”,注意到我們將每個(gè)單詞的首字母大寫并在末尾添加了一個(gè)感嘆號。然而客戶或許不想讓信息這樣顯示,流水線應(yīng)該在 Test 階段停止。

首先,讓我們做一些改動。main.go 文件現(xiàn)在看起來是這樣的:

package main

import (
   "log"
   "net/http"
)

type Server struct{}

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
   w.WriteHeader(http.StatusOK)
   w.Header().Set("Content-Type", "application/json")
   w.Write([]byte(`{"message": "Hello World!"}`))
}

func main() {
   s := &Server{}
   http.Handle("/", s)
   log.Fatal(http.ListenAndServe(":8080", nil))
}

下一步,讓我們提交和推送我們的代碼:

$ git add main.go
$ git commit -m "Changes the greeting message"                                                                                                       
[master 24a310e] Changes the greeting message
 1 file changed, 1 insertion(+), 1 deletion(-)
$ git push
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 319 bytes | 319.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
To https://github.com/MagalixCorp/k8scicd.git
   7954e03..24a310e  master -> master

回到 Jenkins,我們可以看到最后一次構(gòu)建失敗了:

怎樣使用 Kubernetes和Jenkins創(chuàng)建一個(gè)CI/CD流水線

點(diǎn)擊失敗的任務(wù),我們可以看到這個(gè)任務(wù)失敗的原因:

怎樣使用 Kubernetes和Jenkins創(chuàng)建一個(gè)CI/CD流水線

這樣我們錯(cuò)誤的代碼永遠(yuǎn)不會進(jìn)入到目標(biāo)環(huán)境上。

內(nèi)容提要

  • CI/CD 是一個(gè)遵循敏捷方法論的任何現(xiàn)代環(huán)境的一部分。

  • 通過流水線,你可以確保從版本控制系統(tǒng)到目標(biāo)環(huán)境(測試/預(yù)生產(chǎn)/生產(chǎn)/等等)的平穩(wěn)過渡,同時(shí)應(yīng)用所有必要的測試以及質(zhì)量控制實(shí)踐。

  • 這篇文章中,我們有一個(gè)實(shí)踐性的實(shí)驗(yàn)來構(gòu)建一個(gè)持續(xù)交付的流水線來部署一個(gè) Golang 應(yīng)用程序。

  • 通過 Jenkins,我們可以從倉庫拉取代碼,構(gòu)建以及使用一個(gè)相關(guān)聯(lián)的 Docker 鏡像進(jìn)行測試。

  • 下一步,我們進(jìn)行容器化進(jìn)而將已通過我們的測試的應(yīng)用程序推送到 Docker Hub。

  • 最后,我們使用 Ansible 將應(yīng)用程序部署到運(yùn)行在 Kubernetes 上的目標(biāo)環(huán)境當(dāng)中。

  • 使用 Jenkins 流水線和 Ansible 可以非常輕松靈活地修改工作流。例如,我們可以在 Test 階段增加更多的測試,我們可以修改用來構(gòu)建和測試代碼的 Go 的版本號,另外我們還可以使用更多的變量在其他諸如部署和服務(wù)定義的地方進(jìn)行修改。

  • 最好的部分是我們使用 Kubernetes 部署,這能夠確保當(dāng)我們在零停機(jī)時(shí)間的情況下改變?nèi)萜麋R像。因?yàn)樵谀J(rèn)情況下部署使用滾動更新的方式來一次性終止和重建容器。只有在新的容器啟動和健康后舊的容器才會終止。

上述就是小編為大家分享的怎樣使用 Kubernetes和Jenkins創(chuàng)建一個(gè)CI/CD流水線了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI