ansible快速文档

ansible

what:ansible是基于python模块paramiko开发的自动化运维工具

why:实现了批量系统配置、批量程序部署、批量运行命令等功能

Ansible is Simple IT Automation

马哥ansible入门到精通及企业实战_哔哩哔哩_bilibili

运维自动化发展历程,运维职业发展路线 – 运维派 (yunweipai.com)

自动化运维工具——ansible详解(一) - 珂儿吖 - 博客园 (cnblogs.com)

自动化运维工具——ansible详解(二) - 珂儿吖 - 博客园 (cnblogs.com)


Ansible 发展史

作者:Michael DeHaan( Cobbler 与 Func 作者)

ansible 的名称来自科幻小说《安德的游戏》中跨越时空的即时通信工具,使用它可以在相距数光年的距离,远程实时控制前线的舰队战斗

2012-03-09,发布0.0.1版,2015-10-17,Red Hat宣布1.5亿美元收购

Ansible 特性

  • 模块化:调用特定的模块完成特定任务,支持自定义模块,可使用任何编程语言写模块
  • Paramiko(python对ssh的实现),PyYAML,Jinja2(模板语言)三个关键模块
  • 基于Python语言实现
  • 部署简单,基于python和SSH(默认已安装),agentless,无需代理不依赖PKI(无需ssl)
  • 安全,基于OpenSSH
  • 幂等性:一个任务执行1遍和执行n遍效果一样,不因重复执行带来意外情况
  • 支持playbook编排任务,YAML格式,编排任务,支持丰富的数据结构
  • 较强大的多层解决方案role

注意事项

  • 基于模块化工作,本身没有批量部署的能力。真正具有批量部署的是ansible所运行的模块,ansible只是提供一种框架
  • ansible不需要在远程主机上安装client/agents,因为它们是基于ssh来和远程主机通讯的
  • 执行ansible的主机一般称为主控端,中控,master或堡垒机
  • 主控端Python版本需要2.6或以上
  • 被控端Python版本小于2.4,需要安装python-simplejson
  • 被控端如开启SELinux需要安装libselinux-python
  • windows 不能做为主控端

Ansible 架构

组合INVENTORY、API、MODULES、PLUGINS的绿框,可以理解为是ansible命令工具,其为核心执行工具

  • INVENTORY:Ansible管理主机的清单/etc/anaible/hosts
  • MODULES:Ansible执行命令的功能模块,多数为内置核心模块,也可自定义
  • PLUGINS:模块功能的补充,如连接类型插件、循环插件、变量插件、过滤插件等,该功能不常用
  • API:供第三方程序调用的应用程序编程接口

Ansible命令执行过程

  1. 加载自己的配置文件,默认/etc/ansible/ansible.cfg
  2. 加载自己对应的模块文件,如:command
  3. 通过ansible将模块或命令生成对应的临时py文件,并将该文件传输至远程服务器的对应执行用户$HOME/.ansible/tmp/ansible-tmp-数字/XXX.PY文件
  4. 给文件+x执行权限
  5. 执行并返回结果
  6. 删除临时py文件,退出

1.ansible install

1.1使用yum安装

ansible在epel源

yum -y install epel-release
yum makecache
yum -y install ansible
安装的依赖:

Installing:
ansible noarch 2.9.24-2.el7 epel 17 M
Installing for dependencies:
python-babel noarch 0.9.6-8.el7 base 1.4 M
python-backports x86_64 1.0-8.el7 base 5.8 k
python-backports-ssl_match_hostname noarch 3.5.0.1-1.el7 base 13 k
python-cffi x86_64 1.6.0-5.el7 base 218 k
python-enum34 noarch 1.0.4-1.el7 base 52 k
python-idna noarch 2.4-1.el7 base 94 k
python-ipaddress noarch 1.0.16-2.el7 base 34 k
python-jinja2 noarch 2.7.2-4.el7 base 519 k
python-markupsafe x86_64 0.11-10.el7 base 25 k
python-paramiko noarch 2.1.1-9.el7 base 269 k
python-ply noarch 3.4-11.el7 base 123 k
python-pycparser noarch 2.14-1.el7 base 104 k
python-setuptools noarch 0.9.8-7.el7 base 397 k
python2-cryptography x86_64 1.7.2-2.el7 base 502 k
python2-httplib2 noarch 0.18.1-3.el7 epel 125 k
python2-jmespath noarch 0.9.4-2.el7 epel 41 k
python2-pyasn1 noarch 0.1.9-7.el7 base 100 k
sshpass x86_64 1.06-2.el7 extras 21 k

##

2.免密认证

ssh免密码认证 - omgasw - 博客园 (cnblogs.com)

3.配置文件

3.1./etc/ansible/ansible.cfg

ansible的主配置文件,其中大部分配置内容无需修改

[defaults]

# some basic default values...

