Jenkins+Ansible+Gitlab自動化部署三劍客

最近一直在學習Ansible的一些playbook的寫法, 因此一直沒有怎麼更新, 想到目前你們對諸如saltstack, docker, Ansible等自動化部署相關的工具很感興趣, 但又苦於沒有可學習的中文實例, 這裏我就把我這幾個月所接觸到目前國外比較流行的部署經驗給你們分享一下.php

首先給你們介紹的是Ansible, 恩, 重要的問題說三遍, 不是Saltstack, Ansible做爲一個python寫的自動化部署工具, 確實較以前我所接觸的Chef, saltstack, puppet更有本身的一些優點, 首先就是agentless, 無需在Linux client安裝任何服務便可無縫鏈接Linux default ssh端口進行部署(windows須要安裝winrm 開啓ssh服務), 這點其實我以爲很是重要, 能夠想象不少公司自己是對network管理很是嚴格的, 在部署一個產品的同時你須要考慮不少時間成本, 使用其餘部署工具自己很是棘手的問題就是去申請開端口, client量少的話, 咱們能夠去等, 多的話自己你去request, waiting, unblock port等等long long process.... 最後會耗費很長時間. 這個對不少產品自己就是很致命的. 不推薦Saltstack的緣由也是由於其須要在每臺agent逐一去安裝client service並測試, 這自己就會耗費一些時間成本. python

其餘呢? 其實我以爲就是容易上手, 語法簡單, 有現成模板讓你去學習, 加之是咱們很是喜好的python語法, why not? git

Jenkins不用我多說, 估計懂行的人都在用它, 開源, 輕量級, 兼容性和擴展性強, 直觀的GUI管理這都是它的優點, 配合Ansible我以爲用起來會很是easy going. docker

最後提一下Gitlab, 爲何要用Gitlab? 他做爲一個代碼版本控制系統和部署有什麼關係呢? 其實這裏就涉及一個咱們Ansible playbook管理問題, 試想咱們須要維護一個公司龐大的server集羣, 咱們全部須要部署的機器或者產品會對應咱們相對的部署腳本, 咱們使用的Ansible playbook若是隻是保存在Ansible Server的具體某個目錄, 這自己就不便於咱們進行編寫維護更新(想一想每次都跑到遠程去編寫playbook或者每次在本地編寫好後再upload到遠程我都會腦補數以萬計的草泥馬從我眼前呼嘯而來). shell

這裏Gitlab就給咱們提供一個很是方便以及直觀的Playbook management. 咱們須要作的其實就是在Gitlab去創建一個對應產品或者server的playbook倉庫, 而後咱們在本地寫好後直接commit到這個倉庫, 最後在部署的時候, 去讓Jenkins pull這個playbook到其workspace, 並做爲一個Job去run這個playbook, 這樣是否是很規範, 並且便於管理? windows

固然Ansible自己企業版Tower也會提供一個相似管理並維護playbook以及監控ansible自己running process的GUI管理系統, 用起來也很不錯, 但做爲收費版本, 咱們在這裏就不作過多闡述了. 瀏覽器


這裏我推薦Jenkins和Ansible能夠安裝到同一個環境做爲部署server, Gitlab做爲版本控制系統可單獨部署在另外一臺server. session

總結: less

Jenkins首先從Gitlab去抓取咱們寫好的具體產品的playbook, 並使用virtualenv下的Ansible相關命令, 保證咱們在一個clean的環境下使用stable version去批量部署咱們的產品到遠程client. ssh

 

Let's go.....

 

一. 安裝環境

System: CentOS 6.7 x64 (deploy.example.com)

Jenkins: Jenkins ver. 1.650

Ansible: Ansible 2.1.0

Gitlab: GitLab 7.14.3

 

二. Jenkins配置

咱們建立deploy用戶做爲jenkins_user, workspace爲deploy家目錄下的jenkins目錄.

# su - root

# adduser deploy

# wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo

# rpm --import https://jenkins-ci.org/redhat/jenkins-ci.org.key

# yum install jenkins -y

# vi /etc/sysconfig/jenkins

...
JENKINS_HOME="/home/deploy/jenkins"
JENKINS_USER="deploy"
...

# service jenkins start

瀏覽器訪問Jenkins頁面

http://deploy.example.com:8080

