Ansible Playbooks使用小记

407 阅读4分钟

前言

你好,我是言淦!本文承接之前的文章 《Ansible使用小记》

在前面的文章提到过,Ansible的Ad-HocPlaybooks就好比 shell命令shell脚本,下面我会通过部署一个Python项目来介绍Playbooks的用法。

准备一个Python项目

源码如下:

from flask import Flask

app = Flask(__name__)


@app.route('/')
def index():
    return 'Hello World'


if __name__ == '__main__':
    app.run(port=5000, debug=True)

完整内容参见:github.com/yangancode/…

Playbooks 编写

1.如果是简单的项目,一般一份YAML文件就能完成整个项目的部署,而如果是比较复杂的项目,或者是多个项目,建议使用Playbooks Roles 来实现,能够使我们的playbooks文件更具有层次性,更容易管理。

2.roles的机制就是分别将变量、文件、任务、模板及处理器放置于单独的目录中,并通过include关键字衔接起来的一种做法(将大模块拆分成小模块),一般在handlers、tasks、vars等目录都会有一份main.yml文件,ansible会自动装载并执行。

通过roles管理的项目,结构一般如下:

├── deploy.yml              # 主文件,入口文件
└── roles                   # 所有的角色都必须放在roles目录下,每个项目可以理解为一个角色
    └── python
        ├── files           # 此目录用来存放由copy模块或script模块调用的文件
        ├── handlers        # 此目录用于存放此角色中触发条件时执行的动作 (触发器)
        │   └── main.yml
        ├── tasks           # 此目录用于存放次角色的任务列表文件
        │   ├── flask.yml
        │   └── main.yml
        ├── templates       # 此目录用来存放jinjia2模板文件,比如supervisor配置文件
        └── vars            # 此目录用来存放一些用到的变量
            └── main.yml

下面以部署一个Flask项目为例,介绍每份playbook文件该如何填写,希望能帮助到大家(有用的话点个👍 哦)。

部署一个Flask项目大致有以下步骤:

  • 1.检查项目文件夹是否存在,不存在则创建
  • 2.检查supervisor是否安装,不存在则安装(使用supervisor管理进程)
  • 3.检查虚拟环境(virtualenv)是否存在,不存在则安装
  • 4.拷贝项目代码及安装Python依赖
  • 5.拷贝supervisor配置文件
  • 6.使用supervisor启动/重启服务

对应的yaml文件如下:

# deploy.yml
- hosts: "{{ host | default('osa-web-test') }}"
  serial: "{{ serial | default(10) }}"
  vars:
      version: "{{ git_version | default('master') }}"
  roles:
    - osa

# tasks/main.yml
- include: "{{ task }}.yml"

# var/main.yml
remote_srv: /home/yangan/services
local_srv: /home/ansible/flask_lab
virtualenv_path: /home/yangan/virtual_env

# handlers/main.yml
# 触发器,这里是触发supervisor重启服务
- name: update supervisor
  shell: supervisorctl update && supervisorctl restart {{ service_name }}


# tasks/flask.yml (本次的核心文件)
- name: check supervisor install
  stat:
    path: /etc/supervisor
  register: supervisor_stat
  tags:
    - deploy

- name: check remote service folder
  stat:
    path: "{{ remote_srv }}"
  register: remote_service_stat
  tags:
    - deploy
...

# templates/flask.conf (配置文件)
[program: {{ service_name }}]
; 实际命令视项目需要
command={{ virtualenv_path }}/{{ service_name }}/bin/python {{ remote_srv }}/{{service_name}}/main.py
environment=MILOG='format=json&tag_srv=1'
; /home/yangan/services/flask
directory={{ remote_srv }}/{{ service_name }}
autostart=true
autorestart=true
; 这是我自己创建的用户
user=yangan
umask=022
; /home/yangan/services/flask/flask.super.log
stdout_logfile={{ remote_srv }}/{{ service_name }}/{{ service_name }}.super.log
redirect_stderr=true


# Playbook Roles部署
$ ansible-playbook ansible_roles/deploy.yml --sudo --extra-vars 'task=flask service_name=flask'

部署成功后查看服务是否启动:

root@07f1e6b62e12:/home/yangan# supervisorctl
 flask                           RUNNING    pid 3445, uptime 0:01:24
supervisor>