#inventory      = /etc/ansible/hosts        ## 主机列表配置文件
#library        = /usr/share/my_modules/        ## 库文件存放目录
#module_utils   = /usr/share/my_module_utils/
#remote_tmp     = ~/.ansible/tmp        ## 临时python命令文件存放在远程主机目录
#local_tmp      = ~/.ansible/tmp        ## 本机的临时命令执行目录
#forks          = 5        ## 默认并发数
#sudo_user      = root        ## 默认sudo用户
#ask_sudo_pass = True        ##每次执行ansible命令是否询问ssh密码
#ask_pass      = True    
#remote_port    = 22

#host_key_checking = False        ## 检查对应服务器的host_key,建议取消注释
#log_path = /var/log/ansible.log        ## 日志文件,建议启用
#module_name = command        ## 默认模块,可以修改为shell模块

3.2./etc/ansible/hosts

主机清单,可以进行分组

# Ex 1: Ungrouped hosts, specify before any group headers.

## green.example.com
## blue.example.com
## 192.168.100.1
## 192.168.100.10

# Ex 2: A collection of hosts belonging to the 'webservers' group

## [webservers]
## alpha.example.org
## beta.example.org
## 192.168.1.100
## 192.168.1.110

# If you have multiple hosts following a pattern you can specify
# them like this:

## www[001:006].example.com

# Ex 3: A collection of database servers in the 'dbservers' group

## [dbservers]
## 
## db01.intranet.mydomain.net
## db02.intranet.mydomain.net
## 10.25.1.56
## 10.25.1.57

3.3./etc/ansible/roles

用于默认存放roles的文件夹

[root@ansible01 ~]# ansible-galaxy list
# /root/.ansible/roles
# /usr/share/ansible/roles
# /etc/ansible/roles

4.ansible模块

command

默认模块,不支持管道通配等符号

shell

可以修改为默认模块

[root@ansible01 ~]# ansible test -m shell -a 'df -Th'
10.1.10.72 | CHANGED | rc=0 >>
Filesystem              Type      Size  Used Avail Use% Mounted on
devtmpfs                devtmpfs  979M     0  979M   0% /dev
tmpfs                   tmpfs     991M     0  991M   0% /dev/shm
tmpfs                   tmpfs     991M  9.5M  981M   1% /run
tmpfs                   tmpfs     991M     0  991M   0% /sys/fs/cgroup
/dev/mapper/centos-root xfs        25G  1.8G   24G   8% /
/dev/mapper/centos-var  xfs        50G  555M   50G   2% /var
/dev/mapper/centos-home xfs        10G   33M   10G   1% /home
/dev/sda1               xfs       5.0G  196M  4.8G   4% /boot
tmpfs                   tmpfs     199M     0  199M   0% /run/user/0

ping

[root@ansible01 ~]# ansible 10.1.10.72 -m ping
10.1.10.72 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}
[root@ansible01 ~]# ansible all -m ping
10.1.10.72 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}

script

[root@ansible01 ~]# ansible test -m script -a /root/df.sh
10.1.10.72 | CHANGED => {
    "changed": true, 
    "rc": 0, 
    "stderr": "Shared connection to 10.1.10.72 closed.\r\n", 
    "stderr_lines": [
        "Shared connection to 10.1.10.72 closed."
    ], 
    "stdout": "Filesystem              Type      Size  Used Avail Use% Mounted on\r\ndevtmpfs                devtmpfs  979M     0  979M   0% /dev\r\ntmpfs                   tmpfs     991M     0  991M   0% /dev/shm\r\ntmpfs                   tmpfs     991M  9.5M  981M   1% /run\r\ntmpfs                   tmpfs     991M     0  991M   0% /sys/fs/cgroup\r\n/dev/mapper/centos-root xfs        25G  1.8G   24G   8% /\r\n/dev/mapper/centos-var  xfs        50G  555M   50G   2% /var\r\n/dev/mapper/centos-home xfs        10G   33M   10G   1% /home\r\n/dev/sda1               xfs       5.0G  196M  4.8G   4% /boot\r\ntmpfs                   tmpfs     199M     0  199M   0% /run/user/0\r\n", 
    "stdout_lines": [
        "Filesystem              Type      Size  Used Avail Use% Mounted on", 
        "devtmpfs                devtmpfs  979M     0  979M   0% /dev", 
        "tmpfs                   tmpfs     991M     0  991M   0% /dev/shm", 
        "tmpfs                   tmpfs     991M  9.5M  981M   1% /run", 
        "tmpfs                   tmpfs     991M     0  991M   0% /sys/fs/cgroup", 
        "/dev/mapper/centos-root xfs        25G  1.8G   24G   8% /", 
        "/dev/mapper/centos-var  xfs        50G  555M   50G   2% /var", 
        "/dev/mapper/centos-home xfs        10G   33M   10G   1% /home", 
        "/dev/sda1               xfs       5.0G  196M  4.8G   4% /boot", 
        "tmpfs                   tmpfs     199M     0  199M   0% /run/user/0"
    ]
}

copy

