|
最近一直在學(xué)習(xí)Ansible的一些playbook的寫法, 所以一直沒有怎么更新, 想到目前大家對(duì)諸如saltstack, docker, Ansible等自動(dòng)化部署相關(guān)的工具很感興趣, 但又苦于沒有可學(xué)習(xí)的中文實(shí)例, 這里我就把我這幾個(gè)月所接觸到目前國(guó)外比較流行的部署經(jīng)驗(yàn)給大家分享一下.
首先給大家介紹的是Ansible, 恩, 重要的問題說(shuō)三遍, 不是Saltstack, Ansible作為一個(gè)python寫的自動(dòng)化部署工具, 確實(shí)較之前我所接觸的Chef, saltstack, puppet更有自己的一些優(yōu)勢(shì), 首先就是agentless, 無(wú)需在Linux client安裝任何服務(wù)即可無(wú)縫連接Linux default ssh端口進(jìn)行部署(windows需要安裝winrm 開啟ssh服務(wù)), 這點(diǎn)其實(shí)我覺得非常重要, 可以想象很多公司本身是對(duì)network管理非常嚴(yán)格的, 在部署一個(gè)產(chǎn)品的同時(shí)你需要考慮很多時(shí)間成本, 使用其他部署工具本身非常棘手的問題就是去申請(qǐng)開端口, client量少的話, 我們可以去等, 多的話本身你去request, waiting, unblock port等等long long process…. 最后會(huì)耗費(fèi)很長(zhǎng)時(shí)間. 這個(gè)對(duì)很多產(chǎn)品本身就是很致命的. 不推薦Saltstack的原因也是因?yàn)槠湫枰诿颗_(tái)agent逐一去安裝client service并測(cè)試, 這本身就會(huì)耗費(fèi)一些時(shí)間成本.
其他呢? 其實(shí)我覺得就是容易上手, 語(yǔ)法簡(jiǎn)單, 有現(xiàn)成模板讓你去學(xué)習(xí), 加之是我們非常喜愛的python語(yǔ)法, why not?
Jenkins不用我多說(shuō), 估計(jì)懂行的人都在用它, 開源, 輕量級(jí), 兼容性和擴(kuò)展性強(qiáng), 直觀的GUI管理這都是它的優(yōu)勢(shì), 配合Ansible我覺得用起來(lái)會(huì)非常easy going.
最后提一下Gitlab, 為什么要用Gitlab? 他作為一個(gè)代碼版本控制系統(tǒng)和部署有什么關(guān)系呢? 其實(shí)這里就涉及一個(gè)我們Ansible playbook管理問題, 試想我們需要維護(hù)一個(gè)公司龐大的server集群, 我們所有需要部署的機(jī)器或者產(chǎn)品會(huì)對(duì)應(yīng)我們相對(duì)的部署腳本, 我們使用的Ansible playbook如果只是保存在Ansible Server的具體某個(gè)目錄, 這本身就不便于我們進(jìn)行編寫維護(hù)更新(想想每次都跑到遠(yuǎn)程去編寫playbook或者每次在本地編寫好后再upload到遠(yuǎn)程我都會(huì)腦補(bǔ)數(shù)以萬(wàn)計(jì)的草泥馬從我眼前呼嘯而來(lái)).
這里Gitlab就給我們提供一個(gè)非常方便以及直觀的Playbook management. 我們需要做的其實(shí)就是在Gitlab去建立一個(gè)對(duì)應(yīng)產(chǎn)品或者server的playbook倉(cāng)庫(kù), 然后我們?cè)诒镜貙懞煤笾苯觕ommit到這個(gè)倉(cāng)庫(kù), 最后在部署的時(shí)候, 去讓Jenkins pull這個(gè)playbook到其workspace, 并作為一個(gè)Job去run這個(gè)playbook, 這樣是不是很規(guī)范, 而且便于管理?
當(dāng)然Ansible本身企業(yè)版Tower也會(huì)提供一個(gè)類似管理并維護(hù)playbook以及監(jiān)控ansible本身running process的GUI管理系統(tǒng), 用起來(lái)也很不錯(cuò), 但作為收費(fèi)版本, 我們?cè)谶@里就不做過多闡述了.
這里我推薦Jenkins和Ansible可以安裝到同一個(gè)環(huán)境作為部署server, Gitlab作為版本控制系統(tǒng)可單獨(dú)部署在另一臺(tái)server.
總結(jié):
Jenkins首先從Gitlab去抓取我們寫好的具體產(chǎn)品的playbook, 并使用virtualenv下的Ansible相關(guān)命令, 保證我們?cè)谝粋€(gè)clean的環(huán)境下使用stable version去批量部署我們的產(chǎn)品到遠(yuǎn)程client.
Let’s go…..
一. 安裝環(huán)境
System: CentOS 6.7 x64 (deploy.)
Jenkins: Jenkins ver. 1.650
Ansible: Ansible 2.1.0
Gitlab: GitLab 7.14.3
二. Jenkins配置
我們創(chuàng)建deploy用戶作為jenkins_user, workspace為deploy家目錄下的jenkins目錄.
# su – root
# adduser deploy
# wget -O /etc/yum.repos.d/jenkins.repo http://pkg./redhat/jenkins.repo
# rpm –import https:///redhat/.key
# yum install jenkins -y
# vi /etc/sysconfig/jenkins
...
JENKINS_HOME='/home/deploy/jenkins'
JENKINS_USER='deploy'
...
# service jenkins start
瀏覽器訪問Jenkins頁(yè)面
http://deploy.:8080
安裝完成, 以下是我已經(jīng)配置好的一些Jenkins Job.
這里我們使用一個(gè)國(guó)內(nèi)PHP網(wǎng)站模板phpcms作為我們需要部署的產(chǎn)品進(jìn)行本次范例演示, 在進(jìn)行最終的Build前我們需要做一些準(zhǔn)備工作, 稍后我們會(huì)回到這個(gè)界面.
三. Ansible配置
這里我們需要配置virtualenv去隔離我們ansible的發(fā)行版本為最新版本2.1.0, 默認(rèn)pip或者yum安裝的1.9版本因?yàn)锽UG以及對(duì)windows不兼容的原因, 這里不推薦使用.
配置步驟傳送門: http://www./archives/1862
Ansible-playbook范例傳送門: http://www./archives/1649
四. Gitlab配置
部署并使用傳送門: http://www./archives/1285
我們最終會(huì)創(chuàng)建一個(gè)ansible playbook倉(cāng)庫(kù) git@git.example.cn:showerlee/Ansible-showerlee.git, 并在本地編寫好我們的規(guī)則, 最終commit到這個(gè)倉(cāng)庫(kù), 以便Jenkins去調(diào)用我們的部署規(guī)則.
這里博主單獨(dú)clone出來(lái)一份部署phpcms的playbook倉(cāng)庫(kù), 算是給大家的福利:
https://git./showerlee/leon-playbook-phpcms1.1
五.最終部署
準(zhǔn)備工作完畢, 我們接下來(lái)給大家介紹Jenkins Job配置.
1.創(chuàng)建一個(gè)new item
2. 創(chuàng)建一個(gè)freestyle Job, 命名規(guī)則”產(chǎn)品名-環(huán)境”, 這里我們?yōu)镻hpcms-Dev
3. Job配置
1). 定制Build參數(shù).
這里Dynamic Choice Parameter用來(lái)通過Groovy腳本來(lái)抓取這個(gè)git倉(cāng)庫(kù)的所有branch, 并作為一個(gè)多選項(xiàng), 方便我們?cè)谧罱KBuild前去選擇我們需要的這個(gè)產(chǎn)品Branch分支.
Groovy抓取Git branch代碼:
def gettags = ('git ls-remote -h git@git.:showerlee/phpcms.git').execute()
gettags.text.readLines().collect { it.split()[1].replaceAll('refs/heads/', '') }.unique()
Choice Parameter也是用來(lái)給我們Job定制Build前的可選參數(shù), 不過這里的參數(shù)可以直接寫死
deploy_environment為我們的參數(shù)名, 定義我們的部署環(huán)境名, prod, qa為我們具體的可選項(xiàng), 定義我們產(chǎn)品的兩個(gè)環(huán)境.
2). 源代碼管理
我們可以利用Jenkins內(nèi)置的Source Code Management工具去抓取遠(yuǎn)程Git或者SVN倉(cāng)庫(kù)的代碼到本地, 這里我們抓取存放在我們Gitlab上的Playbook到Jenkins的workspace目錄, 用來(lái)進(jìn)行后續(xù)部署工作, 這個(gè)倉(cāng)庫(kù)如需認(rèn)證, 我們可以在Credentials add這個(gè)倉(cāng)庫(kù)的用戶賬號(hào)密碼, 其余均保持默認(rèn)即可(默認(rèn)Jenkins default不支持Git, 需要到其后臺(tái)安裝Git插件)
3). Execute shell進(jìn)行最終的CLI部署.
這個(gè)Build模塊下的Execute shell方法是Jenkins比較常用并非常核心的功能, 用來(lái)執(zhí)行我們部署過程中核心的命令.
開頭和結(jié)尾的set x, set -x用來(lái)打開和關(guān)閉該部分的擴(kuò)展參數(shù)及命令
開啟virtualenv和加載ansible環(huán)境變量
# source /home/deploy/.virtualenv/bin/activate
# . /home/deploy/.virtualenv/ansible/hacking/env-setup -q
進(jìn)入該Job的workspace目錄下保存該playbook的倉(cāng)庫(kù)子目錄下, 檢查ansible版本, 并執(zhí)行最終的部署命令.
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 用來(lái)自定義ansible host文件路徑, ./deploy.yml為ansible-playbook入口文件, -e 后可跟給當(dāng)前session添加的環(huán)境變量.
這里$deploy_environment $branch_selector 為該Job定義好的可選參數(shù), 詳見3-1)
配置完畢后, save保存.
4. 執(zhí)行Job.
選擇master分支和prod環(huán)境
查看該Job最終的console output, 也就是顯示我們實(shí)際在CLI下的輸出結(jié)果.
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 git@git.yanwenbo.cn:showerlee/Ansible-showerlee.git # timeout=10
Fetching upstream changes from git@git.yanwenbo.cn:showerlee/Ansible-showerlee.git
> git --version # timeout=10
> git fetch --tags --progress git@git.yanwenbo.cn: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 http://www.showerlee.com
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 http://www.',
'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 http://www.',
'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到遠(yuǎn)程Client.
|