怎樣用Jenkins、Docker和CI/CD構建無伺服器應用程式?

編程技匠 發佈 2020-02-07T19:34:52+00:00

本文展示一個詳細教程,實現了在無伺服器應用程式中使用 Jenkins 和 Docker,在 Docker 容器運行 Jenkins pipelines,並用 pipelines 將無伺服器應用程式部署到 AWS。我正在用 AWS lambda 開發一個無伺服器架構的自由職業項目。

本文展示一個詳細教程,實現了在無伺服器應用程式中使用 Jenkins 和 Docker,在 Docker 容器運行 Jenkins pipelines,並用 pipelines 將無伺服器應用程式部署到 AWS。

我正在用 AWS lambda 開發一個無伺服器架構的自由職業項目。

用Jenkins和Docker 實現CI/CD,並在 Docker 容器上運行 Jenkins pipelines。我會向你展示如何一步步設置環境。

由於是蘋果電腦,我首先在電腦上安裝 Docker 軟體。還需 Jenkins 軟體。我選擇在 Docker 容器中運行 Jenkins,因為這樣的運行環境更簡單幹凈。於是,我為 Jenkins 找到一個 Docker 鏡像版本(image)。

簡而言之,Docker 把容器當作獨立的計算機來操作。

Docker 會利用鏡像文件創建容器。例如,在使用的這個 Docker 鏡像中,包含了 Linux 作業系統和 Jenkins 軟體。當 Docker 用這個鏡像創建一個容器時,就相當於我們有一台計算機已經預先安裝了 Linux 和 Jenkins。

設置容器

接下來,讓我們看看如何設置這個容器。一開始,我們從 Docker 鏡像的線上資源庫 Docker hub 中提取鏡像文件。

docker pull jenkins/jenkins:lts
lts: Pulling from jenkins/jenkins
844c33c7e6ea: Pull complete 
ada5d61ae65d: Pull complete 
f8427fdf4292: Pull complete 
f025bafc4ab8: Pull complete 
67b8714e1225: Pull complete 
64b12da521a3: Pull complete 
2e38df533772: Pull complete 
b1842c00e465: Pull complete 
b08450b01d3d: Pull complete 
2c6efeb9f289: Pull complete 
0805b9b9cdc4: Pull complete 
f129619fc383: Pull complete 
cd27f3a82cdf: Pull complete 
f31251f493ed: Pull complete 
2c902f1f4dfa: Pull complete 
2fe1d2cb7aab: Pull complete 
908723de775f: Pull complete 
54aa3899e429: Pull complete 
f48cf8764dc1: Pull complete 
Digest: sha256:d5069c543e80454279caacd13457d012fb32c5229b5037a163d8bf61ffa6b80b
Status: Downloaded newer image for jenkins/jenkins:lts

Docker 軟體下載鏡像文件並對之解壓。現在,我們可以在自己的目錄下看到該鏡像文件。

然後,我們可以用這個鏡像構建一個容器並運行。使用以下命令:

docker run -p 8080:8080 -p 50000:50000 jenkins/jenkins:lts

一旦這個容器正常啟動,我們就能使用 Jenkins 軟體,直到該容器關閉。但在容器關閉後會有一個問題:在下一次運行中,我們找不到之前已創建的任何 pipeline 或配置。

這是因為,Docker 是在鏡像文件上運行容器,而鏡像文件本身是不可更改的。這就意味著,當我們在 Jenkins 中定義一個 pipeline 時,Jenkins 會將它保存到容器文件系統中而不是鏡像文件中。當關閉容器時,這些信息就丟失了。

因此,我們必須使用「Volumes」來解決這個問題。

Volumes 用於將虛擬容器的文件系統固化到我們的實際物理計算機文件系統中。為此,我們必須定義新的 Volume 以保留容器中的 Jenkins_home 目錄。這並不難,我們需要更改 run 命令如下:

docker run -p 8080:8080 -p 50000:50000 -v jenkins_home:/var/jenkins_home jenkins/jenkins:lts

這裡 -v 代表「Volume」。如果沒有 Volume,它將自動創建一個 Volume。你可以查看 Docker 相關文檔以了解更多信息。

https://docs.docker.com/engine/reference/commandline/volume_create/

簡而言之,我們用這種方法定義了名為 jenkins_home 的新卷,並掛載容器文件系統中的路徑至:/var/jenkins_home。之後,即使關閉容器,我們的更改也不會丟失。因為 /var/jenkins_home 文件夾下的所有文件都保存在 Volume 中。


我們在 Jenkins 的頁面中輸入十六進位的密碼。之後,我們會完成以下步驟:

  • 安裝建議的插件
  • 創建第一個管理員用戶
  • Jenkins 實例配置
  • 開始使用 Jenkins

到這裡,我們完成本教程的第一部分。

二、實現 pipeline

我們已經得到一個 Jenkins 的實例(instance)。

然後,開始實現 pipeline。該 pipeline 將執行以下步驟:

  • 下面的所有步驟都將在另一個 Docker 容器上運行
  • 從 Git(bitbucket)中提取我的項目代碼,這是用 nodejs 編寫的一個 lambda 項目
  • 使用無伺服器架構將該 lambda 項目部署到 AWS 雲上

我們需要這個新容器的鏡像文件。這個鏡像其實是一台簡單的 linux 計算機。我們從 Docker hub 提取這個新容器的鏡像文件。

docker pull alpine

