返回文章列表

Ansible自動化Jenkins持續整合佈署

本文闡述如何利用 Ansible 自動化組態 Jenkins 伺服器,實作 CI/CD 流程的自動化,包含 Docker 容器化佈署 Jenkins、Ansible Playbook 的撰寫、組態檔案與外掛程式的安裝,以及 Jenkins Job 的建立與過載等關鍵步驟,有效提升軟體交付效率與品質。

DevOps 自動化

Ansible 的自動化能力簡化了 Jenkins 伺服器的組態與管理,尤其在需要頻繁調整或擴充套件 CI/CD 流程的環境中更顯優勢。本文提供的 Ansible Playbook 涵蓋了 Jenkins 伺服器的完整生命週期管理,從容器化佈署、組態檔案管理、外掛程式安裝到 Job 建立,都可透過 Ansible 進行自動化操作。此方法不僅減少了手動操作的錯誤率,也提升了組態效率,讓開發團隊更專注於軟體開發本身。此外,透過 Docker 容器化佈署 Jenkins,更確保了環境的一致性,方便跨平台佈署和管理。

Jenkins:持續整合與交付的強大工具

Jenkins作為一個領先的CI/CD工具,經歷了多次演進,至今已發展到第三代。第三代Jenkins引入了Jenkins Workflow和Jenkinsfile,結合了前兩代的優點,並帶來了更多創新。

Jenkins Workflow與Jenkinsfile的革新

Jenkins Workflow允許使用根據Groovy的DSL(Domain-Specific Language)編寫整個Pipeline(pipeline)。這使得流程可以被寫成一個單一的指令碼,充分利用現有的Jenkins功能。相較於傳統的Jenkins作業定義(XML格式),Workflow指令碼大大減少了程式碼量和作業數量,從而簡化了管理和維護。同時,Jenkinsfile的引入使得開發者可以在程式碼倉函式庫中定義Workflow指令碼,從而更好地控制CI/CDPipeline。這樣一來,責任劃分更加明確:整體Jenkins管理集中化,而個別CI/CDPipeline則與程式碼存放在一起。此外,結合Multibranch Workflow作業型別,可以根據分支對Pipeline進行微調。例如,可以在master分支中定義完整的流程,而在每個feature分支中使用較短的流程。Jenkins會根據分支的建立和刪除自動建立和刪除作業。

Docker Workflow的整合

Docker Workflow的引入使Docker成為Jenkins中的一等公民。這進一步增強了Jenkins在CI/CD領域的領先地位。如果需要更多功能,可以考慮使用CloudBees Jenkins Platform - Enterprise Edition,它提供了出色的功能,特別是在需要大規模執行Jenkins時。

Jenkins的外掛生態系統

Jenkins的強大之處在於其豐富的外掛生態系統。幾乎可以找到滿足任何需求的外掛,從連線到程式碼倉函式庫到向Slack傳送通知,甚至使用自定義公式解析日誌。然而,這種豐富性也是一把雙刃劍。使用者可能會安裝過多的外掛,導致不必要的複雜性。例如,可以使用Ansible外掛作為構建步驟,並填寫相關欄位,如Playbook路徑、Inventory、要跳過的Tags等。但是,一種替代方法是使用Execute Shell構建步驟,直接執行Ansible命令。這樣可以減少需要填寫或忽略的欄位,並且可以使用相同的命令作為參考,以便在Jenkins外部重複相同的過程。

使用指令碼進行自動化

在許多情況下,自動化應該在Jenkins(或任何其他CI/CD工具)外部進行。然後,只需告訴Jenkins要執行的指令碼即可。該指令碼可以儲存在與服務程式碼相同的倉函式庫中(例如deploy.sh),或者透過一些命名約定進行概括並用於所有服務。無論自動化指令碼如何組織,在大多數情況下,在Jenkins中執行與這些指令碼相關的命令是最簡單、最有效的方法。現在,隨著Jenkinsfile的加入,我們可以在專案倉函式庫中保留專案特定的指令碼,並利用Jenkins特定的功能,如在特定節點上執行某些操作,或使用儲存在Jenkins中的身份驗證資訊。

設定Jenkins

首先,我們將建立虛擬機器來探索Jenkins。我們將建立cd節點來託管我們的Jenkins伺服器,以及將透過它執行的Ansible playbooks。

內容解密:

  1. vagrant up cd prod:啟動名為cd和prod的虛擬機器,用於後續的Jenkins安裝和Ansible playbook執行。
  2. vagrant ssh cd:透過SSH連線到cd虛擬機器,以便進行後續操作。
  3. ansible-playbook /vagrant/ansible/prod2.yml -i /vagrant/ansible/hosts/prod:執行Ansible playbook來組態prod節點。
  4. sudo mkdir -p /data/jenkins:建立用於持久化Jenkins資料的目錄。
  5. sudo chmod 0777 /data/jenkins:設定目錄許可權,以允許Jenkins容器存取。
  6. docker run -d --name jenkins -p 8080:8080 -v /data/jenkins:/var/jenkins_home -v /vagrant/.vagrant/machines:/machines jenkins:使用Docker執行Jenkins容器,將主機的8080埠對映到容器的8080埠,並掛載資料卷以持久化Jenkins組態和作業資料。