安裝完成, 如下是我已經配置好的一些Jenkins Job.

QQ20160311-0

這裏咱們使用一個國內PHP網站模板phpcms做爲咱們須要部署的產品進行本次範例演示, 在進行最終的Build前咱們須要作一些準備工做, 稍後咱們會回到這個界面.

 

三. Ansible配置

這裏咱們須要配置virtualenv去隔離咱們ansible的發行版本爲最新版本2.1.0, 默認pip或者yum安裝的1.9版本由於BUG以及對windows不兼容的緣由, 這裏不推薦使用.

配置步驟傳送門: http://www.showerlee.com/archives/1862

Ansible-playbook範例傳送門: http://www.showerlee.com/archives/1649

 

四. Gitlab配置

部署並使用傳送門: http://www.showerlee.com/archives/1285

咱們最終會建立一個ansible playbook倉庫 git@git.example.cn:showerlee/Ansible-showerlee.git, 並在本地編寫好咱們的規則, 最終commit到這個倉庫, 以便Jenkins去調用咱們的部署規則.

這裏博主單獨clone出來一份部署phpcms的playbook倉庫, 算是給你們的福利:

https://git.yanwenbo.cn/showerlee/leon-playbook-phpcms1.1

QQ20160311-2

QQ20160311-3

QQ20160311-4

 

五.最終部署

準備工做完畢, 咱們接下來給你們介紹Jenkins Job配置.

1.建立一個new item

QQ20160311-5

2. 建立一個freestyle Job, 命名規則"產品名-環境", 這裏咱們爲Phpcms-Dev

QQ20160311-6

3. Job配置

1). 定製Build參數.

這裏Dynamic Choice Parameter用來經過Groovy腳原本抓取這個git倉庫的全部branch, 並做爲一個多選項, 方便咱們在最終Build前去選擇咱們須要的這個產品Branch分支.

Groovy抓取Git branch代碼:

 

def gettags = ("git ls-remote -h :showerlee/phpcms.git").execute()  
gettags.text.readLines().collect { it.split()[1].replaceAll('refs/heads/', '')  }.unique()

 

QQ20160311-11

Choice Parameter也是用來給咱們Job定製Build前的可選參數, 不過這裏的參數能夠直接寫死

deploy_environment爲咱們的參數名, 定義咱們的部署環境名, prod, qa爲咱們具體的可選項, 定義咱們產品的兩個環境.

QQ20160311-82). 源代碼管理

咱們能夠利用Jenkins內置的Source Code Management工具去抓取遠程Git或者SVN倉庫的代碼到本地, 這裏咱們抓取存放在咱們Gitlab上的Playbook到Jenkins的workspace目錄, 用來進行後續部署工做, 這個倉庫如需認證, 咱們能夠在Credentials add這個倉庫的用戶帳號密碼, 其他均保持默認便可(默認Jenkins default不支持Git, 須要到其後檯安裝Git插件)

QQ20160311-93). Execute shell進行最終的CLI部署.

這個Build模塊下的Execute shell方法是Jenkins比較經常使用並不是常核心的功能, 用來執行咱們部署過程當中核心的命令.

開頭和結尾的set +x, set -x用來打開和關閉該部分的擴展參數及命令

開啓virtualenv和加載ansible環境變量

# source /home/deploy/.virtualenv/bin/activate
# . /home/deploy/.virtualenv/ansible/hacking/env-setup -q

進入該Job的workspace目錄下保存該playbook的倉庫子目錄下, 檢查ansible版本, 並執行最終的部署命令.

cd $WORKSPACE/leon-playbook-phpcms1.1
ansible --version
ansible-playbook -i inventory/$deploy_environment ./deploy.yml -e project=phpcms -e branch=$branch_selector -e env=$deploy_environment

注: -i 用來自定義ansible host文件路徑, ./deploy.yml爲ansible-playbook入口文件, -e 後可跟給當前session添加的環境變量.

這裏$deploy_environment $branch_selector 爲該Job定義好的可選參數, 詳見3-1)

QQ20160311-10

 

配置完畢後, save保存.

4. 執行Job.

QQ20160311-12

選擇master分支和prod環境

QQ20160311-13

 

查看該Job最終的console output, 也就是顯示咱們實際在CLI下的輸出結果.

QQ20160311-14

 

Console Output

