ansible剧本
文章目录
- ansible剧本
-
- [Shell vs Ansible](#Shell vs Ansible)
- ansible-playbook命令
- 测试与调试
- 简单案例
- 变量类型
-
- [1. 字符串(String)](#1. 字符串(String))
- [2. 数字(Number)](#2. 数字(Number))
- [3. 布尔值(Boolean)](#3. 布尔值(Boolean))
- [4. 列表(List,又称数组)](#4. 列表(List,又称数组))
- [5. 字典(Dictionary,又称哈希 Hash)](#5. 字典(Dictionary,又称哈希 Hash))
- [6. 空值(Null)](#6. 空值(Null))
- 定义变量
- 判断(when)
- 循环
- jinja2模板
-
- 判断
- 循环
- 动态渲染(template)
- [temple vs copy](#temple vs copy)
Ansible Playbook(剧本)是 Ansible 实现自动化的核心载体,它用 YAML 格式 编写,用于描述一系列需要在远程主机上执行的任务(如安装软件、配置文件、启动服务等)。通过 Playbook,你可以将零散的操作标准化、流程化,实现批量主机的自动化管理。
Playbook 核心结构
一个基本的 Playbook 由一个或多个 Play 组成,每个 Play 定义了 "在哪些主机上执行哪些任务"。每个 Play 包含以下核心部分:
| 组成部分 | 作用 |
|---|---|
hosts |
指定目标主机或主机组(来自 inventory 清单) |
tasks |
任务列表,每个任务通过 Ansible 模块(如 yum、copy)执行具体操作 |
become |
是否提权(yes 表示用 sudo 切换到 root,执行需要权限的操作) |
vars |
定义变量(用于任务中动态传递参数) |
handlers |
触发器(任务执行后需要触发的操作,如修改配置后重启服务) |
roles |
引用角色(结构化的任务集合,适合复杂场景) |
Shell vs Ansible
| Shell脚本 | Ansible | |
|---|---|---|
| 执行效率 | 串线执行 | 并行(控制并发) 通过-f或修改配置文件 |
| 应用场景 | 服务管理脚本 | 配置管理,部署/升级服务 |
| 幂等性 | 重复运行相同脚本容易有故障(用户存在,目录存在...) 幂等性不好. | 重复运行一般没什么问题.幂等性好 |
| 灵活性 | 更加灵活 | 判断,循环不是很方便. |
| 应用建议 | 批量检查ping,curl/wget.巡检脚本.复杂逻辑判断,循环,函数... | 部署类服务,配置管理,简单编译安装,复杂操作可以ans+shell |
幂等性:重复执行剧本/脚本对环境的影响
ansible-playbook命令
基础参数
| 选项 | 长选项 | 说明 | 示例 |
|---|---|---|---|
-i <路径> |
--inventory <路径> |
指定主机清单(inventory)路径,默认使用 /etc/ansible/hosts |
ansible-playbook -i ./my_hosts.yml site.yml # 用自定义主机清单 |
-u <用户> |
--user <用户> |
指定远程主机执行任务的用户名(默认用当前本地用户) | ansible-playbook -u appuser site.yml # 以 appuser 身份执行 |
-K |
--ask-become-pass |
手动输入提权(sudo)密码(任务需要 root 权限时使用) | ansible-playbook -K site.yml # 提示输入 sudo 密码 |
-f <数字> |
--forks <数字> |
设置并发执行的进程数(默认 5,数值越大执行越快,受主机性能限制) | ansible-playbook -f 20 site.yml # 20 个并发进程执行(适合批量主机) |
-l <模式> |
--limit <模式> |
限制执行的主机 / 主机组,支持通配符(*)、列表(,分隔) |
ansible-playbook -l web01 site.yml # 仅在 web01 执行ansible-playbook -l 'web*,db01' site.yml # 匹配 web 开头和 db01 |
测试与调试
| 选项 | 长选项 | 说明 | 示例 |
|---|---|---|---|
-C |
--check |
检查模式(Dry Run):仅模拟执行,显示会发生的变更(不实际修改系统) | ansible-playbook -C site.yml # 预览执行后会修改的内容 |
--diff |
与 -C 配合,显示文件内容的具体差异(如 copy/template 模块的修改) |
ansible-playbook -C --diff site.yml # 预览文件修改的具体行(新增 / 删除) |
|
--syntax-check |
仅检查剧本语法是否正确(不执行任务,快速排查缩进、拼写错误) | ansible-playbook --syntax-check site.yml # 验证 YAML 语法是否正确 |
|
-v 至 -vvvv |
--verbose |
详细输出模式:级别越高信息越全(-v 基础,-vvvv 含 SSH 调试) |
ansible-playbook -vvv site.yml # 显示模块调用细节(适合调试) |
-q |
--quiet |
静默模式:仅输出错误信息(忽略正常日志,减少干扰) | ansible-playbook -q site.yml # 只关注执行错误 |
指定任务开始执行
命令格式
bash
ansible-playbook 你的playbook.yml --start-at-task "任务名称"
- 查看任务名称
bash
ansible-playbook -i hosts --list-task install_nginx.yaml
- --step分别执行
bash
ansible-playbook site.yml --step "2.生成nginx配置文件"
tags标签
在 Ansible 中,tags 是用于标记任务(或 play、role 等)的标签机制,允许你在执行 playbook 时只运行特定的任务(或跳过指定任务),而无需执行整个 playbook,尤其适合大型 playbook 的部分更新或测试场景。
如何定义 tags
tags 可以直接在任务(task)、play、include/import 语句、role 等中定义,格式为 tags: 标签名 或 tags: [标签1, 标签2](多个标签)。
- 任务级 tags(最常用)
yaml
- name: 安装Nginx
yum:
name: nginx
state: present
tags: # 单个标签
- install
- nginx_install # 多个标签(任务可被多个标签标记)
- name: 配置Nginx
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
tags:
- config
- nginx_config
- name: 启动Nginx服务
service:
name: nginx
state: started
enabled: yes
tags:
- start
- nginx_start
- play 级 tags
在 play 中定义标签,会自动应用到该 play 中的所有任务(相当于给所有任务统一加标签):
yaml
- hosts: webservers
tags: web # 该play中所有任务都会继承"web"标签
tasks:
- name: 安装httpd
yum: name=httpd state=present # 自动带有"web"标签
- name: 启动httpd
service: name=httpd state=started # 自动带有"web"标签
- role 级 tags
在引用 role 时添加标签,该标签会应用到 role 中的所有任务:
yaml
- hosts: dbservers
roles:
- role: mysql
tags: db # mysql角色中的所有任务都会带有"db"标签
使用tags
-t 只运行标记了指定标签的任务
bash
ansible-playbook nginx.yml -t "install"
- 运行多个标签
bash
ansible-playbook nginx.yml -t "install,config"
--skip-tags 跳过指定标签的任务
bash
ansible-playbook nginx.yml --skip-tags "start"
- 查看标签
bash
ansible-playbook -i hosts install_tomcat.yaml --list-task
retry功能
在 Ansible 中,当 playbook 执行时部分主机失败,下次执行时可以通过retry 文件 结合--limit参数,仅在失败的主机上重新执行任务,具体步骤如下:
- 理解 retry 文件的作用
Ansible 在 playbook 执行过程中,如果有主机任务失败,会自动在当前目录生成一个retry 文件 ,默认文件名格式为[playbook名称].retry(例如site.yml执行失败后生成site.retry)。
该文件中会记录所有执行失败的主机列表(每行一个主机),例如:
plaintext
webserver1
dbserver3
- 下次执行时指定失败主机
下次执行 playbook 时,通过--limit @/路径/到/retry文件参数,即可让 Ansible 仅在 retry 文件记录的失败主机上执行任务。
示例:
假设 playbook 名为deploy.yml,失败后生成deploy.retry,则执行以下命令:
bash
ansible-playbook deploy.yml --limit @deploy.retry
这样,任务只会在deploy.retry中记录的失败主机上运行,避免重复执行成功的主机。
- 开启retry
bash
cat /etc/ansible/ansible.cfg | grep retry
retry_files_enabled = yes # 启用retry文件生成(默认yes,可省略)
retry_files_save_path = /server/ansible/ans-retry/ # 自定义retry文件保存路径
ignore_errors(错误继续执行)
ignore_errors : yes
简单案例
注意事项:
- 对齐,空格2个,禁止使用tab键
- yaml或yml结尾
yaml
- hosts: all
tasks:
- name: 01.打开冰箱门
shell: echo 01.open >/tmp/lidao.txt
- name: 02.大象放进去
shell: echo 02.put >>/tmp/lidao.txt
- name: 03.关门
shell: echo 03.close >>/tmp/lidao.txt
执行
bash
ansible-playbook -i hosts -l data 00.test.yaml
部署tomcat
bash
[root@m01 /server/ansible]# tree /root/ansible/
/root/ansible/
├── nginx
│ ├── bird.conf
│ └── bird.tar.gz
└── tomcat
├── apache-tomcat-9.0.111.tar.gz
└── tomcat.service
- yaml文件
yaml
#tomcat安装剧本
- hosts: data
tasks:
- name: 1.安装openjdk
yum:
name: java-11-openjdk
state: present
- name: 2.创建目录
file:
path: /app/tools/
state: directory
- name: 3.分发tomcat压缩包
unarchive:
src: /root/ansible/tomcat/apache-tomcat-9.0.111.tar.gz
dest: /app/tools/
remote_src: no
- name: 4.软连接
file:
src: /app/tools/apache-tomcat-9.0.111
dest: /app/tools/tomcat
state: link
- name: 5.分发systemctl文件
copy:
src: /root/ansible/tomcat/tomcat.service
dest: /usr/lib/systemd/system/tomcat.service
backup: yes
- name: 6.启动服务
systemd:
name: tomcat
state: started
enabled: yes
daemon_reload: yes
执行
bash
ansible-playbook -i hosts -l data -f 20 install_tomcat.yaml
部署nginx
bash
[root@m01 /server/ansible]# tree /root/ansible/
/root/ansible/
├── nginx
│ ├── bird.conf
│ └── bird.tar.gz
└── tomcat
├── apache-tomcat-9.0.111.tar.gz
└── tomcat.service
- yaml文件
bash
#nginx安装剧本
- hosts: data
vars:
- username: www-ans
- uid: 2000
tasks:
- name: 1.配置yum源
yum_repository:
name: nginx
description: Nginx Official Repository
baseurl: http://nginx.org/packages/centos/8/$basearch/
enabled: yes
gpgcheck: no
- name: 2.安装nginx
yum:
name: nginx
state: present
- name: 3.配置nginx
lineinfile:
path: /etc/nginx/nginx.conf
regexp: "^user.*"
line: "user {{ username }};"
backup: yes
- name: 3.1配置nginx子配置文件(copy)
copy:
src: /root/ansible/nginx/bird.conf
dest: /etc/nginx/conf.d/
- name: 4.添加用户组 gid www-ans
group:
name: "{{username}}"
gid: "{{uid}}"
state: present
- name: 5.添加用户 uid www-ans
user:
name: "{{username}}"
uid: "{{uid}}"
group: "{{username}}"
shell: /sbin/nologin
create_home: no
state: present
- name: 6.创建站点目录
file:
path: /app/code/bird/
state: directory
- name: 7.分发bird.tar.gz
unarchive:
src: /root/ansible/nginx/bird.tar.gz
dest: /app/code/bird/
- name: 启动nginx
systemd:
name: nginx
state: restarted
enabled: yes
批量修改密码剧本
yaml
- hosts: data
vars:
- username: lidao
- password: "Lidao666"
tasks:
- name: echo 输出变量
debug:
msg: "用户名字:{{ username }} 密码:{{ password }} "
- name: 更新指定用户的密码
user:
name: "{{ username }}"
password: "{{ password | password_hash('sha512','lidaowdmwof') }}"
state: present
部署nfs
- 变量文件
bash
[root@m01 /server/ansible]# cat group_vars/nfs/vars.yaml
gx_dir: /nfsdata/
username: www-nfs
uid_gid: 1999
uid: 1999
- 部署nfs
bash
#部署nfs,lsync
- hosts: nfs
tasks:
- name: 1.安装rpcbind,nfs-utils
yum:
name:
- rpcbind
- nfs-utils
state: present
- name: 2.启动服务rpcbind,nfs
systemd:
name: "{{ item }}"
state: started
enabled: yes
loop:
- rpcbind
- nfs
- name: 3.配置exports
lineinfile:
path: /etc/exports
line: "{{gx_dir}} 172.16.1.0/24(rw,all_squash,anonuid={{ uid }},anongid={{uid_gid}})"
backup: yes
- name: 3.5 用户组
group:
name: "{{ username }}"
gid: "{{ uid_gid }}"
state: present
- name: 3.6 用户
user:
name: "{{ username }}"
uid: "{{ uid }}"
group: "{{ username }}"
shell: /sbin/nologin
create_home: no
state: present
- name: 4.创建共享目录,并修改所有者
file:
path: "{{gx_dir}}"
state: directory
owner: "{{ username }}"
group: "{{ username }}"
recurse: yes
- name: 5.重新加载nfs
systemd:
name: nfs
state: reloaded
二进制安装mysql8.4
- 需要准备的文件
bash
[root@m01 ~]# tree ansible/
ansible/
├── mysql
│ ├── my.cnf
│ ├── mysql-8.4.6-linux-glibc2.28-x86_64.tar.xz
│ └── mysql.service
#my.cnf
[mysqld]
user=mysql
basedir=/app/tools/mysql/
datadir=/app/data/3306/
port=3306
socket=/tmp/mysql.sock
[client]
socket=/tmp/mysql.sock
#mysql.service
[Unit]
Description=MySQL Server
Documentation=man:mysqld(8)
Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
After=network.target
After=syslog.target
[Install]
WantedBy=multi-user.target
[Service]
User=mysql
Group=mysql
Type=notify
TimeoutSec=0
OOMScoreAdjust=-1000
ExecStart=/app/tools/mysql/bin/mysqld --defaults-file=/etc/my.cnf $MYSQLD_OPTS
EnvironmentFile=-/etc/sysconfig/mysql
LimitNOFILE = 65536
Restart=on-failure
RestartPreventExitStatus=1
Environment=MYSQLD_PARENT_PID=1
PrivateTmp=false
- yaml
yaml
#部署mysql
- hosts: lx
tasks:
- name: 0.创建虚拟用户
user:
name: mysql
shell: /sbin/nologin
create_home: no
- name: 1.创建目录
file:
name: "{{ item }}"
state: directory
loop:
- /app/tools/
- /app/data/3306/
- name: 2.传输并解压软件包()
unarchive:
src: /root/ansible/mysql/mysql-8.4.6-linux-glibc2.28-x86_64.tar.xz
dest: /app/tools/
tags: jieya
- name: 3.设置软连接
file:
src: /app/tools/mysql-8.4.6-linux-glibc2.28-x86_64
dest: /app/tools/mysql
state: link
owner: mysql
group: mysql
- name: 4.下载依赖
yum:
name: "{{ item }}"
state: present
loop:
- ncurses
- ncurses-devel
- libaio
- libaio-devel
- openssl
- openssl-devel
- openssh
tags: install
- name: 5.传输配置文件my.cnf(copy)
copy:
src: /root/ansible/mysql/my.cnf
dest: /etc/my.cnf
owner: mysql
group: mysql
- name: 6.设置所有者
file:
path: /app/data/3306
state: directory
owner: mysql
group: mysql
recurse: yes
- name: 8.数据库初始化
shell: |
/app/tools/mysql/bin/mysqld --initialize-insecure --user=mysql \
--basedir=/app/tools/mysql/ --datadir=/app/data/3306/
- name: 9.传输mysql.service(copy)
copy:
src: /root/ansible/mysql/mysql.service
dest: /usr/lib/systemd/system/mysql.service
- name: 10.启动服务并设置开机自启
systemd:
name: mysql
state: started
enabled: yes
daemon_reload: yes
部署rsync,lsyncd
- 配置文件
bash
[root@m01 ~]# tree ansible/
ansible/
├── backup
│ └── rsyncd.conf
├── mysql
│ ├── my.cnf
│ ├── mysql-8.4.6-linux-glibc2.28-x86_64.tar.xz
│ └── mysql.service
├── nfs
│ └── lsyncd.conf
├── nginx
│ ├── bird.conf
│ └── bird.tar.gz
└── tomcat
├── apache-tomcat-9.0.111.tar.gz
└── tomcat.service
#backup
rsyncd.conf
# See rsyncd.conf man page for more options.
# configuration example:
fake super = yes
uid = rsync
gid = rsync
use chroot = no
max connections = 2000
timeout = 600
pid file = /var/run/rsyncd.pid
lock file = /var/run/rsync.lock
log file = /var/log/rsyncd.log
ignore errors
read only = false
list = false
hosts allow = 10.0.0.0/24 172.16.1.0/24 60.205.236.0/24
#hosts deny = 0.0.0.0/24
auth users = rsync_backup
secrets file = /etc/rsync.password
####################################
[backup]
path = /backup
comment = www by shf
[blog]
path = /nfs/backup/blog/
comment = www by shf
nfs
#nfs
[root@m01 ~/ansible/nfs]# cat lsyncd.conf
settings {
logfile = "/var/log/lsyncd.log",
pidfile = "/var/run/lsyncd.pid",
statusFile = "/var/log/lsyncd.status",
nodaemon = true,
maxProcesses = 2
}
sync {
default.rsync,
source = "/nfs/blog/",
target = "rsync_backup@172.16.1.41::blog",
delay = 5,
delete = true,
rsync = {
binary = "/usr/bin/rsync",
archive = true,
compress = true,
password_file = "/etc/rsync.client"
}
}
- yaml
yaml
#部署rsync
- hosts: backup
tasks:
- name: 1.安装rsync
yum:
name: rsync
state: present
- name: 2.传输配置文件(copy)
copy:
src: /root/ansible/backup/rsyncd.conf
dest: /etc/rsyncd.conf
backup: yes
- name: 3.启动服务并设置开机自启
systemd:
name: rsyncd
state: restarted
enabled: yes
- name: 4.创建用户rsync
user:
name: rsync
shell: /sbin/nologin
create_home: no
- name: 5.创建密码文件并修改权限
file:
path: /etc/rsync.password
state: touch
mode: 0600
- name: 6.添加内容(lineinfile)
lineinfile:
path: /etc/rsync.password
line: rsync_backup:123
- name: 7.创建目录并设置所有者rsync
file:
path: /nfs/backup/blog/
state: directory
owner: rsync
group: rsync
#部署lsync
- hosts: nfs
tasks:
- name: 1.安装lsync
yum:
name: lsyncd
state: present
- name: 2.传输配置文件
copy:
src: /root/ansible/nfs/lsyncd.conf
dest: /etc/lsyncd.conf
backup: yes
- name: 3.启动服务并设置开机自启
systemd:
name: lsyncd
state: restarted
enabled: yes
- name: 4.创建密码文件
file:
path: /etc/rsync.client
state: touch
mode: 0600
- name: 5.添加内容
lineinfile:
path: /etc/rsync.client
line: 123
变量类型
在 Ansible 中,变量的类型与常见编程语言类似,但其定义和使用需遵循 YAML 语法规范(因为 Ansible 的 playbook、变量文件等主要基于 YAML 格式)。理解变量类型是编写灵活 playbook 的基础,常见的变量类型如下:
| 变量类型 | 定义方式 | 说明 |
|---|---|---|
| 字符串(String) | 可加单引号(')、双引号("),或不加引号(无特殊字符时) |
含特殊字符(如:、空格)时需用引号包裹,避免 YAML 解析错误;加引号的字符串会被原样解析。 |
| 数字(Number) | 直接写数值(整数 / 浮点数),不加引号(加引号会视为字符串) | 支持算术运算(如{``{ port + 100 }});整数和浮点数可直接参与计算。 |
| 布尔值(Boolean) | 用true/false(小写)或yes/no(Ansible 推荐,更直观) |
大小写敏感,True/False会被视为字符串;yes与true等价,no与false等价。 |
| 列表(List) | 多行:用-开头,元素分行;单行:用[]包裹,元素用逗号分隔 |
有序集合,可通过索引访问(如{``{ ports[0] }}),支持loop循环遍历。 |
| 字典(Dictionary) | 多行:key: value格式,键值对缩进对齐;单行:用{}包裹,key:value用逗号分隔 |
键值对集合,支持嵌套(如字典包含列表 / 其他字典),通过key访问值(如{``{ server.ip }})。 |
| 空值(Null) | 用null(小写)或~(YAML 简写)表示 |
表示 "无值" 或 "未定义",常用于默认值或占位符场景。 |
1. 字符串(String)
最常用的类型,用于表示文本内容。
-
定义:可加单引号(
')、双引号("),或不加引号(但建议加引号避免 YAML 语法歧义)。 -
示例:
yamlname: "webserver" # 双引号 hostname: 'db-01' # 单引号 message: hello world # 不加引号(无特殊字符时) -
说明:若字符串包含特殊字符(如冒号
:、空格、换行),建议用引号包裹,避免 YAML 解析错误。
2. 数字(Number)
包括整数(int)和浮点数(float),用于数值计算或配置。
-
定义:直接写数值,无需引号(加引号会被视为字符串)。
-
示例:
yamlport: 8080 # 整数 memory: 4096 # 单位MB(整数) cpu_usage: 75.5 # 浮点数(百分比) timeout: 30 # 超时时间(秒) -
说明:在 Ansible 中,数字可直接用于算术运算(如
{``{ port + 100 }})。
3. 布尔值(Boolean)
表示 "真" 或 "假",常用于条件判断(when语句)或开关配置。
-
定义:YAML 中支持
true/false(小写)或yes/no(Ansible 推荐,更直观)。 -
示例:
yamlenable_service: yes # 等同于true debug_mode: no # 等同于false is_master: true -
说明:注意大小写 ,YAML 不识别
True/False(大写),会被视为字符串;yes/no在 Ansible 中与true/false等价,推荐用yes/no更易读。
4. 列表(List,又称数组)
有序的元素集合,用于存储多个同类型值(如主机列表、端口列表)。
-
定义:用短横线(
-)开头,每个元素占一行;或用方括号([])简写为单行。 -
示例:
yaml# 多行写法(推荐,可读性高) web_ports: - 80 - 443 - 8080 # 单行简写 db_ips: [172.16.1.51, 172.16.1.52, 172.16.1.53] # 列表元素也可以是其他类型(如字符串、字典) users: - "alice" - "bob" - { name: "charlie", uid: 1003 } # 元素为字典 -
说明:可通过索引访问元素(如
{``{ web_ports[0] }}获取第一个元素80),或用loop循环遍历。
5. 字典(Dictionary,又称哈希 Hash)
键值对(key-value)集合,用于存储结构化数据(如主机配置、用户信息)。
-
定义:用
key: value格式,键值对缩进对齐;或用大括号({})简写为单行。 -
示例:
yaml# 多行写法(推荐) server: hostname: web-01 ip: 172.16.1.41 ports: - 80 - 443 enabled: yes # 单行简写 user: { name: "admin", uid: 1000, groups: ["wheel", "docker"] } -
说明:通过
key访问值(如{``{ server.hostname }}获取web-01),支持嵌套(字典中包含列表、其他字典)。
应用示例
yaml
- hosts: data
vars:
rsync_server:
ip: 172.16.1.41
user: rsync
dirs:
- '/tmp/shf/lidao'
- '/tmp/shf/oldboy'
- '/tmp/shf/lidao887'
- '/tmp/shf/oldboy007'
tasks:
- name: 0.创建用户
user:
name: "{{rsync_server.user}}"
state: present
- name: 1.批量创建目录
file:
path: "{{item}}"
state: directory
loop: "{{rsync_server.dirs}}"
- name: 2.ip_dir
file:
path: "/tmp/{{rsync_server.ip}}"
state: directory
6. 空值(Null)
表示 "无值" 或 "未定义",常用于默认值或占位符。
-
定义:用
null(小写)或~(YAML 简写)表示。 -
示例:
yamlbackup_path: null # 未指定备份路径 log_file: ~ # 等同于null,无日志文件
定义变量
| 变量设置方式 | 定义位置 / 方式 | 适用场景 | 优先级(从高到低) | 示例 |
|---|---|---|---|---|
| 命令行传递变量 | 执行 Playbook 时通过 -e 选项传递 |
临时覆盖变量(如动态修改端口、环境参数) | 1(最高) | ansible-playbook site.yml -e "nginx_port=9090 env=test" |
| Playbook 内直接定义 | Play 中通过 vars 关键字定义 |
Playbook 内部临时变量,供当前 Play 内任务复用 | 2 | yaml<br>- hosts: web<br> vars:<br> port: 80<br> tasks: ...<br> |
| 外部变量文件 | 独立 YAML 文件(如 vars.yml),通过 vars_files 引入 |
变量较多时,集中管理(如按环境拆分变量文件:dev_vars.yml、prod_vars.yml) |
3 | yaml<br>- hosts: web<br> vars_files:<br> - ./vars/dev.yml<br> |
| 角色私有变量 | 角色目录下 vars/main.yml |
角色内部固定逻辑(如默认安装路径),不希望被外部修改 | 4 | yaml<br># roles/nginx/vars/main.yml<br>install_path: /usr/local/nginx<br> |
| Inventory 主机变量 | Inventory 中具体主机下定义 | 针对单台主机的特殊配置(如不同主机的端口差异) | 5 | yaml<br># hosts.yml<br>webservers:<br> hosts:<br> web01: nginx_port: 80<br> web02: nginx_port: 8080<br> |
| Inventory 组变量 | Inventory 中主机组下通过 vars 定义 |
同一组主机的通用配置(如所有 web 服务器的根目录) | 6 | yaml<br># hosts.yml<br>webservers:<br> vars:<br> site_root: /var/www<br> hosts: ...<br> |
| 角色默认变量 | 角色目录下 defaults/main.yml |
角色对外暴露的可配置变量(默认值,可被外部覆盖) | 7(最低) | yaml<br># roles/nginx/defaults/main.yml<br>nginx_port: 80 # 可被 Playbook 覆盖<br> |
| Facts 变量(系统信息) | Ansible 自动收集(无需手动定义) | 引用远程主机的系统信息(如 IP、操作系统、内存) | 特殊(自动生成) | yaml<br>tasks:<br> - debug: msg="IP: {``{ ansible_default_ipv4.address }}"<br> |
命令行传递变量(-e)
yaml
#输出变量
- hosts: db
tasks:
- name: 输出
debug:
msg: "{{username}} {{password}}"
- hosts: backup
tasks:
- name: 输出
debug:
msg: "{{username}} {{password}}"
- hosts: nfs
tasks:
- name: 输出
debug:
msg: "{{username}} {{password}}"
- 执行命令,传递变量
bash
ansible-playbook 04.test_vars.yaml -e "username=lidao password=Lidao666"
playbook内直接定义(vars)
bash
[root@m01 /server/ansible]# cat 04.test_vars.yaml
- hosts: db
vars:
- username: song
- password: Ldiao666
tasks:
- name: 输出
debug:
msg: "用户:{{username}} 密码:{{password}}"
- hosts: backup
tasks:
- name: 输出
debug:
msg: "用户:{{username}} 密码:{{password}}"
- hosts: nfs
tasks:
- name: 输出
debug:
msg: "用户:{{username}} 密码:{{password}}"
注意:vars只在当前play部分使用
外部变量文件(vars_files)
- 创建变量文件
bash
[root@m01 /server/ansible]# cat vars/test.yaml
username: song
password: Lidao666
- playbook中引入对应文件
yaml
#输出变量
- hosts: db
vars_files:
- ./vars/test.yaml
tasks:
- name: 输出
debug:
msg: "用户:{{username}} 密码:{{password}}"
- hosts: backup
vars_files:
- ./vars/test.yaml
tasks:
- name: 输出
debug:
msg: "用户:{{username}} 密码:{{password}}"
- hosts: nfs
vars_files:
- ./vars/test.yaml
tasks:
- name: 输出
debug:
msg: "用户:{{username}} 密码:{{password}}"
注意使用vars_files
group_vars分组变量
bash
[root@m01 /server/ansible]# tree group_vars/
group_vars/
├── all
│ └── vars.yaml
└── data
└── vars.yaml
- 分组自动引用变量
yaml
[root@m01 /server/ansible]# cat 04.test_vars.yaml
#输出变量
- hosts: db
tasks:
- name: 输出
debug:
msg: "用户:{{username}} 密码:{{password}}"
- hosts: backup
tasks:
- name: 输出
debug:
msg: "用户:{{username}} 密码:{{password}}"
- hosts: nfs
tasks:
- name: 输出
debug:
msg: "用户:{{username}} 密码:{{password}}"
Facts变量(系统信息)
自动收集(默认开启)
Ansible 执行 Playbook 时,会在所有任务前自动运行 setup 模块收集 Facts,对应 Play 中的 gather_facts: yes(默认值):
yaml
- hosts: all
gather_facts: yes # 默认开启,可省略,no是关闭
tasks:
- name: 引用Facts变量
debug:
msg: "主机IP: {{ ansible_default_ipv4.address }}"
永久关闭
bash
[root@m01 ~]# cat /etc/ansible/ansible.cfg
[defaults]
host_key_checking = False
deprecation_warnings = False
interpreter_python=/usr/bin/python3
gathering = explicit #添加这一行
[inventory]
[privilege_escalation]
[paramiko_connection]
[ssh_connection]
[persistent_connection]
[accelerate]
[selinux]
[colors]
[diff]
常用Facts变量
网络信息
| 变量名 | 说明 | 示例值 |
|---|---|---|
ansible_default_ipv4.address |
默认 IPv4 地址(优先路由的 IP) | 10.0.0.11 |
ansible_default_ipv4.gateway |
默认网关 | 10.0.0.254 |
ansible_default_ipv4.interface |
默认网卡名称 | eth0 |
ansible_all_ipv4_addresses |
所有 IPv4 地址(列表) | ['10.0.0.11', '192.168.1.1'] |
系统信息
| 变量名 | 说明 | 示例值 |
|---|---|---|
ansible_os_family |
操作系统家族(简化分类) | RedHat(CentOS/Rocky)、Debian(Ubuntu) |
ansible_distribution |
具体操作系统名称 | CentOS、Ubuntu、Rocky |
ansible_distribution_version |
操作系统版本 | 7.9(CentOS)、20.04(Ubuntu) |
ansible_kernel |
内核版本 | 3.10.0-1160.el7.x86_64 |
ansible_hostname |
主机名 | web01 |
硬件信息
| 变量名 | 说明 | 示例值 |
|---|---|---|
ansible_processor_vcpus |
CPU 核心数 | 4 |
ansible_memtotal_mb |
总内存(MB) | 8192(8GB) |
ansible_memfree_mb |
空闲内存(MB) | 4096 |
ansible_devices.sda.size |
磁盘 sda 总大小 |
50.00 GB |
软件与服务信息
| 变量名 | 说明 | 示例值 |
|---|---|---|
ansible_pkg_mgr |
系统默认包管理器 | yum、dnf、apt |
ansible_service_mgr |
系统服务管理器 | systemd、upstart |
常用系统信息
bash
批量分发motd文件,显示指定的内容
主机名: {{ ansible_hostname }}
所有ip: {{ ansible_all_ipv4_addresses }}
内存总大小: {{ansible_memtotal_mb}}
系统发行版本: {{ansible_distribution}}
系统版本: {{ansible_distribution_major_version }}
cpu架构: {{ ansible_architecture }}
系统版本昵称: {{ ansible_distribution_release }}
第1块网卡的ip地址: {{ ansible_default_ipv4.address }}
如何查看Facts信息?
bash
# 查看单台主机的Facts(-m setup指定模块)
ansible nfs -m setup
示例: 分发模板
yaml
- hosts: data
gather_facts: yes
tasks:
- name: 输出
debug:
msg: |
主机名: {{ ansible_hostname }}
所有ip: {{ ansible_all_ipv4_addresses }}
内存总大小: {{ansible_memtotal_mb}}
系统发行版本: {{ansible_distribution}}
系统版本: {{ansible_distribution_major_version }}
cpu架构: {{ ansible_architecture }}
系统版本昵称: {{ ansible_distribution_release }}
第1块网卡的ip地址: {{ ansible_default_ipv4.address }}
- name: 分发模板
template:
src: ./motd.j2
dest: /etc/motd
自定义变量(register)
在 Ansible 中,register 并不是一个模块 ,而是一个关键字,用于将任务的执行结果(如命令输出、模块返回值等)捕获并保存到一个变量中,以便后续任务使用。它是实现 "根据前序任务结果执行后续操作" 的核心机制。
基本用法
yaml
- name: 执行一个任务并捕获结果
模块名:
模块参数...
register: 结果变量名 # 自定义变量名,如 result、cmd_out 等
常见字段
| 字段名 | 含义 |
|---|---|
stdout |
任务的标准输出(主要用于 shell/command 等命令类模块)。 |
stderr |
任务的错误输出(命令执行失败时的错误信息)。 |
rc |
返回码(0 表示成功,非 0 表示失败,常用于命令类模块判断执行结果)。 |
changed |
布尔值(true/false),表示任务是否修改了远程主机的状态。 |
failed |
布尔值,表示任务是否执行失败(true 为失败)。 |
stdout_lines |
将 stdout 按换行符分割成的列表(方便遍历多行输出)。 |
stderr_lines |
将 stderr 按换行符分割成的列表。 |
示例
- 捕获命令输出(
shell/command模块)
最常见的场景:执行命令后,用 register 保存输出,供后续使用。
yaml
- name: 示例:捕获命令输出
hosts: all
tasks:
- name: 执行 `df -h` 查看磁盘使用情况
ansible.builtin.shell: df -h
register: disk_usage # 保存结果到 disk_usage 变量
- name: 打印命令的标准输出
ansible.builtin.debug:
msg: "磁盘使用情况:\n{{ disk_usage.stdout }}" # 引用 stdout 字段
- name: 打印按行分割的输出(方便遍历)
ansible.builtin.debug:
var: disk_usage.stdout_lines # 按行分割的列表
- 根据命令返回码判断是否执行后续任务
通过 rc 字段(返回码)判断命令是否成功,结合 when 条件执行后续操作。
yaml
- name: 示例:根据返回码判断结果
hosts: all
tasks:
- name: 检查某个文件是否存在(用命令实现)
ansible.builtin.command: ls /etc/nginx/nginx.conf
register: file_check
ignore_errors: yes # 即使命令失败(文件不存在),也不中断 Playbook
- name: 若文件存在(rc=0),输出成功信息
ansible.builtin.debug:
msg: "Nginx 配置文件存在!"
when: file_check.rc == 0 # 仅当返回码为 0 时执行
- name: 若文件不存在(rc≠0),输出警告
ansible.builtin.debug:
msg: "警告:Nginx 配置文件不存在!"
when: file_check.rc != 0 # 仅当返回码非 0 时执行
- 捕获非命令模块的结果(如
stat模块)
register 不仅用于命令类模块,其他模块的结果也可捕获(如 stat 检查文件状态、package 安装软件等)。
yaml
- name: 示例:捕获 stat 模块的结果
hosts: all
tasks:
- name: 检查 /etc/passwd 文件状态
ansible.builtin.stat:
path: /etc/passwd
register: passwd_stat # 保存文件状态到变量
- name: 打印文件是否存在
ansible.builtin.debug:
msg: "/etc/passwd 存在:{{ passwd_stat.stat.exists }}" # exists 是 stat 模块的字段
- name: 打印文件权限
ansible.builtin.debug:
msg: "/etc/passwd 权限:{{ passwd_stat.stat.mode }}" # mode 字段表示权限
- 遍历命令的多行输出(
stdout_lines)
如果命令输出多行内容(如 ls /etc),可用 stdout_lines 结合循环遍历每一行。
yaml
- name: 示例:遍历多行输出
hosts: all
tasks:
- name: 列出 /etc 目录下的文件
ansible.builtin.command: ls /etc
register: etc_files
- name: 遍历每一行输出并打印
ansible.builtin.debug:
msg: "文件:{{ item }}"
loop: "{{ etc_files.stdout_lines }}" # 遍历 stdout_lines 列表
主机清单变量
bash
[root@m01 /server/ansible]# cat hosts
#主机清单文件 inventory
[lb]
172.16.1.5
172.16.1.6
[web]
172.16.1.9
172.16.1.10
[db]
172.16.1.51
172.16.1.52
[backup]
172.16.1.41 hostname=backup
[nfs]
172.16.1.31 hostname=nfs01
[ubt]
172.16.1.141
[lx]
172.16.1.211
[data:children]
nfs
backup
yaml
[root@m01 /server/ansible]# cat 11-change_hostname.yaml
- hosts: data
tasks:
- name: 修改主机名
hostname:
name: "{{hostname }}"
判断(when)
在 Ansible 中,when 是一个条件判断关键字 ,用于控制任务是否在目标主机上执行。只有当 when 后的条件表达式为 "真(true)" 时,任务才会运行;若为 "假(false)",任务会被跳过。
基本语法
yaml
- name: 只有满足条件时才执行的任务
模块名:
模块参数...
when: 条件表达式 # 条件为真时执行任务
when 后的条件表达式可以使用:
- 变量(如 Playbook 中定义的
vars、主机facts、register捕获的变量等)。 - 比较运算符(
==等于、!=不等于、>大于、<小于、>=大于等于、<=小于等于)。 - 逻辑运算符(
and与、or或、not非,或用括号()组合)。 - 特殊测试(如
is defined变量是否定义、is none是否为None、in成员判断等)。 - Jinja2 测试函数(如
match正则匹配、search模糊匹配等)。
示例
yaml
cat 12-install_when.yaml
- hosts: data
gather_facts: yes
tasks:
- name: 1.红帽系统安装
yum:
name: tree,telnet
state: latest
when: ansible_distribution is match("Kylin")
- name: 2.ubt系统安装
apt:
name: tree,lrzsz
state: latest
when: ansible_distribution is match("Ubuntu")
failed_when
在 Ansible 中,failed_when 是一个用于自定义任务失败条件 的关键字。默认情况下,Ansible 会根据模块的返回结果(如命令返回码 rc、模块的 failed 字段等)自动判断任务是否失败;而 failed_when 允许你手动定义 "什么情况下任务算失败",从而覆盖默认的失败判断逻辑。
基本语法
yaml
- name: 自定义失败条件的任务
模块名:
模块参数...
register: 结果变量 # 通常结合 register 捕获结果,用于条件判断
failed_when: 条件表达式 # 条件为真时,任务标记为失败
基本示例
yaml
- name: 3.6检查配置文件
shell: nginx -t
register: check_conf
failed_when: check_conf.rc != 0
循环
- 批量添加用户,创建目录
| 特性 | with_items(旧语法) |
loop(新语法,推荐) |
|---|---|---|
| 引入版本 | 早期版本(早于 2.5) | Ansible 2.5+ |
| 灵活性 | 仅支持简单列表遍历,功能有限 | 支持所有with_*循环的功能,且可结合过滤器扩展 |
| 变量引用 | 用item引用当前元素 |
用item引用当前元素(与with_items一致) |
| 复杂数据结构支持 | 对嵌套列表会自动 "扁平化"(可能不符合预期) | 默认保留原结构,需手动用flatten过滤器扁平化 |
| 官方推荐 | 不推荐(逐步淘汰) | 推荐(未来主要维护的循环语法) |
while_itme
yaml
- hosts:
tasks:
- name: useradd
user:
name: "{{item}}"
state: present
with_items:
- lidao01
- oldboy02
- song03
- hong04
loop
yaml
- hosts:
tasks:
- name: useradd
user:
name: "{{item}}"
state: present
loop:
- lidao01
- oldboy02
- song03
- hong04
列表
添加用户每个用户指定uid
| 用户名 | uid | 密码 |
|---|---|---|
| lidao007 | 3001 | oldboy123 |
| oldboy007 | 3002 | lidao996 |
| lidao996 | 3003 | oldboy456 |
| olboy996 | 3004 | lidao007 |
示例
yaml
[root@m01 /server/ansible]# cat 13-user_password.yaml
- hosts: data
tasks:
- name: 1.添加用户设置密码
user:
name: "{{ item.username }}"
uid: "{{ item.uid }}"
password: "{{ item.password | password_hash('sha512','lwdwd') }}"
loop:
- { username: "lidao007",uid: 3001,password: "Oldboy123"}
- { username: "lidao996",uid: 3002,password: "Lidao777"}
- 批量创建目录并设置不同的所有者,权限
yaml
[root@m01 /server/ansible]# cat 14-dir_loop.yaml
- hosts: data
tasks:
- name: 1.批量创建目录
file:
path: "{{ item.dir }}"
state: directory
owner: "{{ item.owner }}"
group: "{{ item.group }}"
mode: "{{ item.mode }}"
loop:
- { dir: '/shf/lidao',owner: 'lidao996',group: 'lidao996',mode: '0700' }
- { dir: '/shf/oldboy',owner: 'lidao007',group: 'lidao007',mode: '0755' }
jinja2模板
在 Ansible 中,Jinja2 是默认的模板引擎,用于生成动态配置文件(如 Nginx 配置、应用配置等)。它通过结合变量、逻辑控制(条件判断、循环)、过滤器等功能,实现 "一份模板适配多环境",是 Ansible 自动化部署的核心工具之一。
- 配置文件中包含变量
- 分发带有ans变量的文件,template模块,j2结尾
- 配置文件模板,管理端到被管理端
语法
| 语法类型 | 符号 / 格式 | 作用描述 |
|---|---|---|
| 变量引用 | {``{ 变量名 }} |
插入变量值(支持 Ansible 所有可见变量) |
| 控制结构 | {% 代码块 %} |
包含条件判断、循环、宏定义等逻辑 |
| 注释 | {# 注释内容 #} |
模板内注释(不会输出到最终文件) |
判断
通过 {% if %}、{% elif %}、{% else %} 实现分支逻辑,适用于区分生产 / 测试环境、不同主机角色等场景。
示例
- keepalived.conf.j2模板文件
jinja2
[root@m01 ~]# cat ansible/lb/keepalived.conf.j2
! Configuration File for keepalived
global_defs {
{% if ansible_hostname == "lb01" %}
router_id lb01
{% elif ansible_hostname == "lb02" %}
router_id lb02
{% endif %}
}
vrrp_instance vip_3 {
{% if ansible_hostname == "lb01" %}
state MASTER
priority 100
{% elif ansible_hostname == "lb02" %}
state BACKUP
priority 50
{% endif %}
interface ens33
virtual_router_id 51
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
10.0.0.3 dev ens33 label ens33:0
}
}
- 分发配置文件
yaml
[root@m01 /server/ansible]# cat 16.j2_if_keepalived.yaml
- hosts: lb
gather_facts: yes
tasks:
- name: 1.分发keepalived配置文件
template:
src: /root/ansible/lb/keepalived.conf.j2
dest: /tmp/keepalived.conf
循环
示例
- exports.j2配置文件
bash
[root@m01 ~]# cat ansible/nfs/exports.j2
{% for dir in nfs_dir %}
#nfs服务端目录{{ dir }}
{{dir}} 172.16.1.0/24(rw,all_squash)
{% endfor %}
- 分发exports文件
yaml
[root@m01 /server/ansible]# cat 17.j2_for_exports.yaml
- hosts: lb
vars:
- nfs_dir:
- /backup/
- /lidao888/
- /updata/blog/
tasks:
- name: 1.分发nfs的exports文件
template:
src: /root/ansible/nfs/exports.j2
dest: /tmp/exports
动态渲染(template)
在 Ansible 中,template 模块是用于将本地 Jinja2 模板文件动态渲染后分发到远程主机的核心模块。它的核心作用是:结合变量、条件判断、循环等逻辑,生成个性化的配置文件(如 Nginx 配置、MySQL 配置等),并自动同步到目标主机。
关键参数
| 参数 | 作用 |
|---|---|
src |
本地 Jinja2 模板文件的路径(相对路径基于 Playbook 所在目录,或绝对路径)。 |
dest |
远程主机上生成的目标文件路径(必须是文件,不能是目录)。 |
owner |
目标文件的所有者(如 root、www-data)。 |
group |
目标文件的所属组。 |
mode |
目标文件的权限(如 0644 表示所有者读写、组和其他只读)。 |
force |
若远程文件已存在且内容不同,是否覆盖(默认 yes,设为 no 则不覆盖)。 |
backup |
若更新文件,是否备份原文件(yes 则生成 .bak 备份)。 |
示例
yaml
- name: 示例:分发动态配置文件
ansible.builtin.template:
src: 本地模板文件路径 # 如 ./templates/nginx.conf.j2
dest: 远程目标文件路径 # 如 /etc/nginx/nginx.conf
owner: root # 远程文件的所有者
group: root # 远程文件的所属组
mode: '0644' # 远程文件的权限(字符串形式,如 '0755')
force: yes # 若远程文件已存在,是否强制覆盖(默认 yes)
trim_blocks: yes # Jinja2 模板是否自动修剪空行(默认 yes)
典型示例:生成 Nginx 配置
假设需要为不同主机生成不同端口的 Nginx 配置,步骤如下:
- 创建 Jinja2 模板文件
在 Playbook 同级目录创建 templates 文件夹(Ansible 默认会优先查找此目录),并新建模板文件 nginx.conf.j2:
nginx
# /etc/nginx/conf.d/{{ server_name }}.conf
server {
listen {{ http_port }}; # 引用变量 http_port
server_name {{ server_name }}; # 引用变量 server_name
{% if enable_ssl %} # 条件判断:如果 enable_ssl 为 true,则添加 SSL 配置
listen 443 ssl;
ssl_certificate /etc/ssl/{{ server_name }}.crt;
{% endif %}
root /var/www/{{ server_name }};
index index.html;
}
- 编写 Playbook(使用 template 模块)
创建 deploy_nginx.yml:
yaml
- name: 部署 Nginx 动态配置
hosts: web_servers # 目标主机组
vars:
- server_name: "example.com" # 定义变量(可来自 inventory 或 facts)
- http_port: 8080
- enable_ssl: yes # 启用 SSL 配置
tasks:
- name: 确保 Nginx 已安装
ansible.builtin.package:
name: nginx
state: present
- name: 生成 Nginx 配置文件
ansible.builtin.template:
src: templates/nginx.conf.j2 # 本地模板路径
dest: /etc/nginx/conf.d/example.conf # 远程目标路径
owner: root
group: root
mode: '0644'
- name: 重启 Nginx 使配置生效
ansible.builtin.service:
name: nginx
state: restarted
- 执行 Playbook
bash
ansible-playbook -i inventory.ini deploy_nginx.yml
temple vs copy
copy模块:用于复制静态文件(内容固定),不支持变量或逻辑。template模块:用于处理动态模板(内容随变量 / 逻辑变化),适合生成个性化配置。