歡迎光臨
每天分享高質量文章

如何使用Docker和GitLab構建CI/CD Pipeline?

現如今持續整合(CI)和持續交付(CD)大家已經不陌生了,它們是為了輔助你的產品/工程專案能夠更快、更容易地執行最新版本。在這篇文章中,我將講述如何使用Docker映象和GitLab的CI/CD工具構建一個Pipeline,在一個VPS/KVM Linux伺服器上進行部署。
前提要求

  • 對Linux、Docker以及CI/CD有基本的瞭解。

  • GitLab帳號(免費計劃即可)。

  • 一臺具備SSH訪問許可權的Linux伺服器(非root使用者即可)。我使用的是帶有LAMP[1]技術棧的Ubuntu 16.04 LTS系統。

  • 裝有SSH和LFTP[2]的輕量級Docker映象。

在開始之前,你需要確保:
  • 你已經登入GitLab

  • 你是某個project/repository的擁有者

  • 你能夠在本地機器透過Git訪問這個repo進行pull和push操作

我用的是GitKraken[3],一個Git GUI工具,能夠較為方面的進行Git操作。

關於GitLab的CI/CD

GitLab提供了一種透過Docker和Shared Runners處理CI/CD Pipeline的簡單方法。每次執行Pipeline時,GitLab都會建立一個獨立的虛擬機器並構建一個Docker映象。Pipeline可以使用YAML配置檔案進行配置,一個Pipeline可以有多個job,但如果job太多,Pipeline的執行時間就較長。我們肯定不希望這樣,因為使用免費計劃,每月最多可以有2000分鐘的構建時間
“GitLab.com上的Shared Runners以自動縮放樣式執行,由DigitalOcean提供支援。自動縮放意味著減少啟動構建的等待時間,併為每個專案建立隔離虛擬機器,從而最大限度地提高安全性。”
——來自GitLab檔案中的描
為GitLab的runner建立SSH金鑰

註意:即使你的伺服器上已有具備SSH訪問方式,還是建議你為CI/CD建立一套新的金鑰,同時為部署流程建立一個新的非root使用者。
我們將在Docker容器中透過SSH連線我們的伺服器,這就意味著我們不能輸入使用者密碼(即非互動式登入),因此我們需要在本地計算機中建立無密碼的SSH金鑰對。通常我會建立一個2048位元組的RSA金鑰,因為這足夠安全。
$ ssh-keygen rsa -b 2048

輸入以上命令,跟隨建立步驟,如果對建立步驟有疑問,使用man ssh-key。記住不要為金鑰對設定密碼。建立完成後,我們需要把私鑰匯入我們的伺服器:
$ ssh-copy-id -i /path/to/key user@host

現在你可以嘗試透過以下命令連線:
$ ssh -i /path/to/key user@host

連線過程應該不會讓你輸入密碼。這個私鑰我們後面會使用到。
選擇Dockerfile

我使用Docker Hub來存放我的定製化Dockerfile,這個Dockerfile將基於Alpine構建一個安裝有OpenSSH和LFTP的輕量級映象(大約8Mb)。在GitLab的CI/CD中我們需要使用這個映象來執行Pipeline的job和指令碼,映象越輕量意味著下載映象的時間就越少。你可以用你自己的映象或者用我的Dockerfile[4]。
Pipleline的配置

在正式構建前,你需要在你repo的根目錄建立一個”.gitlab-ci.yml”檔案。接下來我將解釋我使用的配置檔案,如果有興趣,你可以先到GitLab官網[5]閱讀配置檔案格式以及所有可以使用的配置項。
我的配置檔案如下:
image: jimmyadaro/gitlab-ci-cd:latest
Deploy:
 stage: deploy
 only:
 — ‘master’
 when: manual
 allow_failure: false
 before_script:
 #Create .ssh directory
 — mkdir -p ~/.ssh
 #Save the SSH private key
 — echo “$SSH_PRIVATE_KEY” > ~/
.ssh/id_rsa
 — chmod 700 ~/.ssh
 — chmod 600 ~/
.ssh/id_rsa
 — eval $(ssh-agent -s)
 — ssh-add ~/.ssh/id_rsa
 script:
 #Backup everything in /var/www/html/
 — ssh -o StrictHostKeyChecking=no -i ~/.ssh/id_rsa $USERNAME@$HOST “zip -q -r /var/backups/www/01-Deploy-$(date +%F_%H-%M-%S).zip /var/www/html/”
 #Deploy new files to /var/www/html
 — lftp -d -u $USERNAME, -e ‘set sftp:auto-confirm true; set sftp:connect-program “ssh -a -x -i ~/.ssh/id_rsa”; mirror -Rnev ./ /var/www/html — ignore-time — exclude-glob .git* — exclude .git/exit’ sftp://$HOST
 — rm -f ~/.ssh/id_rsa
 — ‘echo Deploy done: $(date “+%F %H:%M:%S”)’

讓我們逐行看看配置檔案的每一步都在做什麼。
image: jimmyadaro/gitlab-ci-cd:latest

這行將告訴runner從Docker Hub上拉取並執行最新版本的容器。你可以在這裡設定你想要使用的映象,但別忘了給映象安裝OpenSSH和LFTP
Deploy:

這行設定了pipeline的job名字,建立一個job必須設定這行內容。
stage: deploy

這行設定了job的stage名字,如果你需要執行多個stage,例如“backup”、“build”、“deploy”等,stage名字將幫助你識別當前Pipeline處於什麼狀態。由於我不需要其他stage,所以我只用了一個job,並且這個job只有一個stage。對於job和stage的名字可以任意設定,例如你的job可以叫“ASDF”,stage可以叫“GHJK”,不過如果你有多個stage,你肯定需要鑒別不同的stage,因此我建議還是規範化這些名字。
only:
 — ‘master’

這行表示Pipeline只有當你repo的master分支收到一個更新(例如git merge)時才會被觸發。因此,我建議開發使用其他分支(例如development、wip等),然後使用master分支作為“產品分支”。
when: manual

這行表示你需要進入你的project的CI/CD配置中手動觸發整個部署流程。當然,這一步是可以跳過的,只是我更喜歡手動觸發Pipeline。如果去掉這行,你所選分支(本例中為master)的任何改動都會觸發一次Pipeline。
allow_failure: false

這行表示如果你的Pipeline中有其他stage,當一個job中發生錯誤時,不允許繼續執行剩餘任務。這是一個可選配置。
before_script:
 #Create .ssh directory
 — mkdir -p ~/.ssh
 #Save the SSH private key
 — echo “$SSH_PRIVATE_KEY” > ~/.ssh/id_rsa
 — chmod 700 ~/.ssh
 — chmod 600 ~/.ssh/id_rsa
 — eval $(ssh-agent -s)
 — ssh-add ~/.ssh/id_rsa

在before_script單元設定的所有命令都會在執行主單元(main script)之前執行。如你所見,每行shell命令需要用短橫線(“-“)指定。上面的命令將把我們剛剛生成的SSH私鑰儲存到容器預設的SSH路徑下,這樣我們就可以免密連線我們的伺服器。
剛剛生成的私鑰將作為Protected變數儲存在我的project的CI/CD配置中,在GitLab的web UI上,點選Settings > CI/CD > Variables將看到這個變數。同樣,我將伺服器地址和部署使用的使用者名稱(非root使用者)也使用Protected變數儲存。
script:
 #Backup everything in /var/www/html/
 — ssh -o StrictHostKeyChecking=no -i ~/.ssh/id_rsa $USERNAME@$HOST “zip -q -r /var/backups/www/01-Deploy-$(date +%F_%H-%M-%S).zip /var/www/html/”
 #Deploy new files to /var/www/html
 — lftp -d -u $USERNAME, -e ‘set sftp:auto-confirm true; set sftp:connect-program “ssh -a -x -i ~/.ssh/id_rsa”; mirror -Rnev ./ /var/www/html — ignore-time — exclude-glob .git* — exclude .git/exit’ sftp://$HOST
 — rm -f ~/.ssh/id_rsa
 — ‘echo Deploy done: $(date “+%F %H:%M:%S”)’