#如目标存在,默认覆盖,此处指定先备份
ansible websrvs -m copy -a “src=/root/test1.sh dest=/tmp/test2.sh    owner=wang  mode=600 backup=yes” 
#指定内容,直接生成目标文件    
ansible websrvs -m copy -a "content='test line1\ntest line2' dest=/tmp/test.txt"
#复制/etc/下的文件,不包括/etc/目录自身
ansible websrvs -m copy -a “src=/etc/ dest=/backup”

fetch

从远程主机提取文件至ansible的主控端,copy相反,目前不支持目录

[root@ansible ~]#ansible   all -m  fetch -a 'src=/etc/redhat-release dest=/data/os'
[root@ansible ~]#tree /data/os/
/data/os/
├── 10.0.0.6
│   └── etc
│       └── redhat-release
├── 10.0.0.7
│   └── etc
│       └── redhat-release
└── 10.0.0.8
    └── etc
        └── redhat-release

file

#创建空文件
ansible all -m  file  -a 'path=/data/test.txt state=touch'
ansible all -m  file  -a 'path=/data/test.txt state=absent'
ansible all -m file -a "path=/root/test.sh owner=wang mode=755“
#创建目录
ansible all -m file -a "path=/data/mysql state=directory owner=mysql group=mysql"
#创建软链接
ansible all -m file -a ‘src=/data/testfile  dest=/data/testfile-link state=link’

archive

打包压缩

ansible websrvs -m archive  -a 'path=/var/log/ dest=/data/log.tar.bz2 format=bz2  owner=wang mode=0600'

unarchive

解包解压缩

1、将ansible主机上的压缩包传到远程主机后解压缩至特定目录,设置copy=yes

2、将远程主机上的某个压缩包解压缩到指定路径下,设置copy=no

常见参数:

copy:默认为yes,当copy=yes,拷贝的文件是从ansible主机复制到远程主机上,如果设置为copy=no,会在远程主机上寻找src源文件

remote_src:和copy功能一样且互斥,yes表示在远程主机,不在ansible主机,no表示文件在ansible主机上

src:源路径,可以是ansible主机上的路径,也可以是远程主机上的路径,如果是远程主机上的路径,则需要设置copy=no

dest:远程主机上的目标路径

mode:设置解压缩后的文件权限

ansible all -m unarchive -a 'src=/data/foo.tgz dest=/var/lib/foo'
ansible all -m unarchive -a 'src=/tmp/foo.zip dest=/data copy=no mode=0777'
ansible all -m unarchive -a 'src=https://example.com/example.zip dest=/data copy=no'

hostname

ansible node1 -m hostname -a “name=websrv” 
ansible 192.168.100.18 -m hostname -a 'name=node18.magedu.com'

cron

#备份数据库脚本
[root@centos8 ~]#cat mysql_backup.sh 
mysqldump -A -F --single-transaction --master-data=2 -q -uroot |gzip > /data/mysql_date +%F_%T.sql.gz
#创建任务
ansible 10.0.0.8 -m cron -a 'hour=2 minute=30 weekday=1-5 name="backup mysql" job=/root/mysql_backup.sh'
ansible websrvs   -m cron -a "minute=*/5 job='/usr/sbin/ntpdate 172.20.0.1 &>/dev/null' name=Synctime"
#禁用计划任务
ansible websrvs   -m cron -a "minute=*/5 job='/usr/sbin/ntpdate 172.20.0.1 &>/dev/null' name=Synctime disabled=yes"
#启用计划任务
ansible websrvs   -m cron -a "minute=*/5 job='/usr/sbin/ntpdate 172.20.0.1 &>/dev/null' name=Synctime disabled=no"
#删除任务
ansible websrvs -m cron -a "name='backup mysql' state=absent"
ansible websrvs -m cron -a 'state=absent name=Synctime'

yum

ansible websrvs -m yum -a ‘name=httpd state=present’  #安装
ansible websrvs -m yum -a ‘name=httpd state=absent’  #删除

service

ansible all -m service -a 'name=httpd state=started enabled=yes'
ansible all -m service -a 'name=httpd state=stopped'
ansible all -m service -a 'name=httpd state=reloaded’
ansible all -m shell -a "sed -i 's/^Listen 80/Listen 8080/' /etc/httpd/conf/httpd.conf"
ansible all -m service -a 'name=httpd state=restarted' 

user

#创建用户
ansible all -m user -a 'name=user1 comment=“test user” uid=2048 home=/app/user1 group=root'
ansible all -m user -a 'name=nginx comment=nginx uid=88 group=nginx groups="root,daemon" shell=/sbin/nologin system=yes create_home=no  home=/data/nginx non_unique=yes'
#删除用户及家目录等数据
ansible all -m user -a 'name=nginx state=absent remove=yes'

group

#创建组
ansible websrvs -m group  -a 'name=nginx gid=88 system=yes'
#删除组
ansible websrvs -m group  -a 'name=nginx state=absent'

lineinfile

ansible在使用sed进行替换时,经常会遇到需要转义的问题,而且ansible在遇到特殊符号进行替换时,存在问题,无法正常进行替换 。其实在ansible自身提供了两个模块:lineinfile模块和replace模块,可以方便的进行替换

