Ansible 详细教程

Ansible 详细教程

一、简介

Ansible 是一个 IT 自动化工具,他能配置系统,部署软件,编排更复杂的 IT 任务,如连续部署或零停机时间滚动更新。
Ansible 用 Python 编写,Ansible 允许不需要在每个节点上安装自己的组件,可以在不止一个地方控制整个基础架构。

二、工作原理

  • Inventory:被管理节点的列表,资源池。
  • PlayBook:类似于 Shell 脚本,通过一系列命令执行自动化操作。
  • Module

在 Ansible 管理体系中,存在 管理节点被管理节点 两种角色。
被管理节点通常被成为资产。
在管理节点上,Ansible 将 AdHoc 或 PlayBook 转换为 python 脚本,并通过 SSH 传输到被管理节点上。
在被管理节点上依次执行 Python 脚本。

三、Ansible 安装

3.1、先决条件

3.2、安装 Ansible

yum 方式:

[root@localhost ~]# yum install epel-release
[root@localhost ~]# yum install ansible

pip 方式:

[root@localhost ~]# yum install epel-release
[root@localhost ~]# yum install python2-pip
[root@localhost ~]# pip install ansible

查看 Ansible 版本:

[root@localhost ~]# ansible --version
ansible 2.9.27
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.5 (default, Oct 14 2020, 14:45:30) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]

四、Ansible 简单部署

4.1、管理节点与被管理节点建立 SSH 信任关系

管理节点 (ansible) 中创建密钥对:

[root@localhost ~]# ssh-keygen -t rsa

将本地的公钥传输到被管理节点:

[root@localhost .ssh]# ssh-copy-id root@192.168.200.135
[root@localhost .ssh]# ssh-copy-id root@192.168.200.136

4.2、场景

4.2.1、检测所有被管理主机在线状态

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

-i : 参数后面是一个列表 (List) , 因此当为一个被管理节点时,我们后面一定要加一个英文逗号 (,) , 告知是 List。

4.2.2、确保 /tmp/a.conf 发布到所有被管理节点上

[root@manager ~]# touch /tmp/a.conf
[root@manager ~]# ansible all -i 192.168.19.135,192.168.19.136 -m copy -a "src=/tmp/a.conf dest=/tmp/a.conf"
192.168.19.136 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": true,
    "checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
    "dest": "/tmp/a.conf",
    "gid": 0,
    "group": "root",
    "md5sum": "d41d8cd98f00b204e9800998ecf8427e",
    "mode": "0644",
    "owner": "root",
    "secontext": "unconfined_u:object_r:admin_home_t:s0",
    "size": 0,
    "src": "/root/.ansible/tmp/ansible-tmp-1702535672.46-6415-225212235428808/source",
    "state": "file",
    "uid": 0
}
192.168.19.135 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": true,
    "checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
    "dest": "/tmp/a.conf",
    "gid": 0,
    "group": "root",
    "md5sum": "d41d8cd98f00b204e9800998ecf8427e",
    "mode": "0644",
    "owner": "root",
    "secontext": "unconfined_u:object_r:admin_home_t:s0",
    "size": 0,
    "src": "/root/.ansible/tmp/ansible-tmp-1702535672.44-6413-170350629067151/source",
    "state": "file",
    "uid": 0
}
  • all: 在 Ansible 中,叫做 pattern , 即匹配,用来在 -i 参数的资产中匹配一部分,all 代表匹配所有
  • -i: 指定 Ansible 的资产,即被管理主机 (也可以是文件名)
  • -m: 指定要运行的模板,比如这里的 ping 模块 和 copy 模块
  • -a: 指定模块的参数,这里 ping 模块没有指定参数,copy 模块指定了 src 和 dest 参数

五、Ansible 资产

实际场景中,被管理的服务器肯定不止 2 台,因此我们可以将被管理服务器写入一个文件或脚本中。

5.1、静态资产

顾名思义,静态资产本身是一个文本文件,一个类似 INI 的文件
默认情况下,Ansible 的资产文件 位于 /etc/ansible/hosts.pip 安装的可能没有这个文件,创建一个即可。
示例:

# This is the default ansible 'hosts' file.
#
# It should live in /etc/ansible/hosts
#
#   - Comments begin with the '#' character
#   - Blank lines are ignored
#   - Groups of hosts are delimited by [header] elements
#   - You can enter hostnames or ip addresses
#   - A hostname/ip can be a member of multiple groups

