Ansible-介绍和基本使用

Ansible 官网

Ansible 官方文档

特点

不需要在被管理节点上安装任何软件 (使用 ssh 进行控制和通信), 且可以模块化扩充 ansible 的功能.

其功能主要基于:

  • API, 提供第三方程序调用接口
  • Modules, 内置的模块
  • Plugins, 内置, 自定义的插件
  • Inventory, 主机清单

基本概念

Ansible 由三个主要部分组成:

  • Control node
  • Inventory
  • Managed node

Control node

指安装了 ansible 的主机.

Inventory

一组 managed node 的逻辑集合. 在 control node 上创建.

Managed node

也即 “hosts”, 被管理的主机.

Playbook

一种 ansible 提供的用于自动化的简单脚本 (以 YAML 的形式).

工作流程

  1. 加载 ansible 配置文件
  2. 查找加载 inventory
  3. 加载对应的模块文件
  4. 通过 ansible 将模块生成临时的 python 文件并传输到受控节点
  5. 受控节点给管理节点发送过来的 python 文件添加执行权限
  6. 执行 python 脚本并返回结果
  7. 删除临时文件

Execution Environment

Execution Environment (EEs) 是把 Ansible control nodes 打包好的 containier images.

Ad hoc command

指直接通过命令快速执行的单个任务, 而无需编写完整的 playbook 如:

1
ansible <hosts> -m <module> -a "<module_arguments>"

安装

一般有两个可选包:

  • ansible-core, 较小, 包含 a set of Ansible.Builtin
  • ansible, 较完整, 包含 Ansible Collections

使用 pip 安装

1
2
dnf install python3-pip
pip3 install ansible

yum 安装

1
yum install -y ansible

配置

配置文件被搜索的路径为:

  • ANSIBLE_CONFIG
  • ansible.cfg (当前目录)
  • ~/.ansible.cfg (家目录)
  • /etc/ansiblle/ansible.cfg

配置采用 INI 格式, 有 #, ; 两种符号用于注释, 其中只有 ; 能用于 inline. 如:

1
2
# some basic default values...
inventory = /etc/ansible/hosts ; This points to the file that lists your hosts

生成一个包含注释的配置文件

1
ansible-config init --disabled -t all > ansible.cfg
  • init, 表明初始化一个 ansible 配置文件
  • --disabled, 表示生成的配置文件中所有的配置项都是被禁用的状态
  • -t all, 表示生成一个包含所有可用配置项的配置文件

创建 inventory

需要先确保 control node 的 public key 写入各 managed node 的 authorized_keys 中 (ssh 才可以免密登录).

  • 一个 inventory 可以是 INI 或者 YAML 两种格式.
  • 可以把 inventory 文件组织到一个目录下
  • 可以用 plugin 动态获取 inventory
1
2
3
4
cd
mkdir ansible_quickstart
cd ansible_quickstart
touch inventory.ini

/etc/ansible/hosts 文件中有示例 inventory 编写.

在 Ansible 的 CLI 工具中, 一般用 -i <path> 来指定 inventory 文件.

编辑 inventory.ini 内容为:

1
2
3
[myhosts]
192.168.177.21
192.168.177.49

这里创建了一个叫 myhosts 的 group.

等价的 inventory.yaml 可以为:

1
2
3
4
5
6
myhosts:
hosts:
my_host_01:
ansible_host: 192.168.177.21
my_host_02:
ansible_host: 192.168.177.49

注意, group name 需要唯一且大小写敏感.

查看 inventory

1
ansible-inventory -i inventory.ini --list

Ping inventory 中的 myhosts group

1
ansible myhosts -m ping -i inventory.ini

Default groups

Ansible 会定义两个默认组:

  • all, 包含所有 hosts
  • ungrouped, 包含没有分配到 group 中的 hosts

ungrouped

如果一个 node 没有分配到任何 group 中, 在 YAML 格式下可以写为:

1
2
3
ungrouped:
hosts:
mail.example.com

Host 位于多个 groups

示例:

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
ungrouped:
hosts:
mail.example.com:
webservers:
hosts:
foo.example.com:
bar.example.com:
dbservers:
hosts:
one.example.com:
two.example.com:
three.example.com:
east:
hosts:
foo.example.com:
one.example.com:
two.example.com:
west:
hosts:
bar.example.com:
three.example.com:
prod:
hosts:
foo.example.com:
one.example.com:
two.example.com:
test:
hosts:
bar.example.com:
three.example.com:

metagroups

metagroups 可以组织多个 group, 语法为:

1
2
metagroupname:
children:

如:

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
leafs:
hosts:
leaf01:
ansible_host: 192.0.2.100
leaf02:
ansible_host: 192.0.2.110