此時,我們在本地機器上已經有這個 Docker 鏡像文件了。但是 Jenkin 運行在另一個容器中。所以 Jenkins 需要連接這個新的 Docker 鏡像。

我們必須在容器和 Docker 之間建立一座橋樑,用「Volume」定義來解決這個問題。

-v /var/run/docker.sock:/var/run/docker.sock  -v $(which docker):$(which docker)

分析一下上面的命令。其中,docke.sock 文件用於偵聽套接字(socket)。在將這些 Volume 添加到命令行之後,docker.sock 會掛載到本地計算機(localmachine)里的 docker.sock 文件中。

如果我們使用 -v,並在之後指定本地計算機的真實路徑,這條命令的意思就是執行「掛載(mount)」。如果我們在 -v 之後使用 $(),則表示運行命令。-v $(which docker):$(which docker) 語句表示,如果「which docker」在容器上運行,Docker 也會在本地計算機上運行「which container」,並將執行結果返回給容器。

必須在以上命令中添加這個參數,因為 Jenkins 通過運行「which docker」來查找具體運行的 Docker。

我們還須改變這個文件的權限,因為預設情況下,Jenkins 用戶無法訪問這個文件。我們需要用根用戶權限(root user)連接到該容器。

執行這個命令,並運行容器。

docker run -p 8080:8080 -p 50000:50000 --name jenkins  -v jenkins_home:/var/jenkins_home -v /var/run/docker.sock:/var/run/docker.sock  -v $(which docker):$(which docker)  jenkins/jenkins:lts

我們使用以下命令打開容器的終端窗口。簡單而言,使用根用戶權限在容器上運行 bash 命令,我們然後用 chmod 更改文件權限。


這裡強調的一個重點是,同一個容器名不能被使用兩次。當關閉容器時,你必須刪除該容器。

docker container rm jenkins

在此之後,下次可以用 --name 命令來使用 Jenkins。

我們現在可以構建 pipeline 了。

點擊容器終端窗口菜單下的「New Item」。為這個 Item 輸入一個名稱。選擇 PipeLine 類型並單擊 OK。

在螢幕上選擇 PipeLine。首先,pipeline 創建一個新容器,並執行容器上的所有命令。

pipeline {
   agent {
        docker { image 'alpine' }
    }

   stages {
      stage('pull project') {
         steps {
             sh 'pwd'
         }
      }
   }
}

現在可以通過 Jenkins 查看日誌,看到的應該類似下圖:

接下來,我們需要從 bitbucket 中提取項目。

首先,我們應該在 Jenkins 上定義一個可以訪問 bitbucket 的用戶。

單擊菜單上的 Credentials/System(證書 / 系統)。然後單擊螢幕上的 Global Credentials(全局證書)。這時菜單會發生改變,我們可以看到 Add Credentials(添加證書)的新菜單。單擊 Add Credentials 並定義你已經在 bitbucket 上預先建立的用戶。

這時要重點關注的是 ID 欄位。當從 bitbucket 中提取出該項目時,我們將使用這個欄位的值。

這時進入 pipeline. 的配置頁面。我們通過編寫 pipeline. 腳本來從 bitbucket 中提取出該項目。

pipeline {
   agent {
        docker { image 'alpine' }
    }
   stages {
      stage('pull project') {
         steps {
             git credentialsId : 'aliyksel', url:'https://aliyksel@bitbucket.org/allscms/scms.git'
         }
      }
   }
}

保存,並運行 pipeline。點擊「Build Now」。

然後,該 pipeline 開始運行,並從 bitbucket 提取項目。

三、運行單元測試

接下來,就需要使用 npm。通常可以使用 npm plug-in 插件。但既然需要為無伺服器創建一個新的鏡像文件,我更傾向於使用新鏡像文件中的 npm,而不是 npm plug-in。因此,我們將創建一個包含 npm 和無伺服器架構的鏡像文件。

首先,提取包含節點的鏡像文件。

docker pull node

之後,我們會把無伺服器架構添加到這個鏡像中。

從節點運行容器。

docker run -it --name node  node bash

現在已經進入容器。我們安裝無伺服器架構。

npm install serverless -g

現在我可以從這個容器創建一個新的鏡像文件。於是在本地機器上運行以下命令。

退出該 Docker 容器。

exit

此時,我們已經有了一個新的無伺服器鏡像,能在 Jenkins 中使用這個鏡像。我們也可以使用 pipeline,該 pipeline 能將無伺服器應用程式部署到 AWS 雲端。

你需要更改鏡像文件的名稱,並向 pipeline 添加以下步驟。

 agent {
        docker { image 'serverlessimg' }
    }
...
stage('pull and deploy project : scms') {
         steps {
               git credentialsId : 'aliyksel', url:'https://aliyksel@bitbucket.org/allscms/scms.git'
               sh 'npm install'
               sh 'serverless config credentials --provider aws --key AKIAIOSFODNN7EXAMPLE --secret wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY'
               sh 'serverless deploy'
             }
         }
      }

我們還需定義用戶信息以實現對 AWS 服務的訪問。如果你還沒建立自己的 AWS 用戶帳戶,可以查看該文檔。鑒於我已有一個 AWS 用戶名了。我將以如下方式設置自己的用戶證書(credentials)。

serverless config credentials --provider aws --key AKIAIOSFODNN7EXAMPLE --secret wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

至此,所有步驟完成,我們為無伺服器架構創建了一個新鏡像,並部署了一個 AWS 應用程式。


作者: Ali Yuksel

來源: 架構頭條公眾號

關鍵字: