'手把手教你從零搭建一個持續集成環境'

"

本文將帶領你從0開始,用Vagrant + Docker + Ansible + Jenkins + Nginx + GitHub等工具和資源來搭建一條可執行可擴展的持續集成流水線,即使這些名字你都沒聽過也沒關係,本文將會在需要的時候一一解釋給你聽。

By: 巧穎 & 天一

總覽

這是我們將要搭建的所有基礎設施的總體架構圖,我們將在本文中手把手教你搭建這樣一個持續集成環境。

"

本文將帶領你從0開始,用Vagrant + Docker + Ansible + Jenkins + Nginx + GitHub等工具和資源來搭建一條可執行可擴展的持續集成流水線,即使這些名字你都沒聽過也沒關係,本文將會在需要的時候一一解釋給你聽。

By: 巧穎 & 天一

總覽

這是我們將要搭建的所有基礎設施的總體架構圖,我們將在本文中手把手教你搭建這樣一個持續集成環境。

手把手教你從零搭建一個持續集成環境

我們會在本地啟動兩臺虛擬機,一臺部署Nginx作為靜態文件服務器,一臺作為Jenkins服務器,在每臺虛擬機內部安裝Docker,使用Docker來完成Nginx與Jenkins的搭建、配置,然後手動在Jenkins配置內配置好一條Pipeline作為持續集成流水線,最後嘗試提交一次代碼去觸發一次持續集成操作,將最新的html項目代碼從Github上部署到Nginx中,實現持續集成。

避免本文過長,部分源代碼沒有貼在文中,本文參考完成源代碼在此:https://github.com/tw-wh-devops-community/cooking-chicken.git。建議在自己嘗試從0開始搭建的同時參考源碼閱讀本文。相信你一定會碰到很多坑,但坑外便是晴天。

首先我們需要兩臺機器

我們需要Vagrant

為什麼呢

無論你用的操作系統是Windows、Mac還是Linux,Oracle的Virtual Box都支持,那麼我們首先會使用Virtual Box來建立一個在硬件上絕對隔離的環境出來。

那麼Vagrant就是通過方便的命令操作來簡化Virtual Box的操作,同時提供了方便的虛擬機配置模塊,所以我們會使用這個工具來提升虛擬機的配置效率。

安裝Vagrant

在Mac上是自帶Virtual Box的,你用的版本可能需要更新才能配合Vagrant使用,Linux上請使用類似sudo apt-get install virtualbox的命令安裝。

