首發於:Jenkins 中文社群
本文介紹如何使用 Jenkins + Ansible 實現對 Nginx 的自動化部署。最終達到的效果有如下幾點:
- 只要你將 Nginx 的配置推送到 GitHub 中,Jenkins 就會自動執行部署,然後目標伺服器的 Nginx 配置自動生效。這個過程是冪等(idempotent)的,只要程式碼不變,執行多少遍,最終效果不變。
- 如果目標機器沒有安裝 Nginx,則會自動安裝 Nginx。
- 自動設定伺服器防火牆規則。
1. 實驗環境介紹
本次實驗使用 Docker Compose 搭建 Jenkins 及 Jenkins agent。使用 Vagrant 啟動一臺虛擬機器,用於部署 Nginx。使用 Vagrant 是可選的,讀者可以使用 VirtualBox 啟動一個虛擬機器。使用 Vagrant 完全是為了自動化搭建實驗環境。
以下是整個實驗環境的架構圖:
注意,圖中的 5123 <-> 80
代表將宿主機的 5123 埠請求轉發到虛擬機器中的 80 埠。
- Vagrant:虛擬機器管理工具,通過它,我們可以使用文字來定義、管理虛擬機器。
- Ansible:自動化運維工具
- Docker Compose:它是一個用於定義和執行多容器 Docker 應用程式的工具。可以使用 YAML 檔案來配置應用程式的服務。
2. 啟動實驗環境
- 克隆程式碼並進入資料夾
git clone https://github.com/zacker330/jenkins-ansible-nginx.git cd jenkins-ansible-nginx 複製程式碼
- 構建 Jenkins agent 的映象
需要自定義 Jenkins agent 映象有兩個原因:
- 本次實驗,使用 Swarm 外掛實現 Jenkins master 與 agent 之間的通訊,所以 Jenkins agent 需要啟動 swarm 客戶端。
- Jenkins agent 必須支援 Ansible。
docker build -f JenkinsSlaveAnsibleDockerfile -t jenkins-swarm-ansible . 複製程式碼
- 啟動 Jenkins master 及 Jenkins agent
通過docker-compose up -d 複製程式碼
http://localhost:8080
訪問 Jenkins master,如果出現“解鎖密碼”頁面,如下圖,則執行命令docker-compose logs jenkins
檢視 Jenkins master 啟動日誌。將日誌中的解鎖密碼輸入到表單中。然後就一步步按提示安裝即可。
- 安裝 Jenkins 外掛
本次實驗需要安裝以下外掛:
- Pipeline 2.6:plugins.jenkins.io/workflow-ag…
- Swarm 3.15:plugins.jenkins.io/swarm 用於 實現 Jenkins master 與 Jenkins agent 自動連線
- Git 3.9.3:plugins.jenkins.io/git
- 配置 Jenkins master 不執行任務 進入頁面:http://localhost:8080/computer/(master)/configure,如下圖所示設定:
- 確認 Jenkins 安全配置有開啟埠,以供 Jenkins agent 連線。 我們設定 Jenkins master 開放的埠,埠可以是固定的 50000 ,也可以設定為隨機。設定連結:http://localhost:8080/configureSecurity/。
- 啟動目標機器,用於部署 Nginx
在命令列中執行以下命令:
注意,Vagrantfile 檔案中的vagrant up 複製程式碼
config.vm.box
值必須改成你的 vagrant box 。
至此,實驗環境已經搭建好了。接下來就可以新建 Jenkins 任務了。
3. 在 Jenkins 上建立部署任務
- 新建流水線任務
- 配置流水線 配置 Jenkins 任務從遠端倉庫拉取 Jenkinsfile,如下圖所示:
除此之外,不需要其它配置了,是不是很簡單?
複製程式碼
4. 手工觸發一次自動化構建
點選“立即構建”:
最終執行日誌如下:
至此,部署已經完成。以後修改 Nginx 的配置,只需要修改程式碼,然後推送到遠端倉庫,就會自動化部署。不需要手工登入到目標機器手工修改了。
最後,我們可以通過訪問 http://localhost:5123
,如果出現如下頁面說明部署成功:
5. 程式碼講解
以上步驟並不能看出自動化部署真正做了什麼。那是因為我們所有的邏輯都寫在程式碼中。是的,可以說是 everything is code。
接下來我們介紹程式碼倉庫。
% tree -L 2
├── JenkinsSlaveAnsibleDockerfile # Jenkins agent 映象 Dockerfile
├── Jenkinsfile # 流水線邏輯
├── README.md
├── Vagrantfile # Vagrant 虛擬機器定義檔案
├── docker-compose.yml # Jenkins 實現環境
├── env-conf # 所有應用配置
│ └── dev # dev 環境的配置
├── deploy # Ansible 部署指令碼所在資料夾
│ ├── playbook.yaml
│ └── roles
└── swarm-client.sh # Jenkins swarm 外掛的客戶端
複製程式碼
5.1流水線邏輯
Jenkinsfile 檔案用於描述整條流水線的邏輯。程式碼如下:
pipeline{
// 任務執行在具有 ansible 標籤的 agent 上
agent { label "ansible"}
environment{
// 設定 Ansible 不檢查 HOST_KEY
ANSIBLE_HOST_KEY_CHECKING = false
}
triggers {
pollSCM('H/1 * * * *')
}
stages{
stage("deploy nginx"){
steps{
sh "ansible-playbook -i env-conf/dev deploy/playbook.yaml"
}
}}}
複製程式碼
environment
部分:用於定義流水線執行過程中的環境變數。triggers
部分:用於定義流水線的觸發機制。pollSCM
定義了每分鐘判斷一次程式碼是否有變化,如果有變化則自動執行流水線。agent
部分:用於定義整條流水線的執行環境。stages
部分:流水線的所有階段,都被定義在這部分。
以上只是定義流水線是如何執行的,目前整條流水線只有一個 deploy nginx
階段,並且只執行了一條 ansible-playbook
命令。但是它並沒有告訴我們部署邏輯是怎麼樣的。
5.2 部署邏輯
所有的部署邏輯,包括 Nginx 的安裝啟動、配置的更新以及載入,都放在 Ansible 指令碼中。對 Ansible 不熟的同學,可以在本文末尾找到介紹 Ansible 的文章。
整個部署邏輯的入口在 deploy/playbook.yaml
,程式碼如下:
---
- hosts: "nginx"
become: true
roles:
# Nginx 的部署
- ansible-role-nginx
# 對防火牆的設定
- ansible-role-firewall
複製程式碼
hosts
:定義了 playbook 部署的目標主機分組名為nginx
。roles
:包含了兩個執行具體部署動作的 role,至於 role 內部邏輯,不在本文討論範圍,有興趣的同學閱讀原始碼。
5.3 配置管理
談到部署,就不得不談配置管理。
回顧前文中流水線中執行的 shell 命令:ansible-playbook -i env-conf/dev deploy/playbook.yaml
我們通過 -i
引數指定部署時所使用的環境配置。通過這種方式實現環境配置與執行指令碼的分離。這樣帶來以下幾個好處:
- 新增環境時,只需要複製現有的環境,然後將裡面的變數的值改成新環境的即可。比如,要對測試環境進行部署,只需要將
-i
引數值改成:env-conf/test
。 - 對配置版本化控制。
本次實驗中,各個環境的配置放在 env-conf
目錄中,目前只有 dev 環境,以下是 env-conf/
目錄結構:
% cd env-conf/
% tree
└── dev
├── group_vars
│ └── nginx.yaml
├── host_vars
│ └── 192.168.52.10
└── hosts
複製程式碼
- hosts檔案:Ansible 中通過“分組”來實現對主機的管理。hosts 檔案內容如下:
[nginx] 192.168.52.10 複製程式碼
- host_vars 目錄:用於存放主機級別的配置變數,本例中
192.168.52.10
是一個 YAML 格式檔案。注意檔名是該主機的 IP。我們在檔案中放主機相關的配置,比如 Ansible 連線主機時使用到的使用者名稱和密碼。 - group_vars 目錄:用於存放組級別的配置變數。比如 nginx.yaml 對應的就是
nginx
這個組的的配置變數。檔名與hosts
中的組名對應。
總結
到此,我們完整的自動化部署已經講解完成。但是還遺留下一些問題:
- 本文只是安裝了一個“空”的 Nginx,但是沒有介紹 Nginx 真正配置。
- 目前主機的連線資訊(SSH 密碼)是明文寫在
host_vars/192.168.52.10
檔案中的,存在安全風險。 - 沒有介紹如何當 Java 應用部署時,如何自動更新 Nginx 的配置。
本文屬於使用 Jenkins + Ansible 實現自動化部署的入門文章,筆者將根據讀者的反饋決定是否寫續集。
如果覺得本文講的 Jenkins 流水線邏輯部分不夠過癮,可以考慮入手一本最近才出版的《Jenkins 2.x實踐指南》。長按下圖進行掃碼購買。
附錄
- 本次實驗環境程式碼:github.com/zacker330/j…
- 簡單易懂 Ansible 系列 —— 解決了什麼:showme.codes/2017-06-12/…
- Puppet,Chef,Ansible 的共性:showme.codes/2016-01-02/…
作者:翟志軍