Started by user Leon Li
Building in workspace /home/deploy/jenkins/workspace/Phpcms-Dev
 > git rev-parse --is-inside-work-tree # timeout=10
Fetching changes from the remote Git repository
 > git config remote.origin.url :showerlee/Ansible-showerlee.git # timeout=10
Fetching upstream changes from :showerlee/Ansible-showerlee.git
 > git --version # timeout=10
 > git fetch --tags --progress :showerlee/Ansible-showerlee.git +refs/heads/*:refs/remotes/origin/*
 > git rev-parse refs/remotes/origin/master^{commit} # timeout=10
 > git rev-parse refs/remotes/origin/origin/master^{commit} # timeout=10
Checking out Revision 6bf787dcad68219d8eee09cecb83cbca36edbef1 (refs/remotes/origin/master)
 > git config core.sparsecheckout # timeout=10
 > git checkout -f 6bf787dcad68219d8eee09cecb83cbca36edbef1
 > git rev-list 6bf787dcad68219d8eee09cecb83cbca36edbef1 # timeout=10
[Phpcms-Dev] $ /bin/sh -xe /tmp/hudson7452069223867148990.sh
+ set +x
ansible 2.1.0 (devel 6ddea3e915) last updated 2016/02/16 16:13:32 (GMT +800)
  lib/ansible/modules/core: (detached HEAD 8d126bd877) last updated 2016/02/16 16:19:09 (GMT +800)
  lib/ansible/modules/extras: (detached HEAD f6c5ed987f) last updated 2016/02/16 16:19:40 (GMT +800)
  config file = /home/deploy/jenkins/workspace/Phpcms-Dev/leon-playbook-phpcms1.1/ansible.cfg
  configured module search path = /home/deploy/active-ansible-modules/

PLAY ***************************************************************************

TASK [setup] *******************************************************************
ok: [127.0.0.1]

TASK [deploy : Backup current source code] *************************************
changed: [127.0.0.1]

cmd: mv /data/deploy_dir/phpcms /data/deploy_dir/phpcms_master_1457681152

start: 2016-03-11 15:25:54.774716

end: 2016-03-11 15:25:54.927415

delta: 0:00:00.152699

TASK [deploy : Get new source code] ********************************************
changed: [127.0.0.1]

TASK [deploy : Check if caches/configs/database.php exists] ********************
ok: [127.0.0.1]

TASK [deploy : Check if test_dir exists] ***************************************
ok: [127.0.0.1]

TASK [deploy : debug] **********************************************************
ok: [127.0.0.1] => {
    "msg": "/data/deploy_dir/phpcms_master_1457681152/caches/configs/database.php exists"
}

msg: /data/deploy_dir/phpcms_master_1457681152/caches/configs/database.php exists

TASK [deploy : debug] **********************************************************
ok: [127.0.0.1] => {
    "msg": "/data/deploy_dir/phpcms_master_1457681152/test_dir exists"
}

msg: /data/deploy_dir/phpcms_master_1457681152/test_dir exists

TASK [deploy : Copy remote necessary original config to new release when Product env] ***
changed: [127.0.0.1] => (item={u'name': u'db_config', u'dir': u'caches/configs/database.php'})
changed: [127.0.0.1] => (item={u'name': u'version_config', u'dir': u'caches/configs/version.php'})

msg: All items completed

results: [
  {
    "src": "/data/deploy_dir/phpcms_master_1457681152/caches/configs/database.php", 
    "changed": true, 
    "group": "deploy", 
    "uid": 606, 
    "dest": "/data/deploy_dir/phpcms/caches/configs/database.php", 
    "checksum": "91869c2faa244f8c5de8a586636c6b4f3c0a2817", 
    "md5sum": "fd88a78a4629bca012a79d22fdcecadd", 
    "owner": "deploy", 
    "_ansible_no_log": false, 
    "item": {
      "name": "db_config", 
      "dir": "caches/configs/database.php"
    }, 
    "state": "file", 
    "gid": 608, 
    "mode": "0644", 
    "invocation": {
      "module_args": {
        "src": "/data/deploy_dir/phpcms_master_1457681152/caches/configs/database.php", 
        "directory_mode": null, 
        "force": true, 
        "remote_src": true, 
        "dest": "/data/deploy_dir/phpcms/caches/configs/database.php", 
        "selevel": null, 
        "seuser": null, 
        "setype": null, 
        "group": null, 
        "content": null, 
        "serole": null, 
        "original_basename": null, 
        "delimiter": null, 
        "mode": "0644", 
        "regexp": null, 
        "owner": null, 
        "follow": false, 
        "validate": null, 
        "backup": false
      }
    }, 
    "size": 302
  }, 
  {
    "src": "/data/deploy_dir/phpcms_master_1457681152/caches/configs/version.php", 
    "changed": true, 
    "group": "deploy", 
    "uid": 606, 
    "dest": "/data/deploy_dir/phpcms/caches/configs/version.php", 
    "checksum": "d0eaedb46a36303eb3f3e2a77cc2a623062eff3c", 
    "md5sum": "7917d8199b7c6d5bc87ff3035a72670e", 
    "owner": "deploy", 
    "_ansible_no_log": false, 
    "item": {
      "name": "version_config", 
      "dir": "caches/configs/version.php"
    }, 
    "state": "file", 
    "gid": 608, 
    "mode": "0644", 
    "invocation": {
      "module_args": {
        "src": "/data/deploy_dir/phpcms_master_1457681152/caches/configs/version.php", 
        "directory_mode": null, 
        "force": true, 
        "remote_src": true, 
        "dest": "/data/deploy_dir/phpcms/caches/configs/version.php", 
        "selevel": null, 
        "seuser": null, 
        "setype": null, 
        "group": null, 
        "content": null, 
        "serole": null, 
        "original_basename": null, 
        "delimiter": null, 
        "mode": "0644", 
        "regexp": null, 
        "owner": null, 
        "follow": false, 
        "validate": null, 
        "backup": false
      }
    }, 
    "size": 127
  }
]

TASK [deploy : Copy dir test_dir to new release when Product env] **************
changed: [127.0.0.1]

cmd: cp -a /data/deploy_dir/phpcms_master_1457681152/test_dir /data/deploy_dir/phpcms/

start: 2016-03-11 15:26:16.966237

end: 2016-03-11 15:26:17.069705

delta: 0:00:00.103468

TASK [deploy : Get php version] ************************************************
changed: [127.0.0.1 -> localhost]

cmd: python /home/deploy/jenkins/workspace/Phpcms-Dev/leon-playbook-phpcms1.1/roles/deploy/files/get_php_version.py start: 2016-03-11 15:26:17.468311

end: 2016-03-11 15:26:51.560313

delta: 0:00:34.092002

stdout: PHP/5.4.13

TASK [deploy : debug] **********************************************************
ok: [127.0.0.1] => {
    "msg": {
        "changed": true, 
        "cmd": "python /home/deploy/jenkins/workspace/Phpcms-Dev/leon-playbook-phpcms1.1/roles/deploy/files/get_php_version.py ", 
        "delta": "0:00:34.092002", 
        "end": "2016-03-11 15:26:51.560313", 
        "rc": 0, 
        "start": "2016-03-11 15:26:17.468311", 
        "stderr": "", 
        "stdout": "PHP/5.4.13", 
        "stdout_lines": [
            "PHP/5.4.13"
        ], 
        "warnings": []
    }
}

msg: {
  "changed": true, 
  "end": "2016-03-11 15:26:51.560313", 
  "stdout": "PHP/5.4.13", 
  "cmd": "python /home/deploy/jenkins/workspace/Phpcms-Dev/leon-playbook-phpcms1.1/roles/deploy/files/get_php_version.py ", 
  "start": "2016-03-11 15:26:17.468311", 
  "delta": "0:00:34.092002", 
  "stderr": "", 
  "rc": 0, 
  "stdout_lines": [
    "PHP/5.4.13"
  ], 
  "warnings": []
}

TASK [deploy : debug] **********************************************************
ok: [127.0.0.1] => {
    "msg": "PHP/5.4.13"
}

msg: PHP/5.4.13

PLAY RECAP *********************************************************************
127.0.0.1                  : ok=12   changed=5    unreachable=0    failed=0   

Finished: SUCCESS

 

這樣咱們就利用Jenkins+Ansible+Gitlab, 成功部署phpcms到遠程Client.

 

 

本文轉載自一路向北的博客http://www.showerlee.com/archives/1880

相關文章
相關標籤/搜索