`Ex 1: 不属于任何组的单独主机,必须放在所有主机组的前面,也就是必须位于文件最前方
green.example.com
blue.example.com
192.168.100.1
192.168.100.10

`Ex 2: 主机组 webservers 包含 4 个主机,调用时可以通过组名匹配主机

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

` 有规律的主机可以使用这总方法显示,这代表 www001.example.com , www002.example.com , ...
www [001:006].example.com

`Ex 3: 主机组可以在 组和主机中间添加空格以便阅读

[dbservers]

db01.intranet.mydomain.net
db02.intranet.mydomain.net
10.25.1.56
10.25.1.57

# Here's another example of host ranges, this time there are no
# leading 0s:

## db-[99:101]-node.example.com

5.1.1、自定义资产

vim /etc/ansible/inventory.ini

# 没有组名的属于 all 组
1.1.1.1
2.2.2.2
3.3.3.[1:15]
test01.lml.com
test03.lml.com
test [05:09].lml.com

[web_servers]
192.168.1.2
192.168.1.3
192.168.1.5

[db_servers]
192.168.2.2
192.168.2.3
192.168.2.5
192.168.1.5

# 创建 all_server 组,并将 db_servers 和 web_servers 添加为自己的子组 
# 选择 all_server 组时,则代表选中了 web_servers 和 db_servers 组下的所有主机
[all_servers]
[all_servers:children]
db_servers
web_servers
  • 1、Ansible 的资产文件中,可以以 IP 地址的形式或者主机名的形式存在。
  • 2、Ansible 的资产若连续,可以使用 [start:end] 的形式去表达。
  • 3、可以将服务器按照业务场景定义成组,比如 db_servers 和 web_servers。
  • 4、组合组之间可以存在继承关系,比如 db_servers 和 web_servers 同时继承 all_servers 组。

5.1.2、如何使用自定义资产

通过 -i 参数指定自定义资产的位置即可 (可以是全路径,也可以是相对路径)。

# ansible all -i inventory.ini .........// 伪命令,不可执行

5.1.3、验证自定义资产

列举出所有资产:

ansible all -i inventory.ini --list-hosts
    hosts (19) :
    1.1.1.1
    2.2.2.2
    3.3.3.1
    ......

列举出选定资产 (比如 db_servers):

ansible db_servers -i inventory.ini --list-hosts

5.2、资产选择器

5.2.1、基本语法格式

ansible PATTERN -i inventory -m moudle -a argument
  • PATTERN:可以是 IP 列表,也可以是组名,值得注意的是,资产中写的什么就要写什么,不能通过域名解析
  • -i:资产列表,从哪里进行筛选
  • -m:使用哪一个模块
  • -a:模块所对应的参数

1、选择一台或几台服务器

[root@localhost ansible]# ansible 1.1.1.1 -i inventory.ini --list-host
  hosts (1):
    1.1.1.1
[root@localhost ansible]# ansible test01.lml.com -i inventory.ini --list-host
  hosts (1):
    test01.lml.com
[root@localhost ansible]# ansible 1.1.1.1,2.2.2.2 -i inventory.ini --list-host
    hosts (2):
    1.1.1.1
    2.2.2.2

2、选择一组服务器

[root@localhost ~]# ansible all_servers -i inventory.ini --list-host
  hosts (6):
    192.168.2.2
    192.168.2.3
    192.168.2.5
    192.168.1.2
    192.168.1.3
    192.168.1.5
# 两个子组的重复部分会被去重

3、使用 * 匹配

[root@localhost ansible]# ansible 3.3.3.1* -i inventory.ini --list-host
  hosts (7):
    3.3.3.10
    3.3.3.11
    3.3.3.12
    3.3.3.13
    3.3.3.14
    3.3.3.15
    3.3.3.1

4、使用逻辑进行匹配
1)并集 (两个组中所有主机,去重)

# 显示两个组中所有的主机
[root@localhost ansible]# ansible 'web_servers:db_servers' -i inventory.ini --list-host
  hosts (6):
    192.168.1.2
    192.168.1.3
    192.168.1.5
    192.168.2.2
    192.168.2.3
    192.168.2.5

2)交集 (两个组中共有主机)

# 显示同时承担 web_server 和 db_server 的主机
[root@localhost ansible]# ansible 'web_servers:&db_servers' -i inventory.ini --list-host
  hosts (1):
    192.168.1.5 

3)差集 (A 有 B 没有,或 B 有 A 没有)

