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

如何使用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)

分享創造快樂