spines:
hosts:
spine01:
ansible_host: 192.0.2.120
spine02:
ansible_host: 192.0.2.130

network:
children:
leafs:
spines:

webservers:
hosts:
webserver01:
ansible_host: 192.0.2.140
webserver02:
ansible_host: 192.0.2.150

datacenter:
children:
network:
webservers:

此时:

  • Child group 的成员此时也是 parent group 的成员
  • Groups 可以有多个 parents 和 children
  • Hosts 可以位于多个 groups 中, 但一个 host 只会有一个 instance

创建变量

1
2
3
4
5
6
7
8
9
10
webservers:
hosts:
webserver01:
ansible_host: 192.0.2.140
http_port: 80
webserver02:
ansible_host: 192.0.2.150
http_port: 443
vars:
ansible_user: my_server_user

.ini 文件格式写:

1
2
[webservers:vars]
ansible_user=my_server_user

这种变量为 “组变量”, 即一个 hosts 组中的都能引用, 若为 host 变量, 如:

1
2
3
[Nginx]
192.168.1.14 host=01
192.168.1.15 host=02

这里的 host 都是主机变量.

常见关键字

以:

1
2
3
4
5
6
7
8
9
10
webservers:
hosts:
webserver01:
ansible_host: 192.0.2.140
http_port: 80
webserver02:
ansible_host: 192.0.2.150
http_port: 443
vars:
ansible_user: my_server_user

为例.

hosts

其下有:

  • ansible_host, 指定 ip 地址
  • http_port, 指定端口号

vars

其下的每一项都是变量.

使用 pattern 添加 hosts

这里的 pattern 和正则表达式似乎不太相同.

对数字:

1
2
3
4
# ...
webservers:
hosts:
www[01:50:2].example.com:

这里的 2 是步长, 可以不指定.

对字母:

1
2
3
4
# ...
webservers:
hosts:
www[01:50:2].example.com:

传入多个 inventory 文件

1
ansible-playbook test.yaml -i stagin -i production

将 inventory 文件组织到目录下

inventory 是一个目录:

1
ansible-playbook example.yml -i inventory

此时需要注意 inventory 的加载顺序, 默认是 filename 的 ASCII 顺序. Child group 的 inventory 文件需要先加载才不会报错.

可以组织为:

1
2
3
4
5
inventory/
01-openstack.yml # configure inventory plugin to get hosts from OpenStack cloud
02-dynamic-inventory.py # add additional hosts with dynamic inventory script
03-on-prem # add static hosts and groups
04-groups-of-groups # add parent groups

Organizing host and group variables

可参考

group_vars/ 目录用于存放与特定 group 相关的变量, 文件名与 group name 相同, 这样文件中的变量会自动应用于 group 中对应的主机.

host_vars/ 目录用于存放与特定 host 相关的变量, 文件名与 host name 相同, 这些变量会应用于特定主机.

注意这些变量是用于 playbook 的, 因此目录也是和 playbook 在同一目录下.

假如定义有 test group, 则目录结构可为:

1
2
3
4
5
6
7
8
.
├── group_vars
│   └── test
│   └── haha.yml
├── host_vars
├── inventory
│   └── inventory_test.yaml
└── playbook_test.yaml

注意 variable 的冲突和覆盖问题.

创建 playbook

Playbook 用 YAML 的格式. 用于部署和管理 nodes.

https://github.com/ansible/ansible-examples 中包含很多 playbook 的示例.

几个概念:

  • Playbook, 一系列有顺序的 plays 用于 ansible 执行
  • Play, 一系列管理 inventory 中 nodes 的 tasks
  • Task, 一个 module 的引用
  • Module, Ansible 可以运行来管理 nodes 的 a unit of code or binary

创建一个 playbook.yaml 文件并写入内容

1
2
3
4
5
6
7
8
9
- name: My first Play
hosts: myhosts
tasks:
- name: Ping my hosts
ansible.builtin.ping:

- name: Print message
ansible.builtin.debug:
msg: Hello world

运行 playbook

1
ansible-playbook -i inventory.ini playbook.yaml

另一个示例:

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
---
- name: Update web servers
hosts: webservers
remote_user: root

tasks:
- name: Ensure apache is at the latest version
ansible.builtin.yum:
name: httpd
state: latest

- name: Write the apache config file
ansible.builtin.template:
src: /srv/httpd.j2
dest: /etc/httpd.conf

- name: Update db servers
hosts: databases
remote_user: root

tasks:
- name: Ensure postgresql is at the latest version
ansible.builtin.yum:
name: postgresql
state: latest

- name: Ensure that postgresql is started
ansible.builtin.service:
name: postgresql
state: started

Playbook 可用的 keywords 可查阅 https://docs.ansible.com/ansible/latest/reference_appendices/playbooks_keywords.html#playbook-keywords.