script下的內容就是GitLab的runner執行的主單元。首先,我會連線到我的伺服器將所有內容備份到一個ZIP檔案中,這個ZIP檔案將使用當前時間(格式為yyyy-mm-dd_hh-mm-ss)進行命名:
— ssh -o StrictHostKeyChecking=no -i ~/.ssh/id_rsa $USERNAME@$HOST “zip -q -r /var/backups/www/01-Deploy-$(date +%F_%H-%M-%S).zip /var/www/html/”

註意:你需要在你的伺服器上安裝ZIP CLI。
在將/var/www/html備份後,使用LFTP連線到我的伺服器並且上傳最新的repo檔案。這裡我用的是SFTP,FTP配置有點不一樣:
— lftp -d -u $USERNAME, -e ‘set sftp:auto-confirm trueset sftp:connect-program “ssh -a -x -i ~/.ssh/id_rsa”; mirror -Rnev ./ /var/www/html — ignore-time — exclude-glob .git* — exclude .git/; exit’ sftp://$HOST

使用mirror -Rnev ./ /var/www/html讓LFTP上傳./(我repo的根目錄)下的所有檔案到我伺服器的/var/www/html路徑下。上面部分引數的意思如下:
  • -u設定了我們sftp://$HOST的SSH使用者名稱。

  • -e用於設定執行命令(使用單引號進行配置)。

  • -R用於設定reverse mirror。

  • -n表示只上傳新的檔案。

  • -e用於刪除在我們源中不存在的檔案。

  • -v用於配置verbose日誌。

  • ignore-time將在決定是否下載時忽略時間。

  • exclude-glob .git`將會排除任何目錄中匹配`.git的所有檔案(例如.gitignore以及.gitkeep)。你可以在這裡設定其他檔案匹配方式。

  • exclude .git/這個配置將會保證不上傳我們repo中的git檔案。

  • exit將會停止LFTP和SSH執行。

註意:所有在我們服務上但是不在我們repository中的檔案將被刪除,記住上面所述的’源’指的就是我們GitLab的repository。
最終,指令碼會在shared runner的容器中刪除我們的私鑰(這是一個安全措施),並且輸出帶有當前時間的結束陳述句。
— rm -f ~/.ssh/id_rsa
 — ‘echo Deploy done: $(date “+%F %H:%M:%S”)’

以上部分就是我配置檔案的所有內容。在GitLab中一個成功的Pipeline執行流程如下圖所示:
執行Docker映象
Pipeline的最終狀態
結論

我嘗試了一些其他的方式,例如使用rsync替代LFTP、使用多階段以及快取依賴(我能夠重用SSH金鑰)的Jobs、使用Docker的ENTRYPOINT和CMD等等,但我發現上面描述的方式對我來說是最快和最容易的。
相關連結:
  1. https://en.wikipedia.org/wiki/LAMP_%28software_bundle%29

  2. https://lftp.yar.ru/

  3. https://www.gitkraken.com/

  4. https://hub.docker.com/r/jimmyadaro/gitlab-ci-cd/

  5. https://docs.gitlab.com/ce/ci/yaml/

原文連結:https://medium.com/@jimmyadaro/build-a-ci-cd-pipeline-with-docker-and-gitlab-f351585a5c83

Kubernetes應用實戰培訓

Kubernetes應用實戰培訓將於2018年11月9日在北京開課,3天時間帶你係統學習Kubernetes本次培訓包括:容器特性、映象、網路;Docker特性、架構、元件、概念、Runtime;Docker安全;Docker實踐;Kubernetes架構、核心元件、基本功能;Kubernetes設計理念、架構設計、基本功能、常用物件、設計原則;Kubernetes的實踐、執行時、網路、外掛已經落地經驗;微服務架構、DevOps等,點選下方圖片檢視詳情。

贊(0)

分享創造快樂