功能:相当于sed,可以修改文件内容

ansible all -m   lineinfile -a "path=/etc/selinux/config regexp='^SELINUX=' line='SELINUX=enforcing'"
ansible all -m lineinfile  -a 'dest=/etc/fstab state=absent regexp="^#"'

replace

该模块有点类似于sed命令,主要也是基于正则进行匹配和替换

ansible all -m replace -a "path=/etc/fstab regexp='^(UUID.*)' replace='#\1'"  
ansible all -m replace -a "path=/etc/fstab regexp='^#(.*)' replace='\1'"

setup

功能: setup 模块来收集主机的系统信息,这些 facts 信息可以直接以变量的形式使用,但是如果主机较多,会影响执行速度

可以使用 gather_facts: no 来禁止 Ansible 收集 facts 信息

[root@ansible01 ~]# ansible test  -m setup
10.1.10.72 | SUCCESS => {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "10.1.10.72"
        ], 
[root@ansible01 ~]# ansible test  -m setup -a 'filter=ansible_all_ipv4_addresses'
10.1.10.72 | SUCCESS => {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "10.1.10.72"
        ], 
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false
}

##

Ansible常用模块详解 – 运维派 (yunweipai.com)

Ansible常用模块介绍_pushiqiang的博客-CSDN博客_ansible模块介绍

ansible 常用模块 - 一只宅男的自我修养 - 博客园 (cnblogs.com)

5.playbook

5.1.yaml语言

The Official YAML Web Site

YAML是一种可读性高的,用来表达资料序列的格式

三种常见的数据格式

  • XML:Extensible Markup Language,可扩展标记语言,可用于数据交换和配置

  • JSON:JavaScript Object Notation, JavaScript 对象表记法,主要用来数据交换或配置,不支持注释

  • YAML:YAML Ain’t Markup Language YAML 不是一种标记语言, 主要用来配置,大小写敏感,不支持tab

可以用工具互相转换,参考网站:

https://www.json2yaml.com/

http://www.bejson.com/json/json2yaml/

ansible-vault

用于加密yml文件

ansible-vault [create|decrypt|edit|encrypt|rekey|view]
ansible-vault encrypt hello.yml     #加密
ansible-vault decrypt hello.yml     #解密
ansible-vault view hello.yml        #查看
ansible-vault edit  hello.yml       #编辑加密文件
ansible-vault rekey  hello.yml      #修改口令
ansible-vault create new.yml        #创建新文件

5.1.1.YAML语法

  • 在单一文件第一行,用连续三个连字号“-” 开始,还有选择性的连续三个点号( … )用来表示文件的结尾

  • 次行开始正常写Playbook的内容,一般建议写明该Playbook的功能

  • 使用#号注释代码

  • 缩进必须是统一的,不能空格和tab混用

  • 缩进的级别也必须是一致的,同样的缩进代表同样的级别,程序判别配置的级别是通过缩进结合换行来实现的

    YAML文件内容是区别大小写的,key/value的值均需大小写敏感

  • 多个key/value可同行写也可换行写,同行使用,分隔

  • v可是个字符串,也可是另一个列表

  • 一个完整的代码块功能需最少元素需包括 name 和 task

  • 一个name只能包括一个task

  • YAML文件扩展名通常为yml或yaml

YAML的语法和其他高阶语言类似,并且可以简单表达清单、散列表、标量等数据结构。其结构(Structure)通过空格来展示,序列(Sequence)里的项用"-"来代表,Map里的键值对用":"分隔

5.1.2.list

列表由多个元素组成,每个元素放在不同行,且元素前均使用“-”打头,或者将所有元素用 [ ] 括起来放在同一行

# A list of tasty fruits
- Apple
- Orange
- Strawberry
- Mango

[Apple,Orange,Strawberry,Mango]

5.1.3.Dictionary字典

字典由多个key与value构成,key和value之间用 :分隔,所有k/v可以放在一行,或者每个 k/v 分别放在不同行

# An employee record
name: Example Developer
job: Developer
skill: Elite
也可以将key:value放置于{}中进行表示,用,分隔多个key:value

# An employee record
{name: “Example Developer”, job: “Developer”, skill: “Elite”}

或

name: John Smith
age: 41
gender: Male
spouse:
  name: Jane Smith
  age: 37
  gender: Female
children:
  - name: Jimmy Smith
    age: 17
    gender: Male
  - name: Jenny Smith
    age 13
    gender: Female

5.2.核心元素

  • Hosts 执行的远程主机列表

  • Tasks 任务集

  • Variables 内置变量或自定义变量在playbook中调用

  • Templates 模板,可替换模板文件中的变量并实现一些简单逻辑的文件

  • Handlers 和 notify 结合使用,由特定条件触发的操作,满足条件方才执行,否则不执行

  • tags 标签 指定某条任务执行,用于选择运行playbook中的部分代码。ansible具有幂等性,因此会自动跳过没有变化的部分,即便如此,有些代码为测试其确实没有发生变化的时间依然会非常地长。此时,如果确信其没有变化,就可以通过tags跳过此些代码片断

