使用 Jenkins + Ansible 實現自動化部署 Nginx

Jenkins中文社群發表於2019-04-25

首發於:Jenkins 中文社群

本文介紹如何使用 Jenkins + Ansible 實現對 Nginx 的自動化部署。最終達到的效果有如下幾點:

  1. 只要你將 Nginx 的配置推送到 GitHub 中,Jenkins 就會自動執行部署,然後目標伺服器的 Nginx 配置自動生效。這個過程是冪等(idempotent)的,只要程式碼不變,執行多少遍,最終效果不變。
  2. 如果目標機器沒有安裝 Nginx,則會自動安裝 Nginx。
  3. 自動設定伺服器防火牆規則。

1. 實驗環境介紹

本次實驗使用 Docker Compose 搭建 Jenkins 及 Jenkins agent。使用 Vagrant 啟動一臺虛擬機器,用於部署 Nginx。使用 Vagrant 是可選的,讀者可以使用 VirtualBox 啟動一個虛擬機器。使用 Vagrant 完全是為了自動化搭建實驗環境。

以下是整個實驗環境的架構圖:

使用 Jenkins + Ansible 實現自動化部署 Nginx

注意,圖中的 5123 <-> 80 代表將宿主機的 5123 埠請求轉發到虛擬機器中的 80 埠。

  • Vagrant:虛擬機器管理工具,通過它,我們可以使用文字來定義、管理虛擬機器。
  • Ansible:自動化運維工具
  • Docker Compose:它是一個用於定義和執行多容器 Docker 應用程式的工具。可以使用 YAML 檔案來配置應用程式的服務。

2. 啟動實驗環境

  1. 克隆程式碼並進入資料夾
    git clone https://github.com/zacker330/jenkins-ansible-nginx.git
    cd jenkins-ansible-nginx
    複製程式碼
  2. 構建 Jenkins agent 的映象 需要自定義 Jenkins agent 映象有兩個原因:
    1. 本次實驗,使用 Swarm 外掛實現 Jenkins master 與 agent 之間的通訊,所以 Jenkins agent 需要啟動 swarm 客戶端。
    2. Jenkins agent 必須支援 Ansible。
    docker build -f JenkinsSlaveAnsibleDockerfile -t jenkins-swarm-ansible .
    複製程式碼
  3. 啟動 Jenkins master 及 Jenkins agent
    docker-compose up -d
    複製程式碼
    通過 http://localhost:8080 訪問 Jenkins master,如果出現“解鎖密碼”頁面,如下圖,則執行命令 docker-compose logs jenkins 檢視 Jenkins master 啟動日誌。將日誌中的解鎖密碼輸入到表單中。然後就一步步按提示安裝即可。

使用 Jenkins + Ansible 實現自動化部署 Nginx

  1. 安裝 Jenkins 外掛 本次實驗需要安裝以下外掛:
  2. 配置 Jenkins master 不執行任務 進入頁面:http://localhost:8080/computer/(master)/configure,如下圖所示設定:

使用 Jenkins + Ansible 實現自動化部署 Nginx

  1. 確認 Jenkins 安全配置有開啟埠,以供 Jenkins agent 連線。 我們設定 Jenkins master 開放的埠,埠可以是固定的 50000 ,也可以設定為隨機。設定連結:http://localhost:8080/configureSecurity/

使用 Jenkins + Ansible 實現自動化部署 Nginx

  1. 啟動目標機器,用於部署 Nginx 在命令列中執行以下命令:
    vagrant up 
    複製程式碼
    注意,Vagrantfile 檔案中的 config.vm.box 值必須改成你的 vagrant box 。

至此,實驗環境已經搭建好了。接下來就可以新建 Jenkins 任務了。

3. 在 Jenkins 上建立部署任務

  1. 新建流水線任務

使用 Jenkins + Ansible 實現自動化部署 Nginx

  1. 配置流水線 配置 Jenkins 任務從遠端倉庫拉取 Jenkinsfile,如下圖所示:

使用 Jenkins + Ansible 實現自動化部署 Nginx

除此之外,不需要其它配置了,是不是很簡單?
複製程式碼

4. 手工觸發一次自動化構建

點選“立即構建”:

使用 Jenkins + Ansible 實現自動化部署 Nginx

最終執行日誌如下:

使用 Jenkins + Ansible 實現自動化部署 Nginx

至此,部署已經完成。以後修改 Nginx 的配置,只需要修改程式碼,然後推送到遠端倉庫,就會自動化部署。不需要手工登入到目標機器手工修改了。

最後,我們可以通過訪問 http://localhost:5123,如果出現如下頁面說明部署成功:

使用 Jenkins + Ansible 實現自動化部署 Nginx

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 引數指定部署時所使用的環境配置。通過這種方式實現環境配置與執行指令碼的分離。這樣帶來以下幾個好處:

  1. 新增環境時,只需要複製現有的環境,然後將裡面的變數的值改成新環境的即可。比如,要對測試環境進行部署,只需要將 -i 引數值改成:env-conf/test
  2. 對配置版本化控制。

本次實驗中,各個環境的配置放在 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 中的組名對應。

總結

到此,我們完整的自動化部署已經講解完成。但是還遺留下一些問題:

  1. 本文只是安裝了一個“空”的 Nginx,但是沒有介紹 Nginx 真正配置。
  2. 目前主機的連線資訊(SSH 密碼)是明文寫在 host_vars/192.168.52.10 檔案中的,存在安全風險。
  3. 沒有介紹如何當 Java 應用部署時,如何自動更新 Nginx 的配置。

本文屬於使用 Jenkins + Ansible 實現自動化部署的入門文章,筆者將根據讀者的反饋決定是否寫續集。

如果覺得本文講的 Jenkins 流水線邏輯部分不夠過癮,可以考慮入手一本最近才出版的《Jenkins 2.x實踐指南》。長按下圖進行掃碼購買。

使用 Jenkins + Ansible 實現自動化部署 Nginx

附錄

作者:翟志軍

使用 Jenkins + Ansible 實現自動化部署 Nginx

相關文章