此圖示說明瞭 Ansible plugin 在 Jenkins 中的使用方式

內容解密:

此圖示展示瞭如何在Jenkins中使用Ansible外掛來執行Ansible Playbook。主要步驟包括組態Playbook路徑和Inventory,然後執行Ansible Playbook。

使用Ansible自動化Jenkins設定

在前面的章節中,我們已經探討瞭如何使用Docker安裝和執行Jenkins。現在,我們將探討如何使用Ansible自動化Jenkins的安裝和設定。

為什麼需要自動化Jenkins?

大多數人使用Jenkins都是透過其圖形使用者介面(GUI)進行操作。雖然GUI非常直觀,但隨著工作數量和複雜度的增加,透過GUI進行管理和維護變得越來越困難。例如,如果我們想要為所有工作新增Slack通知,逐一修改每個工作是不現實的。

自動化Jenkins的方法

有多種方法可以實作Jenkins的自動化。我們可以使用一些Jenkins外掛,如Job DSL和Job Generator外掛。然而,在這裡,我們將採用不同的方法。由於Jenkins的所有設定都儲存在/var/jenkins_home目錄下的XML檔案中,我們可以直接修改這些檔案來改變Jenkins的行為。由於我們已經熟悉Ansible,我們將繼續使用它來安裝和維護Jenkins。

移除現有的Jenkins安裝

首先,我們需要移除現有的Jenkins容器和相關的目錄。

docker rm -f jenkins
sudo rm -rf /data/jenkins

使用Ansible設定Jenkins

使用Ansible設定Jenkins相對簡單。我們將使用jenkins-node.ymljenkins.yml兩個playbook來完成這項工作。

首先,執行以下命令來設定Jenkins節點和Jenkins本身。

ansible-playbook /vagrant/ansible/jenkins-node.yml \
  -i /vagrant/ansible/hosts/prod

ansible-playbook /vagrant/ansible/jenkins.yml \
  -c local

jenkins-node.yml playbook

這個playbook負責設定Jenkins節點。它確保JDK已經安裝,並且建立了/data/jenkins_slaves目錄。

jenkins.yml playbook

這個playbook負責安裝和設定Jenkins。下面是jenkins.yml的內容。

- hosts: localhost
  remote_user: vagrant
  serial: 1
  sudo: yes
  roles:
    - consul-template
    - jenkins

這個playbook安裝了Consul Template和Jenkins。主要的任務定義在roles/jenkins/tasks/main.yml檔案中。

roles/jenkins/tasks/main.yml

這個檔案定義了設定Jenkins所需的任務。

1. 建立必要的目錄

第一個任務是建立必要的目錄。

- name: Directories are created
  file:
    path: "{{ item.dir }}"
    mode: 0777
    recurse: yes
    state: directory
  with_items: configs
  tags: [jenkins]

2. 執行Jenkins容器

接下來的任務是執行Jenkins容器。