5.2.1.hosts

Hosts:playbook中的每一个play的目的都是为了让特定主机以某个指定的用户身份执行任务。hosts用于指定要执行指定任务的主机,须事先定义在主机清单中

one.example.com
one.example.com:two.example.com
192.168.1.50
192.168.1.*
Websrvs:dbsrvs      #或者,两个组的并集
Websrvs:&dbsrvs     #与,两个组的交集
webservers:!phoenix  #在websrvs组,但不在dbsrvs组

举例:
- hosts: websrvs:appsrvs

5.2.2.remote_user

remote_user: 可用于Host和task中。也可以通过指定其通过sudo的方式在远程主机上执行任务,其可用于play全局或某任务;此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户

- hosts: websrvs
  remote_user: root

  tasks:
    - name: test connection
      ping:
      remote_user: magedu
      sudo: yes                 #默认sudo为root
      sudo_user:wang        #sudo为wang

5.2.3.task列表

play的主体部分是task list,task list中有一个或多个task,各个task 按次序逐个在hosts中指定的所有主机上执行,即在所有主机上完成第一个task后,再开始第二个task

task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行是幂等的,这意味着多次执行是安全的,因为其结果均一致

每个task都应该有其name,用于playbook的执行结果输出,建议其内容能清晰地描述任务执行步骤。如果未提供name,则action的结果将用于输出

task两种格式:

(1) action: module arguments

(2) module: arguments 建议使用

注意:shell和command模块后面跟命令,而非key=value

---
- hosts: websrvs
  remote_user: root
  tasks:
    - name: install httpd
      yum: name=httpd 
    - name: start httpd
      service: name=httpd state=started enabled=yes

5.2.4.notify和handlers

某任务的状态在运行后为changed时,可通过'notify'通知给相应的'handlers'

- name: template configuration file
  template: src=template.j2 dest=/etc/foo.conf
  notify:
     - restart memcached
     - restart apache

handlers:
    - name: restart memcached
      service:  name=memcached state=restarted
    - name: restart apache
      service: name=apache state=restarted

5.2.5.tags

任务可以通过'tags'打标签,可在ansible-playbook命令上使用 -t 指定进行调用

---
- hosts: test70
  remote_user: root
  tasks:
  - name: task1
    file:
      path: /testdir/t1
      state: touch
    tags: t1
  - name: task2
    file: path=/testdir/t2
          state=touch
    tags: t2
  - name: task3
    file: path=/testdir/t3
          state=touch
    tags: t3

5.3.变量

变量名:仅能由字母、数字和下划线组成,且只能以字母开头

变量定义:

variable=value

范例:

http_port=80

变量调用方式:

通过{{ variable_name }} 调用变量,且变量名前后建议加空格,有时用“{{ variable_name }}”才生效

变量来源:

5.3.1.ansible 的 setup facts 远程主机的所有变量都可直接调用

---
#var.yml
- hosts: all
  remote_user: root
  gather_facts: yes

  tasks:
    - name: create log file
      file: name=/data/{{ ansible_nodename }}.log state=touch owner=wang mode=600

ansible-playbook  var.yml

5.3.2.通过命令行指定变量,优先级最高

vim var2.yml
---
- hosts: websrvs
  remote_user: root
  tasks:
    - name: install package
      yum: name={{ pkname }} state=present

ansible-playbook  –e pkname=httpd  var2.yml

5.3.3.在playbook文件中定义

vim var3.yml
---
- hosts: websrvs
  remote_user: root
  vars:
    - username: user1
    - groupname: group1

  tasks:
    - name: create group
      group: name={{ groupname }} state=present
    - name: create user
      user: name={{ username }} group={{ groupname }} state=present

ansible-playbook -e "username=user2 groupname=group2”  var3.yml

5.3.4.在独立的变量YAML文件中定义

可以在一个独立的playbook文件中定义变量,在另一个playbook文件中引用变量文件中的变量,比playbook中定义的变量优化级高

cat  vars2.yml
---
var1: httpd
var2: nginx

cat  var5.yml
---         
- hosts: web
  remote_user: root
  vars_files:
    - vars2.yml

   tasks:
     - name: create httpd log
       file: name=/app/{{ var1 }}.log state=touch
     - name: create nginx log
       file: name=/app/{{ var2 }}.log state=touch

5.3.5.主机清单文件中定义变量

主机变量

在inventory 主机清单文件中为指定的主机定义变量以便于在playbook中使用

[websrvs]
www1.magedu.com http_port=80 maxRequestsPerChild=808
www2.magedu.com http_port=8080 maxRequestsPerChild=909

组(公共)变量

在inventory 主机清单文件中赋予给指定组内所有主机上的在playbook中可用的变量,如果和主机变是同名,优先级低于主机变量

[websrvs]
www1.magedu.com
www2.magedu.com

[websrvs:vars]
ntp_server=ntp.magedu.com
nfs_server=nfs.magedu.com