# 在 web_servers 中,但是不在 db_servers 中
[root@localhost ansible]# ansible 'web_servers:!db_servers' -i inventory.ini --list-host
  hosts (2):
    192.168.1.2
    192.168.1.3
# 在 db_servers 中,但是不再 web_servers 中
[root@localhost ansible]# ansible 'db_servers:!web_servers' -i inventory.ini --list-host
  hosts (3):
    192.168.2.2
    192.168.2.3
    192.168.2.5

六、Ansible Ad-Hoc Command

Ad-hoc 命令是一个概念性的名字,是相对于 Ansible playbook 来说的,类似于在命令行敲入 shell 和写 shell scripts 两者之间的关系,可以用于执行一些临时命令。
如果我们敲入一些命令去比较快的完成一些事情,而不需要将这些执行的命令特别保存下载,这样的命令就叫做 ad-hoc 命令。
Ansible 提供两种方式去完成任务,一是 ad-hoc , 一是写 Ansible playbook, 前者可以解决一些简单的任务,后者解决较复杂的任务,比如做配置管理或部署。

6.1、命令格式

命令格式语法如下 :

ansible pattern [-i inventory] -m moudule -a argument
  • pattern: 资产选择器
  • -i: 指定资产清单文件的位置。
  • -m: 指定本次 Ansible ad-hoc 要执行的模块,可以类别成 shell 中的命令。
  • -a: 模块的参数,可以类比成 SHELL 中的命令参数。

6.3、联机帮助

Ansible 的核心模块和附加模块,数量有 1000+ , 很难一次性掌握,因此我们可以使用 Ansible 的帮助文档,它本身提供的命令就是由 Ansible-doc 实现

  • 列出所有的核心模块和附加模块:
    ansible-doc -l
  • 查询某个模块的使用方法:
    ansible-doc modulename

6.4、常用模块

为方便演示,我们使用如下配置文件:
管理机 : 192.168.200.132
被管理机 1 : 192.168.200.133
被管理机 2 : 192.168.200.134
编写如下配置文件到 /etc/ansible/hosts

[dbservers]
192.168.200.133


[webservers]
192.168.200.134

6.4.1、command & shell 模块

两个模块都是在远程服务器上执行命令
command 模块:是 ad-hoc 的默认模块,在执行 ad-hoc 时,若不指定模块的名字则默认使用此模块

[root@localhost ansible]# ansible all -i hosts -a "echo 'hello world'"
192.168.200.133 | CHANGED | rc=0 >>
hello world
192.168.200.134 | CHANGED | rc=0 >>
hello world

[root@localhost ansible]# ansible all -i hosts -m shell -a "echo 'hello world'"
192.168.200.133 | CHANGED | rc=0 >>
hello world
192.168.200.134 | CHANGED | rc=0 >>
hello world

command 模块 和 shell 模块的差异:

  • shell 模块:可以执行 SHELL 的内置命令和特性 (比如管道符)。
  • command 模块:无法执行 SHELL 的内置命令和特性。

实例:

[root@localhost ansible]# ansible all -i hosts -m shell -a "echo 'hello' | grep -o 'e'"
192.168.200.133 | CHANGED | rc=0 >>
e
192.168.200.134 | CHANGED | rc=0 >>
e
[root@localhost ansible]# ansible all -i hosts -m command -a "echo 'hello' | grep -o 'e'"
192.168.200.133 | CHANGED | rc=0 >>
hello | grep -o e
192.168.200.134 | CHANGED | rc=0 >>
hello | grep -o e

6.4.2、script 模块

将管理节点上的脚本传到被管理节点 (远程服务器) 上进行执行,理论上此模块的执行完全不需要被管理服务器上有 Python。
示例:

[root@localhost ansible]# echo "touch /tmp/testfile" > /root/a.sh
[root@localhost ansible]# ansible webservers -i hosts -m script -a "/root/a.sh"
192.168.200.134 | CHANGED => {
    "changed": true,
    "rc": 0,
    "stderr": "Shared connection to 192.168.200.134 closed.\r\n",
    "stderr_lines": [
        "Shared connection to 192.168.200.134 closed."
    ],
    "stdout": "",
    "stdout_lines": []
}
[root@localhost ansible]# ansible webservers -i hosts -m shell -a "ls -l /tmp"
192.168.200.134 | CHANGED | rc=0 >>
-rw-r--r--  1 root root      0 Dec 18 21:23 testfile

6.4.5、yum 模块

