Ansible 是一款功能強大的自動化工具,適用於建構和管理複雜的佈署流程。本文示範如何使用 Ansible 建置 Docker 映像、推播至 Docker Registry,並在目標伺服器上佈署服務。過程中,我們將使用 Ansible 的 Shell 模組執行 Docker 相關指令,並利用 delegate_to 引數將任務委派給本地主機執行。此外,我們也會使用 docker-compose 執行測試,確保服務的穩定性。文章也涵蓋了使用 Ansible 建立服務目錄、複製必要檔案,以及更新 Nginx 設定等步驟,提供一個完整的佈署流程範例。最後,我們也將探討如何整合 CI/CD 工具,例如 Jenkins,來進一步提升自動化程度。
自動化佈署管線的實作
在現代化的軟體開發流程中,自動化佈署管線(Deployment Pipeline)是至關重要的環節。它能夠確保軟體從開發到上線的整個過程順暢、高效且可靠。本文將探討如何利用 Ansible 自動化佈署管線的實作。
使用 Ansible 實作自動化佈署
Ansible 是一種流行的自動化工具,能夠簡化許多重複性的工作。在佈署管線中,Ansible 可以用來自動執行多個任務,例如建置 Docker 映像、推播映像到 Docker Registry 等。
建置測試容器
首先,我們需要建置測試容器。以下是使用 Ansible 的 Shell 模組實作的範例程式碼:
- name: Tests container is pulled
shell: docker pull {{ registry_url }}{{ service_name }}-tests
delegate_to: 127.0.0.1
ignore_errors: yes
tags: [service, tests]
- name: Tests container is built
shell: docker build -t {{ registry_url }}{{ service_name }}-tests -f Dockerfile.test .
args:
chdir: "{{ repo_dir }}"
delegate_to: 127.0.0.1
tags: [service, tests]
程式碼解析
- 提取測試容器映像:首先嘗試從 Docker Registry 提取測試容器映像。如果映像不存在,則忽略錯誤。
- 建置測試容器映像:使用
docker build命令建置測試容器映像,並指定 Dockerfile.test 檔案。 delegate_to引數:將任務委派給本地主機(127.0.0.1)執行,以避免幹擾目標伺服器。chdir引數:指定執行命令的工作目錄為{{ repo_dir }},確保 Dockerfile.test 檔案能夠被正確找到。
其他佈署前任務
除了建置測試容器之外,還需要執行其他佈署前的任務,例如執行測試、建置服務容器、推播服務容器到 Docker Registry 等。以下是對應的 Ansible 程式碼:
- name: Pre-deployment tests are run
shell: docker-compose -f docker-compose-dev.yml run --rm tests
args:
chdir: "{{ repo_dir }}"
delegate_to: 127.0.0.1
tags: [service, tests]
- name: Container is built
shell: docker build -t {{ registry_url }}{{ service_name }} .
args:
chdir: "{{ repo_dir }}"
delegate_to: 127.0.0.1
tags: [service]
- name: Container is pushed
shell: docker push {{ registry_url }}{{ service_name }}
delegate_to: 127.0.0.1
tags: [service]
程式碼解析
- 執行測試:使用
docker-compose命令執行測試容器,並指定docker-compose-dev.yml檔案。 - 建置服務容器:使用
docker build命令建置服務容器,並指定當前目錄下的 Dockerfile 檔案。 - 推播服務容器:使用
docker push命令將建置好的服務容器推播到 Docker Registry。
自動化佈署流程的實施
在現代化的軟體開發流程中,自動化佈署是持續整合與持續佈署(CI/CD)的關鍵環節。本文將探討如何利用 Ansible 自動化工具實作佈署流程的自動化,涵蓋從建立服務目錄到執行後置佈署測試的整個過程。
建立服務目錄與複製必要檔案
首先,我們需要在目標伺服器上建立服務目錄,並將必要的檔案複製到該目錄下。這些檔案包括 docker-compose.yml、nginx-includes.conf 和 nginx-upstreams.ctmpl。利用 Ansible 的 file 和 copy 模組,我們可以輕鬆實作這一步驟。
Ansible 任務範例
- name: 建立服務目錄
file:
path: /data/{{ service_name }}
recurse: yes
state: directory
tags: [service]
- name: 複製必要檔案
copy:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
with_items: files
tags: [service]
檔案清單定義
files:
- src: "{{ repo_dir }}/docker-compose.yml"
dest: "/data/{{ service_name }}/docker-compose.yml"
- src: "{{ repo_dir }}/nginx-includes.conf"
dest: "/data/nginx/includes/{{ service_name }}.conf"
- src: "{{ repo_dir }}/nginx-upstreams.ctmpl"
dest: "/data/nginx/upstreams/{{ service_name }}.ctmpl"
程式碼解析:
- 建立服務目錄:使用
file模組建立/data/{{ service_name }}目錄,其中{{ service_name }}是變數,由執行 playbook 時動態指定。這確保了該角色的通用性,能夠適用於不同的服務。 - 複製必要檔案:使用
copy模組將docker-compose.yml、nginx-includes.conf和nginx-upstreams.ctmpl複製到目標伺服器上的指定位置。檔案來源和目標路徑透過with_items指令動態指定,來源於files變數的定義。
佈署服務
在完成檔案準備後,我們將進行實際的佈署。佈署步驟包括提取最新的 Docker 映像、啟動服務容器,以及更新 Nginx 組態。
佈署命令
docker-compose pull app
docker-compose up -d app
consul-template -consul localhost:8500 -template "/data/nginx/upstreams/books-ms.ctmpl:/data/nginx/upstreams/books-ms.conf:docker kill -s HUP nginx" -once
對應的 Ansible 任務
- name: 提取 Docker 映像
shell: docker-compose pull app
args:
chdir: /data/{{ service_name }}
tags: [service]
- name: 啟動服務容器
shell: docker-compose up -d app
args:
chdir: /data/{{ service_name }}
tags: [service]
- name: 更新 Nginx 組態
shell: consul-template -consul localhost:8500 -template "{{ ct_src }}:{{ ct_dest }}:{{ ct_cmd }}" -once
tags: [service]
程式碼解析:
- 提取 Docker 映像:使用
docker-compose pull app提取最新的服務映像。 - 啟動服務容器:透過
docker-compose up -d app在背景啟動服務容器。如果容器映像或組態發生變化,Docker Compose 將停止當前容器並啟動新的容器,同時保留掛載的卷。 - 更新 Nginx 組態:利用
consul-template更新 Nginx 的 upstream 組態,並重新載入 Nginx。
後置佈署任務
最後,我們需要執行整合測試並將測試容器推播到 Docker 登入檔。
後置佈署命令
docker-compose -f docker-compose-dev.yml run --rm -e DOMAIN=http://10.100.198.201 integ
docker push 10.100.198.200:5000/books-ms-tests
對應的 Ansible 任務
- name: 執行整合測試
shell: docker-compose -f docker-compose-dev.yml run --rm -e DOMAIN={{ proxy_url }} integ
args:
chdir: "{{ repo_dir }}"
delegate_to: 127.0.0.1
tags: [service, tests]
- name: 推播測試容器到 Docker 登入檔
shell: docker push {{ registry_url }}{{ service_name }}-tests
delegate_to: 127.0.0.1
tags: [service, tests]
程式碼解析:
- 執行整合測試:使用
docker-compose命令執行整合測試,環境變數DOMAIN被設定為代理 URL。 - 推播測試容器:將測試容器推播到指定的 Docker 登入檔。
自動化佈署流程的實作
在前面的章節中,我們已經使用Ansible自動化了大部分的流程。目前為止,我們使用了playbook來自動化兩種型別的任務:伺服器組態與佈署流程。雖然Ansible在伺服器組態方面表現出色,但佈署(至少在我們的上下文中)並不是它的強項。我們主要將其用作bash指令碼的替代品。目前大多數的佈署任務都使用了Ansible的shell模組。我們本可以使用shell指令碼來替代,結果會大同小異。Ansible被設計為使用承諾(promises)來確保系統處於正確狀態,但當需要條件、try/catch陳述式和其他型別的邏輯時,它在佈署方面並不十分有效。使用Ansible來佈署容器的主要原因是避免將流程拆分為多個命令(用ansible進行組態,執行指令碼,再進行更多組態,再執行更多指令碼等)。第二個也是更重要的原因是,我們尚未涵蓋CI/CD工具,因此使用了現有的工具。這很快就會改變。
我們的佈署流程中缺少什麼?
我們正在使用Ansible來組態和提供伺服器,這方面效果很好。但我們仍在尋找更好的軟體佈署方式(呼叫Ansible shell模組有些麻煩)。我們還缺少一種監視儲存函式庫的方法,以便在程式碼發生變化時執行新的佈署。當流程的一部分失敗時,我們沒有傳送通知的機制。我們也缺少對所有構建和佈署的視覺化表示。這樣的缺失功能還有很多,但它們都有一個共同點:可以使用CI/CD工具輕鬆解決。因此,我們應該開始尋找可以使用的CI/CD平台。
CI/CD工具比較
一種劃分CI/CD工具的方法是將它們分為雲端服務和自託管解決方案。雲端服務有很多,無論是免費還是付費的。對於較為簡單的流程,大多數雲端服務都是不錯的選擇。如果您有一個小型應用程式,由幾個服務組成,並且只佈署在少數伺服器上,雲端解決方案是極佳的。我曾經在我的個人專案中使用過許多這樣的服務,如Travis、Shippable、CircleCI和Drone.io。它們可以執行您的指令碼,構建您的應用程式和服務,並將它們封裝到容器中。但大多數雲端服務並不適合處理伺服器叢集,尤其是在私有或自託管的情況下。當然,也有一些雲端解決方案能夠滿足這種需求,但它們往往在大規模佈署時過於昂貴。因此,我們應該尋找自託管的解決方案。
市面上有非常多的自託管CI/CD工具,從免費到非常昂貴的都有。其中一些常用的自託管CI/CD工具包括Jenkins、Bamboo、GoCD、Team City和Electric Cloud等。每個工具都有其優缺點。然而,Jenkins憑藉其龐大的社群脫穎而出。沒有其他工具能像Jenkins一樣擁有如此龐大的貢獻者。它擁有出色的支援,透過其外掛幾乎可以擴充套件到任何我們需要的功能。您很難遇到Jenkins無法處理的需求,因為已經有外掛能夠滿足它。即使您發現了尚未被覆寫的使用案例,編寫自己的外掛(並希望將其公開供他人使用)也是非常容易的事情。社群和外掛是Jenkins最大的優勢,這使得它比其他工具更受歡迎。
為什麼選擇Jenkins?
您很可能已經使用過Jenkins,或者至少聽說過它。公司選擇其他工具(尤其是Bamboo和Team City)的主要原因是它們的企業級產品。當組織變得龐大時,它需要企業級產品所提供的支援和可靠性,以及額外的功能和專業知識。Cloud Bees是最近成立的一家公司,提供Jenkins Enterprise版本,並擁有能夠處理幾乎任何與持續整合、交付或佈署相關場景的優秀支援。他們提供免費的Jenkins社群版本,同時也提供付費的企業級功能和支援。這是選擇Jenkins的另一個理由。沒有其他工具(至少在前面提到的那些工具中)能夠同時提供完全免費的工具和付費支援及額外功能。Team City可以免費下載,但代理數量有限。GoCD是免費的,但不提供任何支援。Bamboo與Team City類別似,對免費版本的限制較多。選擇Jenkins意味著選擇經過戰鬥考驗、最廣泛使用的工具,並得到龐大社群的支援,在需要時還能獲得付費支援和功能。
內容解密:
本段落主要探討了在自動化佈署流程中使用CI/CD工具的必要性,以及對比了不同的CI/CD工具,最終選擇了Jenkins作為最佳方案。主要原因包括Jenkins擁有龐大的社群、出色的支援以及豐富的外掛生態系統,能夠滿足大部分的需求。同時,Jenkins提供了免費的社群版本和付費的企業級支援,能夠滿足不同規模和需求的組織。
執行Ansible Playbook進行佈署
1 cd ~/books-ms
2
3 ansible-playbook /vagrant/ansible/service.yml \
4 -i /vagrant/ansible/hosts/prod \
5 --extra-vars "repo_dir=$PWD service_name=books-ms"
內容解密:
這段程式碼展示瞭如何使用Ansible Playbook進行佈署。首先,切換到~/books-ms目錄。然後,執行ansible-playbook命令,使用/vagrant/ansible/service.yml這個playbook檔案,並指定/vagrant/ansible/hosts/prod作為inventory檔案。同時,透過--extra-vars引數傳遞額外的變數,包括repo_dir和service_name。這兩個變數分別代表了目前的工作目錄和要佈署的服務名稱。
銷毀Vagrant虛擬機器
1 exit
2
3 vagrant destroy -f
內容解密:
這段程式碼用於銷毀由Vagrant管理的虛擬機器。首先,離開目前的工作階段或環境。然後,使用vagrant destroy -f命令強制銷毀虛擬機器。這是在完成測試或佈署後清理環境的常見做法。
CI/CD 工具的演進與挑戰
持續整合(CI)與持續交付/佈署(CD)工具在軟體開發領域扮演著至關重要的角色。這些工具的歷史可以追溯到早期的 Jenkins,以及後來興起的 Travis 和 CircleCI 等雲端工具。本文將探討這些工具的發展歷程、優缺點,以及它們如何滿足不同規模專案的需求。
Jenkins 與第一代 CI/CD 工具
Jenkins 是最早廣泛使用的 CI/CD 工具之一,它透過建立和管理作業(jobs)來實作自動化的構建、測試和佈署。這些作業可以串聯起來形成 CI/CD 管道。Jenkins 的成功催生了其他類別似工具,如 Bamboo 和 Team City,它們都採用了類別似的作業連結邏輯。然而,這些工具大多數透過 UI 進行操作和維護,這在專案數量較少時尚可管理,但當專案數量龐大時,維護工作就會變得非常繁瑣。
程式碼範例:Jenkins 作業組態
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'make build'
}
}
stage('Test') {
steps {
sh 'make test'
}
}
}
}
內容解密:
上述 Groovy 指令碼定義了一個簡單的 Jenkins 管道,包含構建和測試兩個階段。agent any 表示該管道可以在任何可用的代理節點上執行。sh 'make build' 和 sh 'make test' 分別執行構建和測試命令。這種以程式碼定義管道的方式提高了可維護性和可讀性。
第二代 CI/CD 工具:雲端與自動發現
隨著時間的推移,第二代 CI/CD 工具如 Travis 和 CircleCI 出現了,它們將 CI/CD 流程遷移到雲端,並根據自動發現和 YAML 組態檔案進行操作。這些工具會檢查程式碼倉函式庫中的組態檔案(如 .travis.yml 或 circle.yml),並根據專案型別自動執行相應的操作,如使用 Gradle 構建和測試 Java 專案。
程式碼範例:Travis CI 組態
language: java
jdk:
- openjdk11
script:
- gradle build
- gradle test
內容解密:
這個 .travis.yml 檔案指定了 Travis CI 的組態。它告訴 Travis 使用 OpenJDK 11 環境,並執行 gradle build 和 gradle test 命令來構建和測試專案。這種組態方式簡單明瞭,便於專案團隊管理。
CI/CD 工具的選擇與挑戰
第一代工具如 Jenkins 提供了強大的功能和靈活性,但維護成本較高。第二代工具如 Travis 和 CircleCI 簡化了組態和維護,但可能無法滿足複雜專案的需求。因此,大型專案通常仍依賴 Jenkins 等工具,而小型專案則更傾向於使用雲端 CI/CD 工具。
未來趨勢與建議
隨著技術的發展,CI/CD 工具不斷演進。未來,我們可能會看到更多結合第一代和第二代工具優點的解決方案。對於開發團隊來說,選擇合適的 CI/CD 工具需要根據專案規模、複雜度和團隊經驗進行綜合考慮。