调用

vim /etc/ansible/hosts

[websrvs]
192.168.0.101 hname=www1 domain=magedu.io
192.168.0.102 hname=www2 

[websvrs:vars]
mark=“-”
domain=magedu.org

ansible  websvrs  –m hostname –a ‘name={{ hname }}{{ mark }}{{ domain }}’
bash
#命令行指定变量: 
ansible  websvrs  –e domain=magedu.cn –m hostname –a    ‘name={{ hname }}{{ mark }}{{ domain }}’

5.4.when

when语句,可以实现条件测试。如果需要根据变量、facts或此前任务的执行结果来做为某task执行与否的前提时要用到条件测试,通过在task后添加when子句即可使用条件测试,jinja2的语法格式

---
- hosts: websrvs
  remote_user: root
  tasks:
    - name: "shutdown RedHat flavored systems"
      command: /sbin/shutdown -h now
      when: ansible_os_family == "RedHat"
---
- hosts: websrvs
  remote_user: root
  tasks: 
    - name: install conf file to centos7
      template: src=nginx.conf.c7.j2 dest=/etc/nginx/nginx.conf
      when: ansible_distribution_major_version == "7"
    - name: install conf file to centos6
      template: src=nginx.conf.c6.j2 dest=/etc/nginx/nginx.conf
      when: ansible_distribution_major_version == "6"
---
- hosts: websrvs
  remote_user: root
  tasks:
    - name: add group nginx
      tags: user
      user: name=nginx state=present
    - name: add user nginx
      user: name=nginx state=present group=nginx
    - name: Install Nginx
      yum: name=nginx state=present
    - name: restart Nginx
      service: name=nginx state=restarted
      when: ansible_distribution_major_version == “6

5.5.with_items

迭代:当有需要重复性执行的任务时,可以使用迭代机制

对迭代项的引用,固定变量名为"item"

要在task中使用with_items给定要迭代的元素列表

列表元素格式:

字符串

字典

---
- hosts: websrvs
  remote_user: root

  tasks:
    - name: add several users
      user: name={{ item }} state=present groups=wheel
      with_items:
        - testuser1
        - testuser2
#上面语句的功能等同于下面的语句
    - name: add user testuser1
      user: name=testuser1 state=present groups=wheel
    - name: add user testuser2
      user: name=testuser2 state=present groups=wheel
---
#remove mariadb server
- hosts: appsrvs:!192.168.38.8
  remote_user: root

  tasks:
    - name: stop service
      shell: /etc/init.d/mysqld stop
    - name:  delete files and dir
      file: path={{item}} state=absent
      with_items:
        - /usr/local/mysql
        - /usr/local/mariadb-10.2.27-linux-x86_64
        - /etc/init.d/mysqld
        - /etc/profile.d/mysql.sh
        - /etc/my.cnf
        - /data/mysql
    - name: delete user
      user: name=mysql state=absent remove=yes 
---
- hosts:websrvs
  remote_user: root

  tasks
    - name: install some packages
      yum: name={{ item }} state=present
      with_items:
        - nginx
        - memcached
        - php-fpm 
---
- hosts: websrvs
  remote_user: root
  tasks:
    - name: copy file
      copy: src={{ item }} dest=/tmp/{{ item }}
      with_items:
        - file1
        - file2
        - file3
    - name: yum install httpd
      yum: name={{ item }}  state=present 
      with_items:
        - apr
        - apr-util
        - httpd

迭代嵌套子变量:

在迭代中,还可以嵌套子变量,关联多个变量在一起使用

---
- hosts: websrvs
  remote_user: root

  tasks:
    - name: add some groups
      group: name={{ item }} state=present
      with_items:
        - nginx
        - mysql
        - apache
    - name: add some users
      user: name={{ item.name }} group={{ item.group }} state=present
      with_items:
        - { name: 'nginx', group: 'nginx' }
        - { name: 'mysql', group: 'mysql' }
        - { name: 'apache', group: 'apache' }
---
- hosts: websrvs
  remote_user: root

  tasks:
    - name: add some groups
      group: name={{ item }} state=present
      with_items:
        - g1
        - g2
        - g3
    - name: add some users
      user: name={{ item.name }} group={{ item.group }} home={{ item.home }} create_home=yes state=present
      with_items:
        - { name: 'user1', group: 'g1', home: '/data/user1' }
        - { name: 'user2', group: 'g2', home: '/data/user2' }
        - { name: 'user3', group: 'g3', home: '/data/user3' }

5.6.template

模板是一个文本文件,可以做为生成文件的模版,并且模板文件中还可嵌套jinja语法

5.4.1.jinjia2语言

jinja2 语言使用字面量,有下面形式:
字符串:使用单引号或双引号
数字:整数,浮点数
列表:[item1, item2, …]
元组:(item1, item2, …)
字典:{key1:value1, key2:value2, …}
布尔型:true/false
算术运算:+, -, *, /, //, %, **
比较操作:==, !=, >, >=, <, <=
逻辑运算:and,or,not
流表达式:For,If,When