等同于 Linux 上的 yum 命令,对远程服务器上 RPM 包进行管理,常用参数如下:

  • name 要安装的软件包名,多个软件包以 ( , ) 隔开。
  • state 对当前指定的软件安装,移除操作 (present installed latest absent removed)。
  • present 确认已经安装,但不升级。
  • installed 确认已经安装。
    • latest 确保安装,且升级为最新。
    • absent 和 removed 确认已删除。
6.4.5.1、安装一个软件包
[root@localhost ansible]# ansible webservers -i hosts -m yum -a "name=nginx state=present"

[root@localhost ansible]# ansible webservers -i hosts -m yum -a "name=nginx state=installed"

[root@localhost ansible]# ansible webservers -i hosts -m yum -a "name=nginx state=latest"

# 检查是否安装
[root@manager ~]# ansible webservers -i /etc/ansible/hosts -m shell -a "nginx -version"
192.168.200.134 | CHANGED | rc=0 >>
nginx version: nginx/1.20.1
6.4.5.2、移除一个软件包
[root@manager ~]# ansible webservers -i /etc/ansible/hosts -m yum -a "name=nginx state=absent"
[root@manager ~]# ansible webservers -i /etc/ansible/hosts -m yum -a "name=nginx state=removed"

[root@manager ~]# ansible webservers -i /etc/ansible/hosts -m shell -a "nginx -version"
192.168.200.134 | FAILED | rc=127 >>
/bin/sh: nginx: command not foundnon-zero return code
6.4.5.3、安装一个软件包组
[root@manager ~]# ansible all -i /etc/ansible/hosts -m yum -a "name='@Developmenttools' state=present"

6.4.6、systemd 模块

CentOS6 之前的版本使用 service 模块,使用 ansible-doc service 命令查看帮助信息。

管理远程节点上的 systemd 服务,就是由 systemd 所管理的服务,常用参数如下

  • daemon_reload:重新载入 systemd , 扫描新的或有变动的单元,值为 yes。
  • enabled:是否开机自启动 yes | no。
  • name:必选项,服务名称,比如 httpd , vsftpd 等。
  • state:对当前服务执行启动,停止,重新加载等操作 (started , stopped , restarted , reloaded)。
6.4.6.1、Example : 重新加载 systemd
[root@localhost ~]# ansible webservers -i /etc/ansible/hosts -m systemd -a "daemon_reload=yes"
192.168.200.134 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "name": null,
    "status": {}
}
6.4.6.2、Example : 启动 nginx
[root@localhost ~]# ansible  webservers -i  /etc/ansible/hosts -m systemd -a "name=nginx state=started"
6.4.6.3、Example : 关闭 nginx
[root@localhost ~]# ansible  webservers -i  /etc/ansible/hosts -m systemd -a "name=nginx state=stopped"

6.4.7、group 模块

对被管理节点的组进行管理,常用参数如下:

  • name:组名称,必须的。
  • system:是否为系统组,yes | no。
6.4.7.1、Example : 创建普通组 db_admin
[root@localhost ~]# ansible all -i /etc/ansible/hosts -m group -a "name=db_admin"
192.168.200.133 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": true,
    "gid": 1001,
    "name": "db_admin",
    "state": "present",
    "system": false
}

6.4.8、user 模块

用于对被管理节点上的用户进行管理,常用参数如下 :

  • name:必须的参数,指定用户名。
  • password:设置用户的密码,这里接受的是一个加密的值,因为会直接存到 shadow , 默认不设置密码。
  • update_password:加入设置的密码不同于原密码,则会更新密码,在 1.3 版本中被加入。
  • home:指定用户的家目录。
  • shell:设置用户的 shell。
  • comment:用户的描述信息。
  • create_home:在创建用户时,是否创建其家目录,默认创建,加入不创建,设置为 no , 在 2.5 版本之前使用 createhome 参数。
  • group:设置用户的主组。
  • groups:将用户加入到多个其他组中,多个用逗号隔开,默认会把用户从其他已经加入的组中删除。
  • append:值为 yes | no , 和 groups 配合使用,值为 yes 时,不会把用户从其他已经加入的组中删除。
  • system:值为 yes 时,会创建一个系统账户。
  • expires:设置用户的过期时间,值为时间戳,会转为天数后,放在 shadow 的第 8 个字段里。
  • generate_ssh_key:设置为 yes 时,会为用户生成密钥,这不会覆盖原来的密钥。
  • ssh_key_type:指定用户的密钥类型,默认 rsa , 具体的类型取决于被管理节点。
  • state:删除或添加用户,yes 为添加,absent 为删除,默认值为 yes。
  • remove 当与 state=absent 一起使用时,删除一个用户及关联的目录,比如家目录,邮箱目录,可选的值为 yes/no。

