ansible剧本

ansible剧本

文章目录

Ansible Playbook(剧本)是 Ansible 实现自动化的核心载体,它用 YAML 格式 编写,用于描述一系列需要在远程主机上执行的任务(如安装软件、配置文件、启动服务等)。通过 Playbook,你可以将零散的操作标准化、流程化,实现批量主机的自动化管理。

Playbook 核心结构

一个基本的 Playbook 由一个或多个 Play 组成,每个 Play 定义了 "在哪些主机上执行哪些任务"。每个 Play 包含以下核心部分:

组成部分 作用
hosts 指定目标主机或主机组(来自 inventory 清单)
tasks 任务列表,每个任务通过 Ansible 模块(如 yumcopy)执行具体操作
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](多个标签)。

  1. 任务级 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
  1. 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"标签
  1. 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参数,仅在失败的主机上重新执行任务,具体步骤如下:

  1. 理解 retry 文件的作用

Ansible 在 playbook 执行过程中,如果有主机任务失败,会自动在当前目录生成一个retry 文件 ,默认文件名格式为[playbook名称].retry(例如site.yml执行失败后生成site.retry)。

该文件中会记录所有执行失败的主机列表(每行一个主机),例如:

plaintext 复制代码
webserver1
dbserver3
  1. 下次执行时指定失败主机

下次执行 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会被视为字符串;yestrue等价,nofalse等价。
列表(List) 多行:用-开头,元素分行;单行:用[]包裹,元素用逗号分隔 有序集合,可通过索引访问(如{``{ ports[0] }}),支持loop循环遍历。
字典(Dictionary) 多行:key: value格式,键值对缩进对齐;单行:用{}包裹,key:value用逗号分隔 键值对集合,支持嵌套(如字典包含列表 / 其他字典),通过key访问值(如{``{ server.ip }})。
空值(Null) null(小写)或~(YAML 简写)表示 表示 "无值" 或 "未定义",常用于默认值或占位符场景。

1. 字符串(String)

最常用的类型,用于表示文本内容。

  • 定义:可加单引号(')、双引号("),或不加引号(但建议加引号避免 YAML 语法歧义)。

  • 示例:

    yaml 复制代码
    name: "webserver"  # 双引号
    hostname: 'db-01'  # 单引号
    message: hello world  # 不加引号(无特殊字符时)
  • 说明:若字符串包含特殊字符(如冒号:、空格、换行),建议用引号包裹,避免 YAML 解析错误。

2. 数字(Number)

包括整数(int)和浮点数(float),用于数值计算或配置。

  • 定义:直接写数值,无需引号(加引号会被视为字符串)。

  • 示例:

    yaml 复制代码
    port: 8080  # 整数
    memory: 4096  # 单位MB(整数)
    cpu_usage: 75.5  # 浮点数(百分比)
    timeout: 30  # 超时时间(秒)
  • 说明:在 Ansible 中,数字可直接用于算术运算(如{``{ port + 100 }})。

3. 布尔值(Boolean)

表示 "真" 或 "假",常用于条件判断(when语句)或开关配置。

  • 定义:YAML 中支持true/false(小写)或yes/no(Ansible 推荐,更直观)。

  • 示例:

    yaml 复制代码
    enable_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 简写)表示。

  • 示例:

    yaml 复制代码
    backup_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.ymlprod_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 具体操作系统名称 CentOSUbuntuRocky
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 系统默认包管理器 yumdnfapt
ansible_service_mgr 系统服务管理器 systemdupstart

常用系统信息

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 按换行符分割成的列表。

示例

  1. 捕获命令输出(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  # 按行分割的列表
  1. 根据命令返回码判断是否执行后续任务

通过 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 时执行
  1. 捕获非命令模块的结果(如 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 字段表示权限
  1. 遍历命令的多行输出(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、主机 factsregister 捕获的变量等)。
  • 比较运算符(== 等于、!= 不等于、> 大于、< 小于、>= 大于等于、<= 小于等于)。
  • 逻辑运算符(and 与、or 或、not 非,或用括号 () 组合)。
  • 特殊测试(如 is defined 变量是否定义、is none 是否为 Nonein 成员判断等)。
  • 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 目标文件的所有者(如 rootwww-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 配置,步骤如下:

  1. 创建 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;
}
  1. 编写 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
  1. 执行 Playbook
bash 复制代码
ansible-playbook -i inventory.ini deploy_nginx.yml

temple vs copy

  • copy 模块:用于复制静态文件(内容固定),不支持变量或逻辑。
  • template 模块:用于处理动态模板(内容随变量 / 逻辑变化),适合生成个性化配置。
相关推荐
oMcLin2 小时前
Linux系统的香港服务器性能调优指南:从 CPU、内存到 I/O
linux·运维·服务器
Lueeee.2 小时前
Linux 字符设备驱动中 “主次设备号的静态 / 动态分配” 实验
linux
不爱学习的笨蛋2 小时前
ubuntu安装gitlab
linux·ubuntu·gitlab
QQ__17646198242 小时前
Ubuntu系统克隆Github仓库项目到本地
linux·ubuntu·github
闻道且行之2 小时前
NLP 部署实操:Langchain-Chatchat API使用方法记录
服务器·自然语言处理·langchain
坚持的小马2 小时前
启动NameServer集群
linux·运维·网络
一只大侠的侠2 小时前
Linux实战:动态进度条从零实现,多版本优化与缓冲区原理全解析
linux·运维·服务器
不染尘.2 小时前
DHCP和HTTP2_3
服务器·网络·网络协议·计算机网络·http·udp·tcp
奔跑吧 android2 小时前
【ubuntu】【unattended-upgrades 介绍】
服务器·数据库·ubuntu