字面量:

表达式最简单的形式就是字面量。字面量表示诸如字符串和数值的 Python 对象。如“Hello World”
双引号或单引号中间的一切都是字符串。无论何时你需要在模板中使用一个字符串(比如函数调用、过滤器或只是包含或继承一个模板的参数),如42,42.23
数值可以为整数和浮点数。如果有小数点,则为浮点数,否则为整数。在 Python 里, 42 和 42.0 是不一样的

算术运算:

Jinja 允许用计算值。支持下面的运算符
+:把两个对象加到一起。通常对象是素质,但是如果两者是字符串或列表,你可以用这 种方式来衔接它们。无论如何这不是首选的连接字符串的方式!连接字符串见 ~ 运算符。 {{ 1 + 1 }} 等于 2
-:用第一个数减去第二个数。 {{ 3 – 2 }} 等于 1
/:对两个数做除法。返回值会是一个浮点数。 {{ 1 / 2 }} 等于 {{ 0.5 }}
//:对两个数做除法,返回整数商。 {{ 20 // 7 }} 等于 2
%:计算整数除法的余数。 {{ 11 % 7 }} 等于 4
:用右边的数乘左边的操作数。 {{ 2 2 }} 会返回 4 。也可以用于重 复一个字符串多次。 {{ ‘=’ 80 }} 会打印 80 个等号的横条\
*:取左操作数的右操作数次幂。 {{ 2**3 }} 会返回 8

比较操作符
== 比较两个对象是否相等
!= 比较两个对象是否不等

如果左边大于右边,返回 true
= 如果左边大于等于右边,返回 true
< 如果左边小于右边,返回 true
<= 如果左边小于等于右边,返回 true

逻辑运算符
对于 if 语句,在 for 过滤或 if 表达式中,它可以用于联合多个表达式
and 如果左操作数和右操作数同为真,返回 true
or 如果左操作数和右操作数有一个为真,返回 true
not 对一个表达式取反
(expr)表达式组
true / false true 永远是 true ,而 false 始终是 false

##

5.4.2.template使用

template功能:可以根据和参考模块文件,动态生成相类似的配置文件

template文件必须存放于templates目录下,且命名为 .j2 结尾

yaml/yml 文件需和templates目录平级,目录结构如下示例:
./
├── temnginx.yml
└── templates
└── nginx.conf.j2

#修改文件nginx.conf.j2 
mkdir templates
vim templates/nginx.conf.j2
worker_processes {{ ansible_processor_vcpus }};

vim temnginx2.yml
---
- hosts: websrvs
  remote_user: root

  tasks:
    - name: install nginx
      yum: name=nginx
    - name: template config to remote hosts
      template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf 
    - name: start service
      service: name=nginx state=started enable=yes

ansible-playbook temnginx2.yml

5.4.3.算术运算

[root@ansible ansible]#vim templates/nginx.conf.j2
worker_processes {{ ansible_processor_vcpus**3 }};

[root@ansible ansible]#cat templnginx.yml
---
- hosts: websrvs
  remote_user: root

  tasks:
    - name: install nginx
      yum: name=nginx
    - name: template config to remote hosts
      template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
      notify: restart nginx
    - name: start service
      service: name=nginx state=started enabled=yes

  handlers:
    - name: restart nginx
      service: name=nginx state=restarted

ansible-playbook  templnginx.yml --limit 10.0.0.8

5.4.4.template中使用流程控制 for 和 if

template中也可以使用流程控制 for 循环和 if 条件判断,实现动态生成文件功能

## for

#temlnginx2.yml
---
- hosts: websrvs
  remote_user: root
  vars:
    nginx_vhosts:
      - 81
      - 82
      - 83
  tasks:
    - name: template config
      template: src=nginx.conf.j2 dest=/data/nginx.conf

#templates/nginx.conf2.j2
{% for vhost in  nginx_vhosts %}
server {
   listen {{ vhost }}
}
{% endfor %}

ansible-playbook -C  templnginx2.yml  --limit 10.0.0.8

#生成的结果:
server {
   listen 81   
}
server {
   listen 82   
}
server {
   listen 83   
}
#temlnginx3.yml
---
- hosts: websrvs
  remote_user: root
  vars:
    nginx_vhosts:
      - listen: 8080
  tasks:
    - name: config file
      template: src=nginx.conf3.j2 dest=/data/nginx3.conf

#templates/nginx.conf3.j2
{% for vhost in nginx_vhosts %}   
server {
  listen {{ vhost.listen }}
}
{% endfor %}

ansible-playbook   templnginx3.yml  --limit 10.0.0.8

#生成的结果
server {
  listen 8080  
}
#templnginx4.yml
- hosts: websrvs
  remote_user: root
  vars:
    nginx_vhosts:
      - listen: 8080
        server_name: "web1.magedu.com"
        root: "/var/www/nginx/web1/"
      - listen: 8081
        server_name: "web2.magedu.com"
        root: "/var/www/nginx/web2/"
      - {listen: 8082, server_name: "web3.magedu.com", root: "/var/www/nginx/web3/"}
  tasks:
    - name: template config 
      template: src=nginx.conf4.j2 dest=/data/nginx4.conf