运行顺序

默认是从上到下按顺序执行, 可以通过更改 strategies 来改变. (官方文档)

检查语法

ansible-playbook 加上 --check, --diff, --list-hosts, 或 --syntax-check 参数.

Templating (Jinja2)

Templating 提供了一种利用 variables 和 facts 来生成动态表达式的方法.

示例:

1
2
3
4
5
6
7
8
---
- name: Write hostname
hosts: all
tasks:
- name: write hostname using jinja2
ansible.builtin.template:
src: templates/test.j2
dest: /tmp/hostname

templates/test.j2 文件中写有:

1
My name is {{ ansible_facts['hostname'] }}

如果目标主机的 hostname 为 “hello” 则最后 /tmp/hostname 文件的内容为:

1
My name is hello

Handlers 和 Notify

notify 用于指定一个 handler 的 name.

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- name: Play Test
hosts: test
remote_user: root
gather_fact: no
tasks:
- name: task1
replace:
path: /etc/zabbix/zabbix_agent2.conf
regexp: '^Server=127.0.0.1$'
replace: 'Server=192.168.1.4'
notify: restart agent2
handlers:
- name: restart agent2
service:
name: zabbix-agent2
state: restarted

注意只有当受控节点 changed 才会触发 notify, 如:

Tags

可用于指定开始运行的位置 (从那个 task 开始):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- name: Play Test
hosts: test
remote_user: root
gather_fact: no
tasks:
- name: task1
tags: modify
replace:
path: /etc/zabbix/zabbix_agent2.conf
regexp: '^Server=127.0.0.1$'
replace: 'Server=192.168.1.4'
notify: restart agent2
handlers:
- name: restart agent2
service:
name: zabbix-agent2
state: restarted

之后在执行时指定:

1
ansible-playbook -t modify playbook.yml -i inventory

Roles

命令行工具

ad hoc commands

/usr/bin/ansible 命令对 one or more managed nodes 运行单个 task.

语法为:

1
$ ansible [pattern] -m [module] -a "[module options]"

[module options]key=value 的形式或者是 JSON string starting with { and ending with }.

ansible 默认调用的 module 为 ansible.builtin.command. 但其不支持 piping 和 redirects. (若要使用这些功能则使用 ansible.builtin.shell 模块)

ansible 默认只会同时开启 5 个 simultaneous process, 如果有很多 hosts, 则不能同时运行命令, 此时可以用 -f 参数来指定.

ansible 默认用当前用户来执行命令, 若要指定其他用户, 可用 -u 参数指定.

若要以 root 用户运行, 需要加上 --become 参数. 若加上 --ask-become-pass 参数则会要求密码输入.

Rebooting servers

假设已经有 atlanta 这个 group, 则:

1
$ ansible atlanta -a "/sbin/reboot" -f 10

文件管理

Ad hoc command 用 SCP 传输文件. 如向 atlanta group 传输一个文件, 使用 ansible.builtin.copy 模块:

1
$ ansible atlanta -m ansible.builtin.copy -a "src=/etc/hosts dest=/tmp/hosts"

修改文件 ownership 和 permission, 以及创建目录 (mkdir -p) 用 ansible.builtin.file 模块:

1
2
3
$ ansible webservers -m ansible.builtin.file -a "dest=/srv/foo/a.txt mode=600"
$ ansible webservers -m ansible.builtin.file -a "dest=/srv/foo/b.txt mode=600 owner=mdehaan group=mdehaan"
$ ansible webservers -m ansible.builtin.file -a "dest=/path/to/c mode=755 owner=mdehaan group=mdehaan state=directory"

删除文件/目录用:

1
$ ansible webservers -m ansible.builtin.file -a "dest=/path/to/c state=absent"

软件包管理

可以用 ansible.builtin.yum 模块来 install, update, or remove packages on managed nodes.

安装一个软件包:

1
$ ansible -m ansible.builtin.yum -a "name=acme state=present"

安装一个特定版本的软件包:

1
$ ansible -m ansible.builtin.yum -a "name=acme-1.5 state=present"

更新一个软件包到最新版本:

1
$ ansible -m ansible.builtin.yum -a "name=acme state=latest"

删除一个软件包:

1
$ ansible -m ansible.builtin.yum -a "name=acme state=absent"

管理用户和组

ansible.builtin.user 模块可以创建, 管理, 移除 user account:

1
2
3
$ ansible all -m ansible.builtin.user -a "name=foo password=<encrypted password here>"

$ ansible all -m ansible.builtin.user -a "name=foo state=absent"

管理服务

ansible.builtin.service 模块:

1
2
3
$ ansible webservers -m ansible.builtin.service -a "name=httpd state=started"
$ ansible webservers -m ansible.builtin.service -a "name=httpd state=restarted"
$ ansible webservers -m ansible.builtin.service -a "name=httpd state=stopped"

