返回文章列表

Ansible自動化佈署管線實作

本文探討如何利用 Ansible 開發自動化佈署管線,涵蓋建置測試容器、執行佈署前任務、建立服務目錄、佈署服務與後置佈署任務等關鍵步驟。同時,文章也分析了 CI/CD 工具的演進,比較了 Jenkins、Travis、CircleCI 等工具的優缺點,並說明瞭選擇 Jenkins 作為 CI/CD

DevOps Web 開發

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]

程式碼解析

  1. 提取測試容器映像:首先嘗試從 Docker Registry 提取測試容器映像。如果映像不存在,則忽略錯誤。
  2. 建置測試容器映像:使用 docker build 命令建置測試容器映像,並指定 Dockerfile.test 檔案。
  3. delegate_to 引數:將任務委派給本地主機(127.0.0.1)執行,以避免幹擾目標伺服器。
  4. 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]

程式碼解析

  1. 執行測試:使用 docker-compose 命令執行測試容器,並指定 docker-compose-dev.yml 檔案。
  2. 建置服務容器:使用 docker build 命令建置服務容器,並指定當前目錄下的 Dockerfile 檔案。
  3. 推播服務容器:使用 docker push 命令將建置好的服務容器推播到 Docker Registry。

自動化佈署流程的實施

在現代化的軟體開發流程中,自動化佈署是持續整合與持續佈署(CI/CD)的關鍵環節。本文將探討如何利用 Ansible 自動化工具實作佈署流程的自動化,涵蓋從建立服務目錄到執行後置佈署測試的整個過程。

建立服務目錄與複製必要檔案

首先,我們需要在目標伺服器上建立服務目錄,並將必要的檔案複製到該目錄下。這些檔案包括 docker-compose.ymlnginx-includes.confnginx-upstreams.ctmpl。利用 Ansible 的 filecopy 模組,我們可以輕鬆實作這一步驟。

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"

程式碼解析:

  1. 建立服務目錄:使用 file 模組建立 /data/{{ service_name }} 目錄,其中 {{ service_name }} 是變數,由執行 playbook 時動態指定。這確保了該角色的通用性,能夠適用於不同的服務。
  2. 複製必要檔案:使用 copy 模組將 docker-compose.ymlnginx-includes.confnginx-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]

程式碼解析:

  1. 提取 Docker 映像:使用 docker-compose pull app 提取最新的服務映像。
  2. 啟動服務容器:透過 docker-compose up -d app 在背景啟動服務容器。如果容器映像或組態發生變化,Docker Compose 將停止當前容器並啟動新的容器,同時保留掛載的卷。
  3. 更新 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]

程式碼解析:

  1. 執行整合測試:使用 docker-compose 命令執行整合測試,環境變數 DOMAIN 被設定為代理 URL。
  2. 推播測試容器:將測試容器推播到指定的 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_dirservice_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.ymlcircle.yml),並根據專案型別自動執行相應的操作,如使用 Gradle 構建和測試 Java 專案。

程式碼範例:Travis CI 組態

language: java
jdk:
  - openjdk11
script:
  - gradle build
  - gradle test

內容解密:

這個 .travis.yml 檔案指定了 Travis CI 的組態。它告訴 Travis 使用 OpenJDK 11 環境,並執行 gradle buildgradle test 命令來構建和測試專案。這種組態方式簡單明瞭,便於專案團隊管理。

CI/CD 工具的選擇與挑戰

第一代工具如 Jenkins 提供了強大的功能和靈活性,但維護成本較高。第二代工具如 Travis 和 CircleCI 簡化了組態和維護,但可能無法滿足複雜專案的需求。因此,大型專案通常仍依賴 Jenkins 等工具,而小型專案則更傾向於使用雲端 CI/CD 工具。

未來趨勢與建議

隨著技術的發展,CI/CD 工具不斷演進。未來,我們可能會看到更多結合第一代和第二代工具優點的解決方案。對於開發團隊來說,選擇合適的 CI/CD 工具需要根據專案規模、複雜度和團隊經驗進行綜合考慮。