Ansible 自动化部署
本文讲解运维自动化的发展与分类、Ansible 的架构与准备工作、inventory 主机清单、ad-hoc 临时命令、常用模块(command、shell、script、copy、stat、get_url、yum、cron、mount、service、user、file 等)、YAML 与 playbook、变量、template 模板以及 roles 角色等内容。
一、运维自动化概述
运维发展经历了三个阶段:
- 靠纯手工、重复地进行软件部署和运维。
- 通过编写脚本方便地进行软件部署和运维。
- 借助第三方工具高效、方便地进行软件部署和运维。
运维自动化就是把零碎的工作集中化,把复杂的工作简单有序化,把流程规范化,最大化地解放生产力,也就是解放运维人员。自动化针对的范围大致可分为安装自动化、部署自动化、监控自动化等。
常见运维自动化工具:
| 安装自动化 | 部署自动化 | 监控自动化 |
|---|---|---|
| kickstart | ansible | Nagios |
| cobbler | ControlTier | Cacti |
| OpenQRM | Func | Zabbix |
| Spacewalk | Puppet | Zenoss Core |
注:原文中的 “Catci” 应为 “Cacti”。
二、Ansible 架构与准备工作
架构特点
Ansible 基于 SSH 协议管理被管机器,无需在被管节点安装 Agent,管理端通过 SSH 连接并执行任务。
开始前准备
- 关闭防火墙和 SELinux。
- 绑定主机名。
- 绑定 hosts。
由于 Ansible 使用 SSH 协议,需要先在每台服务器之间设置好 SSH 等效性(密钥对登录)。
配置 SSH 密钥对登录
第一步:在管理机生成密钥对,全部回车即可:
ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Created directory '/root/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
......
第二步:将公钥写入需要管理的服务器:
ssh-copy-id -i ~/.ssh/id_rsa.pub -p 22 root@3.3.3.9
安装 Ansible
yum -y install ansible
安装完成后查看配置目录:
ll /etc/ansible
总用量 24
-rw-r--r-- 1 root root 19179 1月 30 2018 ansible.cfg
-rw-r--r-- 1 root root 1016 1月 30 2018 hosts
drwxr-xr-x 2 root root 6 1月 30 2018 roles
| 文件/目录 | 作用 |
|---|---|
ansible.cfg |
Ansible 主配置文件 |
hosts |
存放被管理机器列表(inventory) |
roles |
存放 Ansible 的角色(任务文件) |
三、Inventory 主机清单
编辑 /etc/ansible/hosts,指定需要被管理的服务器,并使用组名进行分类:
[client] # 指定服务器群组,下面的 IP 即为该群组的所有成员
3.3.3.9
3.3.3.10
[webserver] # 群组可以有多个
3.3.3.11
3.3.3.12
使用 ansible 命令对指定组或所有主机执行 ping 测试:
ansible client -m ping # client 表示只查看这个群组里的主机,all 表示所有
node2.com | SUCCESS => {
"changed": false,
"ping": "pong"
}
node3.com | SUCCESS => {
"changed": false,
"ping": "pong"
}
四、Ansible 常用模块
查看模块帮助:
ansible-doc -l # 列出 Ansible 支持的模块
ansible-doc ping # 查看 ping 模块帮助信息
1. command 模块
command 是 Ansible 的默认模块,支持所有远程权限范围内的命令,不支持管道。
ansible client -m command -a 'free -m'
node3.com | SUCCESS | rc=0 >>
total used free shared buff/cache available
Mem: 976 613 68 4 294 162
Swap: 1999 225 1774
2. shell 模块
与 command 类似,但支持管道符号。
ansible client -m shell -a 'cat /etc/passwd|head -1'
node2.com | SUCCESS | rc=0 >>
root:x:0:0:root:/root:/bin/bash
3. script 模块
在被管理机器上执行管理机器上的脚本,相当于先 scp 再 sh。
ansible client -m script -a '/root/test.sh'
node3.com | SUCCESS => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to node3.com closed.\r\n",
"stdout": "test\r\n",
"stdout_lines": [
"test"
]
}
4. copy 模块
从管理机器拷贝文件到被管理机器,类似 scp。
ansible client -m copy -a 'src=/root/test.sh dest=/root/ owner=root group=root mode=0755'
| 参数 | 说明 |
|---|---|
src |
指定管理机器上的文件路径 |
dest |
传过去后存放在被管理机器的目录 |
owner |
传过去后文件所有者 |
group |
传过去后文件所属组 |
mode |
传过去后文件的权限 |
5. stat 模块
获取被管理机器上文件的状态信息(atime、ctime、mtime、md5、uid、gid 等)。
ansible client -m stat -a 'path=/etc/passwd'
| 参数 | 说明 |
|---|---|
path |
指定要查看的文件路径 |
6. get_url 模块
让被管理机器下载指定 URL 内容到指定文件内。
ansible client -m get_url -a 'url=http://www.baidu.com dest=/index.html mode=0440 force=yes'
| 参数 | 说明 |
|---|---|
url |
指定要下载的 URL |
dest |
指定下载到哪里 |
mode |
指定下载后文件权限 |
force |
是否强制覆盖 |
原文中对
force的说明为“是否强行对齐代码”,语义不明,此处按模块通用含义修正为“是否强制覆盖”。
7. yum 模块
管理被管理机器上的 RPM 包。
ansible client -m yum -a 'name=nmap'
| 参数 | 说明 |
|---|---|
name |
指定要安装的 RPM 包名称 |
8. cron 模块
修改被管理机的 crontab 任务。
ansible client -m cron -a "name='check dirs' hour='5,2' job='ls -alh > /dev/null'"
| 参数 | 说明 |
|---|---|
name |
指定定时任务名称(加备注) |
hour |
指定定时任务周期 |
job |
指定任务内容(minute、hour、day、month、weekday) |
创建后在被管理机上查看:
crontab -l
#Ansible: check dirs
* 5,2 * * * ls -alh > /dev/null
9. mount 模块
实现被管理机的分区挂载(添加至 /etc/fstab 文件)。
ansible client -m mount -a 'name=/yum src=/dev/sdb1 fstype=ext4 opts=ro state=present'
| 参数 | 说明 |
|---|---|
name |
指定挂载目录 |
src |
指定挂载源 |
fstype |
指定挂载源的文件系统类型 |
opts |
指定挂载后的权限 |
state |
指定状态,取值见下表 |
state 取值:
| 取值 | 说明 |
|---|---|
present |
只修改 fstab 文件内容,不做挂载操作 |
absent |
取消挂载,并将挂载目录删除,还会删除 fstab 文件中对应内容 |
unmounted |
取消当前挂载的内容,而不修改 fstab 文件内容 |
mounted |
如果指定的挂载点没有挂载,则挂载,且将会写入 fstab 文件 |
10. service 模块
管理被管理机器上的服务(启动、停止、重启等)。
ansible client -m service -a "name=nginx state=stopped" # 停止 nginx
ansible client -m service -a "name=nginx state=started" # 启动 nginx
ansible client -m service -a "name=nginx state=restarted" # 重启 nginx
ansible client -m service -a "name=nginx state=reloaded" # 重载 nginx
| 参数 | 说明 |
|---|---|
name |
指定服务名 |
state |
指定需要执行的操作 |
原文将
state=reloaded注释为“查看 nginx 状态”,实际为重载配置,这里按模块真实含义修正。
11. user 模块
管理被管理机器上的用户。
ansible client -m user -a "name=ninmu shell=/bin/sh home=/home/munin group=8888 uid=8888 comment='user ninmu'"
创建后在 /etc/passwd 中格式如下:
ninmu:x:8888:1000:user ninmu:/home/munin:/bin/sh
| 参数 | 说明 |
|---|---|
name |
指定用户名 |
shell |
指定 shell 类型 |
home |
指定用户家目录 |
group |
指定用户所属组(前提是指定的组已经存在) |
uid |
指定用户 uid |
comment |
指定用户描述项 |
remove |
删除用户时是否删除家目录(remove=yes) |
state |
指定状态,absent 表示删除用户 |
删除用户示例:
ansible client -m user -a 'name=ninmu state=absent remove=yes'
12. file 模块
管理被管理机器上的文件和目录(创建、删除等)。
创建目录:
ansible client -m file -a 'name=/data mode=644 state=directory'
创建普通文件:
ansible client -m file -a 'name=/data/test.txt mode=777 state=touch'
删除文件或目录:
ansible client -m file -a 'name=/data/abc state=absent'
创建软链接:
ansible client -m file -a 'name=/data/test.txt dest=/root/test state=link'
| 参数 | 说明 |
|---|---|
name |
指定目录或文件名 |
mode |
指定创建后文件或目录的权限 |
dest |
指定目标路径 |
owner |
指定所属用户 |
group |
指定所属组 |
state |
指定类型:directory、touch、absent、link |
state 取值:
| 取值 | 说明 |
|---|---|
directory |
如果目录不存在则创建该目录 |
touch |
创建普通文件 |
absent |
删除文件或目录 |
link |
创建软链接 |
更多模块请查阅官方文档。
五、YAML 语法与 Playbook
YAML 文件是 playbook 使用的配置管理语言。
一定要注意缩进:playbook 中不同级别间要严格缩进,多一个或少一个空格都会导致脚本无法执行;缩进不能使用 Tab 键。
Ansible 基本目录结构
.
├── ansible.cfg # ansible 主配置文件
├── hosts # 存放被管理机器列表
└── roles # 存放 ansible 的角色
├── files # 存放要推送到被管理机器上的文件,调用该目录文件无需加路径
├── tasks # 存放 yml 执行文件
├── templates # 存放可变文件(内部包含变量)
└── vars # 存放定义变量的文件
YAML 变量格式
键值对(普通变量):
key: value
name: user1
冒号与 value 之间必须有一个空格。
列表:
name:
- user1
- user2
- user3
-与每个 value 之间必须有一个空格。
字典:
name: zhangsan
shell: /bin/bash
home: /home/abc
也可以写成一行:
{name: zhangsan, shell: /bin/bash, home: /home/abc}
六、变量的种类与使用
Ansible 的变量分为几种:
- 写入
vars目录的变量(全局变量)。 - 使用
vars:直接写入动作脚本的变量(局部变量)。 - 使用
with_items:直接写入动作脚本的迭代变量。
1. vars 目录中的全局变量
写入 vars 目录内文件中的变量可理解为全局变量,任何动作脚本都可以调用,格式为 key: values:
vim /etc/ansible/vars/test.yml
user: test
ip: 3.3.3.3
dir: /etc/ansible
2. playbook 内 vars 定义的局部变量
直接定义在动作脚本内的变量为局部变量,仅在当前文件内有效。
vim test.yml
---
- hosts: client
remote_user: root
vars: # 定义变量
user1: test1
user2: test2
tasks:
- name: add user1
user: name={{ user1 }} # 调用变量 user1
- name: add user2
user: name={{ user2 }} # 调用变量 user2
3. vars 目录全局变量实战
创建测试工作路径:
mkdir roles/test/{vars,templates,files,tasks}
cd roles/
创建变量文件,将所有需要的变量写入:
vim test/vars/main.yml
name: testuser
sh: /bin/sh
home: /home/abc
uid: 8888
创建动作文件(名称若不是 main.yml,执行时需要手动指定):
vim test/tasks/main.yml
- name: add server user
user:
name: "{{ name }}" # 直接调用 vars 目录 main.yml 中的变量
shell: "{{ sh }}"
home: "{{ home }}"
uid: "{{ uid }}"
在工作目录创建入口 playbook:
vim adduser.yml
---
- hosts: client
remote_user: root
roles:
- test
执行 playbook:
ansible-playbook adduser.yml
完成后到被管理机检查:
cat /etc/passwd|tail -1
testuser:x:8888:8888::/home/abc:/bin/sh
目录结构关系:
.
├── adduser.yml
└── test
├── files
├── tasks
│ └── main.yml
├── templates
└── vars
└── main.yml
4. with_items 迭代变量
with_items 定义的可迭代变量,调用时会自动从上至下依次使用所有值。
例 1:迭代简单列表
vim /etc/ansible/useradd.yml
---
- hosts: client
remote_user: root
tasks:
- name: add several users
user: name={{ item }} state=present groups=wheel
with_items:
- testuser1
- testuser2
原文示例中
tasks:关键字缺失,已按 playbook 规范补全。
例 2:with_items 中的元素还可以是 hash(字典):
vim useradd.yml
---
- hosts: client
remote_user: root
tasks:
- name: add users
user: name={{ item.name }} shell={{ item.sh }}
with_items:
- { name: 'test5', sh: '/bin/sh' }
- { name: 'test6', sh: '/bin/nologin' }
简单实战练习
- 在被管理机器上批量添加用户。
- 在被管理机器上批量删除用户。
- 在被管理机器上批量安装 httpd 服务并启动。
对应脚本文件名参考:
cat add_user.yml
cat del_user.yml
YAML 语法可通过在线工具校验:
http://www.yamllint.com/。
七、template 模板模块
template 模块类似于 copy 模块,但会自动判断文件是否存在:如果目标文件存在且内容一致则不拷贝;同时可以在拷贝过程中使用 vars 中设置的变量。
目录结构:
.
├── test
│ ├── files
│ ├── tasks
│ │ └── main.yml
│ ├── templates
│ │ └── test.j2
│ └── vars
│ └── main.yml
└── test.yml
定义变量文件 roles/test/vars/main.yml:
user: zhangsan
pass: 123
可变模板文件 roles/test/templates/test.j2(文件名随意,扩展名通常为 .j2,其中引用了两个变量):
username={{ user }}
password={{ pass }}
入口 playbook work_dir/test.yml:
- hosts: client
remote_user: root
roles:
- test
动作文件 roles/test/tasks/main.yml:
- name: copy configfile to nodes
template:
src: test.j2 # 源文件
dest: /tmp/test.conf # 目标地址及目标文件名称
执行 playbook:
ansible-playbook work_dir/test.yml
查看结果:
ansible client -m shell -a 'cat /tmp/test.conf'
3.3.3.5 | SUCCESS | rc=0 >>
username=zhangsan
password=123
3.3.3.4 | SUCCESS | rc=0 >>
username=zhangsan
password=123
八、roles 角色实战练习
练习 1:使用 Ansible 批量安装 MariaDB
要求:
- 将数据目录指定为
/data/mysql。 - 将默认监听端口修改为
3307。 - 修改完成后启动 MariaDB。
参考目录结构:
.
├── ansible.cfg
├── hosts
├── roles
│ ├── del_mariadb
│ │ ├── tasks
│ │ │ └── main.yml
│ │ └── vars
│ │ └── main.yml
│ └── install_mariadb
│ ├── files
│ ├── install_mariadb.yml
│ ├── tasks
│ │ └── main.yml
│ ├── templates
│ │ └── my.cnf
│ └── vars
│ └── main.yml
└── work_dir
├── del_mariadb.yml
└── install_mariadb.yml
配套素材:in_mariadb.tar.gz。
练习 2:批量部署二进制版本 MySQL
要求:先使用 MariaDB 角色批量卸载被管理机器上的 MariaDB,然后批量部署二进制版本的 MySQL,版本不限。
配套素材:in_mysql.tar.gz。
此处评论已关闭