其实整个项目看下来,你会发现原理其实不难,主要是Linux相关知识要比较熟练,唯一比较繁琐的是各种路径要匹配得上。另外,上面的代码其实还涉及到一个ansible标签 (tags),这也是一个比较好用的功能,通过使用不同的标签,你可以对任务进行排列,从而使任务可以得到最大限度的复用。

补充:sudo的配置
由于上面安装supervisor使用了 sudo指令,配置sudo的步骤如下:
1.首先确保远程机器用户(yangan)是sudo用户组的,保证其能执行sudo指令
2.在需要执行sudo的任务下添加sudo指令(也可以全局)

- apt: name=supervisor update_cache=yes
  when: supervisor_stat.stat.exists == False
  sudo: yes
  tags:
    - deploy

3.修改操作机 /etc/ansible/ansible.cfg 配置下的执行用户

poll_interval  = 15
sudo_user      = yangan

4.修改 /etc/ansible/hosts 的机器配置,加上密码

[webservers]
root@172.17.0.4     ansible_ssh_user=yangan   ansible_sudo_pass='yangan'

5.部署命令加上 --sudo

注:完整代码参见 github.com/yangancode/… (有帮助的话请点个star哦😯)

Playbooks指令介绍

在上面的例子用到的一些指令,在这里会做进一步说明和补充。

serial

一般情况下,如果是分布式项目,我们可能需要在几台机,甚至十几台机部署上面的项目,为了保证部署的稳定性,我们一般会采取滚动更新的做法,serial关键字就是帮我们干这件事的。

在下面例子中, 如果webservers包含四个主机,则后面两个主机会等前面两个主机执行完指令后再执行。


- name: test play
  hosts: webservers
  serial: 2
  tasks:
  - name: task one
    comand: hostname

另外,还可以将serial关键字指定为百分比,表示每次并行执行的主机数占总数的比例

- name: test play
  hosts: webservers
  serial: "30%"
  tasks:
  - name: task one
    comand: hostname

command VS shell

这是两个比较相似的指令,主要区别在于会不会使用Linux的 shell 程序执行指令。

对于 command 指令,它并不会使用shell程序执行命令. 因此,像$HOME这样的变量是不可用的。还有像<, >, |, ;, &等符号都是不可用的。

对于 shell 指令,顾名思义,它会通过shell程序执行命令, 默认是/bin/sh, 像<, >, |, ;, &这些符号都是可用的,但需要注意 shell注入的风险。

总体而言,command相比shell更安全,因为它不受用户环境的影响,很大程度避免了潜在的shell注入风险,如果你需要安全地使用 shell 模块,可以使用{{ var | quote }} 代替 {{ var }} ,确保输入不包含分号或者流式操作。

unarchive

该指令用于解压压缩包,支持tar.gz,zip等。如果需要将远程主机上的某个压缩包解压到指定路径下,需要设置copy=no;如果是将ansible主机上的压缩包在本地解压后传到远程主机上,需要设置copy=yes。

- name: test play
  hosts: webservers
  serial: 1
  tasks:
  - name: extract tar.gz
    unarchive: src=xxx.tar.gz dest=/tmp/xxx copy=no mode=0755

template

ansible template文件夹下一般存放一些模板文件,常见的有各种配置文件,如上文中的supervisor配置文件,模板文件采用的语法是jinjia2,jinjia2支持的语法有:字符串、整型、列表、元组、字典、加减乘除、if判断、for循环等。

看网上的文章都需要加 j2 后缀?

参考: www.cnblogs.com/qiuhom-1874…

apt

该指令用于安装一些包,不过只适用于操作系统是Ubuntu/debian的机器,执行的机器需要安装 python-apt 库。

blog.csdn.net/modoo_junko… blog.csdn.net/modoo_junko…

copy

blog.csdn.net/bruce_6/art…

Ansible Copy Module Fails: stackoverflow.com/questions/3…

cron

blog.csdn.net/dylloveyou/…

sudo

www.cnblogs.com/gdlinux/p/1…

只运行一次

stackoverflow.com/questions/2…

额外变量

www.jianshu.com/p/50d2bf6a5…

ansible远程执行的环境变量问题

www.jianshu.com/p/b5c4113b2… www.cnblogs.com/yanjieli/p/…

创作不易,有用的话请点个赞呗!

参考

ansible中serial用法
shell和command区别