先生成加密密码:

[root@localhost ~]# pass=$(echo “LML123456” | openssl passwd -l -stdin)
[root@localhost ~]# echo $pass
111MQBJpWBh$krH/eQgBQcMpyDMKxVpS.0
6.4.8.1、Example : 创建账号,设置密码
[root@localhost ~]# ansible all -i /etc/ansible/hosts -m user -a "name=foo password=${pass}"
6.4.8.2、Example : 创建账号,设置密码,改密钥类型
[root@localhost ~]# ansible all -i /etc/ansible/hosts -m user -a "name=Dragon password=${pass} ssh_key_type=ecdsa"
6.4.8.3 Example : 创建账号,设置密码,有效期,加组

创建 Cai 用户,并设置其有效期到 2024_4_15 日,加入到 db_admin 组中。

[root@localhost ~]# ansible all -i /etc/ansible/hosts -m user -a "name=Cai password=${pass} group=db_admin append=yes"

6.4.9、file 模块

file 模块主要用于远程主机上的文件操作,常用参数:

  • group:定义文件 / 目录的属组。
  • mode:定义文件 / 目录的而权限。
  • owner:定义文件 / 目录属组。
  • path:必选项,操作文件 / 目录 的路径。
  • recurse:递归的设置文件的属性,只对目录有效。
  • src:要被链接 (软/硬) 的源文件的路径,值用于 state=link 的情况。
  • dest:被链接到的路径,只应用于 state=link 的情况。
  • state:对文件执行什么操作。
    • directory:如果目录不存在则创建目录。
    • file:文件不存在则不不会被创建,存在则返回文件的信息,常用于检查文件是否存在。
    • link:创建软连接。
    • hard:创建硬链接。
    • touch:如果文件不存在,则会创建一个新的文件,如果文件或目录存在,则更新其最后修改时间。
    • absent:删除目录,文件或者取消链接。
6.4.9.1、Example : 文件操作
# 创建一个文件
[root@localhost ~]# ansible all -i /etc/ansible/hosts -m file -a "path=/tmp/foo.conf state=touch"

# 改变文件所有者及权限
[root@localhost ~]# ansible all -i /etc/ansible/hosts -m file -a "path=/tmp/foo.conf owner=nobody group=nobody mode=0644"

# 创建一个软连接
[root@localhost ~]# ansible all -i /etc/ansible/hosts -m file -a "src=/tmp/foo.conf dest=/tmp/link.conf state=link"

# 创建一个目录
[root@localhost ~]# ansible all -i /etc/ansible/hosts -m file -a "path=/tmp/test_dir state=directory"

# 取消一个链接
[root@localhost ~]# ansible all -i /etc/ansible/hosts -m file -a "path=/tmp/link.conf state=absent"

# 删除一个文件
[root@localhost ~]# ansible all -i /etc/ansible/hosts -m file -a "path=/tmp/foo.conf state=absent"

6.4.10、cron 模块

管理远程节点的 CRON 服务,等同于 Linux 中的计划任务,常用参数如下。
注意:使用 Ansible 创建的计划任务,是不能使用本地 crontab -e 去编辑,否则 Ansible 无法再次操作此计划任务。

  • name:指定一个 cron job 的名字,一定要指定,便于日后删除。
  • minute:指定分钟,可以设置成 (0-59 , * , /2 等) 格式,默认是 * , 也就是每分钟。
  • hour:指定小时,可以设置达成 (0-23 , * , */2 等) 格式,默认是 * , 也就是每小时。
  • day:指定天,可以设置成 (1-31 , * , */2 等) 格式,默认是 * , 也就是每天。
  • month:指定月份,可以设置成 (1-12 , * , */2 等) 格式,默认是 * , 也就是每周。
  • weekday:指定星期,可以设置成 (0-6 for Sunday-Saturday , * 等) 格式,默认是 * , 也就是每天。
  • job:要执行的内容,通常可以写个脚本,或者一段内容。
  • state:指定这个 job 的状态,可以是新增 (present) , 或者是删除 (absent) , 默认为 (present)。
6.4.10.1、Example 1 : 创建一个 cron job 任务
[root@manager ~]# ansible all -i /etc/ansible/hosts -m cron -a "name=newJob minute='0' job='ls -alh > /dev/null'"

验证