# templates/nginx.conf4.j2
{% for vhost in nginx_vhosts %}
server {
   listen {{ vhost.listen }}
   server_name {{ vhost.server_name }}
   root {{ vhost.root }}  
}
{% endfor %}

ansible-playbook  templnginx4.yml --limit 10.0.0.8

#生成结果:
server {
    listen 8080
    server_name web1.magedu.com
    root /var/www/nginx/web1/  
}
server {
    listen 8081
    server_name web2.magedu.com
    root /var/www/nginx/web2/  
}
server {
    listen 8082
    server_name web3.magedu.com
    root /var/www/nginx/web3/  
} 

在模版文件中还可以使用 if条件判断,决定是否生成相关的配置信息

## if

#templnginx5.yml
- hosts: websrvs
  remote_user: root
  vars:
    nginx_vhosts:
      - web1:
        listen: 8080
        root: "/var/www/nginx/web1/"
      - web2:
        listen: 8080
        server_name: "web2.magedu.com"
        root: "/var/www/nginx/web2/"
      - web3:
        listen: 8080
        server_name: "web3.magedu.com"
        root: "/var/www/nginx/web3/"
  tasks:
    - name: template config to 
      template: src=nginx.conf5.j2 dest=/data/nginx5.conf

#templates/nginx.conf5.j2
{% for vhost in  nginx_vhosts %}
server {
   listen {{ vhost.listen }}
   {% if vhost.server_name is defined %}
server_name {{ vhost.server_name }}
   {% endif %}
root  {{ vhost.root }}
}
{% endfor %}

#生成的结果
server {
   listen 8080
   root  /var/www/nginx/web1/
}
server {
   listen 8080
   server_name web2.magedu.com
   root  /var/www/nginx/web2/
}
server {
   listen 8080
   server_name web3.magedu.com
   root  /var/www/nginx/web3/
}

6.roles

6.1.使用ansible-galaxy下载共享的roles和collection

Ansible Galaxy

ansible-galaxy — Ansible Documentation

ansible-galaxy list
ansible-galaxy install geerlingguy.redis
ansible-galaxy remove geerlingguy.redis
[root@ansible01 ~]# ansible-galaxy collection install community.postgresql
Process install dependency map
Starting collection install process
Installing 'community.postgresql:1.4.0' to '/root/.ansible/collections/ansible_collections/community/postgresql'

6.2.roles目录结构

playbook.yml
roles/
project/    ## 项目名称,有以下子目录
tasks/        ## 定义task,role的基本元素,至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含
files/        ## 存放由copy或script模块等调用的文件
vars/        ## 定义变量,至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含
templates/        ## template模块查找所需要模板文件的目录
handlers/        ## 至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含
default/        ## 设定默认变量时使用此目录中的main.yml文件,比vars的优先级低
meta/        ## 定义当前角色的特殊设定及其依赖关系,至少应该包含一个名为main.yml的文件,其它文件需在此文件中通过include进行包含

6.2.1.创建role的步骤

(1) 创建以roles命名的目录

(2) 在roles目录中分别创建以各角色名称命名的目录,如webservers等

(3) 在每个角色命名的目录中分别创建files、handlers、meta、tasks、templates和vars目录;用不到的目录可以创建为空目录,也可以不创建

(4) 在playbook文件中,调用各角色

针对大型项目使用Roles进行编排

nginx-role.yml 
roles/
└── nginx 
     ├── files
     │    └── main.yml 
     ├── tasks
     │    ├── groupadd.yml 
     │    ├── install.yml 
     │    ├── main.yml 
     │    ├── restart.yml 
     │    └── useradd.yml 
     └── vars 
          └── main.yml

6.2.2.playbook调用roles

---
- hosts: websrvs
  remote_user: root
  roles:
    - mysql
    - memcached
    - nginx   
---
- hosts: all
  remote_user: root
  roles:
    - mysql
    - { role: nginx, username: nginx }        ## 键role用于指定角色名称,后续的k/v用于传递变量给角色
---
- hosts: all
  remote_user: root
  roles:
    - { role: nginx, username: nginx, when: ansible_distribution_major_version == ‘7’  }        ## 基于条件测试实现角色调用
---
- hosts: websrvs
  remote_user: root
  roles:
    - { role: nginx ,tags: [ 'nginx', 'web' ] ,when: ansible_distribution_major_version == "6“ }
    - { role: httpd ,tags: [ 'httpd', 'web' ]  }
    - { role: mysql ,tags: [ 'mysql', 'db' ] }
    - { role: mariadb ,tags: [ 'mariadb', 'db' ] }

ansible-playbook --tags="nginx,httpd,mysql" nginx-role.yml        ## roles中使用tags

 

posted @ 2021-08-13 11:00  chili7  阅读(591)  评论(0编辑  收藏  举报