那麼先裝上Vagrant吧:

  • Mac(https://www.vagrantup.com/downloads.html)
  • Ubuntu(sudo apt-get install vagrant)

安裝Vagrant插件

由於後續操作會涉及到將Nginx機器的私鑰發送給Jenkins機器來配置私鑰來完成虛擬機之間的無密碼訪問。但私鑰是在Nginx虛擬機創建之後才會由Vagrant創建的,所以需要在這個時間節點放到Jenkins目錄下便於Ansible把私鑰放到Jenkins虛擬機中。如果暫時不理解沒有關係,請看完”開始創建世界“之後回頭來看就會明白。

Vagrant的provision模塊可以在虛擬機啟動之後在虛擬機內部執行任意腳本,但是provision模塊並沒有提供執行宿主機上腳本的方式,所以需要你安裝如下模塊:

vagrant plugin install vagrant-host-shell

調試的時候比較有用的操作

  • 進入虛擬機:vagrant ssh
  • 休眠:vagrant suspend
  • 從休眠中恢復:vagrant resume
  • 移除虛擬機所有文件:vagrant destroy

開始創建世界!

Vagrantfile

我們來新建一個工程,在根目錄創建一個名為Vagrantfile的文件,內容如下:

"

本文將帶領你從0開始,用Vagrant + Docker + Ansible + Jenkins + Nginx + GitHub等工具和資源來搭建一條可執行可擴展的持續集成流水線,即使這些名字你都沒聽過也沒關係,本文將會在需要的時候一一解釋給你聽。

By: 巧穎 & 天一

總覽

這是我們將要搭建的所有基礎設施的總體架構圖,我們將在本文中手把手教你搭建這樣一個持續集成環境。

手把手教你從零搭建一個持續集成環境

我們會在本地啟動兩臺虛擬機,一臺部署Nginx作為靜態文件服務器,一臺作為Jenkins服務器,在每臺虛擬機內部安裝Docker,使用Docker來完成Nginx與Jenkins的搭建、配置,然後手動在Jenkins配置內配置好一條Pipeline作為持續集成流水線,最後嘗試提交一次代碼去觸發一次持續集成操作,將最新的html項目代碼從Github上部署到Nginx中,實現持續集成。

避免本文過長,部分源代碼沒有貼在文中,本文參考完成源代碼在此:https://github.com/tw-wh-devops-community/cooking-chicken.git。建議在自己嘗試從0開始搭建的同時參考源碼閱讀本文。相信你一定會碰到很多坑,但坑外便是晴天。

首先我們需要兩臺機器

我們需要Vagrant

為什麼呢

無論你用的操作系統是Windows、Mac還是Linux,Oracle的Virtual Box都支持,那麼我們首先會使用Virtual Box來建立一個在硬件上絕對隔離的環境出來。

那麼Vagrant就是通過方便的命令操作來簡化Virtual Box的操作,同時提供了方便的虛擬機配置模塊,所以我們會使用這個工具來提升虛擬機的配置效率。

安裝Vagrant

在Mac上是自帶Virtual Box的,你用的版本可能需要更新才能配合Vagrant使用,Linux上請使用類似sudo apt-get install virtualbox的命令安裝。

那麼先裝上Vagrant吧:

  • Mac(https://www.vagrantup.com/downloads.html)
  • Ubuntu(sudo apt-get install vagrant)

安裝Vagrant插件

由於後續操作會涉及到將Nginx機器的私鑰發送給Jenkins機器來配置私鑰來完成虛擬機之間的無密碼訪問。但私鑰是在Nginx虛擬機創建之後才會由Vagrant創建的,所以需要在這個時間節點放到Jenkins目錄下便於Ansible把私鑰放到Jenkins虛擬機中。如果暫時不理解沒有關係,請看完”開始創建世界“之後回頭來看就會明白。

Vagrant的provision模塊可以在虛擬機啟動之後在虛擬機內部執行任意腳本,但是provision模塊並沒有提供執行宿主機上腳本的方式,所以需要你安裝如下模塊:

vagrant plugin install vagrant-host-shell

調試的時候比較有用的操作

  • 進入虛擬機:vagrant ssh
  • 休眠:vagrant suspend
  • 從休眠中恢復:vagrant resume
  • 移除虛擬機所有文件:vagrant destroy

開始創建世界!

Vagrantfile

我們來新建一個工程,在根目錄創建一個名為Vagrantfile的文件,內容如下:

手把手教你從零搭建一個持續集成環境

那麼現在可以啟動了,在命令行內跳轉到根目錄,使用vagrant up就可以將虛擬機按上面的配置啟動了,同時在啟動完成之後會調用provision模塊跑Ansible的對應腳本安裝配置虛擬機的依賴工具。啟動完成之後,那麼一個隔離的環境創建完畢,接下來我們可以在裡面任意玩耍了。

特別注意:因為第一次運行需要下載ubuntu/trusty64鏡像,以及把所有的配置甚至通過Docker下載Jenkins鏡像、slave鏡像,以及啟動Jenkins都寫到了Ansible中,所以跑完vagrant up需要較長時間

啟動、執行順序

基本是按Vagrant的配置文件的上下順序來啟動的。具體順序如下:

  1. 按Vagrantfile安裝並啟動Nginx虛擬機
  2. 執行Nginx虛擬機依賴的provision模塊
  3. 按Vagrantfile安裝並啟動Jenkins虛擬機
  4. 執行Jenkins虛擬機依賴的provision模塊

Jenkins訪問Nginx(選修,建議有時間或者將Jenkins搭建完成之後再看)

如果你能把所有環境啟動起來並能訪問Jenkins主頁,但此時你還無法在Jenkins上直接ssh登錄到Nginx,因為此時兩臺機器還沒有互信。但是幸運的是Vagrant啟動完Nginx之後就已經將私鑰(可以拿這個私鑰去訪問Nginx,無論你是誰)放到了宿主機上,那麼你可以手動將這個私鑰複製到Jenkins中,然後就可以在Jenkins中訪問Nginx了。

但是為了自動化上面的操作,進行以下的配置:Vagrant會在啟動一個虛擬機之後,會在Mac上創建.vagrant文件夾並把一些關於這個虛擬機的文件放到裡面,比如該虛擬機的私鑰,後面可以拿到這私鑰作為SSH聯絡的key。

比如下面這段配置會在Nginx虛擬機啟動之後,Jenkins虛擬機啟動之前執行。由於Jenkins虛擬機需要在部署代碼的時候使用到Nginx虛擬機的私鑰來部署,所以需要在Jenkins虛擬機執行Ansible之前將私鑰放到Jenkins的file文件夾中。

"

本文將帶領你從0開始,用Vagrant + Docker + Ansible + Jenkins + Nginx + GitHub等工具和資源來搭建一條可執行可擴展的持續集成流水線,即使這些名字你都沒聽過也沒關係,本文將會在需要的時候一一解釋給你聽。

By: 巧穎 & 天一

總覽

這是我們將要搭建的所有基礎設施的總體架構圖,我們將在本文中手把手教你搭建這樣一個持續集成環境。

手把手教你從零搭建一個持續集成環境

我們會在本地啟動兩臺虛擬機,一臺部署Nginx作為靜態文件服務器,一臺作為Jenkins服務器,在每臺虛擬機內部安裝Docker,使用Docker來完成Nginx與Jenkins的搭建、配置,然後手動在Jenkins配置內配置好一條Pipeline作為持續集成流水線,最後嘗試提交一次代碼去觸發一次持續集成操作,將最新的html項目代碼從Github上部署到Nginx中,實現持續集成。

避免本文過長,部分源代碼沒有貼在文中,本文參考完成源代碼在此:https://github.com/tw-wh-devops-community/cooking-chicken.git。建議在自己嘗試從0開始搭建的同時參考源碼閱讀本文。相信你一定會碰到很多坑,但坑外便是晴天。

首先我們需要兩臺機器

我們需要Vagrant

為什麼呢

無論你用的操作系統是Windows、Mac還是Linux,Oracle的Virtual Box都支持,那麼我們首先會使用Virtual Box來建立一個在硬件上絕對隔離的環境出來。

那麼Vagrant就是通過方便的命令操作來簡化Virtual Box的操作,同時提供了方便的虛擬機配置模塊,所以我們會使用這個工具來提升虛擬機的配置效率。

安裝Vagrant

在Mac上是自帶Virtual Box的,你用的版本可能需要更新才能配合Vagrant使用,Linux上請使用類似sudo apt-get install virtualbox的命令安裝。

那麼先裝上Vagrant吧:

  • Mac(https://www.vagrantup.com/downloads.html)
  • Ubuntu(sudo apt-get install vagrant)

安裝Vagrant插件

由於後續操作會涉及到將Nginx機器的私鑰發送給Jenkins機器來配置私鑰來完成虛擬機之間的無密碼訪問。但私鑰是在Nginx虛擬機創建之後才會由Vagrant創建的,所以需要在這個時間節點放到Jenkins目錄下便於Ansible把私鑰放到Jenkins虛擬機中。如果暫時不理解沒有關係,請看完”開始創建世界“之後回頭來看就會明白。

Vagrant的provision模塊可以在虛擬機啟動之後在虛擬機內部執行任意腳本,但是provision模塊並沒有提供執行宿主機上腳本的方式,所以需要你安裝如下模塊:

vagrant plugin install vagrant-host-shell

調試的時候比較有用的操作

  • 進入虛擬機:vagrant ssh
  • 休眠:vagrant suspend
  • 從休眠中恢復:vagrant resume
  • 移除虛擬機所有文件:vagrant destroy

開始創建世界!

Vagrantfile

我們來新建一個工程,在根目錄創建一個名為Vagrantfile的文件,內容如下:

手把手教你從零搭建一個持續集成環境

那麼現在可以啟動了,在命令行內跳轉到根目錄,使用vagrant up就可以將虛擬機按上面的配置啟動了,同時在啟動完成之後會調用provision模塊跑Ansible的對應腳本安裝配置虛擬機的依賴工具。啟動完成之後,那麼一個隔離的環境創建完畢,接下來我們可以在裡面任意玩耍了。

特別注意:因為第一次運行需要下載ubuntu/trusty64鏡像,以及把所有的配置甚至通過Docker下載Jenkins鏡像、slave鏡像,以及啟動Jenkins都寫到了Ansible中,所以跑完vagrant up需要較長時間

啟動、執行順序

基本是按Vagrant的配置文件的上下順序來啟動的。具體順序如下:

  1. 按Vagrantfile安裝並啟動Nginx虛擬機
  2. 執行Nginx虛擬機依賴的provision模塊
  3. 按Vagrantfile安裝並啟動Jenkins虛擬機
  4. 執行Jenkins虛擬機依賴的provision模塊

Jenkins訪問Nginx(選修,建議有時間或者將Jenkins搭建完成之後再看)

如果你能把所有環境啟動起來並能訪問Jenkins主頁,但此時你還無法在Jenkins上直接ssh登錄到Nginx,因為此時兩臺機器還沒有互信。但是幸運的是Vagrant啟動完Nginx之後就已經將私鑰(可以拿這個私鑰去訪問Nginx,無論你是誰)放到了宿主機上,那麼你可以手動將這個私鑰複製到Jenkins中,然後就可以在Jenkins中訪問Nginx了。

但是為了自動化上面的操作,進行以下的配置:Vagrant會在啟動一個虛擬機之後,會在Mac上創建.vagrant文件夾並把一些關於這個虛擬機的文件放到裡面,比如該虛擬機的私鑰,後面可以拿到這私鑰作為SSH聯絡的key。

比如下面這段配置會在Nginx虛擬機啟動之後,Jenkins虛擬機啟動之前執行。由於Jenkins虛擬機需要在部署代碼的時候使用到Nginx虛擬機的私鑰來部署,所以需要在Jenkins虛擬機執行Ansible之前將私鑰放到Jenkins的file文件夾中。

手把手教你從零搭建一個持續集成環境

另外,在Vagrantfile中,Ansible不是與兩臺虛擬機的配置寫在一起的,那麼Ansible如何判斷在哪臺虛擬機上安裝Nginx還是Jenkins呢?因為不同的虛擬機要執行Ansible的時候會根據主機名匹配來找到對應role的tasks從而還是能找到匹配的tasks。換句話說,Nginx安裝完成之後Vagrant攜帶Nginx相關參數執行下面這樣的一行命令來用limit匹配主機與對應Ansible的tasks:

"

本文將帶領你從0開始,用Vagrant + Docker + Ansible + Jenkins + Nginx + GitHub等工具和資源來搭建一條可執行可擴展的持續集成流水線,即使這些名字你都沒聽過也沒關係,本文將會在需要的時候一一解釋給你聽。

By: 巧穎 & 天一

總覽

這是我們將要搭建的所有基礎設施的總體架構圖,我們將在本文中手把手教你搭建這樣一個持續集成環境。

手把手教你從零搭建一個持續集成環境

我們會在本地啟動兩臺虛擬機,一臺部署Nginx作為靜態文件服務器,一臺作為Jenkins服務器,在每臺虛擬機內部安裝Docker,使用Docker來完成Nginx與Jenkins的搭建、配置,然後手動在Jenkins配置內配置好一條Pipeline作為持續集成流水線,最後嘗試提交一次代碼去觸發一次持續集成操作,將最新的html項目代碼從Github上部署到Nginx中,實現持續集成。

避免本文過長,部分源代碼沒有貼在文中,本文參考完成源代碼在此:https://github.com/tw-wh-devops-community/cooking-chicken.git。建議在自己嘗試從0開始搭建的同時參考源碼閱讀本文。相信你一定會碰到很多坑,但坑外便是晴天。

首先我們需要兩臺機器

我們需要Vagrant

為什麼呢

無論你用的操作系統是Windows、Mac還是Linux,Oracle的Virtual Box都支持,那麼我們首先會使用Virtual Box來建立一個在硬件上絕對隔離的環境出來。

那麼Vagrant就是通過方便的命令操作來簡化Virtual Box的操作,同時提供了方便的虛擬機配置模塊,所以我們會使用這個工具來提升虛擬機的配置效率。

安裝Vagrant

在Mac上是自帶Virtual Box的,你用的版本可能需要更新才能配合Vagrant使用,Linux上請使用類似sudo apt-get install virtualbox的命令安裝。

那麼先裝上Vagrant吧:

  • Mac(https://www.vagrantup.com/downloads.html)
  • Ubuntu(sudo apt-get install vagrant)

安裝Vagrant插件

由於後續操作會涉及到將Nginx機器的私鑰發送給Jenkins機器來配置私鑰來完成虛擬機之間的無密碼訪問。但私鑰是在Nginx虛擬機創建之後才會由Vagrant創建的,所以需要在這個時間節點放到Jenkins目錄下便於Ansible把私鑰放到Jenkins虛擬機中。如果暫時不理解沒有關係,請看完”開始創建世界“之後回頭來看就會明白。

Vagrant的provision模塊可以在虛擬機啟動之後在虛擬機內部執行任意腳本,但是provision模塊並沒有提供執行宿主機上腳本的方式,所以需要你安裝如下模塊:

vagrant plugin install vagrant-host-shell

調試的時候比較有用的操作

  • 進入虛擬機:vagrant ssh
  • 休眠:vagrant suspend
  • 從休眠中恢復:vagrant resume
  • 移除虛擬機所有文件:vagrant destroy

開始創建世界!

Vagrantfile

我們來新建一個工程,在根目錄創建一個名為Vagrantfile的文件,內容如下:

手把手教你從零搭建一個持續集成環境

那麼現在可以啟動了,在命令行內跳轉到根目錄,使用vagrant up就可以將虛擬機按上面的配置啟動了,同時在啟動完成之後會調用provision模塊跑Ansible的對應腳本安裝配置虛擬機的依賴工具。啟動完成之後,那麼一個隔離的環境創建完畢,接下來我們可以在裡面任意玩耍了。

特別注意:因為第一次運行需要下載ubuntu/trusty64鏡像,以及把所有的配置甚至通過Docker下載Jenkins鏡像、slave鏡像,以及啟動Jenkins都寫到了Ansible中,所以跑完vagrant up需要較長時間

啟動、執行順序

基本是按Vagrant的配置文件的上下順序來啟動的。具體順序如下:

  1. 按Vagrantfile安裝並啟動Nginx虛擬機
  2. 執行Nginx虛擬機依賴的provision模塊
  3. 按Vagrantfile安裝並啟動Jenkins虛擬機
  4. 執行Jenkins虛擬機依賴的provision模塊

Jenkins訪問Nginx(選修,建議有時間或者將Jenkins搭建完成之後再看)

如果你能把所有環境啟動起來並能訪問Jenkins主頁,但此時你還無法在Jenkins上直接ssh登錄到Nginx,因為此時兩臺機器還沒有互信。但是幸運的是Vagrant啟動完Nginx之後就已經將私鑰(可以拿這個私鑰去訪問Nginx,無論你是誰)放到了宿主機上,那麼你可以手動將這個私鑰複製到Jenkins中,然後就可以在Jenkins中訪問Nginx了。

但是為了自動化上面的操作,進行以下的配置:Vagrant會在啟動一個虛擬機之後,會在Mac上創建.vagrant文件夾並把一些關於這個虛擬機的文件放到裡面,比如該虛擬機的私鑰,後面可以拿到這私鑰作為SSH聯絡的key。

比如下面這段配置會在Nginx虛擬機啟動之後,Jenkins虛擬機啟動之前執行。由於Jenkins虛擬機需要在部署代碼的時候使用到Nginx虛擬機的私鑰來部署,所以需要在Jenkins虛擬機執行Ansible之前將私鑰放到Jenkins的file文件夾中。

手把手教你從零搭建一個持續集成環境

另外,在Vagrantfile中,Ansible不是與兩臺虛擬機的配置寫在一起的,那麼Ansible如何判斷在哪臺虛擬機上安裝Nginx還是Jenkins呢?因為不同的虛擬機要執行Ansible的時候會根據主機名匹配來找到對應role的tasks從而還是能找到匹配的tasks。換句話說,Nginx安裝完成之後Vagrant攜帶Nginx相關參數執行下面這樣的一行命令來用limit匹配主機與對應Ansible的tasks:

手把手教你從零搭建一個持續集成環境

我們需要Ansible

什麼是Ansible

Ansible是一種自動化部署工具,可以用來自動化管理配置項、持續交付、(AWS)雲服務管理;

簡單來說也就是可以批量的遠程服務器上執行一系列的命令,其原理是基於ssh來和遠程主機進行通信的。

為什麼用Ansible

  • playbook使用的是yml語言,易讀性較好;
  • 沒有主節點和代理,僅僅依賴於SSH,使得應用的部署簡單而輕量;
  • 提供了大量模塊支持Google Compute Engine (GCE), Amazon Web Service(AWS);
  • Ansible支持多臺服務器同時管理部署;

安裝Ansible

Ansible是基於python開發的,需要在安裝有python的機器下才能夠安裝Ansible

  • 在本機安裝python:brew install python(Mac自帶ython,因此這步可以省略,inux系統中需要安裝Python)
  • 安裝pip:sudo apt install python-pip
  • 安裝Ansible:sudo pip install ansible

目錄結構

你可以按如下目錄結構去編寫你的Ansible文件。

"

本文將帶領你從0開始,用Vagrant + Docker + Ansible + Jenkins + Nginx + GitHub等工具和資源來搭建一條可執行可擴展的持續集成流水線,即使這些名字你都沒聽過也沒關係,本文將會在需要的時候一一解釋給你聽。

By: 巧穎 & 天一

總覽

這是我們將要搭建的所有基礎設施的總體架構圖,我們將在本文中手把手教你搭建這樣一個持續集成環境。

手把手教你從零搭建一個持續集成環境

我們會在本地啟動兩臺虛擬機,一臺部署Nginx作為靜態文件服務器,一臺作為Jenkins服務器,在每臺虛擬機內部安裝Docker,使用Docker來完成Nginx與Jenkins的搭建、配置,然後手動在Jenkins配置內配置好一條Pipeline作為持續集成流水線,最後嘗試提交一次代碼去觸發一次持續集成操作,將最新的html項目代碼從Github上部署到Nginx中,實現持續集成。

避免本文過長,部分源代碼沒有貼在文中,本文參考完成源代碼在此:https://github.com/tw-wh-devops-community/cooking-chicken.git。建議在自己嘗試從0開始搭建的同時參考源碼閱讀本文。相信你一定會碰到很多坑,但坑外便是晴天。

首先我們需要兩臺機器

我們需要Vagrant

為什麼呢

無論你用的操作系統是Windows、Mac還是Linux,Oracle的Virtual Box都支持,那麼我們首先會使用Virtual Box來建立一個在硬件上絕對隔離的環境出來。

那麼Vagrant就是通過方便的命令操作來簡化Virtual Box的操作,同時提供了方便的虛擬機配置模塊,所以我們會使用這個工具來提升虛擬機的配置效率。

安裝Vagrant

在Mac上是自帶Virtual Box的,你用的版本可能需要更新才能配合Vagrant使用,Linux上請使用類似sudo apt-get install virtualbox的命令安裝。

那麼先裝上Vagrant吧:

  • Mac(https://www.vagrantup.com/downloads.html)
  • Ubuntu(sudo apt-get install vagrant)

安裝Vagrant插件

由於後續操作會涉及到將Nginx機器的私鑰發送給Jenkins機器來配置私鑰來完成虛擬機之間的無密碼訪問。但私鑰是在Nginx虛擬機創建之後才會由Vagrant創建的,所以需要在這個時間節點放到Jenkins目錄下便於Ansible把私鑰放到Jenkins虛擬機中。如果暫時不理解沒有關係,請看完”開始創建世界“之後回頭來看就會明白。

Vagrant的provision模塊可以在虛擬機啟動之後在虛擬機內部執行任意腳本,但是provision模塊並沒有提供執行宿主機上腳本的方式,所以需要你安裝如下模塊:

vagrant plugin install vagrant-host-shell

調試的時候比較有用的操作

  • 進入虛擬機:vagrant ssh
  • 休眠:vagrant suspend
  • 從休眠中恢復:vagrant resume
  • 移除虛擬機所有文件:vagrant destroy

開始創建世界!

Vagrantfile

我們來新建一個工程,在根目錄創建一個名為Vagrantfile的文件,內容如下:

手把手教你從零搭建一個持續集成環境

那麼現在可以啟動了,在命令行內跳轉到根目錄,使用vagrant up就可以將虛擬機按上面的配置啟動了,同時在啟動完成之後會調用provision模塊跑Ansible的對應腳本安裝配置虛擬機的依賴工具。啟動完成之後,那麼一個隔離的環境創建完畢,接下來我們可以在裡面任意玩耍了。

特別注意:因為第一次運行需要下載ubuntu/trusty64鏡像,以及把所有的配置甚至通過Docker下載Jenkins鏡像、slave鏡像,以及啟動Jenkins都寫到了Ansible中,所以跑完vagrant up需要較長時間

啟動、執行順序

基本是按Vagrant的配置文件的上下順序來啟動的。具體順序如下:

  1. 按Vagrantfile安裝並啟動Nginx虛擬機
  2. 執行Nginx虛擬機依賴的provision模塊
  3. 按Vagrantfile安裝並啟動Jenkins虛擬機
  4. 執行Jenkins虛擬機依賴的provision模塊

Jenkins訪問Nginx(選修,建議有時間或者將Jenkins搭建完成之後再看)

如果你能把所有環境啟動起來並能訪問Jenkins主頁,但此時你還無法在Jenkins上直接ssh登錄到Nginx,因為此時兩臺機器還沒有互信。但是幸運的是Vagrant啟動完Nginx之後就已經將私鑰(可以拿這個私鑰去訪問Nginx,無論你是誰)放到了宿主機上,那麼你可以手動將這個私鑰複製到Jenkins中,然後就可以在Jenkins中訪問Nginx了。

但是為了自動化上面的操作,進行以下的配置:Vagrant會在啟動一個虛擬機之後,會在Mac上創建.vagrant文件夾並把一些關於這個虛擬機的文件放到裡面,比如該虛擬機的私鑰,後面可以拿到這私鑰作為SSH聯絡的key。

比如下面這段配置會在Nginx虛擬機啟動之後,Jenkins虛擬機啟動之前執行。由於Jenkins虛擬機需要在部署代碼的時候使用到Nginx虛擬機的私鑰來部署,所以需要在Jenkins虛擬機執行Ansible之前將私鑰放到Jenkins的file文件夾中。

手把手教你從零搭建一個持續集成環境

另外,在Vagrantfile中,Ansible不是與兩臺虛擬機的配置寫在一起的,那麼Ansible如何判斷在哪臺虛擬機上安裝Nginx還是Jenkins呢?因為不同的虛擬機要執行Ansible的時候會根據主機名匹配來找到對應role的tasks從而還是能找到匹配的tasks。換句話說,Nginx安裝完成之後Vagrant攜帶Nginx相關參數執行下面這樣的一行命令來用limit匹配主機與對應Ansible的tasks:

手把手教你從零搭建一個持續集成環境

我們需要Ansible

什麼是Ansible

Ansible是一種自動化部署工具,可以用來自動化管理配置項、持續交付、(AWS)雲服務管理;

簡單來說也就是可以批量的遠程服務器上執行一系列的命令,其原理是基於ssh來和遠程主機進行通信的。

為什麼用Ansible

  • playbook使用的是yml語言,易讀性較好;
  • 沒有主節點和代理,僅僅依賴於SSH,使得應用的部署簡單而輕量;
  • 提供了大量模塊支持Google Compute Engine (GCE), Amazon Web Service(AWS);
  • Ansible支持多臺服務器同時管理部署;

安裝Ansible

Ansible是基於python開發的,需要在安裝有python的機器下才能夠安裝Ansible

  • 在本機安裝python:brew install python(Mac自帶ython,因此這步可以省略,inux系統中需要安裝Python)
  • 安裝pip:sudo apt install python-pip
  • 安裝Ansible:sudo pip install ansible

目錄結構

你可以按如下目錄結構去編寫你的Ansible文件。

手把手教你從零搭建一個持續集成環境

roles文件夾

roles是基於一個Ansible默認的目錄結構,Ansible在執行任務的時候會去默認加載templates、tasks以及handlers文件夾中的文件等。我們基於roles 對內容進行分組,使得我們可以容易地將不同的環境(如Java與NodeJs)區分開來,本次Demo中的roles下有三個文件夾,分別是common、jenkins和nginx,其中每個文件夾下都會定義一些例如tasks任務與相關配置文件。

role - common

前面已經說過本次demo需要在本地啟動兩臺虛擬機,分別在內部裝上Docker,在common中我們定義了安裝Docker的task,這樣在定義Jenkins服務器和部署nginx的服務器中都可以調用該task來安裝配置Docker環境;

install_docker.yml中應該包含如下內容:

  • 安裝Docker
  • 安裝docker-compose工具
  • 安裝docker-py依賴包(如果我們想用Ansible的docker模塊去執行docker相關命令的話需要這個依賴)

role - jenkins

定義安裝和部署Jenkins服務器的task:其中docker-compose.yml配置文件,是用於分別對jenkins-master和jenkins_slave進行一些基本配置;task下的main.yml文件是配置一系列的安裝命令,類似於在命令行中一行行輸入安裝和部署命令;

role - nginx

與jenkins文件夾類似,對Nginx服務器的一些基本配置:例如Nginx配置文件default.conf,配置文件中定義了templates下的index.html作為Nginx的入口模版文件,使Nginx作為一個文件服務器。task下的main.yml文件則是與jenkins中類似,配置了安裝部署命令,在使用vagrant up時通過Ansible來安裝並運行Nginx服務。

配置文件

Ansible的配置文件包括但不僅限於ansible.cfg、deploy.yml以及hosts

ansible.cfg文件

如在本Demo中用到的幾個配置:

  • forks:設置在與主機通信時的默認並行進程數,默認值為5;
  • inventory:設置主機與組之間的對應關係,在Ansible1.9之前使用的是hostfile;
  • host_key_checking:檢測主機密鑰的功能,可以通過設置值為false來禁用該功能(跳過兩臺主機之間首次連接需要確認的過程);
  • nocows:設置其值為1時禁用調用一些cowsay的特性,cowsay是linux系統下一個在終端用ASCII碼組成的小牛,這個小牛會說出你想要它說的話。
  • gathering:控制默認的遠程系統變量(facts)收集,有三種不同的值;默認是implicit,即每一次play,變量都會被收集,除非設置gather_facts: False;為explicit時,則facts不會被收集;為smart時,則沒有facts的新hosts將不會被掃描,用於節省fact收集;
  • fact_caching_timeout:定義fact緩存超時時間;
  • fact_caching:定義fact的緩存,2.4版本的Ansible支持redis和jsonfile兩種格式的緩存文件;
  • fact_caching_connection:定義cache的存儲位置,根據cache文件的格式不同定義的方式不同;

deploy.yml文件

這是Ansible的入口配置文件:定義hosts主機、以及相應主機需要執行的tasks等;

"

本文將帶領你從0開始,用Vagrant + Docker + Ansible + Jenkins + Nginx + GitHub等工具和資源來搭建一條可執行可擴展的持續集成流水線,即使這些名字你都沒聽過也沒關係,本文將會在需要的時候一一解釋給你聽。

By: 巧穎 & 天一

總覽

這是我們將要搭建的所有基礎設施的總體架構圖,我們將在本文中手把手教你搭建這樣一個持續集成環境。

手把手教你從零搭建一個持續集成環境

我們會在本地啟動兩臺虛擬機,一臺部署Nginx作為靜態文件服務器,一臺作為Jenkins服務器,在每臺虛擬機內部安裝Docker,使用Docker來完成Nginx與Jenkins的搭建、配置,然後手動在Jenkins配置內配置好一條Pipeline作為持續集成流水線,最後嘗試提交一次代碼去觸發一次持續集成操作,將最新的html項目代碼從Github上部署到Nginx中,實現持續集成。

避免本文過長,部分源代碼沒有貼在文中,本文參考完成源代碼在此:https://github.com/tw-wh-devops-community/cooking-chicken.git。建議在自己嘗試從0開始搭建的同時參考源碼閱讀本文。相信你一定會碰到很多坑,但坑外便是晴天。

首先我們需要兩臺機器

我們需要Vagrant

為什麼呢

無論你用的操作系統是Windows、Mac還是Linux,Oracle的Virtual Box都支持,那麼我們首先會使用Virtual Box來建立一個在硬件上絕對隔離的環境出來。

那麼Vagrant就是通過方便的命令操作來簡化Virtual Box的操作,同時提供了方便的虛擬機配置模塊,所以我們會使用這個工具來提升虛擬機的配置效率。

安裝Vagrant

在Mac上是自帶Virtual Box的,你用的版本可能需要更新才能配合Vagrant使用,Linux上請使用類似sudo apt-get install virtualbox的命令安裝。

那麼先裝上Vagrant吧:

  • Mac(https://www.vagrantup.com/downloads.html)
  • Ubuntu(sudo apt-get install vagrant)

安裝Vagrant插件

由於後續操作會涉及到將Nginx機器的私鑰發送給Jenkins機器來配置私鑰來完成虛擬機之間的無密碼訪問。但私鑰是在Nginx虛擬機創建之後才會由Vagrant創建的,所以需要在這個時間節點放到Jenkins目錄下便於Ansible把私鑰放到Jenkins虛擬機中。如果暫時不理解沒有關係,請看完”開始創建世界“之後回頭來看就會明白。

Vagrant的provision模塊可以在虛擬機啟動之後在虛擬機內部執行任意腳本,但是provision模塊並沒有提供執行宿主機上腳本的方式,所以需要你安裝如下模塊:

vagrant plugin install vagrant-host-shell

調試的時候比較有用的操作

  • 進入虛擬機:vagrant ssh
  • 休眠:vagrant suspend
  • 從休眠中恢復:vagrant resume
  • 移除虛擬機所有文件:vagrant destroy

開始創建世界!

Vagrantfile

我們來新建一個工程,在根目錄創建一個名為Vagrantfile的文件,內容如下:

手把手教你從零搭建一個持續集成環境

那麼現在可以啟動了,在命令行內跳轉到根目錄,使用vagrant up就可以將虛擬機按上面的配置啟動了,同時在啟動完成之後會調用provision模塊跑Ansible的對應腳本安裝配置虛擬機的依賴工具。啟動完成之後,那麼一個隔離的環境創建完畢,接下來我們可以在裡面任意玩耍了。

特別注意:因為第一次運行需要下載ubuntu/trusty64鏡像,以及把所有的配置甚至通過Docker下載Jenkins鏡像、slave鏡像,以及啟動Jenkins都寫到了Ansible中,所以跑完vagrant up需要較長時間

啟動、執行順序

基本是按Vagrant的配置文件的上下順序來啟動的。具體順序如下:

  1. 按Vagrantfile安裝並啟動Nginx虛擬機
  2. 執行Nginx虛擬機依賴的provision模塊
  3. 按Vagrantfile安裝並啟動Jenkins虛擬機
  4. 執行Jenkins虛擬機依賴的provision模塊

Jenkins訪問Nginx(選修,建議有時間或者將Jenkins搭建完成之後再看)

如果你能把所有環境啟動起來並能訪問Jenkins主頁,但此時你還無法在Jenkins上直接ssh登錄到Nginx,因為此時兩臺機器還沒有互信。但是幸運的是Vagrant啟動完Nginx之後就已經將私鑰(可以拿這個私鑰去訪問Nginx,無論你是誰)放到了宿主機上,那麼你可以手動將這個私鑰複製到Jenkins中,然後就可以在Jenkins中訪問Nginx了。

但是為了自動化上面的操作,進行以下的配置:Vagrant會在啟動一個虛擬機之後,會在Mac上創建.vagrant文件夾並把一些關於這個虛擬機的文件放到裡面,比如該虛擬機的私鑰,後面可以拿到這私鑰作為SSH聯絡的key。

比如下面這段配置會在Nginx虛擬機啟動之後,Jenkins虛擬機啟動之前執行。由於Jenkins虛擬機需要在部署代碼的時候使用到Nginx虛擬機的私鑰來部署,所以需要在Jenkins虛擬機執行Ansible之前將私鑰放到Jenkins的file文件夾中。

手把手教你從零搭建一個持續集成環境

另外,在Vagrantfile中,Ansible不是與兩臺虛擬機的配置寫在一起的,那麼Ansible如何判斷在哪臺虛擬機上安裝Nginx還是Jenkins呢?因為不同的虛擬機要執行Ansible的時候會根據主機名匹配來找到對應role的tasks從而還是能找到匹配的tasks。換句話說,Nginx安裝完成之後Vagrant攜帶Nginx相關參數執行下面這樣的一行命令來用limit匹配主機與對應Ansible的tasks:

手把手教你從零搭建一個持續集成環境

我們需要Ansible

什麼是Ansible

Ansible是一種自動化部署工具,可以用來自動化管理配置項、持續交付、(AWS)雲服務管理;

簡單來說也就是可以批量的遠程服務器上執行一系列的命令,其原理是基於ssh來和遠程主機進行通信的。

為什麼用Ansible

  • playbook使用的是yml語言,易讀性較好;
  • 沒有主節點和代理,僅僅依賴於SSH,使得應用的部署簡單而輕量;
  • 提供了大量模塊支持Google Compute Engine (GCE), Amazon Web Service(AWS);
  • Ansible支持多臺服務器同時管理部署;

安裝Ansible

Ansible是基於python開發的,需要在安裝有python的機器下才能夠安裝Ansible

  • 在本機安裝python:brew install python(Mac自帶ython,因此這步可以省略,inux系統中需要安裝Python)
  • 安裝pip:sudo apt install python-pip
  • 安裝Ansible:sudo pip install ansible

目錄結構

你可以按如下目錄結構去編寫你的Ansible文件。

手把手教你從零搭建一個持續集成環境

roles文件夾

roles是基於一個Ansible默認的目錄結構,Ansible在執行任務的時候會去默認加載templates、tasks以及handlers文件夾中的文件等。我們基於roles 對內容進行分組,使得我們可以容易地將不同的環境(如Java與NodeJs)區分開來,本次Demo中的roles下有三個文件夾,分別是common、jenkins和nginx,其中每個文件夾下都會定義一些例如tasks任務與相關配置文件。

role - common

前面已經說過本次demo需要在本地啟動兩臺虛擬機,分別在內部裝上Docker,在common中我們定義了安裝Docker的task,這樣在定義Jenkins服務器和部署nginx的服務器中都可以調用該task來安裝配置Docker環境;

install_docker.yml中應該包含如下內容:

  • 安裝Docker
  • 安裝docker-compose工具
  • 安裝docker-py依賴包(如果我們想用Ansible的docker模塊去執行docker相關命令的話需要這個依賴)

role - jenkins

定義安裝和部署Jenkins服務器的task:其中docker-compose.yml配置文件,是用於分別對jenkins-master和jenkins_slave進行一些基本配置;task下的main.yml文件是配置一系列的安裝命令,類似於在命令行中一行行輸入安裝和部署命令;

role - nginx

與jenkins文件夾類似,對Nginx服務器的一些基本配置:例如Nginx配置文件default.conf,配置文件中定義了templates下的index.html作為Nginx的入口模版文件,使Nginx作為一個文件服務器。task下的main.yml文件則是與jenkins中類似,配置了安裝部署命令,在使用vagrant up時通過Ansible來安裝並運行Nginx服務。

配置文件

Ansible的配置文件包括但不僅限於ansible.cfg、deploy.yml以及hosts

ansible.cfg文件

如在本Demo中用到的幾個配置:

  • forks:設置在與主機通信時的默認並行進程數,默認值為5;
  • inventory:設置主機與組之間的對應關係,在Ansible1.9之前使用的是hostfile;
  • host_key_checking:檢測主機密鑰的功能,可以通過設置值為false來禁用該功能(跳過兩臺主機之間首次連接需要確認的過程);
  • nocows:設置其值為1時禁用調用一些cowsay的特性,cowsay是linux系統下一個在終端用ASCII碼組成的小牛,這個小牛會說出你想要它說的話。
  • gathering:控制默認的遠程系統變量(facts)收集,有三種不同的值;默認是implicit,即每一次play,變量都會被收集,除非設置gather_facts: False;為explicit時,則facts不會被收集;為smart時,則沒有facts的新hosts將不會被掃描,用於節省fact收集;
  • fact_caching_timeout:定義fact緩存超時時間;
  • fact_caching:定義fact的緩存,2.4版本的Ansible支持redis和jsonfile兩種格式的緩存文件;
  • fact_caching_connection:定義cache的存儲位置,根據cache文件的格式不同定義的方式不同;

deploy.yml文件

這是Ansible的入口配置文件:定義hosts主機、以及相應主機需要執行的tasks等;

手把手教你從零搭建一個持續集成環境

hosts

然後加上遠程主機的網絡相關配置,這樣Ansible才能通過SSH到虛擬機中執行你寫的任務喲。

以如下命令為例,是為IP地址1192.168.56.102,端口號22的網絡地址設置一個別名nginx,且聲明其ssh private key文件的地址;

"

本文將帶領你從0開始,用Vagrant + Docker + Ansible + Jenkins + Nginx + GitHub等工具和資源來搭建一條可執行可擴展的持續集成流水線,即使這些名字你都沒聽過也沒關係,本文將會在需要的時候一一解釋給你聽。

By: 巧穎 & 天一

總覽

這是我們將要搭建的所有基礎設施的總體架構圖,我們將在本文中手把手教你搭建這樣一個持續集成環境。

手把手教你從零搭建一個持續集成環境

我們會在本地啟動兩臺虛擬機,一臺部署Nginx作為靜態文件服務器,一臺作為Jenkins服務器,在每臺虛擬機內部安裝Docker,使用Docker來完成Nginx與Jenkins的搭建、配置,然後手動在Jenkins配置內配置好一條Pipeline作為持續集成流水線,最後嘗試提交一次代碼去觸發一次持續集成操作,將最新的html項目代碼從Github上部署到Nginx中,實現持續集成。

避免本文過長,部分源代碼沒有貼在文中,本文參考完成源代碼在此:https://github.com/tw-wh-devops-community/cooking-chicken.git。建議在自己嘗試從0開始搭建的同時參考源碼閱讀本文。相信你一定會碰到很多坑,但坑外便是晴天。

首先我們需要兩臺機器

我們需要Vagrant

為什麼呢

無論你用的操作系統是Windows、Mac還是Linux,Oracle的Virtual Box都支持,那麼我們首先會使用Virtual Box來建立一個在硬件上絕對隔離的環境出來。

那麼Vagrant就是通過方便的命令操作來簡化Virtual Box的操作,同時提供了方便的虛擬機配置模塊,所以我們會使用這個工具來提升虛擬機的配置效率。

安裝Vagrant

在Mac上是自帶Virtual Box的,你用的版本可能需要更新才能配合Vagrant使用,Linux上請使用類似sudo apt-get install virtualbox的命令安裝。

那麼先裝上Vagrant吧:

  • Mac(https://www.vagrantup.com/downloads.html)
  • Ubuntu(sudo apt-get install vagrant)

安裝Vagrant插件

由於後續操作會涉及到將Nginx機器的私鑰發送給Jenkins機器來配置私鑰來完成虛擬機之間的無密碼訪問。但私鑰是在Nginx虛擬機創建之後才會由Vagrant創建的,所以需要在這個時間節點放到Jenkins目錄下便於Ansible把私鑰放到Jenkins虛擬機中。如果暫時不理解沒有關係,請看完”開始創建世界“之後回頭來看就會明白。

Vagrant的provision模塊可以在虛擬機啟動之後在虛擬機內部執行任意腳本,但是provision模塊並沒有提供執行宿主機上腳本的方式,所以需要你安裝如下模塊:

vagrant plugin install vagrant-host-shell

調試的時候比較有用的操作

  • 進入虛擬機:vagrant ssh
  • 休眠:vagrant suspend
  • 從休眠中恢復:vagrant resume
  • 移除虛擬機所有文件:vagrant destroy

開始創建世界!

Vagrantfile

我們來新建一個工程,在根目錄創建一個名為Vagrantfile的文件,內容如下:

手把手教你從零搭建一個持續集成環境

那麼現在可以啟動了,在命令行內跳轉到根目錄,使用vagrant up就可以將虛擬機按上面的配置啟動了,同時在啟動完成之後會調用provision模塊跑Ansible的對應腳本安裝配置虛擬機的依賴工具。啟動完成之後,那麼一個隔離的環境創建完畢,接下來我們可以在裡面任意玩耍了。

特別注意:因為第一次運行需要下載ubuntu/trusty64鏡像,以及把所有的配置甚至通過Docker下載Jenkins鏡像、slave鏡像,以及啟動Jenkins都寫到了Ansible中,所以跑完vagrant up需要較長時間

啟動、執行順序

基本是按Vagrant的配置文件的上下順序來啟動的。具體順序如下:

  1. 按Vagrantfile安裝並啟動Nginx虛擬機
  2. 執行Nginx虛擬機依賴的provision模塊
  3. 按Vagrantfile安裝並啟動Jenkins虛擬機
  4. 執行Jenkins虛擬機依賴的provision模塊

Jenkins訪問Nginx(選修,建議有時間或者將Jenkins搭建完成之後再看)

如果你能把所有環境啟動起來並能訪問Jenkins主頁,但此時你還無法在Jenkins上直接ssh登錄到Nginx,因為此時兩臺機器還沒有互信。但是幸運的是Vagrant啟動完Nginx之後就已經將私鑰(可以拿這個私鑰去訪問Nginx,無論你是誰)放到了宿主機上,那麼你可以手動將這個私鑰複製到Jenkins中,然後就可以在Jenkins中訪問Nginx了。

但是為了自動化上面的操作,進行以下的配置:Vagrant會在啟動一個虛擬機之後,會在Mac上創建.vagrant文件夾並把一些關於這個虛擬機的文件放到裡面,比如該虛擬機的私鑰,後面可以拿到這私鑰作為SSH聯絡的key。

比如下面這段配置會在Nginx虛擬機啟動之後,Jenkins虛擬機啟動之前執行。由於Jenkins虛擬機需要在部署代碼的時候使用到Nginx虛擬機的私鑰來部署,所以需要在Jenkins虛擬機執行Ansible之前將私鑰放到Jenkins的file文件夾中。

手把手教你從零搭建一個持續集成環境

另外,在Vagrantfile中,Ansible不是與兩臺虛擬機的配置寫在一起的,那麼Ansible如何判斷在哪臺虛擬機上安裝Nginx還是Jenkins呢?因為不同的虛擬機要執行Ansible的時候會根據主機名匹配來找到對應role的tasks從而還是能找到匹配的tasks。換句話說,Nginx安裝完成之後Vagrant攜帶Nginx相關參數執行下面這樣的一行命令來用limit匹配主機與對應Ansible的tasks:

手把手教你從零搭建一個持續集成環境

我們需要Ansible

什麼是Ansible

Ansible是一種自動化部署工具,可以用來自動化管理配置項、持續交付、(AWS)雲服務管理;

簡單來說也就是可以批量的遠程服務器上執行一系列的命令,其原理是基於ssh來和遠程主機進行通信的。

為什麼用Ansible

  • playbook使用的是yml語言,易讀性較好;
  • 沒有主節點和代理,僅僅依賴於SSH,使得應用的部署簡單而輕量;
  • 提供了大量模塊支持Google Compute Engine (GCE), Amazon Web Service(AWS);
  • Ansible支持多臺服務器同時管理部署;

安裝Ansible

Ansible是基於python開發的,需要在安裝有python的機器下才能夠安裝Ansible

  • 在本機安裝python:brew install python(Mac自帶ython,因此這步可以省略,inux系統中需要安裝Python)
  • 安裝pip:sudo apt install python-pip
  • 安裝Ansible:sudo pip install ansible

目錄結構

你可以按如下目錄結構去編寫你的Ansible文件。

手把手教你從零搭建一個持續集成環境

roles文件夾

roles是基於一個Ansible默認的目錄結構,Ansible在執行任務的時候會去默認加載templates、tasks以及handlers文件夾中的文件等。我們基於roles 對內容進行分組,使得我們可以容易地將不同的環境(如Java與NodeJs)區分開來,本次Demo中的roles下有三個文件夾,分別是common、jenkins和nginx,其中每個文件夾下都會定義一些例如tasks任務與相關配置文件。

role - common

前面已經說過本次demo需要在本地啟動兩臺虛擬機,分別在內部裝上Docker,在common中我們定義了安裝Docker的task,這樣在定義Jenkins服務器和部署nginx的服務器中都可以調用該task來安裝配置Docker環境;

install_docker.yml中應該包含如下內容:

  • 安裝Docker
  • 安裝docker-compose工具
  • 安裝docker-py依賴包(如果我們想用Ansible的docker模塊去執行docker相關命令的話需要這個依賴)

role - jenkins

定義安裝和部署Jenkins服務器的task:其中docker-compose.yml配置文件,是用於分別對jenkins-master和jenkins_slave進行一些基本配置;task下的main.yml文件是配置一系列的安裝命令,類似於在命令行中一行行輸入安裝和部署命令;

role - nginx

與jenkins文件夾類似,對Nginx服務器的一些基本配置:例如Nginx配置文件default.conf,配置文件中定義了templates下的index.html作為Nginx的入口模版文件,使Nginx作為一個文件服務器。task下的main.yml文件則是與jenkins中類似,配置了安裝部署命令,在使用vagrant up時通過Ansible來安裝並運行Nginx服務。

配置文件

Ansible的配置文件包括但不僅限於ansible.cfg、deploy.yml以及hosts

ansible.cfg文件

如在本Demo中用到的幾個配置:

  • forks:設置在與主機通信時的默認並行進程數,默認值為5;
  • inventory:設置主機與組之間的對應關係,在Ansible1.9之前使用的是hostfile;
  • host_key_checking:檢測主機密鑰的功能,可以通過設置值為false來禁用該功能(跳過兩臺主機之間首次連接需要確認的過程);
  • nocows:設置其值為1時禁用調用一些cowsay的特性,cowsay是linux系統下一個在終端用ASCII碼組成的小牛,這個小牛會說出你想要它說的話。
  • gathering:控制默認的遠程系統變量(facts)收集,有三種不同的值;默認是implicit,即每一次play,變量都會被收集,除非設置gather_facts: False;為explicit時,則facts不會被收集;為smart時,則沒有facts的新hosts將不會被掃描,用於節省fact收集;
  • fact_caching_timeout:定義fact緩存超時時間;
  • fact_caching:定義fact的緩存,2.4版本的Ansible支持redis和jsonfile兩種格式的緩存文件;
  • fact_caching_connection:定義cache的存儲位置,根據cache文件的格式不同定義的方式不同;

deploy.yml文件

這是Ansible的入口配置文件:定義hosts主機、以及相應主機需要執行的tasks等;

手把手教你從零搭建一個持續集成環境

hosts

然後加上遠程主機的網絡相關配置,這樣Ansible才能通過SSH到虛擬機中執行你寫的任務喲。

以如下命令為例,是為IP地址1192.168.56.102,端口號22的網絡地址設置一個別名nginx,且聲明其ssh private key文件的地址;

手把手教你從零搭建一個持續集成環境

與Vagrant結合

現在,Ansible的任務已經寫完了,我們需要將Ansible與Vagrant結合,將如下代碼加入到Vagrantfile中,可以在執行vagrant up的時候執行Ansible。

"

本文將帶領你從0開始,用Vagrant + Docker + Ansible + Jenkins + Nginx + GitHub等工具和資源來搭建一條可執行可擴展的持續集成流水線,即使這些名字你都沒聽過也沒關係,本文將會在需要的時候一一解釋給你聽。

By: 巧穎 & 天一

總覽

這是我們將要搭建的所有基礎設施的總體架構圖,我們將在本文中手把手教你搭建這樣一個持續集成環境。

手把手教你從零搭建一個持續集成環境

我們會在本地啟動兩臺虛擬機,一臺部署Nginx作為靜態文件服務器,一臺作為Jenkins服務器,在每臺虛擬機內部安裝Docker,使用Docker來完成Nginx與Jenkins的搭建、配置,然後手動在Jenkins配置內配置好一條Pipeline作為持續集成流水線,最後嘗試提交一次代碼去觸發一次持續集成操作,將最新的html項目代碼從Github上部署到Nginx中,實現持續集成。

避免本文過長,部分源代碼沒有貼在文中,本文參考完成源代碼在此:https://github.com/tw-wh-devops-community/cooking-chicken.git。建議在自己嘗試從0開始搭建的同時參考源碼閱讀本文。相信你一定會碰到很多坑,但坑外便是晴天。

首先我們需要兩臺機器

我們需要Vagrant

為什麼呢

無論你用的操作系統是Windows、Mac還是Linux,Oracle的Virtual Box都支持,那麼我們首先會使用Virtual Box來建立一個在硬件上絕對隔離的環境出來。

那麼Vagrant就是通過方便的命令操作來簡化Virtual Box的操作,同時提供了方便的虛擬機配置模塊,所以我們會使用這個工具來提升虛擬機的配置效率。

安裝Vagrant

在Mac上是自帶Virtual Box的,你用的版本可能需要更新才能配合Vagrant使用,Linux上請使用類似sudo apt-get install virtualbox的命令安裝。

那麼先裝上Vagrant吧:

  • Mac(https://www.vagrantup.com/downloads.html)
  • Ubuntu(sudo apt-get install vagrant)

安裝Vagrant插件

由於後續操作會涉及到將Nginx機器的私鑰發送給Jenkins機器來配置私鑰來完成虛擬機之間的無密碼訪問。但私鑰是在Nginx虛擬機創建之後才會由Vagrant創建的,所以需要在這個時間節點放到Jenkins目錄下便於Ansible把私鑰放到Jenkins虛擬機中。如果暫時不理解沒有關係,請看完”開始創建世界“之後回頭來看就會明白。

Vagrant的provision模塊可以在虛擬機啟動之後在虛擬機內部執行任意腳本,但是provision模塊並沒有提供執行宿主機上腳本的方式,所以需要你安裝如下模塊:

vagrant plugin install vagrant-host-shell

調試的時候比較有用的操作

  • 進入虛擬機:vagrant ssh
  • 休眠:vagrant suspend
  • 從休眠中恢復:vagrant resume
  • 移除虛擬機所有文件:vagrant destroy

開始創建世界!

Vagrantfile

我們來新建一個工程,在根目錄創建一個名為Vagrantfile的文件,內容如下:

手把手教你從零搭建一個持續集成環境

那麼現在可以啟動了,在命令行內跳轉到根目錄,使用vagrant up就可以將虛擬機按上面的配置啟動了,同時在啟動完成之後會調用provision模塊跑Ansible的對應腳本安裝配置虛擬機的依賴工具。啟動完成之後,那麼一個隔離的環境創建完畢,接下來我們可以在裡面任意玩耍了。

特別注意:因為第一次運行需要下載ubuntu/trusty64鏡像,以及把所有的配置甚至通過Docker下載Jenkins鏡像、slave鏡像,以及啟動Jenkins都寫到了Ansible中,所以跑完vagrant up需要較長時間

啟動、執行順序

基本是按Vagrant的配置文件的上下順序來啟動的。具體順序如下:

  1. 按Vagrantfile安裝並啟動Nginx虛擬機
  2. 執行Nginx虛擬機依賴的provision模塊
  3. 按Vagrantfile安裝並啟動Jenkins虛擬機
  4. 執行Jenkins虛擬機依賴的provision模塊

Jenkins訪問Nginx(選修,建議有時間或者將Jenkins搭建完成之後再看)

如果你能把所有環境啟動起來並能訪問Jenkins主頁,但此時你還無法在Jenkins上直接ssh登錄到Nginx,因為此時兩臺機器還沒有互信。但是幸運的是Vagrant啟動完Nginx之後就已經將私鑰(可以拿這個私鑰去訪問Nginx,無論你是誰)放到了宿主機上,那麼你可以手動將這個私鑰複製到Jenkins中,然後就可以在Jenkins中訪問Nginx了。

但是為了自動化上面的操作,進行以下的配置:Vagrant會在啟動一個虛擬機之後,會在Mac上創建.vagrant文件夾並把一些關於這個虛擬機的文件放到裡面,比如該虛擬機的私鑰,後面可以拿到這私鑰作為SSH聯絡的key。

比如下面這段配置會在Nginx虛擬機啟動之後,Jenkins虛擬機啟動之前執行。由於Jenkins虛擬機需要在部署代碼的時候使用到Nginx虛擬機的私鑰來部署,所以需要在Jenkins虛擬機執行Ansible之前將私鑰放到Jenkins的file文件夾中。

手把手教你從零搭建一個持續集成環境

另外,在Vagrantfile中,Ansible不是與兩臺虛擬機的配置寫在一起的,那麼Ansible如何判斷在哪臺虛擬機上安裝Nginx還是Jenkins呢?因為不同的虛擬機要執行Ansible的時候會根據主機名匹配來找到對應role的tasks從而還是能找到匹配的tasks。換句話說,Nginx安裝完成之後Vagrant攜帶Nginx相關參數執行下面這樣的一行命令來用limit匹配主機與對應Ansible的tasks:

手把手教你從零搭建一個持續集成環境

我們需要Ansible

什麼是Ansible

Ansible是一種自動化部署工具,可以用來自動化管理配置項、持續交付、(AWS)雲服務管理;

簡單來說也就是可以批量的遠程服務器上執行一系列的命令,其原理是基於ssh來和遠程主機進行通信的。

為什麼用Ansible

  • playbook使用的是yml語言,易讀性較好;
  • 沒有主節點和代理,僅僅依賴於SSH,使得應用的部署簡單而輕量;
  • 提供了大量模塊支持Google Compute Engine (GCE), Amazon Web Service(AWS);
  • Ansible支持多臺服務器同時管理部署;

安裝Ansible

Ansible是基於python開發的,需要在安裝有python的機器下才能夠安裝Ansible

  • 在本機安裝python:brew install python(Mac自帶ython,因此這步可以省略,inux系統中需要安裝Python)
  • 安裝pip:sudo apt install python-pip
  • 安裝Ansible:sudo pip install ansible

目錄結構

你可以按如下目錄結構去編寫你的Ansible文件。

手把手教你從零搭建一個持續集成環境

roles文件夾

roles是基於一個Ansible默認的目錄結構,Ansible在執行任務的時候會去默認加載templates、tasks以及handlers文件夾中的文件等。我們基於roles 對內容進行分組,使得我們可以容易地將不同的環境(如Java與NodeJs)區分開來,本次Demo中的roles下有三個文件夾,分別是common、jenkins和nginx,其中每個文件夾下都會定義一些例如tasks任務與相關配置文件。

role - common

前面已經說過本次demo需要在本地啟動兩臺虛擬機,分別在內部裝上Docker,在common中我們定義了安裝Docker的task,這樣在定義Jenkins服務器和部署nginx的服務器中都可以調用該task來安裝配置Docker環境;

install_docker.yml中應該包含如下內容:

  • 安裝Docker
  • 安裝docker-compose工具
  • 安裝docker-py依賴包(如果我們想用Ansible的docker模塊去執行docker相關命令的話需要這個依賴)

role - jenkins

定義安裝和部署Jenkins服務器的task:其中docker-compose.yml配置文件,是用於分別對jenkins-master和jenkins_slave進行一些基本配置;task下的main.yml文件是配置一系列的安裝命令,類似於在命令行中一行行輸入安裝和部署命令;

role - nginx

與jenkins文件夾類似,對Nginx服務器的一些基本配置:例如Nginx配置文件default.conf,配置文件中定義了templates下的index.html作為Nginx的入口模版文件,使Nginx作為一個文件服務器。task下的main.yml文件則是與jenkins中類似,配置了安裝部署命令,在使用vagrant up時通過Ansible來安裝並運行Nginx服務。

配置文件

Ansible的配置文件包括但不僅限於ansible.cfg、deploy.yml以及hosts

ansible.cfg文件

如在本Demo中用到的幾個配置:

  • forks:設置在與主機通信時的默認並行進程數,默認值為5;
  • inventory:設置主機與組之間的對應關係,在Ansible1.9之前使用的是hostfile;
  • host_key_checking:檢測主機密鑰的功能,可以通過設置值為false來禁用該功能(跳過兩臺主機之間首次連接需要確認的過程);
  • nocows:設置其值為1時禁用調用一些cowsay的特性,cowsay是linux系統下一個在終端用ASCII碼組成的小牛,這個小牛會說出你想要它說的話。
  • gathering:控制默認的遠程系統變量(facts)收集,有三種不同的值;默認是implicit,即每一次play,變量都會被收集,除非設置gather_facts: False;為explicit時,則facts不會被收集;為smart時,則沒有facts的新hosts將不會被掃描,用於節省fact收集;
  • fact_caching_timeout:定義fact緩存超時時間;
  • fact_caching:定義fact的緩存,2.4版本的Ansible支持redis和jsonfile兩種格式的緩存文件;
  • fact_caching_connection:定義cache的存儲位置,根據cache文件的格式不同定義的方式不同;

deploy.yml文件

這是Ansible的入口配置文件:定義hosts主機、以及相應主機需要執行的tasks等;

手把手教你從零搭建一個持續集成環境

hosts

然後加上遠程主機的網絡相關配置,這樣Ansible才能通過SSH到虛擬機中執行你寫的任務喲。

以如下命令為例,是為IP地址1192.168.56.102,端口號22的網絡地址設置一個別名nginx,且聲明其ssh private key文件的地址;

手把手教你從零搭建一個持續集成環境

與Vagrant結合

現在,Ansible的任務已經寫完了,我們需要將Ansible與Vagrant結合,將如下代碼加入到Vagrantfile中,可以在執行vagrant up的時候執行Ansible。

手把手教你從零搭建一個持續集成環境

虛擬機中的世界是如何構成的呢

現在你已經將所有的環境部署完成了,但是部署應用(Jenkins、Nginx)的過程還沒有提及,下面將帶你從Ansbile的對於每個虛擬機的任務開始,介紹相應的工具與具體的實施步驟。

Docker

什麼是Docker

Docker是一個開源的容器應用引擎,可以理解為一個存放應用容器的平臺,我們只需要簡單的幾行命令就可以構建一個與本地環境相對隔離的環境來運行我們的應用而不影響任何角色;

基本要素:

  • Container:負責應用程序的運行,包括操作系統、用戶添加的文件以及元數據
  • Images:只讀模版,即常說的Docker鏡像,用來運行Docker容器
  • Dockerfile:文件指令集,用來說明如何創建Docker鏡像

為什麼要用Docker

把一個應用封裝起來,可以在任何裝有Docker的環境下運行,統一運行環境;

那個大鯨魚(或者是貨輪)就是操作系統,把要交付的應用程序看成是各種貨物,原本要將各種各樣形狀、尺寸不同的貨物放到大鯨魚上,你得為每件貨物考慮怎麼安放(就是應用程序配套的環境),還得考慮貨物和貨物是否能疊起來(應用程序依賴的環境是否會衝突)。

現在使用了集裝箱(容器)把每件貨物都放到集裝箱裡,這樣大鯨魚可以用同樣地方式安放、堆疊集裝了,省事省力。

Docker中常用的命令

"

本文將帶領你從0開始,用Vagrant + Docker + Ansible + Jenkins + Nginx + GitHub等工具和資源來搭建一條可執行可擴展的持續集成流水線,即使這些名字你都沒聽過也沒關係,本文將會在需要的時候一一解釋給你聽。

By: 巧穎 & 天一

總覽

這是我們將要搭建的所有基礎設施的總體架構圖,我們將在本文中手把手教你搭建這樣一個持續集成環境。

手把手教你從零搭建一個持續集成環境

我們會在本地啟動兩臺虛擬機,一臺部署Nginx作為靜態文件服務器,一臺作為Jenkins服務器,在每臺虛擬機內部安裝Docker,使用Docker來完成Nginx與Jenkins的搭建、配置,然後手動在Jenkins配置內配置好一條Pipeline作為持續集成流水線,最後嘗試提交一次代碼去觸發一次持續集成操作,將最新的html項目代碼從Github上部署到Nginx中,實現持續集成。

避免本文過長,部分源代碼沒有貼在文中,本文參考完成源代碼在此:https://github.com/tw-wh-devops-community/cooking-chicken.git。建議在自己嘗試從0開始搭建的同時參考源碼閱讀本文。相信你一定會碰到很多坑,但坑外便是晴天。

首先我們需要兩臺機器

我們需要Vagrant

為什麼呢

無論你用的操作系統是Windows、Mac還是Linux,Oracle的Virtual Box都支持,那麼我們首先會使用Virtual Box來建立一個在硬件上絕對隔離的環境出來。

那麼Vagrant就是通過方便的命令操作來簡化Virtual Box的操作,同時提供了方便的虛擬機配置模塊,所以我們會使用這個工具來提升虛擬機的配置效率。

安裝Vagrant

在Mac上是自帶Virtual Box的,你用的版本可能需要更新才能配合Vagrant使用,Linux上請使用類似sudo apt-get install virtualbox的命令安裝。

那麼先裝上Vagrant吧:

  • Mac(https://www.vagrantup.com/downloads.html)
  • Ubuntu(sudo apt-get install vagrant)

安裝Vagrant插件

由於後續操作會涉及到將Nginx機器的私鑰發送給Jenkins機器來配置私鑰來完成虛擬機之間的無密碼訪問。但私鑰是在Nginx虛擬機創建之後才會由Vagrant創建的,所以需要在這個時間節點放到Jenkins目錄下便於Ansible把私鑰放到Jenkins虛擬機中。如果暫時不理解沒有關係,請看完”開始創建世界“之後回頭來看就會明白。

Vagrant的provision模塊可以在虛擬機啟動之後在虛擬機內部執行任意腳本,但是provision模塊並沒有提供執行宿主機上腳本的方式,所以需要你安裝如下模塊:

vagrant plugin install vagrant-host-shell

調試的時候比較有用的操作

  • 進入虛擬機:vagrant ssh
  • 休眠:vagrant suspend
  • 從休眠中恢復:vagrant resume
  • 移除虛擬機所有文件:vagrant destroy

開始創建世界!

Vagrantfile

我們來新建一個工程,在根目錄創建一個名為Vagrantfile的文件,內容如下:

手把手教你從零搭建一個持續集成環境

那麼現在可以啟動了,在命令行內跳轉到根目錄,使用vagrant up就可以將虛擬機按上面的配置啟動了,同時在啟動完成之後會調用provision模塊跑Ansible的對應腳本安裝配置虛擬機的依賴工具。啟動完成之後,那麼一個隔離的環境創建完畢,接下來我們可以在裡面任意玩耍了。

特別注意:因為第一次運行需要下載ubuntu/trusty64鏡像,以及把所有的配置甚至通過Docker下載Jenkins鏡像、slave鏡像,以及啟動Jenkins都寫到了Ansible中,所以跑完vagrant up需要較長時間

啟動、執行順序

基本是按Vagrant的配置文件的上下順序來啟動的。具體順序如下:

  1. 按Vagrantfile安裝並啟動Nginx虛擬機
  2. 執行Nginx虛擬機依賴的provision模塊
  3. 按Vagrantfile安裝並啟動Jenkins虛擬機
  4. 執行Jenkins虛擬機依賴的provision模塊

Jenkins訪問Nginx(選修,建議有時間或者將Jenkins搭建完成之後再看)

如果你能把所有環境啟動起來並能訪問Jenkins主頁,但此時你還無法在Jenkins上直接ssh登錄到Nginx,因為此時兩臺機器還沒有互信。但是幸運的是Vagrant啟動完Nginx之後就已經將私鑰(可以拿這個私鑰去訪問Nginx,無論你是誰)放到了宿主機上,那麼你可以手動將這個私鑰複製到Jenkins中,然後就可以在Jenkins中訪問Nginx了。

但是為了自動化上面的操作,進行以下的配置:Vagrant會在啟動一個虛擬機之後,會在Mac上創建.vagrant文件夾並把一些關於這個虛擬機的文件放到裡面,比如該虛擬機的私鑰,後面可以拿到這私鑰作為SSH聯絡的key。

比如下面這段配置會在Nginx虛擬機啟動之後,Jenkins虛擬機啟動之前執行。由於Jenkins虛擬機需要在部署代碼的時候使用到Nginx虛擬機的私鑰來部署,所以需要在Jenkins虛擬機執行Ansible之前將私鑰放到Jenkins的file文件夾中。

手把手教你從零搭建一個持續集成環境

另外,在Vagrantfile中,Ansible不是與兩臺虛擬機的配置寫在一起的,那麼Ansible如何判斷在哪臺虛擬機上安裝Nginx還是Jenkins呢?因為不同的虛擬機要執行Ansible的時候會根據主機名匹配來找到對應role的tasks從而還是能找到匹配的tasks。換句話說,Nginx安裝完成之後Vagrant攜帶Nginx相關參數執行下面這樣的一行命令來用limit匹配主機與對應Ansible的tasks:

手把手教你從零搭建一個持續集成環境

我們需要Ansible

什麼是Ansible

Ansible是一種自動化部署工具,可以用來自動化管理配置項、持續交付、(AWS)雲服務管理;

簡單來說也就是可以批量的遠程服務器上執行一系列的命令,其原理是基於ssh來和遠程主機進行通信的。

為什麼用Ansible

  • playbook使用的是yml語言,易讀性較好;
  • 沒有主節點和代理,僅僅依賴於SSH,使得應用的部署簡單而輕量;
  • 提供了大量模塊支持Google Compute Engine (GCE), Amazon Web Service(AWS);
  • Ansible支持多臺服務器同時管理部署;

安裝Ansible

Ansible是基於python開發的,需要在安裝有python的機器下才能夠安裝Ansible

  • 在本機安裝python:brew install python(Mac自帶ython,因此這步可以省略,inux系統中需要安裝Python)
  • 安裝pip:sudo apt install python-pip
  • 安裝Ansible:sudo pip install ansible

目錄結構

你可以按如下目錄結構去編寫你的Ansible文件。

手把手教你從零搭建一個持續集成環境

roles文件夾

roles是基於一個Ansible默認的目錄結構,Ansible在執行任務的時候會去默認加載templates、tasks以及handlers文件夾中的文件等。我們基於roles 對內容進行分組,使得我們可以容易地將不同的環境(如Java與NodeJs)區分開來,本次Demo中的roles下有三個文件夾,分別是common、jenkins和nginx,其中每個文件夾下都會定義一些例如tasks任務與相關配置文件。

role - common

前面已經說過本次demo需要在本地啟動兩臺虛擬機,分別在內部裝上Docker,在common中我們定義了安裝Docker的task,這樣在定義Jenkins服務器和部署nginx的服務器中都可以調用該task來安裝配置Docker環境;

install_docker.yml中應該包含如下內容:

  • 安裝Docker
  • 安裝docker-compose工具
  • 安裝docker-py依賴包(如果我們想用Ansible的docker模塊去執行docker相關命令的話需要這個依賴)

role - jenkins

定義安裝和部署Jenkins服務器的task:其中docker-compose.yml配置文件,是用於分別對jenkins-master和jenkins_slave進行一些基本配置;task下的main.yml文件是配置一系列的安裝命令,類似於在命令行中一行行輸入安裝和部署命令;

role - nginx

與jenkins文件夾類似,對Nginx服務器的一些基本配置:例如Nginx配置文件default.conf,配置文件中定義了templates下的index.html作為Nginx的入口模版文件,使Nginx作為一個文件服務器。task下的main.yml文件則是與jenkins中類似,配置了安裝部署命令,在使用vagrant up時通過Ansible來安裝並運行Nginx服務。

配置文件

Ansible的配置文件包括但不僅限於ansible.cfg、deploy.yml以及hosts

ansible.cfg文件

如在本Demo中用到的幾個配置:

  • forks:設置在與主機通信時的默認並行進程數,默認值為5;
  • inventory:設置主機與組之間的對應關係,在Ansible1.9之前使用的是hostfile;
  • host_key_checking:檢測主機密鑰的功能,可以通過設置值為false來禁用該功能(跳過兩臺主機之間首次連接需要確認的過程);
  • nocows:設置其值為1時禁用調用一些cowsay的特性,cowsay是linux系統下一個在終端用ASCII碼組成的小牛,這個小牛會說出你想要它說的話。
  • gathering:控制默認的遠程系統變量(facts)收集,有三種不同的值;默認是implicit,即每一次play,變量都會被收集,除非設置gather_facts: False;為explicit時,則facts不會被收集;為smart時,則沒有facts的新hosts將不會被掃描,用於節省fact收集;
  • fact_caching_timeout:定義fact緩存超時時間;
  • fact_caching:定義fact的緩存,2.4版本的Ansible支持redis和jsonfile兩種格式的緩存文件;
  • fact_caching_connection:定義cache的存儲位置,根據cache文件的格式不同定義的方式不同;

deploy.yml文件

這是Ansible的入口配置文件:定義hosts主機、以及相應主機需要執行的tasks等;

手把手教你從零搭建一個持續集成環境

hosts

然後加上遠程主機的網絡相關配置,這樣Ansible才能通過SSH到虛擬機中執行你寫的任務喲。

以如下命令為例,是為IP地址1192.168.56.102,端口號22的網絡地址設置一個別名nginx,且聲明其ssh private key文件的地址;

手把手教你從零搭建一個持續集成環境

與Vagrant結合

現在,Ansible的任務已經寫完了,我們需要將Ansible與Vagrant結合,將如下代碼加入到Vagrantfile中,可以在執行vagrant up的時候執行Ansible。

手把手教你從零搭建一個持續集成環境

虛擬機中的世界是如何構成的呢

現在你已經將所有的環境部署完成了,但是部署應用(Jenkins、Nginx)的過程還沒有提及,下面將帶你從Ansbile的對於每個虛擬機的任務開始,介紹相應的工具與具體的實施步驟。

Docker

什麼是Docker

Docker是一個開源的容器應用引擎,可以理解為一個存放應用容器的平臺,我們只需要簡單的幾行命令就可以構建一個與本地環境相對隔離的環境來運行我們的應用而不影響任何角色;

基本要素:

  • Container:負責應用程序的運行,包括操作系統、用戶添加的文件以及元數據
  • Images:只讀模版,即常說的Docker鏡像,用來運行Docker容器
  • Dockerfile:文件指令集,用來說明如何創建Docker鏡像

為什麼要用Docker

把一個應用封裝起來,可以在任何裝有Docker的環境下運行,統一運行環境;

那個大鯨魚(或者是貨輪)就是操作系統,把要交付的應用程序看成是各種貨物,原本要將各種各樣形狀、尺寸不同的貨物放到大鯨魚上,你得為每件貨物考慮怎麼安放(就是應用程序配套的環境),還得考慮貨物和貨物是否能疊起來(應用程序依賴的環境是否會衝突)。

現在使用了集裝箱(容器)把每件貨物都放到集裝箱裡,這樣大鯨魚可以用同樣地方式安放、堆疊集裝了,省事省力。

Docker中常用的命令

手把手教你從零搭建一個持續集成環境

怎麼用

要注意的是,Ansible對應的任務是在Vagrant啟動虛擬機之後執行的,是在虛擬機的內部,Docker容器的外部

安裝Nginx:由於我們只需要啟動一個Nginx的容器,直接使用Docker中run的命令去repository中下載安裝即可

  • 準備文件,例如default.conf,index.html
  • ```
  • name: copy nginx config file
  • copy:
  • src: default.conf
  • dest: /data/nginx/default.conf
  • name: copy default html file
  • template:
  • src: index.html
  • dest: /data/nginx/html/index.html
  • owner: vagrant
  • group: vagrant
  • ```
  • 使用Ansible中提供的Docker模塊安裝Nginx,包括拉Docker images,設置ports,以及多久需要pull一次新代碼等
"

本文將帶領你從0開始,用Vagrant + Docker + Ansible + Jenkins + Nginx + GitHub等工具和資源來搭建一條可執行可擴展的持續集成流水線,即使這些名字你都沒聽過也沒關係,本文將會在需要的時候一一解釋給你聽。

By: 巧穎 & 天一

總覽

這是我們將要搭建的所有基礎設施的總體架構圖,我們將在本文中手把手教你搭建這樣一個持續集成環境。

手把手教你從零搭建一個持續集成環境

我們會在本地啟動兩臺虛擬機,一臺部署Nginx作為靜態文件服務器,一臺作為Jenkins服務器,在每臺虛擬機內部安裝Docker,使用Docker來完成Nginx與Jenkins的搭建、配置,然後手動在Jenkins配置內配置好一條Pipeline作為持續集成流水線,最後嘗試提交一次代碼去觸發一次持續集成操作,將最新的html項目代碼從Github上部署到Nginx中,實現持續集成。

避免本文過長,部分源代碼沒有貼在文中,本文參考完成源代碼在此:https://github.com/tw-wh-devops-community/cooking-chicken.git。建議在自己嘗試從0開始搭建的同時參考源碼閱讀本文。相信你一定會碰到很多坑,但坑外便是晴天。

首先我們需要兩臺機器

我們需要Vagrant

為什麼呢

無論你用的操作系統是Windows、Mac還是Linux,Oracle的Virtual Box都支持,那麼我們首先會使用Virtual Box來建立一個在硬件上絕對隔離的環境出來。

那麼Vagrant就是通過方便的命令操作來簡化Virtual Box的操作,同時提供了方便的虛擬機配置模塊,所以我們會使用這個工具來提升虛擬機的配置效率。

安裝Vagrant

在Mac上是自帶Virtual Box的,你用的版本可能需要更新才能配合Vagrant使用,Linux上請使用類似sudo apt-get install virtualbox的命令安裝。

那麼先裝上Vagrant吧:

  • Mac(https://www.vagrantup.com/downloads.html)
  • Ubuntu(sudo apt-get install vagrant)

安裝Vagrant插件

由於後續操作會涉及到將Nginx機器的私鑰發送給Jenkins機器來配置私鑰來完成虛擬機之間的無密碼訪問。但私鑰是在Nginx虛擬機創建之後才會由Vagrant創建的,所以需要在這個時間節點放到Jenkins目錄下便於Ansible把私鑰放到Jenkins虛擬機中。如果暫時不理解沒有關係,請看完”開始創建世界“之後回頭來看就會明白。

Vagrant的provision模塊可以在虛擬機啟動之後在虛擬機內部執行任意腳本,但是provision模塊並沒有提供執行宿主機上腳本的方式,所以需要你安裝如下模塊:

vagrant plugin install vagrant-host-shell

調試的時候比較有用的操作

  • 進入虛擬機:vagrant ssh
  • 休眠:vagrant suspend
  • 從休眠中恢復:vagrant resume
  • 移除虛擬機所有文件:vagrant destroy

開始創建世界!

Vagrantfile

我們來新建一個工程,在根目錄創建一個名為Vagrantfile的文件,內容如下:

手把手教你從零搭建一個持續集成環境

那麼現在可以啟動了,在命令行內跳轉到根目錄,使用vagrant up就可以將虛擬機按上面的配置啟動了,同時在啟動完成之後會調用provision模塊跑Ansible的對應腳本安裝配置虛擬機的依賴工具。啟動完成之後,那麼一個隔離的環境創建完畢,接下來我們可以在裡面任意玩耍了。

特別注意:因為第一次運行需要下載ubuntu/trusty64鏡像,以及把所有的配置甚至通過Docker下載Jenkins鏡像、slave鏡像,以及啟動Jenkins都寫到了Ansible中,所以跑完vagrant up需要較長時間

啟動、執行順序

基本是按Vagrant的配置文件的上下順序來啟動的。具體順序如下:

  1. 按Vagrantfile安裝並啟動Nginx虛擬機
  2. 執行Nginx虛擬機依賴的provision模塊
  3. 按Vagrantfile安裝並啟動Jenkins虛擬機
  4. 執行Jenkins虛擬機依賴的provision模塊

Jenkins訪問Nginx(選修,建議有時間或者將Jenkins搭建完成之後再看)

如果你能把所有環境啟動起來並能訪問Jenkins主頁,但此時你還無法在Jenkins上直接ssh登錄到Nginx,因為此時兩臺機器還沒有互信。但是幸運的是Vagrant啟動完Nginx之後就已經將私鑰(可以拿這個私鑰去訪問Nginx,無論你是誰)放到了宿主機上,那麼你可以手動將這個私鑰複製到Jenkins中,然後就可以在Jenkins中訪問Nginx了。

但是為了自動化上面的操作,進行以下的配置:Vagrant會在啟動一個虛擬機之後,會在Mac上創建.vagrant文件夾並把一些關於這個虛擬機的文件放到裡面,比如該虛擬機的私鑰,後面可以拿到這私鑰作為SSH聯絡的key。

比如下面這段配置會在Nginx虛擬機啟動之後,Jenkins虛擬機啟動之前執行。由於Jenkins虛擬機需要在部署代碼的時候使用到Nginx虛擬機的私鑰來部署,所以需要在Jenkins虛擬機執行Ansible之前將私鑰放到Jenkins的file文件夾中。

手把手教你從零搭建一個持續集成環境

另外,在Vagrantfile中,Ansible不是與兩臺虛擬機的配置寫在一起的,那麼Ansible如何判斷在哪臺虛擬機上安裝Nginx還是Jenkins呢?因為不同的虛擬機要執行Ansible的時候會根據主機名匹配來找到對應role的tasks從而還是能找到匹配的tasks。換句話說,Nginx安裝完成之後Vagrant攜帶Nginx相關參數執行下面這樣的一行命令來用limit匹配主機與對應Ansible的tasks:

手把手教你從零搭建一個持續集成環境

我們需要Ansible

什麼是Ansible

Ansible是一種自動化部署工具,可以用來自動化管理配置項、持續交付、(AWS)雲服務管理;

簡單來說也就是可以批量的遠程服務器上執行一系列的命令,其原理是基於ssh來和遠程主機進行通信的。

為什麼用Ansible

  • playbook使用的是yml語言,易讀性較好;
  • 沒有主節點和代理,僅僅依賴於SSH,使得應用的部署簡單而輕量;
  • 提供了大量模塊支持Google Compute Engine (GCE), Amazon Web Service(AWS);
  • Ansible支持多臺服務器同時管理部署;

安裝Ansible

Ansible是基於python開發的,需要在安裝有python的機器下才能夠安裝Ansible

  • 在本機安裝python:brew install python(Mac自帶ython,因此這步可以省略,inux系統中需要安裝Python)
  • 安裝pip:sudo apt install python-pip
  • 安裝Ansible:sudo pip install ansible

目錄結構

你可以按如下目錄結構去編寫你的Ansible文件。

手把手教你從零搭建一個持續集成環境

roles文件夾

roles是基於一個Ansible默認的目錄結構,Ansible在執行任務的時候會去默認加載templates、tasks以及handlers文件夾中的文件等。我們基於roles 對內容進行分組,使得我們可以容易地將不同的環境(如Java與NodeJs)區分開來,本次Demo中的roles下有三個文件夾,分別是common、jenkins和nginx,其中每個文件夾下都會定義一些例如tasks任務與相關配置文件。

role - common

前面已經說過本次demo需要在本地啟動兩臺虛擬機,分別在內部裝上Docker,在common中我們定義了安裝Docker的task,這樣在定義Jenkins服務器和部署nginx的服務器中都可以調用該task來安裝配置Docker環境;

install_docker.yml中應該包含如下內容:

  • 安裝Docker
  • 安裝docker-compose工具
  • 安裝docker-py依賴包(如果我們想用Ansible的docker模塊去執行docker相關命令的話需要這個依賴)

role - jenkins

定義安裝和部署Jenkins服務器的task:其中docker-compose.yml配置文件,是用於分別對jenkins-master和jenkins_slave進行一些基本配置;task下的main.yml文件是配置一系列的安裝命令,類似於在命令行中一行行輸入安裝和部署命令;

role - nginx

與jenkins文件夾類似,對Nginx服務器的一些基本配置:例如Nginx配置文件default.conf,配置文件中定義了templates下的index.html作為Nginx的入口模版文件,使Nginx作為一個文件服務器。task下的main.yml文件則是與jenkins中類似,配置了安裝部署命令,在使用vagrant up時通過Ansible來安裝並運行Nginx服務。

配置文件

Ansible的配置文件包括但不僅限於ansible.cfg、deploy.yml以及hosts

ansible.cfg文件

如在本Demo中用到的幾個配置:

  • forks:設置在與主機通信時的默認並行進程數,默認值為5;
  • inventory:設置主機與組之間的對應關係,在Ansible1.9之前使用的是hostfile;
  • host_key_checking:檢測主機密鑰的功能,可以通過設置值為false來禁用該功能(跳過兩臺主機之間首次連接需要確認的過程);
  • nocows:設置其值為1時禁用調用一些cowsay的特性,cowsay是linux系統下一個在終端用ASCII碼組成的小牛,這個小牛會說出你想要它說的話。
  • gathering:控制默認的遠程系統變量(facts)收集,有三種不同的值;默認是implicit,即每一次play,變量都會被收集,除非設置gather_facts: False;為explicit時,則facts不會被收集;為smart時,則沒有facts的新hosts將不會被掃描,用於節省fact收集;
  • fact_caching_timeout:定義fact緩存超時時間;
  • fact_caching:定義fact的緩存,2.4版本的Ansible支持redis和jsonfile兩種格式的緩存文件;
  • fact_caching_connection:定義cache的存儲位置,根據cache文件的格式不同定義的方式不同;

deploy.yml文件

這是Ansible的入口配置文件:定義hosts主機、以及相應主機需要執行的tasks等;

手把手教你從零搭建一個持續集成環境

hosts

然後加上遠程主機的網絡相關配置,這樣Ansible才能通過SSH到虛擬機中執行你寫的任務喲。

以如下命令為例,是為IP地址1192.168.56.102,端口號22的網絡地址設置一個別名nginx,且聲明其ssh private key文件的地址;

手把手教你從零搭建一個持續集成環境

與Vagrant結合

現在,Ansible的任務已經寫完了,我們需要將Ansible與Vagrant結合,將如下代碼加入到Vagrantfile中,可以在執行vagrant up的時候執行Ansible。

手把手教你從零搭建一個持續集成環境

虛擬機中的世界是如何構成的呢

現在你已經將所有的環境部署完成了,但是部署應用(Jenkins、Nginx)的過程還沒有提及,下面將帶你從Ansbile的對於每個虛擬機的任務開始,介紹相應的工具與具體的實施步驟。

Docker

什麼是Docker

Docker是一個開源的容器應用引擎,可以理解為一個存放應用容器的平臺,我們只需要簡單的幾行命令就可以構建一個與本地環境相對隔離的環境來運行我們的應用而不影響任何角色;

基本要素:

  • Container:負責應用程序的運行,包括操作系統、用戶添加的文件以及元數據
  • Images:只讀模版,即常說的Docker鏡像,用來運行Docker容器
  • Dockerfile:文件指令集,用來說明如何創建Docker鏡像

為什麼要用Docker

把一個應用封裝起來,可以在任何裝有Docker的環境下運行,統一運行環境;

那個大鯨魚(或者是貨輪)就是操作系統,把要交付的應用程序看成是各種貨物,原本要將各種各樣形狀、尺寸不同的貨物放到大鯨魚上,你得為每件貨物考慮怎麼安放(就是應用程序配套的環境),還得考慮貨物和貨物是否能疊起來(應用程序依賴的環境是否會衝突)。

現在使用了集裝箱(容器)把每件貨物都放到集裝箱裡,這樣大鯨魚可以用同樣地方式安放、堆疊集裝了,省事省力。

Docker中常用的命令

手把手教你從零搭建一個持續集成環境

怎麼用

要注意的是,Ansible對應的任務是在Vagrant啟動虛擬機之後執行的,是在虛擬機的內部,Docker容器的外部

安裝Nginx:由於我們只需要啟動一個Nginx的容器,直接使用Docker中run的命令去repository中下載安裝即可

  • 準備文件,例如default.conf,index.html
  • ```
  • name: copy nginx config file
  • copy:
  • src: default.conf
  • dest: /data/nginx/default.conf
  • name: copy default html file
  • template:
  • src: index.html
  • dest: /data/nginx/html/index.html
  • owner: vagrant
  • group: vagrant
  • ```
  • 使用Ansible中提供的Docker模塊安裝Nginx,包括拉Docker images,設置ports,以及多久需要pull一次新代碼等
手把手教你從零搭建一個持續集成環境

安裝Jenkins:demo中需要用到jenkins-master和jenkins-slave兩個container,因此使用docker-compose更加方便docker-compose.yml中定義了鏡像的地址、端口號等,並通過執行它進行在Docker中的部署。其中slave節點選用了jaydp17/jenkins-slave這樣一個包含Java、git、curl環境的Image方便執行持續集成任務。

"

本文將帶領你從0開始,用Vagrant + Docker + Ansible + Jenkins + Nginx + GitHub等工具和資源來搭建一條可執行可擴展的持續集成流水線,即使這些名字你都沒聽過也沒關係,本文將會在需要的時候一一解釋給你聽。

By: 巧穎 & 天一

總覽

這是我們將要搭建的所有基礎設施的總體架構圖,我們將在本文中手把手教你搭建這樣一個持續集成環境。

手把手教你從零搭建一個持續集成環境

我們會在本地啟動兩臺虛擬機,一臺部署Nginx作為靜態文件服務器,一臺作為Jenkins服務器,在每臺虛擬機內部安裝Docker,使用Docker來完成Nginx與Jenkins的搭建、配置,然後手動在Jenkins配置內配置好一條Pipeline作為持續集成流水線,最後嘗試提交一次代碼去觸發一次持續集成操作,將最新的html項目代碼從Github上部署到Nginx中,實現持續集成。

避免本文過長,部分源代碼沒有貼在文中,本文參考完成源代碼在此:https://github.com/tw-wh-devops-community/cooking-chicken.git。建議在自己嘗試從0開始搭建的同時參考源碼閱讀本文。相信你一定會碰到很多坑,但坑外便是晴天。

首先我們需要兩臺機器

我們需要Vagrant

為什麼呢

無論你用的操作系統是Windows、Mac還是Linux,Oracle的Virtual Box都支持,那麼我們首先會使用Virtual Box來建立一個在硬件上絕對隔離的環境出來。

那麼Vagrant就是通過方便的命令操作來簡化Virtual Box的操作,同時提供了方便的虛擬機配置模塊,所以我們會使用這個工具來提升虛擬機的配置效率。

安裝Vagrant

在Mac上是自帶Virtual Box的,你用的版本可能需要更新才能配合Vagrant使用,Linux上請使用類似sudo apt-get install virtualbox的命令安裝。

那麼先裝上Vagrant吧:

  • Mac(https://www.vagrantup.com/downloads.html)
  • Ubuntu(sudo apt-get install vagrant)

安裝Vagrant插件

由於後續操作會涉及到將Nginx機器的私鑰發送給Jenkins機器來配置私鑰來完成虛擬機之間的無密碼訪問。但私鑰是在Nginx虛擬機創建之後才會由Vagrant創建的,所以需要在這個時間節點放到Jenkins目錄下便於Ansible把私鑰放到Jenkins虛擬機中。如果暫時不理解沒有關係,請看完”開始創建世界“之後回頭來看就會明白。

Vagrant的provision模塊可以在虛擬機啟動之後在虛擬機內部執行任意腳本,但是provision模塊並沒有提供執行宿主機上腳本的方式,所以需要你安裝如下模塊:

vagrant plugin install vagrant-host-shell

調試的時候比較有用的操作

  • 進入虛擬機:vagrant ssh
  • 休眠:vagrant suspend
  • 從休眠中恢復:vagrant resume
  • 移除虛擬機所有文件:vagrant destroy

開始創建世界!

Vagrantfile

我們來新建一個工程,在根目錄創建一個名為Vagrantfile的文件,內容如下:

手把手教你從零搭建一個持續集成環境

那麼現在可以啟動了,在命令行內跳轉到根目錄,使用vagrant up就可以將虛擬機按上面的配置啟動了,同時在啟動完成之後會調用provision模塊跑Ansible的對應腳本安裝配置虛擬機的依賴工具。啟動完成之後,那麼一個隔離的環境創建完畢,接下來我們可以在裡面任意玩耍了。

特別注意:因為第一次運行需要下載ubuntu/trusty64鏡像,以及把所有的配置甚至通過Docker下載Jenkins鏡像、slave鏡像,以及啟動Jenkins都寫到了Ansible中,所以跑完vagrant up需要較長時間

啟動、執行順序

基本是按Vagrant的配置文件的上下順序來啟動的。具體順序如下:

  1. 按Vagrantfile安裝並啟動Nginx虛擬機
  2. 執行Nginx虛擬機依賴的provision模塊
  3. 按Vagrantfile安裝並啟動Jenkins虛擬機
  4. 執行Jenkins虛擬機依賴的provision模塊

Jenkins訪問Nginx(選修,建議有時間或者將Jenkins搭建完成之後再看)

如果你能把所有環境啟動起來並能訪問Jenkins主頁,但此時你還無法在Jenkins上直接ssh登錄到Nginx,因為此時兩臺機器還沒有互信。但是幸運的是Vagrant啟動完Nginx之後就已經將私鑰(可以拿這個私鑰去訪問Nginx,無論你是誰)放到了宿主機上,那麼你可以手動將這個私鑰複製到Jenkins中,然後就可以在Jenkins中訪問Nginx了。

但是為了自動化上面的操作,進行以下的配置:Vagrant會在啟動一個虛擬機之後,會在Mac上創建.vagrant文件夾並把一些關於這個虛擬機的文件放到裡面,比如該虛擬機的私鑰,後面可以拿到這私鑰作為SSH聯絡的key。

比如下面這段配置會在Nginx虛擬機啟動之後,Jenkins虛擬機啟動之前執行。由於Jenkins虛擬機需要在部署代碼的時候使用到Nginx虛擬機的私鑰來部署,所以需要在Jenkins虛擬機執行Ansible之前將私鑰放到Jenkins的file文件夾中。

手把手教你從零搭建一個持續集成環境

另外,在Vagrantfile中,Ansible不是與兩臺虛擬機的配置寫在一起的,那麼Ansible如何判斷在哪臺虛擬機上安裝Nginx還是Jenkins呢?因為不同的虛擬機要執行Ansible的時候會根據主機名匹配來找到對應role的tasks從而還是能找到匹配的tasks。換句話說,Nginx安裝完成之後Vagrant攜帶Nginx相關參數執行下面這樣的一行命令來用limit匹配主機與對應Ansible的tasks:

手把手教你從零搭建一個持續集成環境

我們需要Ansible

什麼是Ansible

Ansible是一種自動化部署工具,可以用來自動化管理配置項、持續交付、(AWS)雲服務管理;

簡單來說也就是可以批量的遠程服務器上執行一系列的命令,其原理是基於ssh來和遠程主機進行通信的。

為什麼用Ansible

  • playbook使用的是yml語言,易讀性較好;
  • 沒有主節點和代理,僅僅依賴於SSH,使得應用的部署簡單而輕量;
  • 提供了大量模塊支持Google Compute Engine (GCE), Amazon Web Service(AWS);
  • Ansible支持多臺服務器同時管理部署;

安裝Ansible

Ansible是基於python開發的,需要在安裝有python的機器下才能夠安裝Ansible

  • 在本機安裝python:brew install python(Mac自帶ython,因此這步可以省略,inux系統中需要安裝Python)
  • 安裝pip:sudo apt install python-pip
  • 安裝Ansible:sudo pip install ansible

目錄結構

你可以按如下目錄結構去編寫你的Ansible文件。

手把手教你從零搭建一個持續集成環境

roles文件夾

roles是基於一個Ansible默認的目錄結構,Ansible在執行任務的時候會去默認加載templates、tasks以及handlers文件夾中的文件等。我們基於roles 對內容進行分組,使得我們可以容易地將不同的環境(如Java與NodeJs)區分開來,本次Demo中的roles下有三個文件夾,分別是common、jenkins和nginx,其中每個文件夾下都會定義一些例如tasks任務與相關配置文件。

role - common

前面已經說過本次demo需要在本地啟動兩臺虛擬機,分別在內部裝上Docker,在common中我們定義了安裝Docker的task,這樣在定義Jenkins服務器和部署nginx的服務器中都可以調用該task來安裝配置Docker環境;

install_docker.yml中應該包含如下內容:

  • 安裝Docker
  • 安裝docker-compose工具
  • 安裝docker-py依賴包(如果我們想用Ansible的docker模塊去執行docker相關命令的話需要這個依賴)

role - jenkins

定義安裝和部署Jenkins服務器的task:其中docker-compose.yml配置文件,是用於分別對jenkins-master和jenkins_slave進行一些基本配置;task下的main.yml文件是配置一系列的安裝命令,類似於在命令行中一行行輸入安裝和部署命令;

role - nginx

與jenkins文件夾類似,對Nginx服務器的一些基本配置:例如Nginx配置文件default.conf,配置文件中定義了templates下的index.html作為Nginx的入口模版文件,使Nginx作為一個文件服務器。task下的main.yml文件則是與jenkins中類似,配置了安裝部署命令,在使用vagrant up時通過Ansible來安裝並運行Nginx服務。

配置文件

Ansible的配置文件包括但不僅限於ansible.cfg、deploy.yml以及hosts

ansible.cfg文件

如在本Demo中用到的幾個配置:

  • forks:設置在與主機通信時的默認並行進程數,默認值為5;
  • inventory:設置主機與組之間的對應關係,在Ansible1.9之前使用的是hostfile;
  • host_key_checking:檢測主機密鑰的功能,可以通過設置值為false來禁用該功能(跳過兩臺主機之間首次連接需要確認的過程);
  • nocows:設置其值為1時禁用調用一些cowsay的特性,cowsay是linux系統下一個在終端用ASCII碼組成的小牛,這個小牛會說出你想要它說的話。
  • gathering:控制默認的遠程系統變量(facts)收集,有三種不同的值;默認是implicit,即每一次play,變量都會被收集,除非設置gather_facts: False;為explicit時,則facts不會被收集;為smart時,則沒有facts的新hosts將不會被掃描,用於節省fact收集;
  • fact_caching_timeout:定義fact緩存超時時間;
  • fact_caching:定義fact的緩存,2.4版本的Ansible支持redis和jsonfile兩種格式的緩存文件;
  • fact_caching_connection:定義cache的存儲位置,根據cache文件的格式不同定義的方式不同;

deploy.yml文件

這是Ansible的入口配置文件:定義hosts主機、以及相應主機需要執行的tasks等;

手把手教你從零搭建一個持續集成環境

hosts

然後加上遠程主機的網絡相關配置,這樣Ansible才能通過SSH到虛擬機中執行你寫的任務喲。

以如下命令為例,是為IP地址1192.168.56.102,端口號22的網絡地址設置一個別名nginx,且聲明其ssh private key文件的地址;

手把手教你從零搭建一個持續集成環境

與Vagrant結合

現在,Ansible的任務已經寫完了,我們需要將Ansible與Vagrant結合,將如下代碼加入到Vagrantfile中,可以在執行vagrant up的時候執行Ansible。

手把手教你從零搭建一個持續集成環境

虛擬機中的世界是如何構成的呢

現在你已經將所有的環境部署完成了,但是部署應用(Jenkins、Nginx)的過程還沒有提及,下面將帶你從Ansbile的對於每個虛擬機的任務開始,介紹相應的工具與具體的實施步驟。

Docker

什麼是Docker

Docker是一個開源的容器應用引擎,可以理解為一個存放應用容器的平臺,我們只需要簡單的幾行命令就可以構建一個與本地環境相對隔離的環境來運行我們的應用而不影響任何角色;

基本要素:

  • Container:負責應用程序的運行,包括操作系統、用戶添加的文件以及元數據
  • Images:只讀模版,即常說的Docker鏡像,用來運行Docker容器
  • Dockerfile:文件指令集,用來說明如何創建Docker鏡像

為什麼要用Docker

把一個應用封裝起來,可以在任何裝有Docker的環境下運行,統一運行環境;

那個大鯨魚(或者是貨輪)就是操作系統,把要交付的應用程序看成是各種貨物,原本要將各種各樣形狀、尺寸不同的貨物放到大鯨魚上,你得為每件貨物考慮怎麼安放(就是應用程序配套的環境),還得考慮貨物和貨物是否能疊起來(應用程序依賴的環境是否會衝突)。

現在使用了集裝箱(容器)把每件貨物都放到集裝箱裡,這樣大鯨魚可以用同樣地方式安放、堆疊集裝了,省事省力。

Docker中常用的命令

手把手教你從零搭建一個持續集成環境

怎麼用

要注意的是,Ansible對應的任務是在Vagrant啟動虛擬機之後執行的,是在虛擬機的內部,Docker容器的外部

安裝Nginx:由於我們只需要啟動一個Nginx的容器,直接使用Docker中run的命令去repository中下載安裝即可

  • 準備文件,例如default.conf,index.html
  • ```
  • name: copy nginx config file
  • copy:
  • src: default.conf
  • dest: /data/nginx/default.conf
  • name: copy default html file
  • template:
  • src: index.html
  • dest: /data/nginx/html/index.html
  • owner: vagrant
  • group: vagrant
  • ```
  • 使用Ansible中提供的Docker模塊安裝Nginx,包括拉Docker images,設置ports,以及多久需要pull一次新代碼等
手把手教你從零搭建一個持續集成環境

安裝Jenkins:demo中需要用到jenkins-master和jenkins-slave兩個container,因此使用docker-compose更加方便docker-compose.yml中定義了鏡像的地址、端口號等,並通過執行它進行在Docker中的部署。其中slave節點選用了jaydp17/jenkins-slave這樣一個包含Java、git、curl環境的Image方便執行持續集成任務。

手把手教你從零搭建一個持續集成環境

Nginx

什麼是Nginx

一款輕量級的Web 服務器/反向代理服務器及電子郵件(IMAP/POP3)代理服務器

為什麼用Nginx

首先需要一個服務器來部署我們的應用,而常用的服務器有例如apache的Apache HTTP Server、Nginx、tomcat等;Nginx是為了解決互聯網業內著名的 “C10K” 問題而生;

其中Nginx通常用來做靜態內容服務器,而tomcat一般用於做動態應用的服務器,通常稱之為web容器;Nginx相比於apache的優點:

  • 輕量級,同樣起web服務,比apache佔用更少的內存及資源;
  • 抗併發,Nginx處理請求是異步非阻塞的,而apache則是阻塞型的,在高併發下Nginx能保持低資源低消耗高性能
  • 提供負載均衡;
  • 配置簡潔;
  • 社區活躍,各種高性能模塊出品迅速等;

怎麼用Nginx

在demo中寫了一個role來定義安裝配置Nginx需要的操作流程,用的是Docker提供的Nginx鏡像,在Docker中安裝配置Nginx,為了使Nginx能夠啟動起來,我們還需要進行一系列的配置,包括配置文件和模版文件等;default.conf就是Nginx的配置文件,此處http模塊的相關配置:

  • listen 80:監聽的端口號是80;
  • default_server:設定為默認虛擬主機;
  • server_name localhost:設置虛擬主機名稱為localhost;
  • root /usr/share/nginx/html:設置web服務URL資源映射的本地文件系統的資源所在的目錄;
  • index index.html index.htm:定義默認主頁面,需要自己編寫並放到Ansbile對應目錄;
"

本文將帶領你從0開始,用Vagrant + Docker + Ansible + Jenkins + Nginx + GitHub等工具和資源來搭建一條可執行可擴展的持續集成流水線,即使這些名字你都沒聽過也沒關係,本文將會在需要的時候一一解釋給你聽。

By: 巧穎 & 天一

總覽

這是我們將要搭建的所有基礎設施的總體架構圖,我們將在本文中手把手教你搭建這樣一個持續集成環境。

手把手教你從零搭建一個持續集成環境

我們會在本地啟動兩臺虛擬機,一臺部署Nginx作為靜態文件服務器,一臺作為Jenkins服務器,在每臺虛擬機內部安裝Docker,使用Docker來完成Nginx與Jenkins的搭建、配置,然後手動在Jenkins配置內配置好一條Pipeline作為持續集成流水線,最後嘗試提交一次代碼去觸發一次持續集成操作,將最新的html項目代碼從Github上部署到Nginx中,實現持續集成。

避免本文過長,部分源代碼沒有貼在文中,本文參考完成源代碼在此:https://github.com/tw-wh-devops-community/cooking-chicken.git。建議在自己嘗試從0開始搭建的同時參考源碼閱讀本文。相信你一定會碰到很多坑,但坑外便是晴天。

首先我們需要兩臺機器

我們需要Vagrant

為什麼呢

無論你用的操作系統是Windows、Mac還是Linux,Oracle的Virtual Box都支持,那麼我們首先會使用Virtual Box來建立一個在硬件上絕對隔離的環境出來。

那麼Vagrant就是通過方便的命令操作來簡化Virtual Box的操作,同時提供了方便的虛擬機配置模塊,所以我們會使用這個工具來提升虛擬機的配置效率。

安裝Vagrant

在Mac上是自帶Virtual Box的,你用的版本可能需要更新才能配合Vagrant使用,Linux上請使用類似sudo apt-get install virtualbox的命令安裝。

那麼先裝上Vagrant吧:

  • Mac(https://www.vagrantup.com/downloads.html)
  • Ubuntu(sudo apt-get install vagrant)

安裝Vagrant插件

由於後續操作會涉及到將Nginx機器的私鑰發送給Jenkins機器來配置私鑰來完成虛擬機之間的無密碼訪問。但私鑰是在Nginx虛擬機創建之後才會由Vagrant創建的,所以需要在這個時間節點放到Jenkins目錄下便於Ansible把私鑰放到Jenkins虛擬機中。如果暫時不理解沒有關係,請看完”開始創建世界“之後回頭來看就會明白。

Vagrant的provision模塊可以在虛擬機啟動之後在虛擬機內部執行任意腳本,但是provision模塊並沒有提供執行宿主機上腳本的方式,所以需要你安裝如下模塊:

vagrant plugin install vagrant-host-shell

調試的時候比較有用的操作

  • 進入虛擬機:vagrant ssh
  • 休眠:vagrant suspend
  • 從休眠中恢復:vagrant resume
  • 移除虛擬機所有文件:vagrant destroy

開始創建世界!

Vagrantfile

我們來新建一個工程,在根目錄創建一個名為Vagrantfile的文件,內容如下:

手把手教你從零搭建一個持續集成環境

那麼現在可以啟動了,在命令行內跳轉到根目錄,使用vagrant up就可以將虛擬機按上面的配置啟動了,同時在啟動完成之後會調用provision模塊跑Ansible的對應腳本安裝配置虛擬機的依賴工具。啟動完成之後,那麼一個隔離的環境創建完畢,接下來我們可以在裡面任意玩耍了。

特別注意:因為第一次運行需要下載ubuntu/trusty64鏡像,以及把所有的配置甚至通過Docker下載Jenkins鏡像、slave鏡像,以及啟動Jenkins都寫到了Ansible中,所以跑完vagrant up需要較長時間

啟動、執行順序

基本是按Vagrant的配置文件的上下順序來啟動的。具體順序如下:

  1. 按Vagrantfile安裝並啟動Nginx虛擬機
  2. 執行Nginx虛擬機依賴的provision模塊
  3. 按Vagrantfile安裝並啟動Jenkins虛擬機
  4. 執行Jenkins虛擬機依賴的provision模塊

Jenkins訪問Nginx(選修,建議有時間或者將Jenkins搭建完成之後再看)

如果你能把所有環境啟動起來並能訪問Jenkins主頁,但此時你還無法在Jenkins上直接ssh登錄到Nginx,因為此時兩臺機器還沒有互信。但是幸運的是Vagrant啟動完Nginx之後就已經將私鑰(可以拿這個私鑰去訪問Nginx,無論你是誰)放到了宿主機上,那麼你可以手動將這個私鑰複製到Jenkins中,然後就可以在Jenkins中訪問Nginx了。

但是為了自動化上面的操作,進行以下的配置:Vagrant會在啟動一個虛擬機之後,會在Mac上創建.vagrant文件夾並把一些關於這個虛擬機的文件放到裡面,比如該虛擬機的私鑰,後面可以拿到這私鑰作為SSH聯絡的key。

比如下面這段配置會在Nginx虛擬機啟動之後,Jenkins虛擬機啟動之前執行。由於Jenkins虛擬機需要在部署代碼的時候使用到Nginx虛擬機的私鑰來部署,所以需要在Jenkins虛擬機執行Ansible之前將私鑰放到Jenkins的file文件夾中。

手把手教你從零搭建一個持續集成環境

另外,在Vagrantfile中,Ansible不是與兩臺虛擬機的配置寫在一起的,那麼Ansible如何判斷在哪臺虛擬機上安裝Nginx還是Jenkins呢?因為不同的虛擬機要執行Ansible的時候會根據主機名匹配來找到對應role的tasks從而還是能找到匹配的tasks。換句話說,Nginx安裝完成之後Vagrant攜帶Nginx相關參數執行下面這樣的一行命令來用limit匹配主機與對應Ansible的tasks:

手把手教你從零搭建一個持續集成環境

我們需要Ansible

什麼是Ansible

Ansible是一種自動化部署工具,可以用來自動化管理配置項、持續交付、(AWS)雲服務管理;

簡單來說也就是可以批量的遠程服務器上執行一系列的命令,其原理是基於ssh來和遠程主機進行通信的。

為什麼用Ansible

  • playbook使用的是yml語言,易讀性較好;
  • 沒有主節點和代理,僅僅依賴於SSH,使得應用的部署簡單而輕量;
  • 提供了大量模塊支持Google Compute Engine (GCE), Amazon Web Service(AWS);
  • Ansible支持多臺服務器同時管理部署;

安裝Ansible

Ansible是基於python開發的,需要在安裝有python的機器下才能夠安裝Ansible

  • 在本機安裝python:brew install python(Mac自帶ython,因此這步可以省略,inux系統中需要安裝Python)
  • 安裝pip:sudo apt install python-pip
  • 安裝Ansible:sudo pip install ansible

目錄結構

你可以按如下目錄結構去編寫你的Ansible文件。

手把手教你從零搭建一個持續集成環境

roles文件夾

roles是基於一個Ansible默認的目錄結構,Ansible在執行任務的時候會去默認加載templates、tasks以及handlers文件夾中的文件等。我們基於roles 對內容進行分組,使得我們可以容易地將不同的環境(如Java與NodeJs)區分開來,本次Demo中的roles下有三個文件夾,分別是common、jenkins和nginx,其中每個文件夾下都會定義一些例如tasks任務與相關配置文件。

role - common

前面已經說過本次demo需要在本地啟動兩臺虛擬機,分別在內部裝上Docker,在common中我們定義了安裝Docker的task,這樣在定義Jenkins服務器和部署nginx的服務器中都可以調用該task來安裝配置Docker環境;

install_docker.yml中應該包含如下內容:

  • 安裝Docker
  • 安裝docker-compose工具
  • 安裝docker-py依賴包(如果我們想用Ansible的docker模塊去執行docker相關命令的話需要這個依賴)

role - jenkins

定義安裝和部署Jenkins服務器的task:其中docker-compose.yml配置文件,是用於分別對jenkins-master和jenkins_slave進行一些基本配置;task下的main.yml文件是配置一系列的安裝命令,類似於在命令行中一行行輸入安裝和部署命令;

role - nginx

與jenkins文件夾類似,對Nginx服務器的一些基本配置:例如Nginx配置文件default.conf,配置文件中定義了templates下的index.html作為Nginx的入口模版文件,使Nginx作為一個文件服務器。task下的main.yml文件則是與jenkins中類似,配置了安裝部署命令,在使用vagrant up時通過Ansible來安裝並運行Nginx服務。

配置文件

Ansible的配置文件包括但不僅限於ansible.cfg、deploy.yml以及hosts

ansible.cfg文件

如在本Demo中用到的幾個配置:

  • forks:設置在與主機通信時的默認並行進程數,默認值為5;
  • inventory:設置主機與組之間的對應關係,在Ansible1.9之前使用的是hostfile;
  • host_key_checking:檢測主機密鑰的功能,可以通過設置值為false來禁用該功能(跳過兩臺主機之間首次連接需要確認的過程);
  • nocows:設置其值為1時禁用調用一些cowsay的特性,cowsay是linux系統下一個在終端用ASCII碼組成的小牛,這個小牛會說出你想要它說的話。
  • gathering:控制默認的遠程系統變量(facts)收集,有三種不同的值;默認是implicit,即每一次play,變量都會被收集,除非設置gather_facts: False;為explicit時,則facts不會被收集;為smart時,則沒有facts的新hosts將不會被掃描,用於節省fact收集;
  • fact_caching_timeout:定義fact緩存超時時間;
  • fact_caching:定義fact的緩存,2.4版本的Ansible支持redis和jsonfile兩種格式的緩存文件;
  • fact_caching_connection:定義cache的存儲位置,根據cache文件的格式不同定義的方式不同;

deploy.yml文件

這是Ansible的入口配置文件:定義hosts主機、以及相應主機需要執行的tasks等;

手把手教你從零搭建一個持續集成環境

hosts

然後加上遠程主機的網絡相關配置,這樣Ansible才能通過SSH到虛擬機中執行你寫的任務喲。

以如下命令為例,是為IP地址1192.168.56.102,端口號22的網絡地址設置一個別名nginx,且聲明其ssh private key文件的地址;

手把手教你從零搭建一個持續集成環境

與Vagrant結合

現在,Ansible的任務已經寫完了,我們需要將Ansible與Vagrant結合,將如下代碼加入到Vagrantfile中,可以在執行vagrant up的時候執行Ansible。

手把手教你從零搭建一個持續集成環境

虛擬機中的世界是如何構成的呢

現在你已經將所有的環境部署完成了,但是部署應用(Jenkins、Nginx)的過程還沒有提及,下面將帶你從Ansbile的對於每個虛擬機的任務開始,介紹相應的工具與具體的實施步驟。

Docker

什麼是Docker

Docker是一個開源的容器應用引擎,可以理解為一個存放應用容器的平臺,我們只需要簡單的幾行命令就可以構建一個與本地環境相對隔離的環境來運行我們的應用而不影響任何角色;

基本要素:

  • Container:負責應用程序的運行,包括操作系統、用戶添加的文件以及元數據
  • Images:只讀模版,即常說的Docker鏡像,用來運行Docker容器
  • Dockerfile:文件指令集,用來說明如何創建Docker鏡像

為什麼要用Docker

把一個應用封裝起來,可以在任何裝有Docker的環境下運行,統一運行環境;

那個大鯨魚(或者是貨輪)就是操作系統,把要交付的應用程序看成是各種貨物,原本要將各種各樣形狀、尺寸不同的貨物放到大鯨魚上,你得為每件貨物考慮怎麼安放(就是應用程序配套的環境),還得考慮貨物和貨物是否能疊起來(應用程序依賴的環境是否會衝突)。

現在使用了集裝箱(容器)把每件貨物都放到集裝箱裡,這樣大鯨魚可以用同樣地方式安放、堆疊集裝了,省事省力。

Docker中常用的命令

手把手教你從零搭建一個持續集成環境

怎麼用

要注意的是,Ansible對應的任務是在Vagrant啟動虛擬機之後執行的,是在虛擬機的內部,Docker容器的外部

安裝Nginx:由於我們只需要啟動一個Nginx的容器,直接使用Docker中run的命令去repository中下載安裝即可

  • 準備文件,例如default.conf,index.html
  • ```
  • name: copy nginx config file
  • copy:
  • src: default.conf
  • dest: /data/nginx/default.conf
  • name: copy default html file
  • template:
  • src: index.html
  • dest: /data/nginx/html/index.html
  • owner: vagrant
  • group: vagrant
  • ```
  • 使用Ansible中提供的Docker模塊安裝Nginx,包括拉Docker images,設置ports,以及多久需要pull一次新代碼等
手把手教你從零搭建一個持續集成環境

安裝Jenkins:demo中需要用到jenkins-master和jenkins-slave兩個container,因此使用docker-compose更加方便docker-compose.yml中定義了鏡像的地址、端口號等,並通過執行它進行在Docker中的部署。其中slave節點選用了jaydp17/jenkins-slave這樣一個包含Java、git、curl環境的Image方便執行持續集成任務。

手把手教你從零搭建一個持續集成環境

Nginx

什麼是Nginx

一款輕量級的Web 服務器/反向代理服務器及電子郵件(IMAP/POP3)代理服務器

為什麼用Nginx

首先需要一個服務器來部署我們的應用,而常用的服務器有例如apache的Apache HTTP Server、Nginx、tomcat等;Nginx是為了解決互聯網業內著名的 “C10K” 問題而生;

其中Nginx通常用來做靜態內容服務器,而tomcat一般用於做動態應用的服務器,通常稱之為web容器;Nginx相比於apache的優點:

  • 輕量級,同樣起web服務,比apache佔用更少的內存及資源;
  • 抗併發,Nginx處理請求是異步非阻塞的,而apache則是阻塞型的,在高併發下Nginx能保持低資源低消耗高性能
  • 提供負載均衡;
  • 配置簡潔;
  • 社區活躍,各種高性能模塊出品迅速等;

怎麼用Nginx

在demo中寫了一個role來定義安裝配置Nginx需要的操作流程,用的是Docker提供的Nginx鏡像,在Docker中安裝配置Nginx,為了使Nginx能夠啟動起來,我們還需要進行一系列的配置,包括配置文件和模版文件等;default.conf就是Nginx的配置文件,此處http模塊的相關配置:

  • listen 80:監聽的端口號是80;
  • default_server:設定為默認虛擬主機;
  • server_name localhost:設置虛擬主機名稱為localhost;
  • root /usr/share/nginx/html:設置web服務URL資源映射的本地文件系統的資源所在的目錄;
  • index index.html index.htm:定義默認主頁面,需要自己編寫並放到Ansbile對應目錄;
手把手教你從零搭建一個持續集成環境

還有一些其他的配置,詳情請參考https://www.nginx.com/resources/wiki/start/topics/examples/full/

Ansible關於Nginx的task中yml文件的配置:

  • 創建文件夾
  • copy Nginx的配置文件到環境中
  • copy模版文件
  • 以及使用Docker鏡像運行Nginx
"

本文將帶領你從0開始,用Vagrant + Docker + Ansible + Jenkins + Nginx + GitHub等工具和資源來搭建一條可執行可擴展的持續集成流水線,即使這些名字你都沒聽過也沒關係,本文將會在需要的時候一一解釋給你聽。

By: 巧穎 & 天一

總覽

這是我們將要搭建的所有基礎設施的總體架構圖,我們將在本文中手把手教你搭建這樣一個持續集成環境。

手把手教你從零搭建一個持續集成環境

我們會在本地啟動兩臺虛擬機,一臺部署Nginx作為靜態文件服務器,一臺作為Jenkins服務器,在每臺虛擬機內部安裝Docker,使用Docker來完成Nginx與Jenkins的搭建、配置,然後手動在Jenkins配置內配置好一條Pipeline作為持續集成流水線,最後嘗試提交一次代碼去觸發一次持續集成操作,將最新的html項目代碼從Github上部署到Nginx中,實現持續集成。

避免本文過長,部分源代碼沒有貼在文中,本文參考完成源代碼在此:https://github.com/tw-wh-devops-community/cooking-chicken.git。建議在自己嘗試從0開始搭建的同時參考源碼閱讀本文。相信你一定會碰到很多坑,但坑外便是晴天。

首先我們需要兩臺機器

我們需要Vagrant

為什麼呢

無論你用的操作系統是Windows、Mac還是Linux,Oracle的Virtual Box都支持,那麼我們首先會使用Virtual Box來建立一個在硬件上絕對隔離的環境出來。

那麼Vagrant就是通過方便的命令操作來簡化Virtual Box的操作,同時提供了方便的虛擬機配置模塊,所以我們會使用這個工具來提升虛擬機的配置效率。

安裝Vagrant

在Mac上是自帶Virtual Box的,你用的版本可能需要更新才能配合Vagrant使用,Linux上請使用類似sudo apt-get install virtualbox的命令安裝。

那麼先裝上Vagrant吧:

  • Mac(https://www.vagrantup.com/downloads.html)
  • Ubuntu(sudo apt-get install vagrant)

安裝Vagrant插件

由於後續操作會涉及到將Nginx機器的私鑰發送給Jenkins機器來配置私鑰來完成虛擬機之間的無密碼訪問。但私鑰是在Nginx虛擬機創建之後才會由Vagrant創建的,所以需要在這個時間節點放到Jenkins目錄下便於Ansible把私鑰放到Jenkins虛擬機中。如果暫時不理解沒有關係,請看完”開始創建世界“之後回頭來看就會明白。

Vagrant的provision模塊可以在虛擬機啟動之後在虛擬機內部執行任意腳本,但是provision模塊並沒有提供執行宿主機上腳本的方式,所以需要你安裝如下模塊:

vagrant plugin install vagrant-host-shell

調試的時候比較有用的操作

  • 進入虛擬機:vagrant ssh
  • 休眠:vagrant suspend
  • 從休眠中恢復:vagrant resume
  • 移除虛擬機所有文件:vagrant destroy

開始創建世界!

Vagrantfile

我們來新建一個工程,在根目錄創建一個名為Vagrantfile的文件,內容如下:

手把手教你從零搭建一個持續集成環境

那麼現在可以啟動了,在命令行內跳轉到根目錄,使用vagrant up就可以將虛擬機按上面的配置啟動了,同時在啟動完成之後會調用provision模塊跑Ansible的對應腳本安裝配置虛擬機的依賴工具。啟動完成之後,那麼一個隔離的環境創建完畢,接下來我們可以在裡面任意玩耍了。

特別注意:因為第一次運行需要下載ubuntu/trusty64鏡像,以及把所有的配置甚至通過Docker下載Jenkins鏡像、slave鏡像,以及啟動Jenkins都寫到了Ansible中,所以跑完vagrant up需要較長時間

啟動、執行順序

基本是按Vagrant的配置文件的上下順序來啟動的。具體順序如下:

  1. 按Vagrantfile安裝並啟動Nginx虛擬機
  2. 執行Nginx虛擬機依賴的provision模塊
  3. 按Vagrantfile安裝並啟動Jenkins虛擬機
  4. 執行Jenkins虛擬機依賴的provision模塊

Jenkins訪問Nginx(選修,建議有時間或者將Jenkins搭建完成之後再看)

如果你能把所有環境啟動起來並能訪問Jenkins主頁,但此時你還無法在Jenkins上直接ssh登錄到Nginx,因為此時兩臺機器還沒有互信。但是幸運的是Vagrant啟動完Nginx之後就已經將私鑰(可以拿這個私鑰去訪問Nginx,無論你是誰)放到了宿主機上,那麼你可以手動將這個私鑰複製到Jenkins中,然後就可以在Jenkins中訪問Nginx了。

但是為了自動化上面的操作,進行以下的配置:Vagrant會在啟動一個虛擬機之後,會在Mac上創建.vagrant文件夾並把一些關於這個虛擬機的文件放到裡面,比如該虛擬機的私鑰,後面可以拿到這私鑰作為SSH聯絡的key。

比如下面這段配置會在Nginx虛擬機啟動之後,Jenkins虛擬機啟動之前執行。由於Jenkins虛擬機需要在部署代碼的時候使用到Nginx虛擬機的私鑰來部署,所以需要在Jenkins虛擬機執行Ansible之前將私鑰放到Jenkins的file文件夾中。

手把手教你從零搭建一個持續集成環境

另外,在Vagrantfile中,Ansible不是與兩臺虛擬機的配置寫在一起的,那麼Ansible如何判斷在哪臺虛擬機上安裝Nginx還是Jenkins呢?因為不同的虛擬機要執行Ansible的時候會根據主機名匹配來找到對應role的tasks從而還是能找到匹配的tasks。換句話說,Nginx安裝完成之後Vagrant攜帶Nginx相關參數執行下面這樣的一行命令來用limit匹配主機與對應Ansible的tasks:

手把手教你從零搭建一個持續集成環境

我們需要Ansible

什麼是Ansible

Ansible是一種自動化部署工具,可以用來自動化管理配置項、持續交付、(AWS)雲服務管理;

簡單來說也就是可以批量的遠程服務器上執行一系列的命令,其原理是基於ssh來和遠程主機進行通信的。

為什麼用Ansible

  • playbook使用的是yml語言,易讀性較好;
  • 沒有主節點和代理,僅僅依賴於SSH,使得應用的部署簡單而輕量;
  • 提供了大量模塊支持Google Compute Engine (GCE), Amazon Web Service(AWS);
  • Ansible支持多臺服務器同時管理部署;

安裝Ansible

Ansible是基於python開發的,需要在安裝有python的機器下才能夠安裝Ansible

  • 在本機安裝python:brew install python(Mac自帶ython,因此這步可以省略,inux系統中需要安裝Python)
  • 安裝pip:sudo apt install python-pip
  • 安裝Ansible:sudo pip install ansible

目錄結構

你可以按如下目錄結構去編寫你的Ansible文件。

手把手教你從零搭建一個持續集成環境

roles文件夾

roles是基於一個Ansible默認的目錄結構,Ansible在執行任務的時候會去默認加載templates、tasks以及handlers文件夾中的文件等。我們基於roles 對內容進行分組,使得我們可以容易地將不同的環境(如Java與NodeJs)區分開來,本次Demo中的roles下有三個文件夾,分別是common、jenkins和nginx,其中每個文件夾下都會定義一些例如tasks任務與相關配置文件。

role - common

前面已經說過本次demo需要在本地啟動兩臺虛擬機,分別在內部裝上Docker,在common中我們定義了安裝Docker的task,這樣在定義Jenkins服務器和部署nginx的服務器中都可以調用該task來安裝配置Docker環境;

install_docker.yml中應該包含如下內容:

  • 安裝Docker
  • 安裝docker-compose工具
  • 安裝docker-py依賴包(如果我們想用Ansible的docker模塊去執行docker相關命令的話需要這個依賴)

role - jenkins

定義安裝和部署Jenkins服務器的task:其中docker-compose.yml配置文件,是用於分別對jenkins-master和jenkins_slave進行一些基本配置;task下的main.yml文件是配置一系列的安裝命令,類似於在命令行中一行行輸入安裝和部署命令;

role - nginx

與jenkins文件夾類似,對Nginx服務器的一些基本配置:例如Nginx配置文件default.conf,配置文件中定義了templates下的index.html作為Nginx的入口模版文件,使Nginx作為一個文件服務器。task下的main.yml文件則是與jenkins中類似,配置了安裝部署命令,在使用vagrant up時通過Ansible來安裝並運行Nginx服務。

配置文件

Ansible的配置文件包括但不僅限於ansible.cfg、deploy.yml以及hosts

ansible.cfg文件

如在本Demo中用到的幾個配置:

  • forks:設置在與主機通信時的默認並行進程數,默認值為5;
  • inventory:設置主機與組之間的對應關係,在Ansible1.9之前使用的是hostfile;
  • host_key_checking:檢測主機密鑰的功能,可以通過設置值為false來禁用該功能(跳過兩臺主機之間首次連接需要確認的過程);
  • nocows:設置其值為1時禁用調用一些cowsay的特性,cowsay是linux系統下一個在終端用ASCII碼組成的小牛,這個小牛會說出你想要它說的話。
  • gathering:控制默認的遠程系統變量(facts)收集,有三種不同的值;默認是implicit,即每一次play,變量都會被收集,除非設置gather_facts: False;為explicit時,則facts不會被收集;為smart時,則沒有facts的新hosts將不會被掃描,用於節省fact收集;
  • fact_caching_timeout:定義fact緩存超時時間;
  • fact_caching:定義fact的緩存,2.4版本的Ansible支持redis和jsonfile兩種格式的緩存文件;
  • fact_caching_connection:定義cache的存儲位置,根據cache文件的格式不同定義的方式不同;

deploy.yml文件

這是Ansible的入口配置文件:定義hosts主機、以及相應主機需要執行的tasks等;

手把手教你從零搭建一個持續集成環境

hosts

然後加上遠程主機的網絡相關配置,這樣Ansible才能通過SSH到虛擬機中執行你寫的任務喲。

以如下命令為例,是為IP地址1192.168.56.102,端口號22的網絡地址設置一個別名nginx,且聲明其ssh private key文件的地址;

手把手教你從零搭建一個持續集成環境

與Vagrant結合

現在,Ansible的任務已經寫完了,我們需要將Ansible與Vagrant結合,將如下代碼加入到Vagrantfile中,可以在執行vagrant up的時候執行Ansible。

手把手教你從零搭建一個持續集成環境

虛擬機中的世界是如何構成的呢

現在你已經將所有的環境部署完成了,但是部署應用(Jenkins、Nginx)的過程還沒有提及,下面將帶你從Ansbile的對於每個虛擬機的任務開始,介紹相應的工具與具體的實施步驟。

Docker

什麼是Docker

Docker是一個開源的容器應用引擎,可以理解為一個存放應用容器的平臺,我們只需要簡單的幾行命令就可以構建一個與本地環境相對隔離的環境來運行我們的應用而不影響任何角色;

基本要素:

  • Container:負責應用程序的運行,包括操作系統、用戶添加的文件以及元數據
  • Images:只讀模版,即常說的Docker鏡像,用來運行Docker容器
  • Dockerfile:文件指令集,用來說明如何創建Docker鏡像

為什麼要用Docker

把一個應用封裝起來,可以在任何裝有Docker的環境下運行,統一運行環境;

那個大鯨魚(或者是貨輪)就是操作系統,把要交付的應用程序看成是各種貨物,原本要將各種各樣形狀、尺寸不同的貨物放到大鯨魚上,你得為每件貨物考慮怎麼安放(就是應用程序配套的環境),還得考慮貨物和貨物是否能疊起來(應用程序依賴的環境是否會衝突)。

現在使用了集裝箱(容器)把每件貨物都放到集裝箱裡,這樣大鯨魚可以用同樣地方式安放、堆疊集裝了,省事省力。

Docker中常用的命令

手把手教你從零搭建一個持續集成環境

怎麼用

要注意的是,Ansible對應的任務是在Vagrant啟動虛擬機之後執行的,是在虛擬機的內部,Docker容器的外部

安裝Nginx:由於我們只需要啟動一個Nginx的容器,直接使用Docker中run的命令去repository中下載安裝即可

  • 準備文件,例如default.conf,index.html
  • ```
  • name: copy nginx config file
  • copy:
  • src: default.conf
  • dest: /data/nginx/default.conf
  • name: copy default html file
  • template:
  • src: index.html
  • dest: /data/nginx/html/index.html
  • owner: vagrant
  • group: vagrant
  • ```
  • 使用Ansible中提供的Docker模塊安裝Nginx,包括拉Docker images,設置ports,以及多久需要pull一次新代碼等
手把手教你從零搭建一個持續集成環境

安裝Jenkins:demo中需要用到jenkins-master和jenkins-slave兩個container,因此使用docker-compose更加方便docker-compose.yml中定義了鏡像的地址、端口號等,並通過執行它進行在Docker中的部署。其中slave節點選用了jaydp17/jenkins-slave這樣一個包含Java、git、curl環境的Image方便執行持續集成任務。

手把手教你從零搭建一個持續集成環境

Nginx

什麼是Nginx

一款輕量級的Web 服務器/反向代理服務器及電子郵件(IMAP/POP3)代理服務器

為什麼用Nginx

首先需要一個服務器來部署我們的應用,而常用的服務器有例如apache的Apache HTTP Server、Nginx、tomcat等;Nginx是為了解決互聯網業內著名的 “C10K” 問題而生;

其中Nginx通常用來做靜態內容服務器,而tomcat一般用於做動態應用的服務器,通常稱之為web容器;Nginx相比於apache的優點:

  • 輕量級,同樣起web服務,比apache佔用更少的內存及資源;
  • 抗併發,Nginx處理請求是異步非阻塞的,而apache則是阻塞型的,在高併發下Nginx能保持低資源低消耗高性能
  • 提供負載均衡;
  • 配置簡潔;
  • 社區活躍,各種高性能模塊出品迅速等;

怎麼用Nginx

在demo中寫了一個role來定義安裝配置Nginx需要的操作流程,用的是Docker提供的Nginx鏡像,在Docker中安裝配置Nginx,為了使Nginx能夠啟動起來,我們還需要進行一系列的配置,包括配置文件和模版文件等;default.conf就是Nginx的配置文件,此處http模塊的相關配置:

  • listen 80:監聽的端口號是80;
  • default_server:設定為默認虛擬主機;
  • server_name localhost:設置虛擬主機名稱為localhost;
  • root /usr/share/nginx/html:設置web服務URL資源映射的本地文件系統的資源所在的目錄;
  • index index.html index.htm:定義默認主頁面,需要自己編寫並放到Ansbile對應目錄;
手把手教你從零搭建一個持續集成環境

還有一些其他的配置,詳情請參考https://www.nginx.com/resources/wiki/start/topics/examples/full/

Ansible關於Nginx的task中yml文件的配置:

  • 創建文件夾
  • copy Nginx的配置文件到環境中
  • copy模版文件
  • 以及使用Docker鏡像運行Nginx
手把手教你從零搭建一個持續集成環境

世界有了,來聯通各國吧

到現在為止,你已經瞭解了所有我們使用的工具以及通過運行命令搭建完成了一套持續集成環境的基礎設施,但是還需要對Jenkins進行一些配置才能真正做到持續集成。

Jenkins的配置

現在你可以訪問 http://192.168.56.102:8080 了,然後頁面提示需要你輸入Administrator password。該密碼可以通過下面的方式獲取:

  1. 進入Jenkins虛擬機:vagrant ssh jenkins
  2. 獲取root權限:sudo su
  3. 進入Jenkins master容器:docker exec -it jenkins_master bash
  4. 找到密碼:cat /var/jenkins_home/secrets/initialAdminPassword

然後將密碼複製到頁面上點擊確定,隨後點擊安裝推薦的插件,本文將使用到的Jenkins功能不會超出推薦的插件的範圍。然後創建好用戶就可以登錄了。

Slave

來到主界面之後,接下來我們來配置一臺slave節點來幫我們執行任務,依次點擊Manage Jenkins -> Manage Nodes -> New Node,按照下圖進行配置。

"

本文將帶領你從0開始,用Vagrant + Docker + Ansible + Jenkins + Nginx + GitHub等工具和資源來搭建一條可執行可擴展的持續集成流水線,即使這些名字你都沒聽過也沒關係,本文將會在需要的時候一一解釋給你聽。

By: 巧穎 & 天一

總覽

這是我們將要搭建的所有基礎設施的總體架構圖,我們將在本文中手把手教你搭建這樣一個持續集成環境。

手把手教你從零搭建一個持續集成環境

我們會在本地啟動兩臺虛擬機,一臺部署Nginx作為靜態文件服務器,一臺作為Jenkins服務器,在每臺虛擬機內部安裝Docker,使用Docker來完成Nginx與Jenkins的搭建、配置,然後手動在Jenkins配置內配置好一條Pipeline作為持續集成流水線,最後嘗試提交一次代碼去觸發一次持續集成操作,將最新的html項目代碼從Github上部署到Nginx中,實現持續集成。

避免本文過長,部分源代碼沒有貼在文中,本文參考完成源代碼在此:https://github.com/tw-wh-devops-community/cooking-chicken.git。建議在自己嘗試從0開始搭建的同時參考源碼閱讀本文。相信你一定會碰到很多坑,但坑外便是晴天。

首先我們需要兩臺機器

我們需要Vagrant

為什麼呢

無論你用的操作系統是Windows、Mac還是Linux,Oracle的Virtual Box都支持,那麼我們首先會使用Virtual Box來建立一個在硬件上絕對隔離的環境出來。

那麼Vagrant就是通過方便的命令操作來簡化Virtual Box的操作,同時提供了方便的虛擬機配置模塊,所以我們會使用這個工具來提升虛擬機的配置效率。

安裝Vagrant

在Mac上是自帶Virtual Box的,你用的版本可能需要更新才能配合Vagrant使用,Linux上請使用類似sudo apt-get install virtualbox的命令安裝。

那麼先裝上Vagrant吧:

  • Mac(https://www.vagrantup.com/downloads.html)
  • Ubuntu(sudo apt-get install vagrant)

安裝Vagrant插件

由於後續操作會涉及到將Nginx機器的私鑰發送給Jenkins機器來配置私鑰來完成虛擬機之間的無密碼訪問。但私鑰是在Nginx虛擬機創建之後才會由Vagrant創建的,所以需要在這個時間節點放到Jenkins目錄下便於Ansible把私鑰放到Jenkins虛擬機中。如果暫時不理解沒有關係,請看完”開始創建世界“之後回頭來看就會明白。

Vagrant的provision模塊可以在虛擬機啟動之後在虛擬機內部執行任意腳本,但是provision模塊並沒有提供執行宿主機上腳本的方式,所以需要你安裝如下模塊:

vagrant plugin install vagrant-host-shell

調試的時候比較有用的操作

  • 進入虛擬機:vagrant ssh
  • 休眠:vagrant suspend
  • 從休眠中恢復:vagrant resume
  • 移除虛擬機所有文件:vagrant destroy

開始創建世界!

Vagrantfile

我們來新建一個工程,在根目錄創建一個名為Vagrantfile的文件,內容如下:

手把手教你從零搭建一個持續集成環境

那麼現在可以啟動了,在命令行內跳轉到根目錄,使用vagrant up就可以將虛擬機按上面的配置啟動了,同時在啟動完成之後會調用provision模塊跑Ansible的對應腳本安裝配置虛擬機的依賴工具。啟動完成之後,那麼一個隔離的環境創建完畢,接下來我們可以在裡面任意玩耍了。

特別注意:因為第一次運行需要下載ubuntu/trusty64鏡像,以及把所有的配置甚至通過Docker下載Jenkins鏡像、slave鏡像,以及啟動Jenkins都寫到了Ansible中,所以跑完vagrant up需要較長時間

啟動、執行順序

基本是按Vagrant的配置文件的上下順序來啟動的。具體順序如下:

  1. 按Vagrantfile安裝並啟動Nginx虛擬機
  2. 執行Nginx虛擬機依賴的provision模塊
  3. 按Vagrantfile安裝並啟動Jenkins虛擬機
  4. 執行Jenkins虛擬機依賴的provision模塊

Jenkins訪問Nginx(選修,建議有時間或者將Jenkins搭建完成之後再看)

如果你能把所有環境啟動起來並能訪問Jenkins主頁,但此時你還無法在Jenkins上直接ssh登錄到Nginx,因為此時兩臺機器還沒有互信。但是幸運的是Vagrant啟動完Nginx之後就已經將私鑰(可以拿這個私鑰去訪問Nginx,無論你是誰)放到了宿主機上,那麼你可以手動將這個私鑰複製到Jenkins中,然後就可以在Jenkins中訪問Nginx了。

但是為了自動化上面的操作,進行以下的配置:Vagrant會在啟動一個虛擬機之後,會在Mac上創建.vagrant文件夾並把一些關於這個虛擬機的文件放到裡面,比如該虛擬機的私鑰,後面可以拿到這私鑰作為SSH聯絡的key。

比如下面這段配置會在Nginx虛擬機啟動之後,Jenkins虛擬機啟動之前執行。由於Jenkins虛擬機需要在部署代碼的時候使用到Nginx虛擬機的私鑰來部署,所以需要在Jenkins虛擬機執行Ansible之前將私鑰放到Jenkins的file文件夾中。

手把手教你從零搭建一個持續集成環境

另外,在Vagrantfile中,Ansible不是與兩臺虛擬機的配置寫在一起的,那麼Ansible如何判斷在哪臺虛擬機上安裝Nginx還是Jenkins呢?因為不同的虛擬機要執行Ansible的時候會根據主機名匹配來找到對應role的tasks從而還是能找到匹配的tasks。換句話說,Nginx安裝完成之後Vagrant攜帶Nginx相關參數執行下面這樣的一行命令來用limit匹配主機與對應Ansible的tasks:

手把手教你從零搭建一個持續集成環境

我們需要Ansible

什麼是Ansible

Ansible是一種自動化部署工具,可以用來自動化管理配置項、持續交付、(AWS)雲服務管理;

簡單來說也就是可以批量的遠程服務器上執行一系列的命令,其原理是基於ssh來和遠程主機進行通信的。

為什麼用Ansible

  • playbook使用的是yml語言,易讀性較好;
  • 沒有主節點和代理,僅僅依賴於SSH,使得應用的部署簡單而輕量;
  • 提供了大量模塊支持Google Compute Engine (GCE), Amazon Web Service(AWS);
  • Ansible支持多臺服務器同時管理部署;

安裝Ansible

Ansible是基於python開發的,需要在安裝有python的機器下才能夠安裝Ansible

  • 在本機安裝python:brew install python(Mac自帶ython,因此這步可以省略,inux系統中需要安裝Python)
  • 安裝pip:sudo apt install python-pip
  • 安裝Ansible:sudo pip install ansible

目錄結構

你可以按如下目錄結構去編寫你的Ansible文件。

手把手教你從零搭建一個持續集成環境

roles文件夾

roles是基於一個Ansible默認的目錄結構,Ansible在執行任務的時候會去默認加載templates、tasks以及handlers文件夾中的文件等。我們基於roles 對內容進行分組,使得我們可以容易地將不同的環境(如Java與NodeJs)區分開來,本次Demo中的roles下有三個文件夾,分別是common、jenkins和nginx,其中每個文件夾下都會定義一些例如tasks任務與相關配置文件。

role - common

前面已經說過本次demo需要在本地啟動兩臺虛擬機,分別在內部裝上Docker,在common中我們定義了安裝Docker的task,這樣在定義Jenkins服務器和部署nginx的服務器中都可以調用該task來安裝配置Docker環境;

install_docker.yml中應該包含如下內容:

  • 安裝Docker
  • 安裝docker-compose工具
  • 安裝docker-py依賴包(如果我們想用Ansible的docker模塊去執行docker相關命令的話需要這個依賴)

role - jenkins

定義安裝和部署Jenkins服務器的task:其中docker-compose.yml配置文件,是用於分別對jenkins-master和jenkins_slave進行一些基本配置;task下的main.yml文件是配置一系列的安裝命令,類似於在命令行中一行行輸入安裝和部署命令;

role - nginx

與jenkins文件夾類似,對Nginx服務器的一些基本配置:例如Nginx配置文件default.conf,配置文件中定義了templates下的index.html作為Nginx的入口模版文件,使Nginx作為一個文件服務器。task下的main.yml文件則是與jenkins中類似,配置了安裝部署命令,在使用vagrant up時通過Ansible來安裝並運行Nginx服務。

配置文件

Ansible的配置文件包括但不僅限於ansible.cfg、deploy.yml以及hosts

ansible.cfg文件

如在本Demo中用到的幾個配置:

  • forks:設置在與主機通信時的默認並行進程數,默認值為5;
  • inventory:設置主機與組之間的對應關係,在Ansible1.9之前使用的是hostfile;
  • host_key_checking:檢測主機密鑰的功能,可以通過設置值為false來禁用該功能(跳過兩臺主機之間首次連接需要確認的過程);
  • nocows:設置其值為1時禁用調用一些cowsay的特性,cowsay是linux系統下一個在終端用ASCII碼組成的小牛,這個小牛會說出你想要它說的話。
  • gathering:控制默認的遠程系統變量(facts)收集,有三種不同的值;默認是implicit,即每一次play,變量都會被收集,除非設置gather_facts: False;為explicit時,則facts不會被收集;為smart時,則沒有facts的新hosts將不會被掃描,用於節省fact收集;
  • fact_caching_timeout:定義fact緩存超時時間;
  • fact_caching:定義fact的緩存,2.4版本的Ansible支持redis和jsonfile兩種格式的緩存文件;
  • fact_caching_connection:定義cache的存儲位置,根據cache文件的格式不同定義的方式不同;

deploy.yml文件

這是Ansible的入口配置文件:定義hosts主機、以及相應主機需要執行的tasks等;

手把手教你從零搭建一個持續集成環境

hosts

然後加上遠程主機的網絡相關配置,這樣Ansible才能通過SSH到虛擬機中執行你寫的任務喲。

以如下命令為例,是為IP地址1192.168.56.102,端口號22的網絡地址設置一個別名nginx,且聲明其ssh private key文件的地址;

手把手教你從零搭建一個持續集成環境

與Vagrant結合

現在,Ansible的任務已經寫完了,我們需要將Ansible與Vagrant結合,將如下代碼加入到Vagrantfile中,可以在執行vagrant up的時候執行Ansible。

手把手教你從零搭建一個持續集成環境

虛擬機中的世界是如何構成的呢

現在你已經將所有的環境部署完成了,但是部署應用(Jenkins、Nginx)的過程還沒有提及,下面將帶你從Ansbile的對於每個虛擬機的任務開始,介紹相應的工具與具體的實施步驟。

Docker

什麼是Docker

Docker是一個開源的容器應用引擎,可以理解為一個存放應用容器的平臺,我們只需要簡單的幾行命令就可以構建一個與本地環境相對隔離的環境來運行我們的應用而不影響任何角色;

基本要素:

  • Container:負責應用程序的運行,包括操作系統、用戶添加的文件以及元數據
  • Images:只讀模版,即常說的Docker鏡像,用來運行Docker容器
  • Dockerfile:文件指令集,用來說明如何創建Docker鏡像

為什麼要用Docker

把一個應用封裝起來,可以在任何裝有Docker的環境下運行,統一運行環境;

那個大鯨魚(或者是貨輪)就是操作系統,把要交付的應用程序看成是各種貨物,原本要將各種各樣形狀、尺寸不同的貨物放到大鯨魚上,你得為每件貨物考慮怎麼安放(就是應用程序配套的環境),還得考慮貨物和貨物是否能疊起來(應用程序依賴的環境是否會衝突)。

現在使用了集裝箱(容器)把每件貨物都放到集裝箱裡,這樣大鯨魚可以用同樣地方式安放、堆疊集裝了,省事省力。

Docker中常用的命令

手把手教你從零搭建一個持續集成環境

怎麼用

要注意的是,Ansible對應的任務是在Vagrant啟動虛擬機之後執行的,是在虛擬機的內部,Docker容器的外部

安裝Nginx:由於我們只需要啟動一個Nginx的容器,直接使用Docker中run的命令去repository中下載安裝即可

  • 準備文件,例如default.conf,index.html
  • ```
  • name: copy nginx config file
  • copy:
  • src: default.conf
  • dest: /data/nginx/default.conf
  • name: copy default html file
  • template:
  • src: index.html
  • dest: /data/nginx/html/index.html
  • owner: vagrant
  • group: vagrant
  • ```
  • 使用Ansible中提供的Docker模塊安裝Nginx,包括拉Docker images,設置ports,以及多久需要pull一次新代碼等
手把手教你從零搭建一個持續集成環境

安裝Jenkins:demo中需要用到jenkins-master和jenkins-slave兩個container,因此使用docker-compose更加方便docker-compose.yml中定義了鏡像的地址、端口號等,並通過執行它進行在Docker中的部署。其中slave節點選用了jaydp17/jenkins-slave這樣一個包含Java、git、curl環境的Image方便執行持續集成任務。

手把手教你從零搭建一個持續集成環境

Nginx

什麼是Nginx

一款輕量級的Web 服務器/反向代理服務器及電子郵件(IMAP/POP3)代理服務器

為什麼用Nginx

首先需要一個服務器來部署我們的應用,而常用的服務器有例如apache的Apache HTTP Server、Nginx、tomcat等;Nginx是為了解決互聯網業內著名的 “C10K” 問題而生;

其中Nginx通常用來做靜態內容服務器,而tomcat一般用於做動態應用的服務器,通常稱之為web容器;Nginx相比於apache的優點:

  • 輕量級,同樣起web服務,比apache佔用更少的內存及資源;
  • 抗併發,Nginx處理請求是異步非阻塞的,而apache則是阻塞型的,在高併發下Nginx能保持低資源低消耗高性能
  • 提供負載均衡;
  • 配置簡潔;
  • 社區活躍,各種高性能模塊出品迅速等;

怎麼用Nginx

在demo中寫了一個role來定義安裝配置Nginx需要的操作流程,用的是Docker提供的Nginx鏡像,在Docker中安裝配置Nginx,為了使Nginx能夠啟動起來,我們還需要進行一系列的配置,包括配置文件和模版文件等;default.conf就是Nginx的配置文件,此處http模塊的相關配置:

  • listen 80:監聽的端口號是80;
  • default_server:設定為默認虛擬主機;
  • server_name localhost:設置虛擬主機名稱為localhost;
  • root /usr/share/nginx/html:設置web服務URL資源映射的本地文件系統的資源所在的目錄;
  • index index.html index.htm:定義默認主頁面,需要自己編寫並放到Ansbile對應目錄;
手把手教你從零搭建一個持續集成環境

還有一些其他的配置,詳情請參考https://www.nginx.com/resources/wiki/start/topics/examples/full/

Ansible關於Nginx的task中yml文件的配置:

  • 創建文件夾
  • copy Nginx的配置文件到環境中
  • copy模版文件
  • 以及使用Docker鏡像運行Nginx
手把手教你從零搭建一個持續集成環境

世界有了,來聯通各國吧

到現在為止,你已經瞭解了所有我們使用的工具以及通過運行命令搭建完成了一套持續集成環境的基礎設施,但是還需要對Jenkins進行一些配置才能真正做到持續集成。

Jenkins的配置

現在你可以訪問 http://192.168.56.102:8080 了,然後頁面提示需要你輸入Administrator password。該密碼可以通過下面的方式獲取:

  1. 進入Jenkins虛擬機:vagrant ssh jenkins
  2. 獲取root權限:sudo su
  3. 進入Jenkins master容器:docker exec -it jenkins_master bash
  4. 找到密碼:cat /var/jenkins_home/secrets/initialAdminPassword

然後將密碼複製到頁面上點擊確定,隨後點擊安裝推薦的插件,本文將使用到的Jenkins功能不會超出推薦的插件的範圍。然後創建好用戶就可以登錄了。

Slave

來到主界面之後,接下來我們來配置一臺slave節點來幫我們執行任務,依次點擊Manage Jenkins -> Manage Nodes -> New Node,按照下圖進行配置。

手把手教你從零搭建一個持續集成環境

簡單起見,用密碼登錄的方式進行身份驗證,用戶名密碼都為jenkins。

那麼問題來了,為什麼slave節點的用戶名密碼是jenkins呢?是在這個Dockerfile裡配置的。我們用的雖然是jaydp17/jenkins-slave,但是你可以看到這個鏡像的構建文件中引用了evarga/jenkins-slave,其中echo "jenkins:jenkins" | chpasswd可以設置密碼。

"

本文將帶領你從0開始,用Vagrant + Docker + Ansible + Jenkins + Nginx + GitHub等工具和資源來搭建一條可執行可擴展的持續集成流水線,即使這些名字你都沒聽過也沒關係,本文將會在需要的時候一一解釋給你聽。

By: 巧穎 & 天一

總覽

這是我們將要搭建的所有基礎設施的總體架構圖,我們將在本文中手把手教你搭建這樣一個持續集成環境。

手把手教你從零搭建一個持續集成環境

我們會在本地啟動兩臺虛擬機,一臺部署Nginx作為靜態文件服務器,一臺作為Jenkins服務器,在每臺虛擬機內部安裝Docker,使用Docker來完成Nginx與Jenkins的搭建、配置,然後手動在Jenkins配置內配置好一條Pipeline作為持續集成流水線,最後嘗試提交一次代碼去觸發一次持續集成操作,將最新的html項目代碼從Github上部署到Nginx中,實現持續集成。

避免本文過長,部分源代碼沒有貼在文中,本文參考完成源代碼在此:https://github.com/tw-wh-devops-community/cooking-chicken.git。建議在自己嘗試從0開始搭建的同時參考源碼閱讀本文。相信你一定會碰到很多坑,但坑外便是晴天。

首先我們需要兩臺機器

我們需要Vagrant

為什麼呢

無論你用的操作系統是Windows、Mac還是Linux,Oracle的Virtual Box都支持,那麼我們首先會使用Virtual Box來建立一個在硬件上絕對隔離的環境出來。

那麼Vagrant就是通過方便的命令操作來簡化Virtual Box的操作,同時提供了方便的虛擬機配置模塊,所以我們會使用這個工具來提升虛擬機的配置效率。

安裝Vagrant

在Mac上是自帶Virtual Box的,你用的版本可能需要更新才能配合Vagrant使用,Linux上請使用類似sudo apt-get install virtualbox的命令安裝。

那麼先裝上Vagrant吧:

  • Mac(https://www.vagrantup.com/downloads.html)
  • Ubuntu(sudo apt-get install vagrant)

安裝Vagrant插件

由於後續操作會涉及到將Nginx機器的私鑰發送給Jenkins機器來配置私鑰來完成虛擬機之間的無密碼訪問。但私鑰是在Nginx虛擬機創建之後才會由Vagrant創建的,所以需要在這個時間節點放到Jenkins目錄下便於Ansible把私鑰放到Jenkins虛擬機中。如果暫時不理解沒有關係,請看完”開始創建世界“之後回頭來看就會明白。

Vagrant的provision模塊可以在虛擬機啟動之後在虛擬機內部執行任意腳本,但是provision模塊並沒有提供執行宿主機上腳本的方式,所以需要你安裝如下模塊:

vagrant plugin install vagrant-host-shell

調試的時候比較有用的操作

  • 進入虛擬機:vagrant ssh
  • 休眠:vagrant suspend
  • 從休眠中恢復:vagrant resume
  • 移除虛擬機所有文件:vagrant destroy

開始創建世界!

Vagrantfile

我們來新建一個工程,在根目錄創建一個名為Vagrantfile的文件,內容如下:

手把手教你從零搭建一個持續集成環境

那麼現在可以啟動了,在命令行內跳轉到根目錄,使用vagrant up就可以將虛擬機按上面的配置啟動了,同時在啟動完成之後會調用provision模塊跑Ansible的對應腳本安裝配置虛擬機的依賴工具。啟動完成之後,那麼一個隔離的環境創建完畢,接下來我們可以在裡面任意玩耍了。

特別注意:因為第一次運行需要下載ubuntu/trusty64鏡像,以及把所有的配置甚至通過Docker下載Jenkins鏡像、slave鏡像,以及啟動Jenkins都寫到了Ansible中,所以跑完vagrant up需要較長時間

啟動、執行順序

基本是按Vagrant的配置文件的上下順序來啟動的。具體順序如下:

  1. 按Vagrantfile安裝並啟動Nginx虛擬機
  2. 執行Nginx虛擬機依賴的provision模塊
  3. 按Vagrantfile安裝並啟動Jenkins虛擬機
  4. 執行Jenkins虛擬機依賴的provision模塊

Jenkins訪問Nginx(選修,建議有時間或者將Jenkins搭建完成之後再看)

如果你能把所有環境啟動起來並能訪問Jenkins主頁,但此時你還無法在Jenkins上直接ssh登錄到Nginx,因為此時兩臺機器還沒有互信。但是幸運的是Vagrant啟動完Nginx之後就已經將私鑰(可以拿這個私鑰去訪問Nginx,無論你是誰)放到了宿主機上,那麼你可以手動將這個私鑰複製到Jenkins中,然後就可以在Jenkins中訪問Nginx了。

但是為了自動化上面的操作,進行以下的配置:Vagrant會在啟動一個虛擬機之後,會在Mac上創建.vagrant文件夾並把一些關於這個虛擬機的文件放到裡面,比如該虛擬機的私鑰,後面可以拿到這私鑰作為SSH聯絡的key。

比如下面這段配置會在Nginx虛擬機啟動之後,Jenkins虛擬機啟動之前執行。由於Jenkins虛擬機需要在部署代碼的時候使用到Nginx虛擬機的私鑰來部署,所以需要在Jenkins虛擬機執行Ansible之前將私鑰放到Jenkins的file文件夾中。

手把手教你從零搭建一個持續集成環境

另外,在Vagrantfile中,Ansible不是與兩臺虛擬機的配置寫在一起的,那麼Ansible如何判斷在哪臺虛擬機上安裝Nginx還是Jenkins呢?因為不同的虛擬機要執行Ansible的時候會根據主機名匹配來找到對應role的tasks從而還是能找到匹配的tasks。換句話說,Nginx安裝完成之後Vagrant攜帶Nginx相關參數執行下面這樣的一行命令來用limit匹配主機與對應Ansible的tasks:

手把手教你從零搭建一個持續集成環境

我們需要Ansible

什麼是Ansible

Ansible是一種自動化部署工具,可以用來自動化管理配置項、持續交付、(AWS)雲服務管理;

簡單來說也就是可以批量的遠程服務器上執行一系列的命令,其原理是基於ssh來和遠程主機進行通信的。

為什麼用Ansible

  • playbook使用的是yml語言,易讀性較好;
  • 沒有主節點和代理,僅僅依賴於SSH,使得應用的部署簡單而輕量;
  • 提供了大量模塊支持Google Compute Engine (GCE), Amazon Web Service(AWS);
  • Ansible支持多臺服務器同時管理部署;

安裝Ansible

Ansible是基於python開發的,需要在安裝有python的機器下才能夠安裝Ansible

  • 在本機安裝python:brew install python(Mac自帶ython,因此這步可以省略,inux系統中需要安裝Python)
  • 安裝pip:sudo apt install python-pip
  • 安裝Ansible:sudo pip install ansible

目錄結構

你可以按如下目錄結構去編寫你的Ansible文件。

手把手教你從零搭建一個持續集成環境

roles文件夾

roles是基於一個Ansible默認的目錄結構,Ansible在執行任務的時候會去默認加載templates、tasks以及handlers文件夾中的文件等。我們基於roles 對內容進行分組,使得我們可以容易地將不同的環境(如Java與NodeJs)區分開來,本次Demo中的roles下有三個文件夾,分別是common、jenkins和nginx,其中每個文件夾下都會定義一些例如tasks任務與相關配置文件。

role - common

前面已經說過本次demo需要在本地啟動兩臺虛擬機,分別在內部裝上Docker,在common中我們定義了安裝Docker的task,這樣在定義Jenkins服務器和部署nginx的服務器中都可以調用該task來安裝配置Docker環境;

install_docker.yml中應該包含如下內容:

  • 安裝Docker
  • 安裝docker-compose工具
  • 安裝docker-py依賴包(如果我們想用Ansible的docker模塊去執行docker相關命令的話需要這個依賴)

role - jenkins

定義安裝和部署Jenkins服務器的task:其中docker-compose.yml配置文件,是用於分別對jenkins-master和jenkins_slave進行一些基本配置;task下的main.yml文件是配置一系列的安裝命令,類似於在命令行中一行行輸入安裝和部署命令;

role - nginx

與jenkins文件夾類似,對Nginx服務器的一些基本配置:例如Nginx配置文件default.conf,配置文件中定義了templates下的index.html作為Nginx的入口模版文件,使Nginx作為一個文件服務器。task下的main.yml文件則是與jenkins中類似,配置了安裝部署命令,在使用vagrant up時通過Ansible來安裝並運行Nginx服務。

配置文件

Ansible的配置文件包括但不僅限於ansible.cfg、deploy.yml以及hosts

ansible.cfg文件

如在本Demo中用到的幾個配置:

  • forks:設置在與主機通信時的默認並行進程數,默認值為5;
  • inventory:設置主機與組之間的對應關係,在Ansible1.9之前使用的是hostfile;
  • host_key_checking:檢測主機密鑰的功能,可以通過設置值為false來禁用該功能(跳過兩臺主機之間首次連接需要確認的過程);
  • nocows:設置其值為1時禁用調用一些cowsay的特性,cowsay是linux系統下一個在終端用ASCII碼組成的小牛,這個小牛會說出你想要它說的話。
  • gathering:控制默認的遠程系統變量(facts)收集,有三種不同的值;默認是implicit,即每一次play,變量都會被收集,除非設置gather_facts: False;為explicit時,則facts不會被收集;為smart時,則沒有facts的新hosts將不會被掃描,用於節省fact收集;
  • fact_caching_timeout:定義fact緩存超時時間;
  • fact_caching:定義fact的緩存,2.4版本的Ansible支持redis和jsonfile兩種格式的緩存文件;
  • fact_caching_connection:定義cache的存儲位置,根據cache文件的格式不同定義的方式不同;

deploy.yml文件

這是Ansible的入口配置文件:定義hosts主機、以及相應主機需要執行的tasks等;

手把手教你從零搭建一個持續集成環境

hosts

然後加上遠程主機的網絡相關配置,這樣Ansible才能通過SSH到虛擬機中執行你寫的任務喲。

以如下命令為例,是為IP地址1192.168.56.102,端口號22的網絡地址設置一個別名nginx,且聲明其ssh private key文件的地址;

手把手教你從零搭建一個持續集成環境

與Vagrant結合

現在,Ansible的任務已經寫完了,我們需要將Ansible與Vagrant結合,將如下代碼加入到Vagrantfile中,可以在執行vagrant up的時候執行Ansible。

手把手教你從零搭建一個持續集成環境

虛擬機中的世界是如何構成的呢

現在你已經將所有的環境部署完成了,但是部署應用(Jenkins、Nginx)的過程還沒有提及,下面將帶你從Ansbile的對於每個虛擬機的任務開始,介紹相應的工具與具體的實施步驟。

Docker

什麼是Docker

Docker是一個開源的容器應用引擎,可以理解為一個存放應用容器的平臺,我們只需要簡單的幾行命令就可以構建一個與本地環境相對隔離的環境來運行我們的應用而不影響任何角色;

基本要素:

  • Container:負責應用程序的運行,包括操作系統、用戶添加的文件以及元數據
  • Images:只讀模版,即常說的Docker鏡像,用來運行Docker容器
  • Dockerfile:文件指令集,用來說明如何創建Docker鏡像

為什麼要用Docker

把一個應用封裝起來,可以在任何裝有Docker的環境下運行,統一運行環境;

那個大鯨魚(或者是貨輪)就是操作系統,把要交付的應用程序看成是各種貨物,原本要將各種各樣形狀、尺寸不同的貨物放到大鯨魚上,你得為每件貨物考慮怎麼安放(就是應用程序配套的環境),還得考慮貨物和貨物是否能疊起來(應用程序依賴的環境是否會衝突)。

現在使用了集裝箱(容器)把每件貨物都放到集裝箱裡,這樣大鯨魚可以用同樣地方式安放、堆疊集裝了,省事省力。

Docker中常用的命令

手把手教你從零搭建一個持續集成環境

怎麼用

要注意的是,Ansible對應的任務是在Vagrant啟動虛擬機之後執行的,是在虛擬機的內部,Docker容器的外部

安裝Nginx:由於我們只需要啟動一個Nginx的容器,直接使用Docker中run的命令去repository中下載安裝即可

  • 準備文件,例如default.conf,index.html
  • ```
  • name: copy nginx config file
  • copy:
  • src: default.conf
  • dest: /data/nginx/default.conf
  • name: copy default html file
  • template:
  • src: index.html
  • dest: /data/nginx/html/index.html
  • owner: vagrant
  • group: vagrant
  • ```
  • 使用Ansible中提供的Docker模塊安裝Nginx,包括拉Docker images,設置ports,以及多久需要pull一次新代碼等
手把手教你從零搭建一個持續集成環境

安裝Jenkins:demo中需要用到jenkins-master和jenkins-slave兩個container,因此使用docker-compose更加方便docker-compose.yml中定義了鏡像的地址、端口號等,並通過執行它進行在Docker中的部署。其中slave節點選用了jaydp17/jenkins-slave這樣一個包含Java、git、curl環境的Image方便執行持續集成任務。

手把手教你從零搭建一個持續集成環境

Nginx

什麼是Nginx

一款輕量級的Web 服務器/反向代理服務器及電子郵件(IMAP/POP3)代理服務器

為什麼用Nginx

首先需要一個服務器來部署我們的應用,而常用的服務器有例如apache的Apache HTTP Server、Nginx、tomcat等;Nginx是為了解決互聯網業內著名的 “C10K” 問題而生;

其中Nginx通常用來做靜態內容服務器,而tomcat一般用於做動態應用的服務器,通常稱之為web容器;Nginx相比於apache的優點:

  • 輕量級,同樣起web服務,比apache佔用更少的內存及資源;
  • 抗併發,Nginx處理請求是異步非阻塞的,而apache則是阻塞型的,在高併發下Nginx能保持低資源低消耗高性能
  • 提供負載均衡;
  • 配置簡潔;
  • 社區活躍,各種高性能模塊出品迅速等;

怎麼用Nginx

在demo中寫了一個role來定義安裝配置Nginx需要的操作流程,用的是Docker提供的Nginx鏡像,在Docker中安裝配置Nginx,為了使Nginx能夠啟動起來,我們還需要進行一系列的配置,包括配置文件和模版文件等;default.conf就是Nginx的配置文件,此處http模塊的相關配置:

  • listen 80:監聽的端口號是80;
  • default_server:設定為默認虛擬主機;
  • server_name localhost:設置虛擬主機名稱為localhost;
  • root /usr/share/nginx/html:設置web服務URL資源映射的本地文件系統的資源所在的目錄;
  • index index.html index.htm:定義默認主頁面,需要自己編寫並放到Ansbile對應目錄;
手把手教你從零搭建一個持續集成環境

還有一些其他的配置,詳情請參考https://www.nginx.com/resources/wiki/start/topics/examples/full/

Ansible關於Nginx的task中yml文件的配置:

  • 創建文件夾
  • copy Nginx的配置文件到環境中
  • copy模版文件
  • 以及使用Docker鏡像運行Nginx
手把手教你從零搭建一個持續集成環境

世界有了,來聯通各國吧

到現在為止,你已經瞭解了所有我們使用的工具以及通過運行命令搭建完成了一套持續集成環境的基礎設施,但是還需要對Jenkins進行一些配置才能真正做到持續集成。

Jenkins的配置

現在你可以訪問 http://192.168.56.102:8080 了,然後頁面提示需要你輸入Administrator password。該密碼可以通過下面的方式獲取:

  1. 進入Jenkins虛擬機:vagrant ssh jenkins
  2. 獲取root權限:sudo su
  3. 進入Jenkins master容器:docker exec -it jenkins_master bash
  4. 找到密碼:cat /var/jenkins_home/secrets/initialAdminPassword

然後將密碼複製到頁面上點擊確定,隨後點擊安裝推薦的插件,本文將使用到的Jenkins功能不會超出推薦的插件的範圍。然後創建好用戶就可以登錄了。

Slave

來到主界面之後,接下來我們來配置一臺slave節點來幫我們執行任務,依次點擊Manage Jenkins -> Manage Nodes -> New Node,按照下圖進行配置。

手把手教你從零搭建一個持續集成環境

簡單起見,用密碼登錄的方式進行身份驗證,用戶名密碼都為jenkins。

那麼問題來了,為什麼slave節點的用戶名密碼是jenkins呢?是在這個Dockerfile裡配置的。我們用的雖然是jaydp17/jenkins-slave,但是你可以看到這個鏡像的構建文件中引用了evarga/jenkins-slave,其中echo "jenkins:jenkins" | chpasswd可以設置密碼。

手把手教你從零搭建一個持續集成環境

另外要注意一下,我們通過設置Host key verification strategy為Non verifying verification strategy從而關閉了slave主機的公鑰檢查,更多瞭解請參看這篇文章。

如果你現在能在Jenkins界面上看到你剛剛創建的slave節點,那麼已經完成配置了。另外,為了讓部署過程僅僅在slave節點上執行來確認slave是否已經部署成功,可以嘗試點擊master節點右方的配置按鈕將默認開啟的master節點中的executors數量改為0。

創建Pipeline

接下來我們將創建一條流水線。回到Jenkins首頁,然後

  1. 點擊 create new jobs
  2. 選擇Pipeline分類點擊OK
  3. 勾上Poll SCM,並填入* * * * *,讓Jenkins每分鐘幫我們check一次Github上是否有提交。
  4. Definition中選擇’Pipeline script from SCM’,我們通過Jenkinsfile去定義整條Pipeline
  5. SCM中選擇Git,Repository URL 填入 https://github.com/xbox1994/chicken-html.git 或者你自己創建的包含Jenkinsfile、部署腳本、index.html的項目。
  6. 完成配置,點擊Save,Jenkins會自動觸發第一次的持續集成。

當你能在deploy階段看到下面的輸出

"

本文將帶領你從0開始,用Vagrant + Docker + Ansible + Jenkins + Nginx + GitHub等工具和資源來搭建一條可執行可擴展的持續集成流水線,即使這些名字你都沒聽過也沒關係,本文將會在需要的時候一一解釋給你聽。

By: 巧穎 & 天一

總覽

這是我們將要搭建的所有基礎設施的總體架構圖,我們將在本文中手把手教你搭建這樣一個持續集成環境。

手把手教你從零搭建一個持續集成環境

我們會在本地啟動兩臺虛擬機,一臺部署Nginx作為靜態文件服務器,一臺作為Jenkins服務器,在每臺虛擬機內部安裝Docker,使用Docker來完成Nginx與Jenkins的搭建、配置,然後手動在Jenkins配置內配置好一條Pipeline作為持續集成流水線,最後嘗試提交一次代碼去觸發一次持續集成操作,將最新的html項目代碼從Github上部署到Nginx中,實現持續集成。

避免本文過長,部分源代碼沒有貼在文中,本文參考完成源代碼在此:https://github.com/tw-wh-devops-community/cooking-chicken.git。建議在自己嘗試從0開始搭建的同時參考源碼閱讀本文。相信你一定會碰到很多坑,但坑外便是晴天。

首先我們需要兩臺機器

我們需要Vagrant

為什麼呢

無論你用的操作系統是Windows、Mac還是Linux,Oracle的Virtual Box都支持,那麼我們首先會使用Virtual Box來建立一個在硬件上絕對隔離的環境出來。

那麼Vagrant就是通過方便的命令操作來簡化Virtual Box的操作,同時提供了方便的虛擬機配置模塊,所以我們會使用這個工具來提升虛擬機的配置效率。

安裝Vagrant

在Mac上是自帶Virtual Box的,你用的版本可能需要更新才能配合Vagrant使用,Linux上請使用類似sudo apt-get install virtualbox的命令安裝。

那麼先裝上Vagrant吧:

  • Mac(https://www.vagrantup.com/downloads.html)
  • Ubuntu(sudo apt-get install vagrant)

安裝Vagrant插件

由於後續操作會涉及到將Nginx機器的私鑰發送給Jenkins機器來配置私鑰來完成虛擬機之間的無密碼訪問。但私鑰是在Nginx虛擬機創建之後才會由Vagrant創建的,所以需要在這個時間節點放到Jenkins目錄下便於Ansible把私鑰放到Jenkins虛擬機中。如果暫時不理解沒有關係,請看完”開始創建世界“之後回頭來看就會明白。

Vagrant的provision模塊可以在虛擬機啟動之後在虛擬機內部執行任意腳本,但是provision模塊並沒有提供執行宿主機上腳本的方式,所以需要你安裝如下模塊:

vagrant plugin install vagrant-host-shell

調試的時候比較有用的操作

  • 進入虛擬機:vagrant ssh
  • 休眠:vagrant suspend
  • 從休眠中恢復:vagrant resume
  • 移除虛擬機所有文件:vagrant destroy

開始創建世界!

Vagrantfile

我們來新建一個工程,在根目錄創建一個名為Vagrantfile的文件,內容如下:

手把手教你從零搭建一個持續集成環境

那麼現在可以啟動了,在命令行內跳轉到根目錄,使用vagrant up就可以將虛擬機按上面的配置啟動了,同時在啟動完成之後會調用provision模塊跑Ansible的對應腳本安裝配置虛擬機的依賴工具。啟動完成之後,那麼一個隔離的環境創建完畢,接下來我們可以在裡面任意玩耍了。

特別注意:因為第一次運行需要下載ubuntu/trusty64鏡像,以及把所有的配置甚至通過Docker下載Jenkins鏡像、slave鏡像,以及啟動Jenkins都寫到了Ansible中,所以跑完vagrant up需要較長時間

啟動、執行順序

基本是按Vagrant的配置文件的上下順序來啟動的。具體順序如下:

  1. 按Vagrantfile安裝並啟動Nginx虛擬機
  2. 執行Nginx虛擬機依賴的provision模塊
  3. 按Vagrantfile安裝並啟動Jenkins虛擬機
  4. 執行Jenkins虛擬機依賴的provision模塊

Jenkins訪問Nginx(選修,建議有時間或者將Jenkins搭建完成之後再看)

如果你能把所有環境啟動起來並能訪問Jenkins主頁,但此時你還無法在Jenkins上直接ssh登錄到Nginx,因為此時兩臺機器還沒有互信。但是幸運的是Vagrant啟動完Nginx之後就已經將私鑰(可以拿這個私鑰去訪問Nginx,無論你是誰)放到了宿主機上,那麼你可以手動將這個私鑰複製到Jenkins中,然後就可以在Jenkins中訪問Nginx了。

但是為了自動化上面的操作,進行以下的配置:Vagrant會在啟動一個虛擬機之後,會在Mac上創建.vagrant文件夾並把一些關於這個虛擬機的文件放到裡面,比如該虛擬機的私鑰,後面可以拿到這私鑰作為SSH聯絡的key。

比如下面這段配置會在Nginx虛擬機啟動之後,Jenkins虛擬機啟動之前執行。由於Jenkins虛擬機需要在部署代碼的時候使用到Nginx虛擬機的私鑰來部署,所以需要在Jenkins虛擬機執行Ansible之前將私鑰放到Jenkins的file文件夾中。

手把手教你從零搭建一個持續集成環境

另外,在Vagrantfile中,Ansible不是與兩臺虛擬機的配置寫在一起的,那麼Ansible如何判斷在哪臺虛擬機上安裝Nginx還是Jenkins呢?因為不同的虛擬機要執行Ansible的時候會根據主機名匹配來找到對應role的tasks從而還是能找到匹配的tasks。換句話說,Nginx安裝完成之後Vagrant攜帶Nginx相關參數執行下面這樣的一行命令來用limit匹配主機與對應Ansible的tasks:

手把手教你從零搭建一個持續集成環境

我們需要Ansible

什麼是Ansible

Ansible是一種自動化部署工具,可以用來自動化管理配置項、持續交付、(AWS)雲服務管理;

簡單來說也就是可以批量的遠程服務器上執行一系列的命令,其原理是基於ssh來和遠程主機進行通信的。

為什麼用Ansible

  • playbook使用的是yml語言,易讀性較好;
  • 沒有主節點和代理,僅僅依賴於SSH,使得應用的部署簡單而輕量;
  • 提供了大量模塊支持Google Compute Engine (GCE), Amazon Web Service(AWS);
  • Ansible支持多臺服務器同時管理部署;

安裝Ansible

Ansible是基於python開發的,需要在安裝有python的機器下才能夠安裝Ansible

  • 在本機安裝python:brew install python(Mac自帶ython,因此這步可以省略,inux系統中需要安裝Python)
  • 安裝pip:sudo apt install python-pip
  • 安裝Ansible:sudo pip install ansible

目錄結構

你可以按如下目錄結構去編寫你的Ansible文件。

手把手教你從零搭建一個持續集成環境

roles文件夾

roles是基於一個Ansible默認的目錄結構,Ansible在執行任務的時候會去默認加載templates、tasks以及handlers文件夾中的文件等。我們基於roles 對內容進行分組,使得我們可以容易地將不同的環境(如Java與NodeJs)區分開來,本次Demo中的roles下有三個文件夾,分別是common、jenkins和nginx,其中每個文件夾下都會定義一些例如tasks任務與相關配置文件。

role - common

前面已經說過本次demo需要在本地啟動兩臺虛擬機,分別在內部裝上Docker,在common中我們定義了安裝Docker的task,這樣在定義Jenkins服務器和部署nginx的服務器中都可以調用該task來安裝配置Docker環境;

install_docker.yml中應該包含如下內容:

  • 安裝Docker
  • 安裝docker-compose工具
  • 安裝docker-py依賴包(如果我們想用Ansible的docker模塊去執行docker相關命令的話需要這個依賴)

role - jenkins

定義安裝和部署Jenkins服務器的task:其中docker-compose.yml配置文件,是用於分別對jenkins-master和jenkins_slave進行一些基本配置;task下的main.yml文件是配置一系列的安裝命令,類似於在命令行中一行行輸入安裝和部署命令;

role - nginx

與jenkins文件夾類似,對Nginx服務器的一些基本配置:例如Nginx配置文件default.conf,配置文件中定義了templates下的index.html作為Nginx的入口模版文件,使Nginx作為一個文件服務器。task下的main.yml文件則是與jenkins中類似,配置了安裝部署命令,在使用vagrant up時通過Ansible來安裝並運行Nginx服務。

配置文件

Ansible的配置文件包括但不僅限於ansible.cfg、deploy.yml以及hosts

ansible.cfg文件

如在本Demo中用到的幾個配置:

  • forks:設置在與主機通信時的默認並行進程數,默認值為5;
  • inventory:設置主機與組之間的對應關係,在Ansible1.9之前使用的是hostfile;
  • host_key_checking:檢測主機密鑰的功能,可以通過設置值為false來禁用該功能(跳過兩臺主機之間首次連接需要確認的過程);
  • nocows:設置其值為1時禁用調用一些cowsay的特性,cowsay是linux系統下一個在終端用ASCII碼組成的小牛,這個小牛會說出你想要它說的話。
  • gathering:控制默認的遠程系統變量(facts)收集,有三種不同的值;默認是implicit,即每一次play,變量都會被收集,除非設置gather_facts: False;為explicit時,則facts不會被收集;為smart時,則沒有facts的新hosts將不會被掃描,用於節省fact收集;
  • fact_caching_timeout:定義fact緩存超時時間;
  • fact_caching:定義fact的緩存,2.4版本的Ansible支持redis和jsonfile兩種格式的緩存文件;
  • fact_caching_connection:定義cache的存儲位置,根據cache文件的格式不同定義的方式不同;

deploy.yml文件

這是Ansible的入口配置文件:定義hosts主機、以及相應主機需要執行的tasks等;

手把手教你從零搭建一個持續集成環境

hosts

然後加上遠程主機的網絡相關配置,這樣Ansible才能通過SSH到虛擬機中執行你寫的任務喲。

以如下命令為例,是為IP地址1192.168.56.102,端口號22的網絡地址設置一個別名nginx,且聲明其ssh private key文件的地址;

手把手教你從零搭建一個持續集成環境

與Vagrant結合

現在,Ansible的任務已經寫完了,我們需要將Ansible與Vagrant結合,將如下代碼加入到Vagrantfile中,可以在執行vagrant up的時候執行Ansible。

手把手教你從零搭建一個持續集成環境

虛擬機中的世界是如何構成的呢

現在你已經將所有的環境部署完成了,但是部署應用(Jenkins、Nginx)的過程還沒有提及,下面將帶你從Ansbile的對於每個虛擬機的任務開始,介紹相應的工具與具體的實施步驟。

Docker

什麼是Docker

Docker是一個開源的容器應用引擎,可以理解為一個存放應用容器的平臺,我們只需要簡單的幾行命令就可以構建一個與本地環境相對隔離的環境來運行我們的應用而不影響任何角色;

基本要素:

  • Container:負責應用程序的運行,包括操作系統、用戶添加的文件以及元數據
  • Images:只讀模版,即常說的Docker鏡像,用來運行Docker容器
  • Dockerfile:文件指令集,用來說明如何創建Docker鏡像

為什麼要用Docker

把一個應用封裝起來,可以在任何裝有Docker的環境下運行,統一運行環境;

那個大鯨魚(或者是貨輪)就是操作系統,把要交付的應用程序看成是各種貨物,原本要將各種各樣形狀、尺寸不同的貨物放到大鯨魚上,你得為每件貨物考慮怎麼安放(就是應用程序配套的環境),還得考慮貨物和貨物是否能疊起來(應用程序依賴的環境是否會衝突)。

現在使用了集裝箱(容器)把每件貨物都放到集裝箱裡,這樣大鯨魚可以用同樣地方式安放、堆疊集裝了,省事省力。

Docker中常用的命令

手把手教你從零搭建一個持續集成環境

怎麼用

要注意的是,Ansible對應的任務是在Vagrant啟動虛擬機之後執行的,是在虛擬機的內部,Docker容器的外部

安裝Nginx:由於我們只需要啟動一個Nginx的容器,直接使用Docker中run的命令去repository中下載安裝即可

  • 準備文件,例如default.conf,index.html
  • ```
  • name: copy nginx config file
  • copy:
  • src: default.conf
  • dest: /data/nginx/default.conf
  • name: copy default html file
  • template:
  • src: index.html
  • dest: /data/nginx/html/index.html
  • owner: vagrant
  • group: vagrant
  • ```
  • 使用Ansible中提供的Docker模塊安裝Nginx,包括拉Docker images,設置ports,以及多久需要pull一次新代碼等
手把手教你從零搭建一個持續集成環境

安裝Jenkins:demo中需要用到jenkins-master和jenkins-slave兩個container,因此使用docker-compose更加方便docker-compose.yml中定義了鏡像的地址、端口號等,並通過執行它進行在Docker中的部署。其中slave節點選用了jaydp17/jenkins-slave這樣一個包含Java、git、curl環境的Image方便執行持續集成任務。

手把手教你從零搭建一個持續集成環境

Nginx

什麼是Nginx

一款輕量級的Web 服務器/反向代理服務器及電子郵件(IMAP/POP3)代理服務器

為什麼用Nginx

首先需要一個服務器來部署我們的應用,而常用的服務器有例如apache的Apache HTTP Server、Nginx、tomcat等;Nginx是為了解決互聯網業內著名的 “C10K” 問題而生;

其中Nginx通常用來做靜態內容服務器,而tomcat一般用於做動態應用的服務器,通常稱之為web容器;Nginx相比於apache的優點:

  • 輕量級,同樣起web服務,比apache佔用更少的內存及資源;
  • 抗併發,Nginx處理請求是異步非阻塞的,而apache則是阻塞型的,在高併發下Nginx能保持低資源低消耗高性能
  • 提供負載均衡;
  • 配置簡潔;
  • 社區活躍,各種高性能模塊出品迅速等;

怎麼用Nginx

在demo中寫了一個role來定義安裝配置Nginx需要的操作流程,用的是Docker提供的Nginx鏡像,在Docker中安裝配置Nginx,為了使Nginx能夠啟動起來,我們還需要進行一系列的配置,包括配置文件和模版文件等;default.conf就是Nginx的配置文件,此處http模塊的相關配置:

  • listen 80:監聽的端口號是80;
  • default_server:設定為默認虛擬主機;
  • server_name localhost:設置虛擬主機名稱為localhost;
  • root /usr/share/nginx/html:設置web服務URL資源映射的本地文件系統的資源所在的目錄;
  • index index.html index.htm:定義默認主頁面,需要自己編寫並放到Ansbile對應目錄;
手把手教你從零搭建一個持續集成環境

還有一些其他的配置,詳情請參考https://www.nginx.com/resources/wiki/start/topics/examples/full/

Ansible關於Nginx的task中yml文件的配置:

  • 創建文件夾
  • copy Nginx的配置文件到環境中
  • copy模版文件
  • 以及使用Docker鏡像運行Nginx
手把手教你從零搭建一個持續集成環境

世界有了,來聯通各國吧

到現在為止,你已經瞭解了所有我們使用的工具以及通過運行命令搭建完成了一套持續集成環境的基礎設施,但是還需要對Jenkins進行一些配置才能真正做到持續集成。

Jenkins的配置

現在你可以訪問 http://192.168.56.102:8080 了,然後頁面提示需要你輸入Administrator password。該密碼可以通過下面的方式獲取:

  1. 進入Jenkins虛擬機:vagrant ssh jenkins
  2. 獲取root權限:sudo su
  3. 進入Jenkins master容器:docker exec -it jenkins_master bash
  4. 找到密碼:cat /var/jenkins_home/secrets/initialAdminPassword

然後將密碼複製到頁面上點擊確定,隨後點擊安裝推薦的插件,本文將使用到的Jenkins功能不會超出推薦的插件的範圍。然後創建好用戶就可以登錄了。

Slave

來到主界面之後,接下來我們來配置一臺slave節點來幫我們執行任務,依次點擊Manage Jenkins -> Manage Nodes -> New Node,按照下圖進行配置。

手把手教你從零搭建一個持續集成環境

簡單起見,用密碼登錄的方式進行身份驗證,用戶名密碼都為jenkins。

那麼問題來了,為什麼slave節點的用戶名密碼是jenkins呢?是在這個Dockerfile裡配置的。我們用的雖然是jaydp17/jenkins-slave,但是你可以看到這個鏡像的構建文件中引用了evarga/jenkins-slave,其中echo "jenkins:jenkins" | chpasswd可以設置密碼。

手把手教你從零搭建一個持續集成環境

另外要注意一下,我們通過設置Host key verification strategy為Non verifying verification strategy從而關閉了slave主機的公鑰檢查,更多瞭解請參看這篇文章。

如果你現在能在Jenkins界面上看到你剛剛創建的slave節點,那麼已經完成配置了。另外,為了讓部署過程僅僅在slave節點上執行來確認slave是否已經部署成功,可以嘗試點擊master節點右方的配置按鈕將默認開啟的master節點中的executors數量改為0。

創建Pipeline

接下來我們將創建一條流水線。回到Jenkins首頁,然後

  1. 點擊 create new jobs
  2. 選擇Pipeline分類點擊OK
  3. 勾上Poll SCM,並填入* * * * *,讓Jenkins每分鐘幫我們check一次Github上是否有提交。
  4. Definition中選擇’Pipeline script from SCM’,我們通過Jenkinsfile去定義整條Pipeline
  5. SCM中選擇Git,Repository URL 填入 https://github.com/xbox1994/chicken-html.git 或者你自己創建的包含Jenkinsfile、部署腳本、index.html的項目。
  6. 完成配置,點擊Save,Jenkins會自動觸發第一次的持續集成。

當你能在deploy階段看到下面的輸出

手把手教你從零搭建一個持續集成環境

並且訪問http://192.168.56.101 ,能看到下面的文字,那麼恭喜你,順利通關!

觸發Pipeline

請盡情的提交吧,試試看Jenkins會不會把你的代碼拉下來觸發Pipeline。

html項目的腳本配置

即使你已經成功觸發多次Pipeline,但是其中還有些配置沒有講到,這些配置隱藏在項目代碼中。個人認為對於這個項目有關的配置就應該放到項目代碼中,除非有其他統一的配置管理方式。

比如chicken-html中的目錄如下:

"

本文將帶領你從0開始,用Vagrant + Docker + Ansible + Jenkins + Nginx + GitHub等工具和資源來搭建一條可執行可擴展的持續集成流水線,即使這些名字你都沒聽過也沒關係,本文將會在需要的時候一一解釋給你聽。

By: 巧穎 & 天一

總覽

這是我們將要搭建的所有基礎設施的總體架構圖,我們將在本文中手把手教你搭建這樣一個持續集成環境。

手把手教你從零搭建一個持續集成環境

我們會在本地啟動兩臺虛擬機,一臺部署Nginx作為靜態文件服務器,一臺作為Jenkins服務器,在每臺虛擬機內部安裝Docker,使用Docker來完成Nginx與Jenkins的搭建、配置,然後手動在Jenkins配置內配置好一條Pipeline作為持續集成流水線,最後嘗試提交一次代碼去觸發一次持續集成操作,將最新的html項目代碼從Github上部署到Nginx中,實現持續集成。

避免本文過長,部分源代碼沒有貼在文中,本文參考完成源代碼在此:https://github.com/tw-wh-devops-community/cooking-chicken.git。建議在自己嘗試從0開始搭建的同時參考源碼閱讀本文。相信你一定會碰到很多坑,但坑外便是晴天。

首先我們需要兩臺機器

我們需要Vagrant

為什麼呢

無論你用的操作系統是Windows、Mac還是Linux,Oracle的Virtual Box都支持,那麼我們首先會使用Virtual Box來建立一個在硬件上絕對隔離的環境出來。

那麼Vagrant就是通過方便的命令操作來簡化Virtual Box的操作,同時提供了方便的虛擬機配置模塊,所以我們會使用這個工具來提升虛擬機的配置效率。

安裝Vagrant

在Mac上是自帶Virtual Box的,你用的版本可能需要更新才能配合Vagrant使用,Linux上請使用類似sudo apt-get install virtualbox的命令安裝。

那麼先裝上Vagrant吧:

  • Mac(https://www.vagrantup.com/downloads.html)
  • Ubuntu(sudo apt-get install vagrant)

安裝Vagrant插件

由於後續操作會涉及到將Nginx機器的私鑰發送給Jenkins機器來配置私鑰來完成虛擬機之間的無密碼訪問。但私鑰是在Nginx虛擬機創建之後才會由Vagrant創建的,所以需要在這個時間節點放到Jenkins目錄下便於Ansible把私鑰放到Jenkins虛擬機中。如果暫時不理解沒有關係,請看完”開始創建世界“之後回頭來看就會明白。

Vagrant的provision模塊可以在虛擬機啟動之後在虛擬機內部執行任意腳本,但是provision模塊並沒有提供執行宿主機上腳本的方式,所以需要你安裝如下模塊:

vagrant plugin install vagrant-host-shell

調試的時候比較有用的操作

  • 進入虛擬機:vagrant ssh
  • 休眠:vagrant suspend
  • 從休眠中恢復:vagrant resume
  • 移除虛擬機所有文件:vagrant destroy

開始創建世界!

Vagrantfile

我們來新建一個工程,在根目錄創建一個名為Vagrantfile的文件,內容如下:

手把手教你從零搭建一個持續集成環境

那麼現在可以啟動了,在命令行內跳轉到根目錄,使用vagrant up就可以將虛擬機按上面的配置啟動了,同時在啟動完成之後會調用provision模塊跑Ansible的對應腳本安裝配置虛擬機的依賴工具。啟動完成之後,那麼一個隔離的環境創建完畢,接下來我們可以在裡面任意玩耍了。

特別注意:因為第一次運行需要下載ubuntu/trusty64鏡像,以及把所有的配置甚至通過Docker下載Jenkins鏡像、slave鏡像,以及啟動Jenkins都寫到了Ansible中,所以跑完vagrant up需要較長時間

啟動、執行順序

基本是按Vagrant的配置文件的上下順序來啟動的。具體順序如下:

  1. 按Vagrantfile安裝並啟動Nginx虛擬機
  2. 執行Nginx虛擬機依賴的provision模塊
  3. 按Vagrantfile安裝並啟動Jenkins虛擬機
  4. 執行Jenkins虛擬機依賴的provision模塊

Jenkins訪問Nginx(選修,建議有時間或者將Jenkins搭建完成之後再看)

如果你能把所有環境啟動起來並能訪問Jenkins主頁,但此時你還無法在Jenkins上直接ssh登錄到Nginx,因為此時兩臺機器還沒有互信。但是幸運的是Vagrant啟動完Nginx之後就已經將私鑰(可以拿這個私鑰去訪問Nginx,無論你是誰)放到了宿主機上,那麼你可以手動將這個私鑰複製到Jenkins中,然後就可以在Jenkins中訪問Nginx了。

但是為了自動化上面的操作,進行以下的配置:Vagrant會在啟動一個虛擬機之後,會在Mac上創建.vagrant文件夾並把一些關於這個虛擬機的文件放到裡面,比如該虛擬機的私鑰,後面可以拿到這私鑰作為SSH聯絡的key。

比如下面這段配置會在Nginx虛擬機啟動之後,Jenkins虛擬機啟動之前執行。由於Jenkins虛擬機需要在部署代碼的時候使用到Nginx虛擬機的私鑰來部署,所以需要在Jenkins虛擬機執行Ansible之前將私鑰放到Jenkins的file文件夾中。

手把手教你從零搭建一個持續集成環境

另外,在Vagrantfile中,Ansible不是與兩臺虛擬機的配置寫在一起的,那麼Ansible如何判斷在哪臺虛擬機上安裝Nginx還是Jenkins呢?因為不同的虛擬機要執行Ansible的時候會根據主機名匹配來找到對應role的tasks從而還是能找到匹配的tasks。換句話說,Nginx安裝完成之後Vagrant攜帶Nginx相關參數執行下面這樣的一行命令來用limit匹配主機與對應Ansible的tasks:

手把手教你從零搭建一個持續集成環境

我們需要Ansible

什麼是Ansible

Ansible是一種自動化部署工具,可以用來自動化管理配置項、持續交付、(AWS)雲服務管理;

簡單來說也就是可以批量的遠程服務器上執行一系列的命令,其原理是基於ssh來和遠程主機進行通信的。

為什麼用Ansible

  • playbook使用的是yml語言,易讀性較好;
  • 沒有主節點和代理,僅僅依賴於SSH,使得應用的部署簡單而輕量;
  • 提供了大量模塊支持Google Compute Engine (GCE), Amazon Web Service(AWS);
  • Ansible支持多臺服務器同時管理部署;

安裝Ansible

Ansible是基於python開發的,需要在安裝有python的機器下才能夠安裝Ansible

  • 在本機安裝python:brew install python(Mac自帶ython,因此這步可以省略,inux系統中需要安裝Python)
  • 安裝pip:sudo apt install python-pip
  • 安裝Ansible:sudo pip install ansible

目錄結構

你可以按如下目錄結構去編寫你的Ansible文件。

手把手教你從零搭建一個持續集成環境

roles文件夾

roles是基於一個Ansible默認的目錄結構,Ansible在執行任務的時候會去默認加載templates、tasks以及handlers文件夾中的文件等。我們基於roles 對內容進行分組,使得我們可以容易地將不同的環境(如Java與NodeJs)區分開來,本次Demo中的roles下有三個文件夾,分別是common、jenkins和nginx,其中每個文件夾下都會定義一些例如tasks任務與相關配置文件。

role - common

前面已經說過本次demo需要在本地啟動兩臺虛擬機,分別在內部裝上Docker,在common中我們定義了安裝Docker的task,這樣在定義Jenkins服務器和部署nginx的服務器中都可以調用該task來安裝配置Docker環境;

install_docker.yml中應該包含如下內容:

  • 安裝Docker
  • 安裝docker-compose工具
  • 安裝docker-py依賴包(如果我們想用Ansible的docker模塊去執行docker相關命令的話需要這個依賴)

role - jenkins

定義安裝和部署Jenkins服務器的task:其中docker-compose.yml配置文件,是用於分別對jenkins-master和jenkins_slave進行一些基本配置;task下的main.yml文件是配置一系列的安裝命令,類似於在命令行中一行行輸入安裝和部署命令;

role - nginx

與jenkins文件夾類似,對Nginx服務器的一些基本配置:例如Nginx配置文件default.conf,配置文件中定義了templates下的index.html作為Nginx的入口模版文件,使Nginx作為一個文件服務器。task下的main.yml文件則是與jenkins中類似,配置了安裝部署命令,在使用vagrant up時通過Ansible來安裝並運行Nginx服務。

配置文件

Ansible的配置文件包括但不僅限於ansible.cfg、deploy.yml以及hosts

ansible.cfg文件

如在本Demo中用到的幾個配置:

  • forks:設置在與主機通信時的默認並行進程數,默認值為5;
  • inventory:設置主機與組之間的對應關係,在Ansible1.9之前使用的是hostfile;
  • host_key_checking:檢測主機密鑰的功能,可以通過設置值為false來禁用該功能(跳過兩臺主機之間首次連接需要確認的過程);
  • nocows:設置其值為1時禁用調用一些cowsay的特性,cowsay是linux系統下一個在終端用ASCII碼組成的小牛,這個小牛會說出你想要它說的話。
  • gathering:控制默認的遠程系統變量(facts)收集,有三種不同的值;默認是implicit,即每一次play,變量都會被收集,除非設置gather_facts: False;為explicit時,則facts不會被收集;為smart時,則沒有facts的新hosts將不會被掃描,用於節省fact收集;
  • fact_caching_timeout:定義fact緩存超時時間;
  • fact_caching:定義fact的緩存,2.4版本的Ansible支持redis和jsonfile兩種格式的緩存文件;
  • fact_caching_connection:定義cache的存儲位置,根據cache文件的格式不同定義的方式不同;

deploy.yml文件

這是Ansible的入口配置文件:定義hosts主機、以及相應主機需要執行的tasks等;

手把手教你從零搭建一個持續集成環境

hosts

然後加上遠程主機的網絡相關配置,這樣Ansible才能通過SSH到虛擬機中執行你寫的任務喲。

以如下命令為例,是為IP地址1192.168.56.102,端口號22的網絡地址設置一個別名nginx,且聲明其ssh private key文件的地址;

手把手教你從零搭建一個持續集成環境

與Vagrant結合

現在,Ansible的任務已經寫完了,我們需要將Ansible與Vagrant結合,將如下代碼加入到Vagrantfile中,可以在執行vagrant up的時候執行Ansible。

手把手教你從零搭建一個持續集成環境

虛擬機中的世界是如何構成的呢

現在你已經將所有的環境部署完成了,但是部署應用(Jenkins、Nginx)的過程還沒有提及,下面將帶你從Ansbile的對於每個虛擬機的任務開始,介紹相應的工具與具體的實施步驟。

Docker

什麼是Docker

Docker是一個開源的容器應用引擎,可以理解為一個存放應用容器的平臺,我們只需要簡單的幾行命令就可以構建一個與本地環境相對隔離的環境來運行我們的應用而不影響任何角色;

基本要素:

  • Container:負責應用程序的運行,包括操作系統、用戶添加的文件以及元數據
  • Images:只讀模版,即常說的Docker鏡像,用來運行Docker容器
  • Dockerfile:文件指令集,用來說明如何創建Docker鏡像

為什麼要用Docker

把一個應用封裝起來,可以在任何裝有Docker的環境下運行,統一運行環境;

那個大鯨魚(或者是貨輪)就是操作系統,把要交付的應用程序看成是各種貨物,原本要將各種各樣形狀、尺寸不同的貨物放到大鯨魚上,你得為每件貨物考慮怎麼安放(就是應用程序配套的環境),還得考慮貨物和貨物是否能疊起來(應用程序依賴的環境是否會衝突)。

現在使用了集裝箱(容器)把每件貨物都放到集裝箱裡,這樣大鯨魚可以用同樣地方式安放、堆疊集裝了,省事省力。

Docker中常用的命令

手把手教你從零搭建一個持續集成環境

怎麼用

要注意的是,Ansible對應的任務是在Vagrant啟動虛擬機之後執行的,是在虛擬機的內部,Docker容器的外部

安裝Nginx:由於我們只需要啟動一個Nginx的容器,直接使用Docker中run的命令去repository中下載安裝即可

  • 準備文件,例如default.conf,index.html
  • ```
  • name: copy nginx config file
  • copy:
  • src: default.conf
  • dest: /data/nginx/default.conf
  • name: copy default html file
  • template:
  • src: index.html
  • dest: /data/nginx/html/index.html
  • owner: vagrant
  • group: vagrant
  • ```
  • 使用Ansible中提供的Docker模塊安裝Nginx,包括拉Docker images,設置ports,以及多久需要pull一次新代碼等
手把手教你從零搭建一個持續集成環境

安裝Jenkins:demo中需要用到jenkins-master和jenkins-slave兩個container,因此使用docker-compose更加方便docker-compose.yml中定義了鏡像的地址、端口號等,並通過執行它進行在Docker中的部署。其中slave節點選用了jaydp17/jenkins-slave這樣一個包含Java、git、curl環境的Image方便執行持續集成任務。

手把手教你從零搭建一個持續集成環境

Nginx

什麼是Nginx

一款輕量級的Web 服務器/反向代理服務器及電子郵件(IMAP/POP3)代理服務器

為什麼用Nginx

首先需要一個服務器來部署我們的應用,而常用的服務器有例如apache的Apache HTTP Server、Nginx、tomcat等;Nginx是為了解決互聯網業內著名的 “C10K” 問題而生;

其中Nginx通常用來做靜態內容服務器,而tomcat一般用於做動態應用的服務器,通常稱之為web容器;Nginx相比於apache的優點:

  • 輕量級,同樣起web服務,比apache佔用更少的內存及資源;
  • 抗併發,Nginx處理請求是異步非阻塞的,而apache則是阻塞型的,在高併發下Nginx能保持低資源低消耗高性能
  • 提供負載均衡;
  • 配置簡潔;
  • 社區活躍,各種高性能模塊出品迅速等;

怎麼用Nginx

在demo中寫了一個role來定義安裝配置Nginx需要的操作流程,用的是Docker提供的Nginx鏡像,在Docker中安裝配置Nginx,為了使Nginx能夠啟動起來,我們還需要進行一系列的配置,包括配置文件和模版文件等;default.conf就是Nginx的配置文件,此處http模塊的相關配置:

  • listen 80:監聽的端口號是80;
  • default_server:設定為默認虛擬主機;
  • server_name localhost:設置虛擬主機名稱為localhost;
  • root /usr/share/nginx/html:設置web服務URL資源映射的本地文件系統的資源所在的目錄;
  • index index.html index.htm:定義默認主頁面,需要自己編寫並放到Ansbile對應目錄;
手把手教你從零搭建一個持續集成環境

還有一些其他的配置,詳情請參考https://www.nginx.com/resources/wiki/start/topics/examples/full/

Ansible關於Nginx的task中yml文件的配置:

  • 創建文件夾
  • copy Nginx的配置文件到環境中
  • copy模版文件
  • 以及使用Docker鏡像運行Nginx
手把手教你從零搭建一個持續集成環境

世界有了,來聯通各國吧

到現在為止,你已經瞭解了所有我們使用的工具以及通過運行命令搭建完成了一套持續集成環境的基礎設施,但是還需要對Jenkins進行一些配置才能真正做到持續集成。

Jenkins的配置

現在你可以訪問 http://192.168.56.102:8080 了,然後頁面提示需要你輸入Administrator password。該密碼可以通過下面的方式獲取:

  1. 進入Jenkins虛擬機:vagrant ssh jenkins
  2. 獲取root權限:sudo su
  3. 進入Jenkins master容器:docker exec -it jenkins_master bash
  4. 找到密碼:cat /var/jenkins_home/secrets/initialAdminPassword

然後將密碼複製到頁面上點擊確定,隨後點擊安裝推薦的插件,本文將使用到的Jenkins功能不會超出推薦的插件的範圍。然後創建好用戶就可以登錄了。

Slave

來到主界面之後,接下來我們來配置一臺slave節點來幫我們執行任務,依次點擊Manage Jenkins -> Manage Nodes -> New Node,按照下圖進行配置。

手把手教你從零搭建一個持續集成環境

簡單起見,用密碼登錄的方式進行身份驗證,用戶名密碼都為jenkins。

那麼問題來了,為什麼slave節點的用戶名密碼是jenkins呢?是在這個Dockerfile裡配置的。我們用的雖然是jaydp17/jenkins-slave,但是你可以看到這個鏡像的構建文件中引用了evarga/jenkins-slave,其中echo "jenkins:jenkins" | chpasswd可以設置密碼。

手把手教你從零搭建一個持續集成環境

另外要注意一下,我們通過設置Host key verification strategy為Non verifying verification strategy從而關閉了slave主機的公鑰檢查,更多瞭解請參看這篇文章。

如果你現在能在Jenkins界面上看到你剛剛創建的slave節點,那麼已經完成配置了。另外,為了讓部署過程僅僅在slave節點上執行來確認slave是否已經部署成功,可以嘗試點擊master節點右方的配置按鈕將默認開啟的master節點中的executors數量改為0。

創建Pipeline

接下來我們將創建一條流水線。回到Jenkins首頁,然後

  1. 點擊 create new jobs
  2. 選擇Pipeline分類點擊OK
  3. 勾上Poll SCM,並填入* * * * *,讓Jenkins每分鐘幫我們check一次Github上是否有提交。
  4. Definition中選擇’Pipeline script from SCM’,我們通過Jenkinsfile去定義整條Pipeline
  5. SCM中選擇Git,Repository URL 填入 https://github.com/xbox1994/chicken-html.git 或者你自己創建的包含Jenkinsfile、部署腳本、index.html的項目。
  6. 完成配置,點擊Save,Jenkins會自動觸發第一次的持續集成。

當你能在deploy階段看到下面的輸出

手把手教你從零搭建一個持續集成環境

並且訪問http://192.168.56.101 ,能看到下面的文字,那麼恭喜你,順利通關!

觸發Pipeline

請盡情的提交吧,試試看Jenkins會不會把你的代碼拉下來觸發Pipeline。

html項目的腳本配置

即使你已經成功觸發多次Pipeline,但是其中還有些配置沒有講到,這些配置隱藏在項目代碼中。個人認為對於這個項目有關的配置就應該放到項目代碼中,除非有其他統一的配置管理方式。

比如chicken-html中的目錄如下:

手把手教你從零搭建一個持續集成環境

測試、構建

如果你用到gradle、maven這樣的工具來管理你的項目構建。平時在開發的時候只需要運行./gradlew clean build和./gradlew test來進行構建與測試。那麼到Jenkins上也是基於這些命令來進行的

部署代碼到服務器

部署代碼這步操作是會在Jenkins slave節點上進行,將從Github上拉來的代碼部署到Nginx服務器中,那麼最簡單的方式就是使用scp命令將需要部署的文件發送到Nginx服務器。在Ansbile腳本中已經把Nginx服務器的私鑰複製到了slave節點所在的服務器中了,所以可以直接執行scp命令。

在本文涉及到的html項目中的部署腳本如下:

"

本文將帶領你從0開始,用Vagrant + Docker + Ansible + Jenkins + Nginx + GitHub等工具和資源來搭建一條可執行可擴展的持續集成流水線,即使這些名字你都沒聽過也沒關係,本文將會在需要的時候一一解釋給你聽。

By: 巧穎 & 天一

總覽

這是我們將要搭建的所有基礎設施的總體架構圖,我們將在本文中手把手教你搭建這樣一個持續集成環境。

手把手教你從零搭建一個持續集成環境

我們會在本地啟動兩臺虛擬機,一臺部署Nginx作為靜態文件服務器,一臺作為Jenkins服務器,在每臺虛擬機內部安裝Docker,使用Docker來完成Nginx與Jenkins的搭建、配置,然後手動在Jenkins配置內配置好一條Pipeline作為持續集成流水線,最後嘗試提交一次代碼去觸發一次持續集成操作,將最新的html項目代碼從Github上部署到Nginx中,實現持續集成。

避免本文過長,部分源代碼沒有貼在文中,本文參考完成源代碼在此:https://github.com/tw-wh-devops-community/cooking-chicken.git。建議在自己嘗試從0開始搭建的同時參考源碼閱讀本文。相信你一定會碰到很多坑,但坑外便是晴天。

首先我們需要兩臺機器

我們需要Vagrant

為什麼呢

無論你用的操作系統是Windows、Mac還是Linux,Oracle的Virtual Box都支持,那麼我們首先會使用Virtual Box來建立一個在硬件上絕對隔離的環境出來。

那麼Vagrant就是通過方便的命令操作來簡化Virtual Box的操作,同時提供了方便的虛擬機配置模塊,所以我們會使用這個工具來提升虛擬機的配置效率。

安裝Vagrant

在Mac上是自帶Virtual Box的,你用的版本可能需要更新才能配合Vagrant使用,Linux上請使用類似sudo apt-get install virtualbox的命令安裝。

那麼先裝上Vagrant吧:

  • Mac(https://www.vagrantup.com/downloads.html)
  • Ubuntu(sudo apt-get install vagrant)

安裝Vagrant插件

由於後續操作會涉及到將Nginx機器的私鑰發送給Jenkins機器來配置私鑰來完成虛擬機之間的無密碼訪問。但私鑰是在Nginx虛擬機創建之後才會由Vagrant創建的,所以需要在這個時間節點放到Jenkins目錄下便於Ansible把私鑰放到Jenkins虛擬機中。如果暫時不理解沒有關係,請看完”開始創建世界“之後回頭來看就會明白。

Vagrant的provision模塊可以在虛擬機啟動之後在虛擬機內部執行任意腳本,但是provision模塊並沒有提供執行宿主機上腳本的方式,所以需要你安裝如下模塊:

vagrant plugin install vagrant-host-shell

調試的時候比較有用的操作

  • 進入虛擬機:vagrant ssh
  • 休眠:vagrant suspend
  • 從休眠中恢復:vagrant resume
  • 移除虛擬機所有文件:vagrant destroy

開始創建世界!

Vagrantfile

我們來新建一個工程,在根目錄創建一個名為Vagrantfile的文件,內容如下:

手把手教你從零搭建一個持續集成環境

那麼現在可以啟動了,在命令行內跳轉到根目錄,使用vagrant up就可以將虛擬機按上面的配置啟動了,同時在啟動完成之後會調用provision模塊跑Ansible的對應腳本安裝配置虛擬機的依賴工具。啟動完成之後,那麼一個隔離的環境創建完畢,接下來我們可以在裡面任意玩耍了。

特別注意:因為第一次運行需要下載ubuntu/trusty64鏡像,以及把所有的配置甚至通過Docker下載Jenkins鏡像、slave鏡像,以及啟動Jenkins都寫到了Ansible中,所以跑完vagrant up需要較長時間

啟動、執行順序

基本是按Vagrant的配置文件的上下順序來啟動的。具體順序如下:

  1. 按Vagrantfile安裝並啟動Nginx虛擬機
  2. 執行Nginx虛擬機依賴的provision模塊
  3. 按Vagrantfile安裝並啟動Jenkins虛擬機
  4. 執行Jenkins虛擬機依賴的provision模塊

Jenkins訪問Nginx(選修,建議有時間或者將Jenkins搭建完成之後再看)

如果你能把所有環境啟動起來並能訪問Jenkins主頁,但此時你還無法在Jenkins上直接ssh登錄到Nginx,因為此時兩臺機器還沒有互信。但是幸運的是Vagrant啟動完Nginx之後就已經將私鑰(可以拿這個私鑰去訪問Nginx,無論你是誰)放到了宿主機上,那麼你可以手動將這個私鑰複製到Jenkins中,然後就可以在Jenkins中訪問Nginx了。

但是為了自動化上面的操作,進行以下的配置:Vagrant會在啟動一個虛擬機之後,會在Mac上創建.vagrant文件夾並把一些關於這個虛擬機的文件放到裡面,比如該虛擬機的私鑰,後面可以拿到這私鑰作為SSH聯絡的key。

比如下面這段配置會在Nginx虛擬機啟動之後,Jenkins虛擬機啟動之前執行。由於Jenkins虛擬機需要在部署代碼的時候使用到Nginx虛擬機的私鑰來部署,所以需要在Jenkins虛擬機執行Ansible之前將私鑰放到Jenkins的file文件夾中。

手把手教你從零搭建一個持續集成環境

另外,在Vagrantfile中,Ansible不是與兩臺虛擬機的配置寫在一起的,那麼Ansible如何判斷在哪臺虛擬機上安裝Nginx還是Jenkins呢?因為不同的虛擬機要執行Ansible的時候會根據主機名匹配來找到對應role的tasks從而還是能找到匹配的tasks。換句話說,Nginx安裝完成之後Vagrant攜帶Nginx相關參數執行下面這樣的一行命令來用limit匹配主機與對應Ansible的tasks:

手把手教你從零搭建一個持續集成環境

我們需要Ansible

什麼是Ansible

Ansible是一種自動化部署工具,可以用來自動化管理配置項、持續交付、(AWS)雲服務管理;

簡單來說也就是可以批量的遠程服務器上執行一系列的命令,其原理是基於ssh來和遠程主機進行通信的。

為什麼用Ansible

  • playbook使用的是yml語言,易讀性較好;
  • 沒有主節點和代理,僅僅依賴於SSH,使得應用的部署簡單而輕量;
  • 提供了大量模塊支持Google Compute Engine (GCE), Amazon Web Service(AWS);
  • Ansible支持多臺服務器同時管理部署;

安裝Ansible

Ansible是基於python開發的,需要在安裝有python的機器下才能夠安裝Ansible

  • 在本機安裝python:brew install python(Mac自帶ython,因此這步可以省略,inux系統中需要安裝Python)
  • 安裝pip:sudo apt install python-pip
  • 安裝Ansible:sudo pip install ansible

目錄結構

你可以按如下目錄結構去編寫你的Ansible文件。

手把手教你從零搭建一個持續集成環境

roles文件夾

roles是基於一個Ansible默認的目錄結構,Ansible在執行任務的時候會去默認加載templates、tasks以及handlers文件夾中的文件等。我們基於roles 對內容進行分組,使得我們可以容易地將不同的環境(如Java與NodeJs)區分開來,本次Demo中的roles下有三個文件夾,分別是common、jenkins和nginx,其中每個文件夾下都會定義一些例如tasks任務與相關配置文件。

role - common

前面已經說過本次demo需要在本地啟動兩臺虛擬機,分別在內部裝上Docker,在common中我們定義了安裝Docker的task,這樣在定義Jenkins服務器和部署nginx的服務器中都可以調用該task來安裝配置Docker環境;

install_docker.yml中應該包含如下內容:

  • 安裝Docker
  • 安裝docker-compose工具
  • 安裝docker-py依賴包(如果我們想用Ansible的docker模塊去執行docker相關命令的話需要這個依賴)

role - jenkins

定義安裝和部署Jenkins服務器的task:其中docker-compose.yml配置文件,是用於分別對jenkins-master和jenkins_slave進行一些基本配置;task下的main.yml文件是配置一系列的安裝命令,類似於在命令行中一行行輸入安裝和部署命令;

role - nginx

與jenkins文件夾類似,對Nginx服務器的一些基本配置:例如Nginx配置文件default.conf,配置文件中定義了templates下的index.html作為Nginx的入口模版文件,使Nginx作為一個文件服務器。task下的main.yml文件則是與jenkins中類似,配置了安裝部署命令,在使用vagrant up時通過Ansible來安裝並運行Nginx服務。

配置文件

Ansible的配置文件包括但不僅限於ansible.cfg、deploy.yml以及hosts

ansible.cfg文件

如在本Demo中用到的幾個配置:

  • forks:設置在與主機通信時的默認並行進程數,默認值為5;
  • inventory:設置主機與組之間的對應關係,在Ansible1.9之前使用的是hostfile;
  • host_key_checking:檢測主機密鑰的功能,可以通過設置值為false來禁用該功能(跳過兩臺主機之間首次連接需要確認的過程);
  • nocows:設置其值為1時禁用調用一些cowsay的特性,cowsay是linux系統下一個在終端用ASCII碼組成的小牛,這個小牛會說出你想要它說的話。
  • gathering:控制默認的遠程系統變量(facts)收集,有三種不同的值;默認是implicit,即每一次play,變量都會被收集,除非設置gather_facts: False;為explicit時,則facts不會被收集;為smart時,則沒有facts的新hosts將不會被掃描,用於節省fact收集;
  • fact_caching_timeout:定義fact緩存超時時間;
  • fact_caching:定義fact的緩存,2.4版本的Ansible支持redis和jsonfile兩種格式的緩存文件;
  • fact_caching_connection:定義cache的存儲位置,根據cache文件的格式不同定義的方式不同;

deploy.yml文件

這是Ansible的入口配置文件:定義hosts主機、以及相應主機需要執行的tasks等;

手把手教你從零搭建一個持續集成環境

hosts

然後加上遠程主機的網絡相關配置,這樣Ansible才能通過SSH到虛擬機中執行你寫的任務喲。

以如下命令為例,是為IP地址1192.168.56.102,端口號22的網絡地址設置一個別名nginx,且聲明其ssh private key文件的地址;

手把手教你從零搭建一個持續集成環境

與Vagrant結合

現在,Ansible的任務已經寫完了,我們需要將Ansible與Vagrant結合,將如下代碼加入到Vagrantfile中,可以在執行vagrant up的時候執行Ansible。

手把手教你從零搭建一個持續集成環境

虛擬機中的世界是如何構成的呢

現在你已經將所有的環境部署完成了,但是部署應用(Jenkins、Nginx)的過程還沒有提及,下面將帶你從Ansbile的對於每個虛擬機的任務開始,介紹相應的工具與具體的實施步驟。

Docker

什麼是Docker

Docker是一個開源的容器應用引擎,可以理解為一個存放應用容器的平臺,我們只需要簡單的幾行命令就可以構建一個與本地環境相對隔離的環境來運行我們的應用而不影響任何角色;

基本要素:

  • Container:負責應用程序的運行,包括操作系統、用戶添加的文件以及元數據
  • Images:只讀模版,即常說的Docker鏡像,用來運行Docker容器
  • Dockerfile:文件指令集,用來說明如何創建Docker鏡像

為什麼要用Docker

把一個應用封裝起來,可以在任何裝有Docker的環境下運行,統一運行環境;

那個大鯨魚(或者是貨輪)就是操作系統,把要交付的應用程序看成是各種貨物,原本要將各種各樣形狀、尺寸不同的貨物放到大鯨魚上,你得為每件貨物考慮怎麼安放(就是應用程序配套的環境),還得考慮貨物和貨物是否能疊起來(應用程序依賴的環境是否會衝突)。

現在使用了集裝箱(容器)把每件貨物都放到集裝箱裡,這樣大鯨魚可以用同樣地方式安放、堆疊集裝了,省事省力。

Docker中常用的命令

手把手教你從零搭建一個持續集成環境

怎麼用

要注意的是,Ansible對應的任務是在Vagrant啟動虛擬機之後執行的,是在虛擬機的內部,Docker容器的外部

安裝Nginx:由於我們只需要啟動一個Nginx的容器,直接使用Docker中run的命令去repository中下載安裝即可

  • 準備文件,例如default.conf,index.html
  • ```
  • name: copy nginx config file
  • copy:
  • src: default.conf
  • dest: /data/nginx/default.conf
  • name: copy default html file
  • template:
  • src: index.html
  • dest: /data/nginx/html/index.html
  • owner: vagrant
  • group: vagrant
  • ```
  • 使用Ansible中提供的Docker模塊安裝Nginx,包括拉Docker images,設置ports,以及多久需要pull一次新代碼等
手把手教你從零搭建一個持續集成環境

安裝Jenkins:demo中需要用到jenkins-master和jenkins-slave兩個container,因此使用docker-compose更加方便docker-compose.yml中定義了鏡像的地址、端口號等,並通過執行它進行在Docker中的部署。其中slave節點選用了jaydp17/jenkins-slave這樣一個包含Java、git、curl環境的Image方便執行持續集成任務。

手把手教你從零搭建一個持續集成環境

Nginx

什麼是Nginx

一款輕量級的Web 服務器/反向代理服務器及電子郵件(IMAP/POP3)代理服務器

為什麼用Nginx

首先需要一個服務器來部署我們的應用,而常用的服務器有例如apache的Apache HTTP Server、Nginx、tomcat等;Nginx是為了解決互聯網業內著名的 “C10K” 問題而生;

其中Nginx通常用來做靜態內容服務器,而tomcat一般用於做動態應用的服務器,通常稱之為web容器;Nginx相比於apache的優點:

  • 輕量級,同樣起web服務,比apache佔用更少的內存及資源;
  • 抗併發,Nginx處理請求是異步非阻塞的,而apache則是阻塞型的,在高併發下Nginx能保持低資源低消耗高性能
  • 提供負載均衡;
  • 配置簡潔;
  • 社區活躍,各種高性能模塊出品迅速等;

怎麼用Nginx

在demo中寫了一個role來定義安裝配置Nginx需要的操作流程,用的是Docker提供的Nginx鏡像,在Docker中安裝配置Nginx,為了使Nginx能夠啟動起來,我們還需要進行一系列的配置,包括配置文件和模版文件等;default.conf就是Nginx的配置文件,此處http模塊的相關配置:

  • listen 80:監聽的端口號是80;
  • default_server:設定為默認虛擬主機;
  • server_name localhost:設置虛擬主機名稱為localhost;
  • root /usr/share/nginx/html:設置web服務URL資源映射的本地文件系統的資源所在的目錄;
  • index index.html index.htm:定義默認主頁面,需要自己編寫並放到Ansbile對應目錄;
手把手教你從零搭建一個持續集成環境

還有一些其他的配置,詳情請參考https://www.nginx.com/resources/wiki/start/topics/examples/full/

Ansible關於Nginx的task中yml文件的配置:

  • 創建文件夾
  • copy Nginx的配置文件到環境中
  • copy模版文件
  • 以及使用Docker鏡像運行Nginx
手把手教你從零搭建一個持續集成環境

世界有了,來聯通各國吧

到現在為止,你已經瞭解了所有我們使用的工具以及通過運行命令搭建完成了一套持續集成環境的基礎設施,但是還需要對Jenkins進行一些配置才能真正做到持續集成。

Jenkins的配置

現在你可以訪問 http://192.168.56.102:8080 了,然後頁面提示需要你輸入Administrator password。該密碼可以通過下面的方式獲取:

  1. 進入Jenkins虛擬機:vagrant ssh jenkins
  2. 獲取root權限:sudo su
  3. 進入Jenkins master容器:docker exec -it jenkins_master bash
  4. 找到密碼:cat /var/jenkins_home/secrets/initialAdminPassword

然後將密碼複製到頁面上點擊確定,隨後點擊安裝推薦的插件,本文將使用到的Jenkins功能不會超出推薦的插件的範圍。然後創建好用戶就可以登錄了。

Slave

來到主界面之後,接下來我們來配置一臺slave節點來幫我們執行任務,依次點擊Manage Jenkins -> Manage Nodes -> New Node,按照下圖進行配置。

手把手教你從零搭建一個持續集成環境

簡單起見,用密碼登錄的方式進行身份驗證,用戶名密碼都為jenkins。

那麼問題來了,為什麼slave節點的用戶名密碼是jenkins呢?是在這個Dockerfile裡配置的。我們用的雖然是jaydp17/jenkins-slave,但是你可以看到這個鏡像的構建文件中引用了evarga/jenkins-slave,其中echo "jenkins:jenkins" | chpasswd可以設置密碼。

手把手教你從零搭建一個持續集成環境

另外要注意一下,我們通過設置Host key verification strategy為Non verifying verification strategy從而關閉了slave主機的公鑰檢查,更多瞭解請參看這篇文章。

如果你現在能在Jenkins界面上看到你剛剛創建的slave節點,那麼已經完成配置了。另外,為了讓部署過程僅僅在slave節點上執行來確認slave是否已經部署成功,可以嘗試點擊master節點右方的配置按鈕將默認開啟的master節點中的executors數量改為0。

創建Pipeline

接下來我們將創建一條流水線。回到Jenkins首頁,然後

  1. 點擊 create new jobs
  2. 選擇Pipeline分類點擊OK
  3. 勾上Poll SCM,並填入* * * * *,讓Jenkins每分鐘幫我們check一次Github上是否有提交。
  4. Definition中選擇’Pipeline script from SCM’,我們通過Jenkinsfile去定義整條Pipeline
  5. SCM中選擇Git,Repository URL 填入 https://github.com/xbox1994/chicken-html.git 或者你自己創建的包含Jenkinsfile、部署腳本、index.html的項目。
  6. 完成配置,點擊Save,Jenkins會自動觸發第一次的持續集成。

當你能在deploy階段看到下面的輸出

手把手教你從零搭建一個持續集成環境

並且訪問http://192.168.56.101 ,能看到下面的文字,那麼恭喜你,順利通關!

觸發Pipeline

請盡情的提交吧,試試看Jenkins會不會把你的代碼拉下來觸發Pipeline。

html項目的腳本配置

即使你已經成功觸發多次Pipeline,但是其中還有些配置沒有講到,這些配置隱藏在項目代碼中。個人認為對於這個項目有關的配置就應該放到項目代碼中,除非有其他統一的配置管理方式。

比如chicken-html中的目錄如下:

手把手教你從零搭建一個持續集成環境

測試、構建

如果你用到gradle、maven這樣的工具來管理你的項目構建。平時在開發的時候只需要運行./gradlew clean build和./gradlew test來進行構建與測試。那麼到Jenkins上也是基於這些命令來進行的

部署代碼到服務器

部署代碼這步操作是會在Jenkins slave節點上進行,將從Github上拉來的代碼部署到Nginx服務器中,那麼最簡單的方式就是使用scp命令將需要部署的文件發送到Nginx服務器。在Ansbile腳本中已經把Nginx服務器的私鑰複製到了slave節點所在的服務器中了,所以可以直接執行scp命令。

在本文涉及到的html項目中的部署腳本如下:

手把手教你從零搭建一個持續集成環境

對於Nginx服務器來說,如果配置中指定的html文件發生變化,會檢測到並將最新的html文件返回給用戶。

Jenkinsfile

"

本文將帶領你從0開始,用Vagrant + Docker + Ansible + Jenkins + Nginx + GitHub等工具和資源來搭建一條可執行可擴展的持續集成流水線,即使這些名字你都沒聽過也沒關係,本文將會在需要的時候一一解釋給你聽。

By: 巧穎 & 天一

總覽

這是我們將要搭建的所有基礎設施的總體架構圖,我們將在本文中手把手教你搭建這樣一個持續集成環境。

手把手教你從零搭建一個持續集成環境

我們會在本地啟動兩臺虛擬機,一臺部署Nginx作為靜態文件服務器,一臺作為Jenkins服務器,在每臺虛擬機內部安裝Docker,使用Docker來完成Nginx與Jenkins的搭建、配置,然後手動在Jenkins配置內配置好一條Pipeline作為持續集成流水線,最後嘗試提交一次代碼去觸發一次持續集成操作,將最新的html項目代碼從Github上部署到Nginx中,實現持續集成。

避免本文過長,部分源代碼沒有貼在文中,本文參考完成源代碼在此:https://github.com/tw-wh-devops-community/cooking-chicken.git。建議在自己嘗試從0開始搭建的同時參考源碼閱讀本文。相信你一定會碰到很多坑,但坑外便是晴天。

首先我們需要兩臺機器

我們需要Vagrant

為什麼呢

無論你用的操作系統是Windows、Mac還是Linux,Oracle的Virtual Box都支持,那麼我們首先會使用Virtual Box來建立一個在硬件上絕對隔離的環境出來。

那麼Vagrant就是通過方便的命令操作來簡化Virtual Box的操作,同時提供了方便的虛擬機配置模塊,所以我們會使用這個工具來提升虛擬機的配置效率。

安裝Vagrant

在Mac上是自帶Virtual Box的,你用的版本可能需要更新才能配合Vagrant使用,Linux上請使用類似sudo apt-get install virtualbox的命令安裝。

那麼先裝上Vagrant吧:

  • Mac(https://www.vagrantup.com/downloads.html)
  • Ubuntu(sudo apt-get install vagrant)

安裝Vagrant插件

由於後續操作會涉及到將Nginx機器的私鑰發送給Jenkins機器來配置私鑰來完成虛擬機之間的無密碼訪問。但私鑰是在Nginx虛擬機創建之後才會由Vagrant創建的,所以需要在這個時間節點放到Jenkins目錄下便於Ansible把私鑰放到Jenkins虛擬機中。如果暫時不理解沒有關係,請看完”開始創建世界“之後回頭來看就會明白。

Vagrant的provision模塊可以在虛擬機啟動之後在虛擬機內部執行任意腳本,但是provision模塊並沒有提供執行宿主機上腳本的方式,所以需要你安裝如下模塊:

vagrant plugin install vagrant-host-shell

調試的時候比較有用的操作

  • 進入虛擬機:vagrant ssh
  • 休眠:vagrant suspend
  • 從休眠中恢復:vagrant resume
  • 移除虛擬機所有文件:vagrant destroy

開始創建世界!

Vagrantfile

我們來新建一個工程,在根目錄創建一個名為Vagrantfile的文件,內容如下:

手把手教你從零搭建一個持續集成環境

那麼現在可以啟動了,在命令行內跳轉到根目錄,使用vagrant up就可以將虛擬機按上面的配置啟動了,同時在啟動完成之後會調用provision模塊跑Ansible的對應腳本安裝配置虛擬機的依賴工具。啟動完成之後,那麼一個隔離的環境創建完畢,接下來我們可以在裡面任意玩耍了。

特別注意:因為第一次運行需要下載ubuntu/trusty64鏡像,以及把所有的配置甚至通過Docker下載Jenkins鏡像、slave鏡像,以及啟動Jenkins都寫到了Ansible中,所以跑完vagrant up需要較長時間

啟動、執行順序

基本是按Vagrant的配置文件的上下順序來啟動的。具體順序如下:

  1. 按Vagrantfile安裝並啟動Nginx虛擬機
  2. 執行Nginx虛擬機依賴的provision模塊
  3. 按Vagrantfile安裝並啟動Jenkins虛擬機
  4. 執行Jenkins虛擬機依賴的provision模塊

Jenkins訪問Nginx(選修,建議有時間或者將Jenkins搭建完成之後再看)

如果你能把所有環境啟動起來並能訪問Jenkins主頁,但此時你還無法在Jenkins上直接ssh登錄到Nginx,因為此時兩臺機器還沒有互信。但是幸運的是Vagrant啟動完Nginx之後就已經將私鑰(可以拿這個私鑰去訪問Nginx,無論你是誰)放到了宿主機上,那麼你可以手動將這個私鑰複製到Jenkins中,然後就可以在Jenkins中訪問Nginx了。

但是為了自動化上面的操作,進行以下的配置:Vagrant會在啟動一個虛擬機之後,會在Mac上創建.vagrant文件夾並把一些關於這個虛擬機的文件放到裡面,比如該虛擬機的私鑰,後面可以拿到這私鑰作為SSH聯絡的key。

比如下面這段配置會在Nginx虛擬機啟動之後,Jenkins虛擬機啟動之前執行。由於Jenkins虛擬機需要在部署代碼的時候使用到Nginx虛擬機的私鑰來部署,所以需要在Jenkins虛擬機執行Ansible之前將私鑰放到Jenkins的file文件夾中。

手把手教你從零搭建一個持續集成環境

另外,在Vagrantfile中,Ansible不是與兩臺虛擬機的配置寫在一起的,那麼Ansible如何判斷在哪臺虛擬機上安裝Nginx還是Jenkins呢?因為不同的虛擬機要執行Ansible的時候會根據主機名匹配來找到對應role的tasks從而還是能找到匹配的tasks。換句話說,Nginx安裝完成之後Vagrant攜帶Nginx相關參數執行下面這樣的一行命令來用limit匹配主機與對應Ansible的tasks:

手把手教你從零搭建一個持續集成環境

我們需要Ansible

什麼是Ansible

Ansible是一種自動化部署工具,可以用來自動化管理配置項、持續交付、(AWS)雲服務管理;

簡單來說也就是可以批量的遠程服務器上執行一系列的命令,其原理是基於ssh來和遠程主機進行通信的。

為什麼用Ansible

  • playbook使用的是yml語言,易讀性較好;
  • 沒有主節點和代理,僅僅依賴於SSH,使得應用的部署簡單而輕量;
  • 提供了大量模塊支持Google Compute Engine (GCE), Amazon Web Service(AWS);
  • Ansible支持多臺服務器同時管理部署;

安裝Ansible

Ansible是基於python開發的,需要在安裝有python的機器下才能夠安裝Ansible

  • 在本機安裝python:brew install python(Mac自帶ython,因此這步可以省略,inux系統中需要安裝Python)
  • 安裝pip:sudo apt install python-pip
  • 安裝Ansible:sudo pip install ansible

目錄結構

你可以按如下目錄結構去編寫你的Ansible文件。

手把手教你從零搭建一個持續集成環境

roles文件夾

roles是基於一個Ansible默認的目錄結構,Ansible在執行任務的時候會去默認加載templates、tasks以及handlers文件夾中的文件等。我們基於roles 對內容進行分組,使得我們可以容易地將不同的環境(如Java與NodeJs)區分開來,本次Demo中的roles下有三個文件夾,分別是common、jenkins和nginx,其中每個文件夾下都會定義一些例如tasks任務與相關配置文件。

role - common

前面已經說過本次demo需要在本地啟動兩臺虛擬機,分別在內部裝上Docker,在common中我們定義了安裝Docker的task,這樣在定義Jenkins服務器和部署nginx的服務器中都可以調用該task來安裝配置Docker環境;

install_docker.yml中應該包含如下內容:

  • 安裝Docker
  • 安裝docker-compose工具
  • 安裝docker-py依賴包(如果我們想用Ansible的docker模塊去執行docker相關命令的話需要這個依賴)

role - jenkins

定義安裝和部署Jenkins服務器的task:其中docker-compose.yml配置文件,是用於分別對jenkins-master和jenkins_slave進行一些基本配置;task下的main.yml文件是配置一系列的安裝命令,類似於在命令行中一行行輸入安裝和部署命令;

role - nginx

與jenkins文件夾類似,對Nginx服務器的一些基本配置:例如Nginx配置文件default.conf,配置文件中定義了templates下的index.html作為Nginx的入口模版文件,使Nginx作為一個文件服務器。task下的main.yml文件則是與jenkins中類似,配置了安裝部署命令,在使用vagrant up時通過Ansible來安裝並運行Nginx服務。

配置文件

Ansible的配置文件包括但不僅限於ansible.cfg、deploy.yml以及hosts

ansible.cfg文件

如在本Demo中用到的幾個配置:

  • forks:設置在與主機通信時的默認並行進程數,默認值為5;
  • inventory:設置主機與組之間的對應關係,在Ansible1.9之前使用的是hostfile;
  • host_key_checking:檢測主機密鑰的功能,可以通過設置值為false來禁用該功能(跳過兩臺主機之間首次連接需要確認的過程);
  • nocows:設置其值為1時禁用調用一些cowsay的特性,cowsay是linux系統下一個在終端用ASCII碼組成的小牛,這個小牛會說出你想要它說的話。
  • gathering:控制默認的遠程系統變量(facts)收集,有三種不同的值;默認是implicit,即每一次play,變量都會被收集,除非設置gather_facts: False;為explicit時,則facts不會被收集;為smart時,則沒有facts的新hosts將不會被掃描,用於節省fact收集;
  • fact_caching_timeout:定義fact緩存超時時間;
  • fact_caching:定義fact的緩存,2.4版本的Ansible支持redis和jsonfile兩種格式的緩存文件;
  • fact_caching_connection:定義cache的存儲位置,根據cache文件的格式不同定義的方式不同;

deploy.yml文件

這是Ansible的入口配置文件:定義hosts主機、以及相應主機需要執行的tasks等;

手把手教你從零搭建一個持續集成環境

hosts

然後加上遠程主機的網絡相關配置,這樣Ansible才能通過SSH到虛擬機中執行你寫的任務喲。

以如下命令為例,是為IP地址1192.168.56.102,端口號22的網絡地址設置一個別名nginx,且聲明其ssh private key文件的地址;

手把手教你從零搭建一個持續集成環境

與Vagrant結合

現在,Ansible的任務已經寫完了,我們需要將Ansible與Vagrant結合,將如下代碼加入到Vagrantfile中,可以在執行vagrant up的時候執行Ansible。

手把手教你從零搭建一個持續集成環境

虛擬機中的世界是如何構成的呢

現在你已經將所有的環境部署完成了,但是部署應用(Jenkins、Nginx)的過程還沒有提及,下面將帶你從Ansbile的對於每個虛擬機的任務開始,介紹相應的工具與具體的實施步驟。

Docker

什麼是Docker

Docker是一個開源的容器應用引擎,可以理解為一個存放應用容器的平臺,我們只需要簡單的幾行命令就可以構建一個與本地環境相對隔離的環境來運行我們的應用而不影響任何角色;

基本要素:

  • Container:負責應用程序的運行,包括操作系統、用戶添加的文件以及元數據
  • Images:只讀模版,即常說的Docker鏡像,用來運行Docker容器
  • Dockerfile:文件指令集,用來說明如何創建Docker鏡像

為什麼要用Docker

把一個應用封裝起來,可以在任何裝有Docker的環境下運行,統一運行環境;

那個大鯨魚(或者是貨輪)就是操作系統,把要交付的應用程序看成是各種貨物,原本要將各種各樣形狀、尺寸不同的貨物放到大鯨魚上,你得為每件貨物考慮怎麼安放(就是應用程序配套的環境),還得考慮貨物和貨物是否能疊起來(應用程序依賴的環境是否會衝突)。

現在使用了集裝箱(容器)把每件貨物都放到集裝箱裡,這樣大鯨魚可以用同樣地方式安放、堆疊集裝了,省事省力。

Docker中常用的命令

手把手教你從零搭建一個持續集成環境

怎麼用

要注意的是,Ansible對應的任務是在Vagrant啟動虛擬機之後執行的,是在虛擬機的內部,Docker容器的外部

安裝Nginx:由於我們只需要啟動一個Nginx的容器,直接使用Docker中run的命令去repository中下載安裝即可

  • 準備文件,例如default.conf,index.html
  • ```
  • name: copy nginx config file
  • copy:
  • src: default.conf
  • dest: /data/nginx/default.conf
  • name: copy default html file
  • template:
  • src: index.html
  • dest: /data/nginx/html/index.html
  • owner: vagrant
  • group: vagrant
  • ```
  • 使用Ansible中提供的Docker模塊安裝Nginx,包括拉Docker images,設置ports,以及多久需要pull一次新代碼等
手把手教你從零搭建一個持續集成環境

安裝Jenkins:demo中需要用到jenkins-master和jenkins-slave兩個container,因此使用docker-compose更加方便docker-compose.yml中定義了鏡像的地址、端口號等,並通過執行它進行在Docker中的部署。其中slave節點選用了jaydp17/jenkins-slave這樣一個包含Java、git、curl環境的Image方便執行持續集成任務。

手把手教你從零搭建一個持續集成環境

Nginx

什麼是Nginx

一款輕量級的Web 服務器/反向代理服務器及電子郵件(IMAP/POP3)代理服務器

為什麼用Nginx

首先需要一個服務器來部署我們的應用,而常用的服務器有例如apache的Apache HTTP Server、Nginx、tomcat等;Nginx是為了解決互聯網業內著名的 “C10K” 問題而生;

其中Nginx通常用來做靜態內容服務器,而tomcat一般用於做動態應用的服務器,通常稱之為web容器;Nginx相比於apache的優點:

  • 輕量級,同樣起web服務,比apache佔用更少的內存及資源;
  • 抗併發,Nginx處理請求是異步非阻塞的,而apache則是阻塞型的,在高併發下Nginx能保持低資源低消耗高性能
  • 提供負載均衡;
  • 配置簡潔;
  • 社區活躍,各種高性能模塊出品迅速等;

怎麼用Nginx

在demo中寫了一個role來定義安裝配置Nginx需要的操作流程,用的是Docker提供的Nginx鏡像,在Docker中安裝配置Nginx,為了使Nginx能夠啟動起來,我們還需要進行一系列的配置,包括配置文件和模版文件等;default.conf就是Nginx的配置文件,此處http模塊的相關配置:

  • listen 80:監聽的端口號是80;
  • default_server:設定為默認虛擬主機;
  • server_name localhost:設置虛擬主機名稱為localhost;
  • root /usr/share/nginx/html:設置web服務URL資源映射的本地文件系統的資源所在的目錄;
  • index index.html index.htm:定義默認主頁面,需要自己編寫並放到Ansbile對應目錄;
手把手教你從零搭建一個持續集成環境

還有一些其他的配置,詳情請參考https://www.nginx.com/resources/wiki/start/topics/examples/full/

Ansible關於Nginx的task中yml文件的配置:

  • 創建文件夾
  • copy Nginx的配置文件到環境中
  • copy模版文件
  • 以及使用Docker鏡像運行Nginx
手把手教你從零搭建一個持續集成環境

世界有了,來聯通各國吧

到現在為止,你已經瞭解了所有我們使用的工具以及通過運行命令搭建完成了一套持續集成環境的基礎設施,但是還需要對Jenkins進行一些配置才能真正做到持續集成。

Jenkins的配置

現在你可以訪問 http://192.168.56.102:8080 了,然後頁面提示需要你輸入Administrator password。該密碼可以通過下面的方式獲取:

  1. 進入Jenkins虛擬機:vagrant ssh jenkins
  2. 獲取root權限:sudo su
  3. 進入Jenkins master容器:docker exec -it jenkins_master bash
  4. 找到密碼:cat /var/jenkins_home/secrets/initialAdminPassword

然後將密碼複製到頁面上點擊確定,隨後點擊安裝推薦的插件,本文將使用到的Jenkins功能不會超出推薦的插件的範圍。然後創建好用戶就可以登錄了。

Slave

來到主界面之後,接下來我們來配置一臺slave節點來幫我們執行任務,依次點擊Manage Jenkins -> Manage Nodes -> New Node,按照下圖進行配置。

手把手教你從零搭建一個持續集成環境

簡單起見,用密碼登錄的方式進行身份驗證,用戶名密碼都為jenkins。

那麼問題來了,為什麼slave節點的用戶名密碼是jenkins呢?是在這個Dockerfile裡配置的。我們用的雖然是jaydp17/jenkins-slave,但是你可以看到這個鏡像的構建文件中引用了evarga/jenkins-slave,其中echo "jenkins:jenkins" | chpasswd可以設置密碼。

手把手教你從零搭建一個持續集成環境

另外要注意一下,我們通過設置Host key verification strategy為Non verifying verification strategy從而關閉了slave主機的公鑰檢查,更多瞭解請參看這篇文章。

如果你現在能在Jenkins界面上看到你剛剛創建的slave節點,那麼已經完成配置了。另外,為了讓部署過程僅僅在slave節點上執行來確認slave是否已經部署成功,可以嘗試點擊master節點右方的配置按鈕將默認開啟的master節點中的executors數量改為0。

創建Pipeline

接下來我們將創建一條流水線。回到Jenkins首頁,然後

  1. 點擊 create new jobs
  2. 選擇Pipeline分類點擊OK
  3. 勾上Poll SCM,並填入* * * * *,讓Jenkins每分鐘幫我們check一次Github上是否有提交。
  4. Definition中選擇’Pipeline script from SCM’,我們通過Jenkinsfile去定義整條Pipeline
  5. SCM中選擇Git,Repository URL 填入 https://github.com/xbox1994/chicken-html.git 或者你自己創建的包含Jenkinsfile、部署腳本、index.html的項目。
  6. 完成配置,點擊Save,Jenkins會自動觸發第一次的持續集成。

當你能在deploy階段看到下面的輸出

手把手教你從零搭建一個持續集成環境

並且訪問http://192.168.56.101 ,能看到下面的文字,那麼恭喜你,順利通關!

觸發Pipeline

請盡情的提交吧,試試看Jenkins會不會把你的代碼拉下來觸發Pipeline。

html項目的腳本配置

即使你已經成功觸發多次Pipeline,但是其中還有些配置沒有講到,這些配置隱藏在項目代碼中。個人認為對於這個項目有關的配置就應該放到項目代碼中,除非有其他統一的配置管理方式。

比如chicken-html中的目錄如下:

手把手教你從零搭建一個持續集成環境

測試、構建

如果你用到gradle、maven這樣的工具來管理你的項目構建。平時在開發的時候只需要運行./gradlew clean build和./gradlew test來進行構建與測試。那麼到Jenkins上也是基於這些命令來進行的

部署代碼到服務器

部署代碼這步操作是會在Jenkins slave節點上進行,將從Github上拉來的代碼部署到Nginx服務器中,那麼最簡單的方式就是使用scp命令將需要部署的文件發送到Nginx服務器。在Ansbile腳本中已經把Nginx服務器的私鑰複製到了slave節點所在的服務器中了,所以可以直接執行scp命令。

在本文涉及到的html項目中的部署腳本如下:

手把手教你從零搭建一個持續集成環境

對於Nginx服務器來說,如果配置中指定的html文件發生變化,會檢測到並將最新的html文件返回給用戶。

Jenkinsfile

手把手教你從零搭建一個持續集成環境

這個文件定義了Jenkins中這個項目的Pipeline裡應該如何被執行,每一步都做些什麼操作,如定義了4個stage分別對應拉代碼、測試、構建、部署,其中部署腳本執行的就是使用scp命令執行的。當然這個是最簡單的Pipeline任務定義,你可以參考https://jenkins.io/doc/book/pipeline/jenkinsfile/來使用更方便的功能如“when”語句來檢測上一個stage是否成功完成。

來源:http://sina.lt/gp9f,本文來自於wangtianyi的博客。




"

相關推薦

推薦中...