[root@host1 ~]# crontab -l
#Ansible: newJob
0 * * * * ls -alh > /dev/null
6.4.10.2、Example 2 : 删除一个 cron job 任务
[root@manager ~]# ansible all -i /etc/ansible/hosts -m cron -a "name=newJob state=absent"

6.4.11、debug 模块

6.4.11.1、Example 1 : 打印变量

debug 模块主要用于调试时使用,通常的作用是将一个变量的值打印出来,常用参数如下:

  • var:直接打印一个指定的变量值。
  • msg:打印一段可以格式化的字符串。
# 直接打印一个变量 (-e 是传入变量)
[root@manager ~]# ansible all -i /etc/ansible/hosts -m debug -a "var=role" -e "role=web"
# 打印带字符串的 变量
[root@manager ~]# ansible all -i /etc/ansible/hosts -m debug -a "msg='role is {{role}}'" -e "role=web"

6.4.12、template 模块

template 模块使用了 jinjia2 格式作文文件模板,可以进行文档内变量的替换。
它的每次使用都会被 ansible 标记为 “changed” 状态,文件以 .j2 结尾,常用参数如下:

  • src:指定 Ansible 控制端的文件路径。
  • dest:指定 Ansible 被控制端的文件路径。
  • owner:指定文件的属主。
  • group:指定文件的属组。
  • mode:指定文件的权限。
  • backup:创建一个包含时间错信息的备份文件,这样如果以某种方式损坏了原始文件,就可以将其复原,yes/no。
6.4.12.1、Example 1 : 传递文件 (带变量)
# 1. 创建一个 hello_world.j2 文件
[root@manager ~]# cat hello_world.j2
Hello {{var}} !

# 2. 执行命令,并且设置变量 var 的值为 world
[root@manager ~]# ansible all -i /etc/ansible/hosts -m template -a "src=hello_world.j2 dest=/tmp/hello_world.world" -e "var=world"

# 3. 在被控主机上验证
Hello world !

6.4.13、lineinfile 模块