获取 managed node 的信息

ansible.builtin.setup 模块:

1
$ ansible all -m ansible.builtin.setup

Check mode

ansible 命令的 -C 参数, 其不会对 managed nodes 做修改, 而是打印命令结果. 如:

1
$  ansible all -m copy -a "content=foo dest=/root/bar.txt" -C

可用命令

  • ansible
  • ansible-config
  • ansible-console
  • ansible-doc
  • ansible-galaxy
  • ansible-inventory
  • ansible-playbook
  • ansible-pull
  • ansible-vault

ansible-playbook

--verbose 参数可以查看详细的运行过程.

Pattern 的使用

在 ad hoc command 中应用:

1
ansible <hosts> -m <module> -a "<module_arguments>"

在 playbook 中则应用于 hosts: 中:

1
2
- name: <play_name>
hosts: <pattern>

常用 patterns

  • *
  • :, ,, 指定多个, 如 host1:host2, host1,host2
  • !, 排除, 如 group1:!group2
  • &, intersection, 如 webservers:&staging

Pattern 的处理顺序

  1. :,
  2. &
  3. !

高阶使用

需要 ansible-playbook 开启 -e 选项, 此时可以在 pattern 中使用变量, 如:

1
webservers:!{{ excluded }}:&{{ required }}

使用索引

索引从 0 开始, 也可以是负数, 切片:

1
2
3
webservers[0]
webservers[-1]
webservers[0:2]

使用正则表达式

需要以 ~ 开头:

1
~(web|db).*\.example\.com

ad-hoc commands

结合 --limit option:

1
$ ansible all -m <module> -a "<module options>" --limit 'all:!host1'

从文件中读取 hosts 列表

--limit option, 需要在文件名前加上 @:

1
ansible-playbook site.yml --limit @retry_hosts.txt

常用模块

Ansible 中的关键模块为:

  • Paramike, 提供 ssh 的 python 库
  • PyYAML, 处理 YAML 格式的数据
  • Jinja2, 处理 template

Command

常见选项有:

  • chdir
  • cmd (这个似乎用正在 playbook 里)
  • creates
  • removes
  • warn

Shell

选项:

  • cmd (用在 playbook 中)

Script

发送脚本到 managed nodes 上执行.

选项:

  • cmd (用在 playbook 中)

Copy 和 Fetch

Copy 将 control nodes 的文件传输至 managed nodes. (支持目录)

而 Fetch 将 managed nodes 的文件传输至 control nodes. (不支持目录)

常用选项:

  • src
  • dest
  • content, Copy 的选项, 不能与 src 一起使用, 用于将文本复制到目标文件
  • owner, group, mode
  • force, 是否覆盖

File

用于文件和文件属性管理.

常用选项:

  • force
  • owner, group, mode
  • path
  • recurse
  • src, dest, 当 state=link 时使用
  • state, 其值有:
    • touch
    • directory
    • link, hard
    • absent

Archive 和 Unarchive

Archive 用于打包压缩. 常用选项有:

  • owner, group, mode
  • format, 默认为 gz
  • path
  • exclude_path
  • remove, 是否移除原文件

Unarchive 用于解压. 常用选项有:

  • copy, 若为 copy=yes, 表示压缩包位于 control nodes, 若为 copy=no, 则压缩包位于 managed nodes
  • mode
  • remote_src, 同 copy, 但不能一起使用

Linefile 和 Replace

用于文件内容修改.

Linefile 常用选项:

  • path
  • line, 替换或插入的内容
  • regexp
  • insertbefore
  • insertafter

Replace 常用选项:

  • path
  • regexp
  • replace, 替换正则表达式匹配的内容
  • before
  • after
  • owner, group, mode

User 和 Group

用于管理用户和组.

User 模块的常用选项有:

  • name
  • group, 设置主用户组
  • groups, 设置其他组
  • password
  • home
  • comment
  • uid

Group 模块的常用选项:

  • gid
  • name

Hostname, Cron, Yum 和 Service

Hostname 用于修改 managed nodes 的主机名, 可用选项为 name.

Cron 的常用选项有:

  • minute, hour, day, mouth, weekday
  • job, 指定命令或脚本
  • name, 任务名称
  • state, 设置为 absent 用于删除
  • disable, yes 启用或 no 关闭

Yum 的常用选项:

  • name, 包名
  • state, absent 为卸载, present 为安装, latest 为安装最新版本

Service 的常用选项:

  • name
  • enabled
  • state, started 为开启, stopped 为关闭, restarted 为重启

Ansible-介绍和基本使用
http://example.com/2024/03/02/Ansible-介绍和基本使用/
作者
Jie
发布于
2024年3月2日
许可协议