#### 內容解密:
此任務使用Docker模組執行Jenkins容器。由於容器的啟動速度很快,但Jenkins本身需要一些時間才能完全執行,因此我們註冊了一個變數`container_result`,並在稍後暫停playbook的執行,以確保Jenkins已經完全執行。
```yml
- name: Run Jenkins container
  docker_container:
    name: jenkins
    image: jenkins/jenkins:lts
    ports:
      - "8080:8080"
    volumes:
      - /data/jenkins:/var/jenkins_home
  register: container_result

3. 等待Jenkins完全執行

為了確保Jenkins已經完全執行,我們暫停playbook的執行。

- name: Pause playbook execution
  pause:
    seconds: 30
  when: container_result.changed

內容解密:

此任務暫停playbook的執行30秒,以確保Jenkins已經完全執行。只有在container_result發生變化時才會執行此任務。

此圖示展示了使用Ansible自動化Jenkins設定的流程

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

title Ansible自動化Jenkins持續整合佈署

package "Docker 架構" {
    actor "開發者" as dev

    package "Docker Engine" {
        component [Docker Daemon] as daemon
        component [Docker CLI] as cli
        component [REST API] as api
    }

    package "容器運行時" {
        component [containerd] as containerd
        component [runc] as runc
    }

    package "儲存" {
        database [Images] as images
        database [Volumes] as volumes
        database [Networks] as networks
    }

    cloud "Registry" as registry
}

dev --> cli : 命令操作
cli --> api : API 呼叫
api --> daemon : 處理請求
daemon --> containerd : 容器管理
containerd --> runc : 執行容器
daemon --> images : 映像檔管理
daemon --> registry : 拉取/推送
daemon --> volumes : 資料持久化
daemon --> networks : 網路配置

@enduml

內容解密:

此圖示展示了使用Ansible自動化Jenkins設定的流程。首先,移除現有的Jenkins安裝。然後,執行jenkins-node.ymljenkins.yml兩個playbook。接下來,建立必要的目錄,執行Jenkins容器,並等待Jenkins完全執行。最後,完成整個流程。

持續整合(CI)、交付與佈署(CD)工具的 Ansible 自動化組態

在現代化的軟體開發流程中,持續整合(CI)和持續交付/佈署(CD)扮演著至關重要的角色。透過自動化工具的輔助,開發團隊能夠更高效地進行程式碼整合、測試和佈署,從而加快軟體的交付速度並提高品質。本文將探討如何使用 Ansible 自動化組態 Jenkins 伺服器,以實作 CI/CD 流程的自動化。

Jenkins 伺服器的容器化佈署

首先,我們使用 Docker 容器來佈署 Jenkins 伺服器。透過以下 Ansible playbook,我們可以輕鬆地啟動一個 Jenkins 容器並對映必要的埠和卷。

- name: Container is running
  docker:
    name: jenkins
    image: jenkins
    ports: 8080:8080
    volumes:
      - /data/jenkins:/var/jenkins_home
      - /vagrant/.vagrant/machines:/machines
  register: container_result
  tags: [jenkins]

- pause: seconds=30
  when: container_result|changed
  tags: [jenkins]

內容解密:

  1. docker 模組:用於管理 Docker 容器。在這裡,我們指定了容器的名稱為 jenkins,使用的映象也是 jenkins,並將主機的 8080 埠對映到容器的 8080 埠。同時,我們掛載了兩個卷,分別用於持久化 Jenkins 的主目錄和存取 Vagrant 虛擬機器的相關資訊。
  2. register:將任務的執行結果註冊到變數 container_result 中,以便後續任務根據此結果進行條件判斷。
  3. pause 模組:讓 Ansible 暫停執行 30 秒,確保 Jenkins 容器有足夠的時間啟動。當 container_result 發生變化時(即容器被建立或重新啟動),這個任務才會執行。

組態檔案的佈署

接下來,我們需要將一些組態檔案複製到 Jenkins 容器中,例如憑證檔案 (credentials.xml) 和一些節點組態檔案 (cd_config.xml, prod_config.xml 等)。這些檔案對於 Jenkins 的正常執行至關重要。

- name: Configurations are present
  copy:
    src: "{{ item.src }}"
    dest: "{{ item.dir }}/{{ item.file }}"
    mode: 0777
  with_items: configs
  register: configs_result
  tags: [jenkins]

內容解密:

  1. copy 模組:用於將檔案從控制節點複製到受控節點(此處指 Jenkins 容器)。透過迴圈變數 configs,我們可以批次複製多個組態檔案。
  2. with_items:迴圈遍歷 configs 列表中的每個專案,並執行複製操作。
  3. register:將任務結果註冊到 configs_result,以便後續任務根據組態檔案的變化情況進行相應操作。

Jenkins 外掛程式的安裝

為了使 Jenkins 支援 Git 操作和日誌解析等功能,我們需要安裝一些必要的外掛程式。與直接下載外掛程式不同,我們採用了透過傳送 HTTP 請求到 Jenkins 的 /pluginManager/installNecessaryPlugins 介面來安裝外掛程式及其依賴項的方法。

- name: Plugins are installed
  shell: "curl -X POST \
    -d '<jenkins><install plugin=\"{{ item }}@latest\" /></jenkins>' \
    --header 'Content-Type: text/xml' \
    http://{{ ip }}:8080/pluginManager/installNecessaryPlugins"
  args:
    creates: /data/jenkins/plugins/{{ item }}
  with_items: plugins
  register: plugins_result
  tags: [jenkins]

內容解密:

  1. shell 模組:執行 shell 命令,在這裡我們使用 curl 傳送 POST 請求到 Jenkins 的外掛程式安裝介面,請求體中包含了需要安裝的外掛程式名稱。
  2. args:指定了 creates 引數,用於檢查指定的外掛程式目錄是否存在。如果存在,則跳過該任務,避免重複安裝。
  3. with_items:遍歷 plugins 列表,批次安裝所需的外掛程式。

Jenkins Job 的建立與過載

最後,我們使用 Ansible 的 template 模組來建立 Jenkins Job。透過定義一個範本,我們可以為多個服務建立相似的 Job 組態,從而簡化了 Job 的建立和管理過程。

- name: Job directories are present
  file:
    path: "{{ home }}/jobs/{{ item.name }}"
    state: directory
    mode: 0777
  with_items: jobs
  tags: [jenkins]

- name: Jobs are present
  template:
    src: "{{ item.src }}"
    dest: "{{ home }}/jobs/{{ item.name }}/config.xml"
    mode: 0777
  with_items: jobs
  register: jobs_result
  tags: [jenkins]

- name: Jenkins is reloaded
  uri:
    url: http://{{ ip }}:8080/reload
    method: POST
    status_code: 200,302
  when: jobs_result|changed
  ignore_errors: yes
  tags: [jenkins]

內容解密:

  1. file 模組:為每個 Job 建立一個目錄,用於存放 Job 的組態檔案。
  2. template 模組:根據範本生成 Job 的組態檔案 (config.xml)。透過替換範本中的變數,可以為不同的服務生成特定的 Job 組態。
  3. uri 模組:當 Job 組態發生變化時,傳送過載請求到 Jenkins,使新的 Job 組態生效。