在被管理节点上,使用正则匹配的方式对目标文件的一行内容修改删除等操作。
如果是一个文件中把所有匹配到的多行进行统一处理,参考 replace 模块。
如果相对一个文件进行一次性 添加 / 更新 / 删除等多行内容操作,参考 blockinfile 模块。
常用参数如下:

  • path:目标文件路径,必须的。
  • state:可选值 present 替换 (默认 | absent 删除。
  • regexp:在文件的每一行中查找的正则表达式,对于 state=present , 进找到的最后一行将被替代。
  • line:要在文件中插入/替换的行,需要 state=present。
  • create:文件不存在时,是否要创建文件并添加内容,yes/no。
6.4.13.1、Example 1 : 删除被控节点文件里的某一条内容
[root@manager ~]# ansible all -i /etc/ansible/hosts -m lineinfile -a "path=/etc/sudoers regexp='^% wheel' state=absent"
6.4.13.2、Example 1 : 关闭远程主机的 selinux
[root@manager ~]# ansible all -i /etc/ansible/hosts -m lineinfile -a "path=/etc/selinux/config regexp='^SELINUX=' line='SELINUX=disabled' state=present"

七、Ansible-Playbook

Ad-Hoc 的问题:AD-HOC 每次只能在被管理节点上执行简单的命令。
而日常工作中,我们往往面临的是一系列复杂的操作,例如我们可能需要安装软件,更新配置,重启服务等等一系列操作的组合,此时 Ad-Hoc 有些力不从心,使用 PLAYBOOK 可以帮助我们解决这个问题。

7.1、什么是 PalyBook

Playbook 通常被大家翻译成剧本。
可以认为它是 Ansible 自定义的一门语言 (可以将 Playbook 比作 Linux 中的 shell) , 而 Ansible 中的 Module 可以比作为 Linux 中的各种命令。

7.2、YAML 学习

安装 pip 对 yaml 文件格式进行检查。
yum install python2-pip

7.2.1、YAML 特点

# YAML 文件以 # 为注释
# YAML 文件以 .yml 或 .yaml 结尾
# YAML 文件以 --- 开始,以... 结束,但是开始和结束标志都是可选的

7.2.2、基本语法

  • 大小写敏感。
  • 使用缩进表示层级关系,一般规范 2 个空格。
  • 缩进时使用 tab 键,还是空格 一定要达到统一,建议使用空格。
  • 相同层级的元素必须左侧对齐。

YAML 支持的数据结构有三种:

  • 字符串
  • 列表
  • 字典
7.2.2.5、校验 YAML 语句

将 YAML 文件,通过 Python 的 YAML 模块进行验证:

# 安装 python2-pip
[root@manager ~]# yum install python2-pip

# 安装 pyyaml
[root@manager ~]# pip install pyyaml

# cat test.yaml
---
- red
- green
- blue
...

# 对 YAML 格式文件进行检验
[root@manager ~]# python -c 'import yaml,sys; print yaml.load (sys.stdin)' < test.yaml
['red', 'green', 'blue']

7.3、定义一个 Playbook

一个 Playbook 是由一个或多个 Play 构成,那么一个含有多个 Play 的 Playbook 结构上应该是如下的样子:

---
- key1: value1
  key2: value2
  key3: value3
...

一个含有多个 Play 的 Playbook 结构山应该是如下的样子:

---
# 一个含有 3 个 Play 的伪 PlayBook 构成
- key1: value1
  key2: value2
  key3: value3
- key4: value1
  key5: value2
  key6: value3
- key1: value1
  key2: value2
  key3: value3
...

7.3.1、Play 的属性

Play 中的每一个 key , 比如 key1 , key2 等,这些 key 在 PlayBook 中被定义为 Play 的属性。
这些属性具有特殊意义,我们不能随意的自定义 Play 的属性,常用属性如下:

  • name:每个 play 的名字,用于任务执行后的回显 (一定要写)。
  • hosts:每个 play 涉及的被管理服务器,通 ad hoc 中的 pattern。
  • tasks:每个 play 中具体要完成的任务,以列表的形式表达。
  • become:如果需要提权,则加上 become 相关属性。
  • become_user:若提权的话,提权到哪个用户上。
  • remote_user:指定连接用户,若不指定,则默认使用当前执行 ansible Playbook 的用户。
  • 等等

7.3.2、一个完整的剧本

最常规写法:

---
- name: the first play example
  hosts: all
  remote_user: root
  tasks: 
    - name: install nginx packet
      yum: name=nginx state=present
    - name: copy nginx.conf to remote server
      copy: src=nginx.conf dest=/etc/nginx/nginx.conf
    - name: start nginx service
      service: name=nginx enabled=true state=started
...

tasks 属性中任务的多种写法:

# 以启动 nginx 服务,并增加开机启动为例

# 一行的形式
service: name=nginx enabled=true state-started

# 多行的形式
service: 
  name=nginx
  enabled=true
  state=started
  
# 多行字典的形式
service:
  name: nginx
  enabled: true
  state: started

7.3.3、具有多个 Play 的 Playbook

---
- name: manage web servers
  hosts: webservers
  remote_user: root
  tasks:
    - name: install nginx packet
      yum: name=nginx state=present
    - name: copy nginx.conf to remote server
      copy: src=nginx.conf dest=/etc/nginx/nginx.conf
    - name: start nginx server
      service: name=nginx enabled=true state=started
- name: manager db servers
  hosts: dbservers
  tasks: 
    - name: update database config
      copy: src=my.cnf dest=/etc/my.cnf
...

7.4、校验一个 PlayBook

下面校验的方法,只能校验 PlayBook 是否正确,而不能校验 YAML 文件是否语法正确。
之前 YAML 校验的方法:

[root@manager ~]# python -c 'import yaml,sys; print yaml.load (sys.stdin)' < test.yaml

PlayBook 校验:

[root@manager ~]# ansible-playbook myplaybook.yml --syntax-check

playbook: myplaybook.yml

7.5、运行一个 PlayBook

[root@manager ~]# ansible-playbook myplaybook.yml

7.6、如何单步跟从调试 PlayBook

ansible-playbook myplaybook.yml --step

7.7、如何测试运行 PlayBook

// 会执行完整个 PlayBook , 但是所有 Task 中的行为都不会在远程服务器上执行,所有执行都是模拟行为
# ansible-playbook myplaybook.yml -C
//-C 为大写字母 C

八、Ansible 变量

8.1、Ansible 变量介绍

变量由 字母 数字 下划线 组成。
但 只能以字母开头,保留关键字不能作为变量名称。

8.2、变量类型

根据变量的作用范围,大体的将变量分为:

  • 全局变量
  • 剧本变量
  • 资产变量

但这只是一个比较除粗糙的划分,不能囊括 Ansible 中的所有变量,下面将分别从这三种变量入手,去介绍变量的使用。

8.2.1、全局变量

全局变量 是 我们使用 ansible 或者使用 ansible-playbook 时,手动通过 -e 参数传递给 Ansible 的变量。
通过 ansible 或 ansible-playbook 的 help 帮助,可以获取具体格式使用方式。
普通的 key-value 模式:

[root@manager ~]# ansible webservers -i /etc/ansible/hosts -m debug -a "msg='name is {{key}}'" -e "key='LiuMenglong'"
192.168.200.133 | SUCCESS => {
    "msg": "name is LiuMenglong"
}

传递一个 YAML/JSON 的形式 (他们的最终形式必须是字典):

# 指定时必须加 @
[root@manager ~]# cat a.json
{"name": "LiuML", "age": "16"}

[root@manager ~]# ansible webservers -i /etc/ansible/hosts -m debug -a "msg='name is {{name}} , age is {{age}}'" -e @a.json
[WARNING]: Found variable using reserved name: name
192.168.200.133 | SUCCESS => {
    "msg": "name is LiuML , age is 16"
}


[root@manager ~]# cat b.yaml
---
name: lisi
age: 33
...
[root@manager ~]# ansible webservers -i /etc/ansible/hosts -m debug -a "msg='name is {{name}} , age is {{age}}'" -e @b.yaml
[WARNING]: Found variable using reserved name: name
192.168.200.133 | SUCCESS => {
    "msg": "name is lisi , age is 33"
}

8.2.2、剧本变量

在 Playbook 中使用的变量叫做剧本变量,他的定义由多种方式,我们使用两种,文件内定义即引用文件。

8.2.2.1、通过 PLAY 属性 vars 定义
---
- name: test play vars
  hosts: all
  vars: 
    user: lisi
    home: /home/lisi
...
8.2.2.2、通过 PLAY 属性 vars_file 定义
---
- name: test play vars
  hosts: all
  vars_files: 
    - vars/users.yaml
...

cat vars/users/yaml

---
user: lilei
home: /home/lilei
...
8.2.2.3、如何在 Playbook 中使用这些变量

在 PlayBook 中使用变量时,使用 {{ 变量名 }} 来使用变量,在使用变量是,大部分情况外侧要加双引号即 “{{ 变量 }}”

Example1:

---
- name: Test Vars using in playbook
  hosts: all
  vars: 
    user: lisi
    home: /home/lisi
  tasks: 
    - name: create the users {{user}}
      user: name={{user}} home={{home}}
...
[root@manager ~]# ansible-playbook 123456.yaml -C
[root@manager ~]# ansible-playbook 123456.yaml

注意事项:在下面的例子 (字典) 中,{{ 变量 }} 外一定要加双引号,否则会 yaml 解析错误

Example2

---
- name: Test Vars using in playbook
  hosts: all
  vars: 
    user: lisi
    home: /home/lisi
  tasks: 
    - name: create the users {{user}}
      user: 
        name: "{{user}}"
        home: "{{home}}"
...

8.2.3、资产变量

资产变量是和资产紧密相关的一种变量,资产变量分为 主机变量 和 主机组变量,分别针对单个主机和一组主机。

8.2.3.1、主机变量
# cat hostsandhostvars
[webservers]
192.168.200.133 user=lisi age=18
192.168.200.134

验证:

[root@localhost ansible]# ansible webservers -i /etc/ansible/hostsandhostvars -m debug -a "var=user"
192.168.200.133 | SUCCESS => {
    "user": "lisi"
}
192.168.200.134 | SUCCESS => {
    "user": "VARIABLE IS NOT DEFINED!"
}
8.2.3.2、主机组变量

主机变量优先于主机组变量。

# cat hostsandhostvars
[webservers]
192.168.200.133 user=lisi age=18
192.168.200.134

[webservers:vars]
user=tom

验证:

[root@localhost ansible]# ansible webservers -i /etc/ansible/hostsandhostvars -m debug -a "var=user"
192.168.200.133 | SUCCESS => {
    "user": "lisi"
}
192.168.200.134 | SUCCESS => {
    "user": "tom"
}
8.2.3.3、变量的继承

变量是可以继承的:

# cat host_v3
[dbservers]
192.168.200.133

[webservers]
192.168.200.134

[allserver]
[allserver:children]
webservers
dbservers


[allserver:vars]
user=lml

验证:

[root@localhost ansible]# ansible webservers -i /etc/ansible/host_v3 -m debug -a "var=user"
192.168.200.134 | SUCCESS => {
    "user": "lml"
}

参考:
Ansible 超详细教程
w3cschoo Ansible
Ansible 中文权威指南

评论

暂无

添加新评论