小笙's Blog

使用ansible + git + cgi搭建部署系统2018.05.31 17:09

Ansible

ansible是个什么东西呢?官方的title是“Ansible is Simple IT Automation”——简单的自动化IT工具。这个工具的目标有这么几项:让我们自动化部署APP;自动化管理配置项;自动化的持续交付;自动化的(AWS)云服务管理,基于 paramiko 开发。

这个paramiko是什么呢?它是一个纯Python实现的ssh协议库。所以就不需要在远程主机上安装client/agents,因为它们是基于ssh来和远程主机通讯的。

安装

以centos为例

1
sudo yum install ansible

安装完成,配置文件默认在/etc/ansible/ansible.cfg

为了方便后续的开发,需要修改配置文件            

1
2
3
4
#失败后不在本地生成retry文件,终端也不输出
retry_files_enabled = False
#将执行过程及结果以json形式返回
stdout_callback = json

Inventory文件

Ansible 可同时操作属于一个组的多台主机,组和主机之间的关系通过 inventory 文件配置. 默认的文件路径为 /etc/ansible/hosts

除默认文件外,你还可以同时使用多个 inventory 文件,也可以从动态源,或云上拉取 inventory 配置信息.

以本次项目为例,我们需要从云端查询线上机器IP列表(例如:阿里云SLB下的具体ECS IP列表),最后以JSON格式返回

1
2
3
4
5
6
7
8
9
10
$ cat ./hosts.py
#!/usr/bin/python
import json
#为了演示方便,此处使用初始化好的ip文件
list_txt_file="/home/git/deploylist.txt"
f=open(list_txt_file, 'r')
ips={"hosts":[]}
for line in f.readlines():
       ips["hosts"].append(line.strip())
print json.dumps(ips)

给文件加上可执行权限

1
$ chmod +x ./hosts.py

执行查看输出

1
2
$ ./hosts.py
{"hosts": ["192.168.x.x", "..."]}

Playbooks

Playbooks 是 Ansible的配置,部署,编排语言.他们可以被描述为一个需要希望远程主机执行命令的方案,或者一组IT程序运行的命令集合.

如果 Ansible 模块你是工作室中的工具,那么 playbooks 就是你设置的方案计划.

Playbooks使用yaml文件管理ansible命令。

接下来可以编写我们的部署逻辑,检测项目根目录是否存在,不存在则创建,最后更新版本库代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
---
- hosts: all
 remote_user: git
 tasks:
   - name: check www
     stat: path="{{www_dir}}"
     register: www_stat
   - name: init www
     file:
         path: "{{www_dir}}"
         state: directory
         owner: git
         group: git
         recurse: yes
     when: not www_stat.stat.exists
   - name: update code
     git:
       repo: "{{repo}}"
       dest: "{{www_dir}}"
       accept_hostkey: yes
       version: "{{version}}"
       update: yes
       key_file: /home/git/.ssh/id_rsa
     become_user: git

此yaml会接收三个参数

www_dir: 部署目标路径

repo: Git版本库

version: Git版本号,可以使具体的版本号,也可以是分支或master

注意:此处git授权使用秘钥,所以git server需要预先设置好对git用户的认证(/home/git/.ssh/id_rsa),一般情况下,所有的线上机器都会使用同一个SSH秘钥,方便机器的SSH管理及GIT管理。

我们使用终端测试功能是否能正常运行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ ansible-playbook -i ./hosts.py ./deploy.yml  --extra-vars 'version=master&repo=git@gitlab.a.com:test.git&www_dir=/home/git/demo8'
{
   "plays": [
       {
           "play": {
               "id": "00163e0a-7e89-518c-8220-000000000008",
               "name": "all"
           },
           "tasks": [
               {
                   "hosts": {
                       ...
   ],
   "stats": {
       "192.168.x.x": {
           "changed": 3,
           "failures": 0,
           "ok": 0,
           "skipped": 0,
           "unreachable": 0
       }
   }
}

我们关注stats ok及failures数据即可。

CGI

接下来我们使用Apache cgi来搭建我们的WEB部署接口。

1
sudo yum install httpd

修改apache配置文件,以支持cgi运行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ vi /etc/httpd/conf/httpd.conf
Listen 8080
ScriptAlias /cgi/ "/home/git/httpd/cgi/"
<Directory "/home/git/httpd/cgi">
#    AllowOverride None
#Options None
       Options +ExecCGI
#    Order allow,deny
#    Allow from all
</Directory>
AddHandler cgi-script .cgi .py
LoadModule cgi_module modules/mod_cgi.so
LoadModule cgid_module modules/mod_cgid.so
DocumentRoot "/home/git/httpd"
<Directory "/home/git/httpd">
   Options Indexes FollowSymLinks
   AllowOverride None
   Order allow,deny
   Allow from all
</Directory>

启动并测试Apache运行是否正常,假设服务器内网IP为192.168.0.1

1
2
3
$ sudo apachectl start
< HTTP/1.1 200 OK

最后编写我们的cgi脚本,用来接收POST参数并调用本机的ansible-playbook部署代码并返回执行结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#!/usr/bin/python
#cgi文件必须要声明的mime类型
print "Content-Type:application/json; Charset=utf-8\n\n"
import cgi, cgitb, json, sys, commands, time, random
default_dir = '/home/git/www'
default_ver = 'HEAD'
error_log = '/home/git/logs/cgi/%s'
form = cgi.FieldStorage()
repo = form.getvalue('repo')
www_dir = form.getvalue('www_dir')
version = form.getvalue('version')
if not version: version = default_ver
if not www_dir: www_dir = default_dir
if not repo:
   print json.dumps({"err_code":400, "err_msg":"Bad Args"})
   sys.exit()
command="/usr/local/bin/ansible-playbook -i /home/git/ansible/hosts.py /home/git/ansible/deploy.yml  --extra-vars 'repo=%s www_dir=%s version=%s'"%(repo, www_dir, version)
status,deploy_ret = commands.getstatusoutput(command)
ret_json = json.loads(deploy_ret)
if not ret_json.has_key('stats'):
   print json.dumps({"err_code":500, "err_msg":"SysError", "err_trace":deploy_ret})
   sys.exit()
ret = {"success":{"list":[]}, "error":{"list":[], "debug":[]}}
err_count = 0
for ip in ret_json['stats']:
   is_error = ret_json['stats'][ip]['failures']
   if is_error:
       ret['error']['list'].append(ip)
       ret_json['stats'][ip]['ip'] = ip
       ret['error']['debug'].append(ret_json['stats'][ip])
       err_count = err_count+1
   else:
       ret['success']['list'].append(ip)
if err_count:
   error_file = error_log%( time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime()))
   fo = open(error_file, 'a+')
   fo.write(deploy_ret)
   fo.close()
print json.dumps(ret)

测试接口功能

1
2
$ curl -d 'version=master&repo=git@gitlab.a.com:test.git&www_dir=/home/git/demo8' 'http://192.168.0.1:8080/cgi/deploy.py'
{"success": {"list": ["192.168.x.x", "192.168.x.x", "xxx"]}, "error": {"debug": [], "list": []}}

接下来我们就可以在前端结合gitlab api以及我们的部署API,进行可视化展示、部署、回滚等操作,这里就不在赘述了。


  • 正在加载用户留言,请稍后~
点击这里取消回复

  • 请选择邮箱类型
  • @qq.com
  • @163.com
  • @sina.com
  • @126.com
  • @vip.qq.com
  • @sina.com.cn

:love: :kiss: :twist: :top: :shake: :bye: :han: :sleep: :lula: :rou: :happy: