PlayBook 详解

4)Playbook

4.1)Playbook 介绍

PlayBookad-hoc 相比,是一种完全不同的运用 Ansible 的方式,类似与 Saltstack 的 state 状态文件。ad-hoc 无法持久使用,PlayBook 可以持久使用。
PlayBook 剧本是 由一个或多个 “Play” 组成 的列表
Play 的主要功能在于将预定义的一组主机,装扮成事先通过 Ansible 中的 Task 定义好的角色。
从根本上来讲,所谓的 Task 无非是调用 Ansible 的一个 module。将多个 Play 组织在一个 PlayBook 中,即可以让它们联合起来按事先编排的机制完成某一任务。

PlayBook 文件是采用 YAML 语言 编写的。

4.1.1)PlayBook 核心元素

  • Host: 执行的远程主机列表
  • Tasks: 任务集
  • Varniables: 内置变量或自定义变量在 PlayBook 中调用
  • Templates: 模板文件,即使用模板语法的文件,比如配置文件等
  • Handlers: 和 notity 结合使用,由特定条件触发的操作,满足条件方才执行,否则不执行
  • Tags: 标签,指定某条任务执行,用于选择运行 PlayBook中的部分代码。

PlayBook 翻译过来就是 剧本,可以简单理解为使用不同的模块完成一件事情,
具体 PlayBook 组成如下

  • Play:定义的是主机的角色
  • Task:定义的是具体执行的任务
  • PlayBook:由一个或多个 Play 组成,一个 Play 可以包含多个 Task 任务

image.png

4.1.2)PlayBook 优势

  • 功能比 ad-hoc 更全
  • 能很好的控制先后执行顺序,以及依赖关系
  • 语法展现更加的直观
  • ad-hoc 无法持久使用,PlayBook 可以持久使用

4.1.3)PlayBook 语法

PlayBook 的配置语法是由 yaml 语法描述的,扩展名是 yml 或 yaml,遵循 yaml 格式

  • 缩进: YAML 使用固定的缩进风格表示层级结构,每个缩进由两个空格组成,不能使用 Tab
  • 冒号: 以冒号结尾的除外,其他所有冒号后面所有必须有空格
  • 短横线: 表示列表项,使用一个短横杠加一个空格,多个项使用同样的缩进级别作为同一列表

4.2)YAML 语言

4.2.1)YAML 语言介绍

YAML: YAML Ain’t Markup Language,即 YAML 不是标记语言。
不过,在开发的这种语言时,YAML 的意思其实是:“Yet Another Markup Language”( 仍是一种标记语言 )

YAML 是一个可读性高的用来表达资料序列的格式。

YAML 参考了其他多种语言,包括:XML、C 语言、Python、Perl 以及电子邮件格式 RFC2822 等。Clark Evans 在 2001 年在首次发表了这种语言,另外 Ingy döt Net 与 Oren Ben-Kiki 也是这语言的共同设计者,目前很多最新的软件比较流行采用此格式的文件存放配置信息,如:Ubuntu,Anisble,Docker,Kubernetes 等

YAML 官方网站:http://www.yaml.org
Ansible 官网: https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html

4.2.2)YAML 语言特性

  • YAML 的可读性好
  • YAML 和脚本语言的交互性好
  • YAML 使用实现语言的数据类型
  • YAML 有一个一致的信息模型
  • YAML 易于实现
  • YAML 可以基于流来处理
  • YAML 表达能力强,扩展性好

4.2.3)YAML 语法简介

  1. 在单一文件第一行,用连续** 三个连字号 “-” 开始**
  2. 还有 选择性的连续三个点号 ( … ) 用来 表示文件的结尾
  3. 次行开始正常写 Playbook 的内容,一般建议写明该 Playbook 的功能描述
  4. 可以使用 # 号注释代码
  5. 缩进必须是统一的,不能空格和 Tab 混用**( 正常使用两个空格缩进 )**
  6. 缩进的级别也必须是一致的,同样的缩进代表同样的级别,程序判别配置的级别是通过缩进结合换行来实现的
  7. YAML 文件内容是区别大小写的,key/value 的值 均需大小写敏感
  8. 多个 key/value 可同行写也可换行写,同行使用,分隔
  9. key 后面冒号要加一个空格,比如:key: value
  10. value 可是个字符串,也可是另一个列表
  11. YAML 文件扩展名通常为 yml 或 yaml

4.2.4)支持的数据类型

YAML 支持以下 常用几种数据类型

  • 标量: 单个的、不可再分的值
    • 示例: age: 18
  • 对象: 键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)
    • **示例:**account: { name: wang, age: 30 }
  • 数组: 一组按次序排列的值,又称为序列(sequence) / 列表(list)
    • 示例: course: [ linux , golang , python ]
4.2.4.1)标量:scalar

方式一: 键值对

name: wang
age: 18

方式二: 使用缩进方式

name:wang
age:18

标量是最基本的,不可再分的值,包括:

  • 字符串
  • 布尔值
  • 整数
  • 浮点数
  • Null
  • 时间
  • 日期
4.2.4.2)字典:Dictionary

字典由多个 key 与 value 构成,key 和 value 之间用 **:**分隔

并且,后面有一个空格,所有 k/v 可以放在一行,或者每个 k/v 分别放在不同行

格式

account: { name: wang, age: 30 }

使用缩进方式

account: name: wangage: 18

范例:

# 不同行
# An employee record
name: Example Developer
job: Developer
skill: Elite(社会精英)# 同一行, 也可以将 key:value放置于{}中进行表示,用,分隔多个key:value
# An employee record
{name: "Example Developer", job: "Developer", skill: "Elite"}
4.2.4.3)列表:List

列表由多个元素组成,每个元素放在不同行,且元素前均使用 “-” 打头,并且 - 后有一个空格

或者将所有元素用 [ ] 括起来放在同一行

// 格式
course: [ linux , golang , python ]// 也可以写成以 - 开头的多行
course:- linux- golang- python// 数据里面也可以包含字典
course:- linux: manjaro- golang: gin- python: django

范例:

# 不同行, 行以-开头, 后面有一个空格
# A list of tasty fruits
- Apple
- Orange
- Strawberry
- Mango# 同一行
[Apple,Orange,Strawberry,Mango]

**范例:**YAML 表示一个家庭

name: John Smith
age: 41
gender: Male
spouse: { name: Jane Smith, age: 37, gender: Female } # 1) 写在一行里name: Jane Smith   # 2) 也可以写成多行age: 37gender: Femalechildren: [ {name: Jimmy Smith,age: 17, gender: Male}, {name: Jenny Smith, age: 13, gender: Female}, {name: hao Smith, age: 20, gender: Male } ]  # 写在一行- name: Jimmy Smith    # 3) 写在多行, 更为推荐的写法age: 17gender: Male- {name: Jenny Smith, age: 13, gender: Female}- {name: hao Smith, age: 20, gender: Male }    

4.2.5)三种常见的数据格式

参考:https://juejin.cn/post/7041815877825593374

XML:Extensible Markup Language,可扩展标记语言,可用于数据交换和配置。
JSON:JavaScript Object Notation,JavaScript 对象表记法,主要用来数据交换或配置,不支持注释。
YAML:YAML Ain’t Markup Language YAML 不是一种标记语言, 主要用来配置,大小写敏感,不支持 Tab。


也可以用工具互相转换,参考网站:
https://www.json2yaml.com/
http://www.bejson.com/json/json2yaml/

4.3)Playbook 核心组件

官方文档:https://docs.ansible.com/ansible/latest/reference_appendices/playbooks_keywords.html#playbook-keywords

一个 PlayBook 中由多个组件组成,其中所用到的 **常见组件类型 **如下:

  • Hosts:执行的 远程主机列表
  • Tasks: 任务集,由多个 task 的元素组成的列表实现,每个 task 是一个字典,一个完整的代码块功能需最少元素需包括 name 和 task,一个 name 只能包括一个 task
  • Variables: 内置变量或自定义变量 在 PlayBook 中调用
  • Templates: 模板,可替换模板文件中的变量并实现一些简单逻辑的文件
  • Handlersnotify 结合使用,由特定条件触发的操作,满足条件方才执行,否则不执行
  • Tags: 标签 指定某条任务执行,用于选择运行 playbook 中的部分代码。ansible 具有幂等性,因此会自动跳过没有变化的部分,即便如此,有些代码为测试其确实没有发生变化的时间依然会非常地长。此时,如果确信其没有变化,就可以通过tags 跳过此些代码片段。

4.3.1)hosts 组件

Hosts: PlayBook 中的每一个 Play 的目的都是为了让特定主机以某个指定的用户身份执行任务。hosts 用于指定要执行指定任务的主机,须事先定义在主机清单中。

one.example.com
one.example.com:two.example.com
192.168.1.50
192.168.1.*
Websrvs:dbsrvs     # 或者, 两个组的并集
Websrvs:&dbsrvs    # 与, 两个组的交集
webservers:!dbsrvs # 在 websrvs 组, 但不在dbsrvs组

案例:

- hosts: websrvs:appsrvs

4.3.2)remote_user 组件

remote_user:可用于 Host 和 task 中。也可以通过指定其通过 sudo 的方式在远程主机上执行任务,其可用于 play 全局或某任务;此外,甚至可以在 sudo 时使用 sudo_user 指定 sudo 时切换的用户

 remote_user: root            # 方式一tasks:- name: test connectionping:remote_user: magedu    # 方式二sudo: yes         		  # 默认 sudo 为 rootsudo_user:wang    			# sudo 为 wang

4.3.3)task 列表和 action 组件

Play 的主体部分是 task list,task list 中有一个或多个 task,各个 task 按次序逐个在 hosts 中指定的所有主机上执行,即在所有主机上完成第一个 task 后,再开始第二个 task。

task 的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行是幂等的,这意味着多次执行是安全的,因为其结果均一致。

每个 task 都应该有其 name,用于 PlayBook 的执行结果输出,建议其内容能清晰地描述任务执行步骤。如果未提供 name,则 action 的结果将用于输出。

task 两种格式:

action: module arguments    # 示例: action: shell wall hello 
module: arguments           # 建议使用 # 示例: shell: wall hello 

注意: Shell 和 Command 模块后面跟命令,而非 key=value

范例:

[root@ansible ansible] cat hello.yaml
---
# first yaml file 
- hosts: websrvsremote_user: rootgather_facts: no   # 不收集系统信息, 提高执行效率tasks:- name: test network connectionping:- name: wallshell: wall "hello world!"# 检查语法
[root@ansible ansible] ansible-playbook --syntax-check hello.yaml# 验证脚本 ( 不真实执行 )
# 模拟执行 hello.yaml 文件中定义的 playbook, 不会在被控节点上应用任何更改
[root@ansible ansible] ansible-playbook -C hello.yaml# 真实执行
[root@ansible ansible] ansible-playbook hello.yaml

范例: 初识 Ansible

[root@ansible ansible] vim test.yml
---
# 初识 Ansible
- hosts: websrvsremote_user: rootgather_facts: yes     # 需开启,否则无法收集到主机信息tasks:- name: '存活性检测'ping:- name: '查看主机名信息'setup: filter=ansible_nodename- name: '查看操作系统版本'setup: filter=ansible_distribution_major_version- name: '查看内核版本'setup: filter=ansible_kernel- name: '查看时间'shell: datetasks:- name: '安装 HTTPD'yum: name=httpd- name: '启动 HTTPD'                                                                   service: name=httpd state=started enabled=yes# 检查语法
[root@ansible ansible] ansible-playbook --syntax-check test.yml# 执行脚本
[root@ansible ansible] ansible-playbook test.yml

范例:

Ansible PlayBook 由有序列表中的一个或多个 Play 组成。在这里,您可以认为剧本是执行指令以实现剧本总体目标的代码的一部分。

每个 Play 运行一个 Task,每个 Task 调用 Ansible Modules 在一个或多个 Nodes 托管目标节点上执行指令。

---
- hosts: websrvsremote_user: rootgather_facts: no           # 是否收集系统 facts 信息tasks:- name: install httpd    # 描述信息yum: name=httpd        # 调用 yum 模块- name: start httpdservice: name=httpd state=started enabled=yes    # 调用 service 模块

image.png

---
- hosts: websrvsremote_user: rootgather_facts: no    # 是否收集系统 facts 信息tasks:- name: pingping:- name: wallshell: wall hello                   - hosts: websrvsremote_user: root                  tasks:- name: install httpdyum: name=httpd- name: start httpdservice: name=httpd state=started enabled=yes# 验证脚本 ( 不真实执行 )
[root@ansible ansible] ansible-playbook -C hello.yaml# 真实执行
[root@ansible ansible] ansible-playbook hello.yaml      

4.3.4)其它组件

某任务的状态在运行后为 changed 时,可通过 "notify" 通知给相应的 handlers 任务。
还可以通过 "tags" 给 task 打标签,可在 ansible-playbook 命令上使用 -t 指定进行调用

4.3.5)Shell Scripts VS Playbook 案例

# SHELL 脚本实现
#!/bin/bash
# 安装 Apache
yum install --quiet -y httpd# 复制配置文件
cp /tmp/httpd.conf /etc/httpd/conf/httpd.conf
cp /tmp/vhosts.conf /etc/httpd/conf.d/# 启动 Apache, 并设置开机启动
systemctl enable --now httpd
# Playbook 实现
---
- hosts: dbsrvsremote_user: rootgather_facts: no        # 是否收集系统 facts 信息 ( 取消收集能提高 ansible 执行速度 )tasks:- name: "安装Apache"yum: name=httpd- name: "复制配置文件"copy: src=/tmp/httpd.conf dest=/etc/httpd/conf/- name: "复制配置文件"copy: src=/tmp/vhosts.conf dest=/etc/httpd/conf.d/- name: "启动Apache, 并设置开机启动"service: name=httpd state=started enabled=yes

4.4)PlayBook 命令

// 格式
ansible-playbook <filename.yml> ... [options]

PlayBook 常用选项

// "常见选项"
--syntax-check    # 语法检查, 可缩写成 --syntax, 相当于 bash -n 
-C --check        # 模拟执行, 只检测可能会发生的改变, 但不真正执行操作, dry run
--list-hosts      # 列出运行任务的主机    # 举例: ansible-playbook hello.yaml --list-hosts
--list-tags       # 列出 tag             
--list-tasks      # 列出 task            # 举例: ansible-playbook hello.yaml --list-tasks
--limit 主机列表  # 针对主机列表中的特定主机执行    # 举例: ansible-playbook hello.yaml --limit 192.168.80.28
-i INVENTORY      # 指定主机清单文件, 通常一个项对应一个主机清单文件    # 举例: ansible-playbook hello.yaml -i /root/hosts
--start-at-task START_AT_TASK    # 从指定 task 开始执行, 而非从头开始, START_AT_TASK 为任务的 name    # 举例: ansible-playbook hello.yml --start-at="start httpd"
-v -vv  -vvv      # 显示过程
// 举例: ansible-playbook hello.yaml --list-hosts
// 举例: ansible-playbook hello.yaml --list-tasks
// 举例: ansible-playbook hello.yaml --limit 192.168.80.28
// 举例: ansible-playbook hello.yaml -i /root/hosts
// 举例: ansible-playbook hello.yml --start-at="start httpd"

4.5)Playbook 初步

4.5.1)利用 PlayBook 创建 MySQL 用户

根据写 Shell 脚本的思路来编写 PlayBook 即可。( 顺序执行 )

范例: mysql_user.yml

---
- hosts: dbsrvsname: 创建 MySQL 用户remote_user: rootgather_facts: notasks:- name: '创建 MySQL 用户组'group: name: mysql gid: 306 system: yes- name: '创建 MySQL 用户'user: name: mysql uid: 306 group: mysql system: yesshell: /sbin/nologinhome: /data/mysqlcreate_home: yes- name: '查看 MySQL 用户信息'shell: id mysql# 检查远程主机用户信息              
[root@ansible ansible] ansible dbsrvs -m shell -a "id mysql"# 验证 PlayBook 脚本                
[root@ansible ansible] ansible-playbook -C mysql_user.yml# 执行脚本
[root@ansible ansible] ansible-playbook mysql_user.yml

image.png

范例: delete-mysql-user.yaml

[root@ansible ansible] vim delete-mysql-user.yaml
---
- hosts: dbsrvsname: 移除 MySQL 用户remote_user: rootgather_facts: notasks:- name: '删除 MySQL 用户'user: name=mysql state=absent remove=yes[root@ansible ansible] ansible-playbook delete-mysql-user.yaml

image.png

4.5.2)利用 PlayBook 安装 nginx

范例: install_nginx.yml

# 先将远程主机的 HTTPD 服务卸载
[root@ansible ansible] ansible websrvs -m yum -a 'name=httpd state=absent'# Ansible 控制节点 安装 nginx 软件包 ( 实验: 主要为了拿到 nginx conf 文件 )
[root@ansible ansible] yum install nginx -y
[root@ansible ansible] mkdir files# 拷贝 nginx 配置文件
[root@ansible ansible] cp /etc/nginx/nginx.conf files/
[root@ansible ansible] vim files/nginx.confserver {listen       8080;           # 修改该行                                                           listen       [::]:80;server_name  _;root         /usr/share/nginx/html;# 编写 HTML 文件 ( 增加 UTF-8 防止乱码 )
[root@ansible ansible] vim files/index.html
<!DOCTYPE html>
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><h1> 微信公众号: 开源极客行 </h1>                                                       
</head>
<body>
</body>
</html>
# 编写 PlayBook 文件
[root@ansible ansible] vim install_nginx.yml
---
# install nginx
- hosts: websrvsremote_user: rootgather_facts: notasks:- name: "创建 nginx 用户组"group: name=nginx state=present- name: "创建 nginx 用户"user: name=nginx state=present group=nginx- name: "安装 nginx"yum: name=nginx state=present- name: "拷贝 nginx 配置文件"copy: src=files/nginx.conf dest=/etc/nginx/nginx.conf                                 - name: "拷贝 nginx 网页文件"copy: src=files/index.html dest=/usr/share/nginx/html/index.html- name: "启动 nginx 服务"service: name=nginx state=started enabled=yes# 验证 PlayBook 脚本 ( 重要 )
[root@ansible ansible] ansible-playbook -C install_nginx.yml# 执行 PalyBook 脚本
[root@ansible ansible] ansible-playbook install_nginx.yml# 验证控制节点端口启用情况
[root@ansible ansible] ansible websrvs -m shell -a 'netstat -nltp | grep 8080'


$ vim remove-nginx.yaml
---
- hosts: websrvsname: 移除 nginx 软件remote_user: rootgather_facts: notasks:- name: 停止nginx服务service: name=nginx state=stopped- name: 移除nginx软件yum: name=nginx state=absent- name: 删除nginx用户user: name=nginx state=absent remove=yes- name: 删除nginx用户组group: name=nginx state=absent

4.5.3)利用 PlayBook 安装和卸载 httpd

范例: install_httpd.yml

[root@centos8 ansible] vim files/index.html
<!DOCTYPE html>
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><h1> 微信公众号: 开源极客行 </h1>                                                       
</head>
<body>
</body>
</html>[root@centos8 ansible] vim install_httpd.yml 
---
# install httpd
- hosts: websrvsremote_user: rootgather_facts: notasks:- name: "Install httpd"yum: name=httpd state=present- name: "Modify config listen port"lineinfile:path: /etc/httpd/conf/httpd.confregexp: '^Listen'line: 'Listen 8080'- name: "Modify config data directory one"lineinfile:path: /etc/httpd/conf/httpd.confregexp: '^DocumentRoot "/var/www/html"'line: 'DocumentRoot "/data/html"'- name: "Modify config data directory two"lineinfile:path: /etc/httpd/conf/httpd.confregexp: '^<Directory "/var/www/html">'line: '<Directory "/data/html">'- name: "Mkdir website directory"file: path=/data/html state=directory- name: "copy Web html file"copy: src=files/index.html dest=/data/html/- name: "Start httpd service"service: name=httpd state=started enabled=yes# 仅针对 192.168.80.28 执行操作
[root@centos8 ansible] ansible-playbook install_httpd.yml --limit 192.168.80.28

image.png
image.png

范例: remove_httpd.yml

[root@centos8 ansible] vim remove_httpd.yml
---
- hosts: websrvsremote_user: rootgather_facts: notasks:- name: "remove httpd package"yum: name=httpd state=absent- name: "remove apache user"user: name=apache state=absent- name: "remove config file"file: name=/etc/httpd state=absent- name: "remove web html"file: name=/data/html/ state=absent# 验证 PlayBook 脚本 ( 重要 )                           
[root@centos8 ansible] ansible-playbook -C remove_httpd.yml# 执行 PlayBook 脚本
[root@centos8 ansible] ansible-playbook remove_httpd.yml 

image.png

4.5.4)利用 PlayBook 安装 MySQL 5.6

范例: 安装 mysql-5.6.46-linux-glibc2.12
注意: 建议 MySQL 客户机的内存需超过 2 G,否则可能会报错

# 下载 MySQL 软件包
[root@ansible ~] mkdir /data/ansible/files -p && cd /data/ansible/files
[root@ansible ~] wget https://ftp.iij.ad.jp/pub/db/mysql/Downloads/MySQL-5.6/mysql-5.6.46-linux-glibc2.12-x86_64.tar.gz# MySQL 配置文件
[root@ansible ~] vim /data/ansible/files/my.cnf
[mysqld]
socket=/tmp/mysql.sock
user=mysql
symbolic-links=0
datadir=/data/mysql
innodb_file_per_table=1
log-bin
pid-file=/data/mysql/mysqld.pid[client]
port=3306
socket=/tmp/mysql.sock[mysqld_safe]
log-error=/var/log/mysqld.log# 编写 MySQL 初始脚本
[root@ansible ~] vim /data/ansible/files/secure_mysql.sh
#!/bin/bash
/usr/local/mysql/bin/mysql_secure_installation <<EOF
y
123456
123456
y
y
y
y[root@ansible files] chmod +x secure_mysql.sh[root@ansible files]# tree /data/ansible/files/
/data/ansible/files/
├── my.cnf
├── mysql-5.6.46-linux-glibc2.12-x86_64.tar.gz
└── secure_mysql.sh0 directories, 3 files
# 编写 PlayBook
[root@ansible ~] vim /data/ansible/install_mysql.yml
---
# install mysql-5.6.46-linux-glibc2.12-x86_64.tar.gz
- hosts: dbsrvsremote_user: rootgather_facts: notasks:- name: "install packages"yum: name=libaio,perl-Data-Dumper,perl-Getopt-Long- name: "create mysql group"group: name=mysql gid=306- name: "create mysql user"user: name=mysql uid=306 group=mysql shell=/sbin/nologin system=yes create_home=no home=/data/mysql- name: "copy tar to remote host and file mode"unarchive: src=/data/ansible/files/mysql-5.6.46-linux-glibc2.12-x86_64.tar.gz dest=/usr/local/ owner=root group=root- name: "create linkfile /usr/local/mysql"file: src=/usr/local/mysql-5.6.46-linux-glibc2.12-x86_64 dest=/usr/local/mysql state=link- name: "create dir /data/mysql"file: path=/data/mysql state=directory- name: "data dir"	# 该步骤貌似有点问题shell: chdir=/usr/local/mysql ./scripts/mysql_install_db --datadir=/data/mysql --user=mysqltags: dataignore_errors: yes	# 忽略错误,继续执行- name: "config my.cnf"copy: src=/data/ansible/files/my.cnf dest=/etc/my.cnf - name: "service script"shell: /bin/cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld- name: "enable service"shell: /etc/init.d/mysqld start;chkconfig --add mysqld;chkconfig mysqld ontags: service- name: "PATH variable"copy: content='PATH=/usr/local/mysql/bin:$PATH' dest=/etc/profile.d/mysql.sh- name: "secure script"script: src=/data/ansible/files/secure_mysql.shtags: script# 执行 PlayBook 脚本
[root@ansible ~] ansible-playbook install_mysql.yml

image.png

范例: install_mariadb.yml

# 编写 PlayBook
[root@ansible ~] vim /data/ansible/install_mariadb.yml
---
# Installing MariaDB Binary Tarballs
- hosts: dbsrvsremote_user: rootgather_facts: notasks:- name: create groupgroup: name=mysql gid=27 system=yes- name: create useruser: name=mysql uid=27 system=yes group=mysql shell=/sbin/nologin home=/data/mysql create_home=no- name: mkdir datadirfile: path=/data/mysql owner=mysql group=mysql state=directory- name: unarchive packageunarchive: src=/data/ansible/files/mariadb-10.2.27-linux-x86_64.tar.gz dest=/usr/local/ owner=root group=root- name: linkfile: src=/usr/local/mariadb-10.2.27-linux-x86_64 path=/usr/local/mysql state=link- name: install databaseshell: chdir=/usr/local/mysql  ./scripts/mysql_install_db --datadir=/data/mysql --user=mysql- name: config filecopy: src=/data/ansible/files/my.cnf  dest=/etc/ backup=yes- name: service scriptshell: /bin/cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld- name: start serviceservice: name=mysqld state=started enabled=yes- name: PATH variablecopy: content='PATH=/usr/local/mysql/bin:$PATH' dest=/etc/profile.d/mysql.sh# 执行 PlayBook 脚本
[root@ansible ~] ansible-playbook install_mariadb.yml    

4.6)ignore_errors 忽略错误

如果一个 Task 出错,默认将不会继续执行后续的其它 Task

我们可以利用 **ignore_errors:yes ** 忽略此 Task 的错误,继续向下执行 PlayBook 其它 Task

[root@ansible ansible] vim test_ignore.yml
---
- hosts: websrvstasks:- name: error testcommand: /bin/false    # 返回失败结果的命令ignore_errors: yes     # 忽略错误, 继续执行- name: continuecommand: wall continue[root@ansible ansible] ansible-playbook test_ignore.yml

4.7)Playbook 中使用 handlers 和 notify

Handlers 本质是 task list,类似于 MySQL 中的触发器触发的行为,其中的 task 与前述的 task 并没有本质上的不同,主要用于当关注的资源发生变化时,才会采取一定的操作。
而 Notify 对应的 action 可用于在每个 play 的最后被触发,这样可避免多次有改变发生时每次都执行指定的操作,仅在所有的变化发生完成后一次性地执行指定操作。在 notify 中列出的操作称为 handler,也即 notify 中调用 handler 中定义的操作。

注意:

  • 如果多个 Task 通知了相同的 handlers, 此 handlers 仅会在所有 Tasks 结束后运行一次。
  • 只有 notify 对应的 task 发生改变了才会通知 handlers,没有改变则不会触发 handlers。
  • handlers 是在所有前面的 tasks 都成功执行才会执行,如果前面任何一个 task 失败,会导致 handler 跳过执行,可以使用 force_handlers:yes 强制执行 handler。

案例:

---
- hosts: websrvsremote_user: rootgather_facts: notasks:- name : Install httpdyum: name=httpd state=present- name : Install configure filecopy: src=files/httpd.conf dest=/etc/httpd/conf/# 修改 http 服务的端口号- name: config httpd conflineinfile: "path=/etc/httpd/conf/httpd.conf regexp='^Listen' line='Listen 8080'"notify:- restart httpd - wall- name: ensure apache is runningservice: name=httpd state=started enabled=yeshandlers:- name: restart httpdservice: name=httpd state=restarted- name: wallcommand: wall "The config file is changed"

案例:
在 Ansible 中,handlers 部分 用于定义当某些条件满足时应该执行的任务。
这些任务通常是 由 notify 指令触发的,这些 notify 指令可以放在其他任务中。
当任务完成并且其状态发生变化时,与任务相关联的 notify 指令会触发相应的 handler。
案例: 当 Copy Nginx Config File 任务完成并发生改变时,它会触发名为 Restart Nginx Service 的 handler。Nginx 服务将被重启,以应用新的配置。
模块的大概执行流程:https://blog.csdn.net/wangjiachenga/article/details/122980073

[root@ansible ansible] vim files/nginx.confserver {listen       80;                # 修改该行listen       [::]:80;server_name  _;root         /usr/share/nginx/html;[root@ansible ansible] vim install_nginx.yml
---
# install nginx
- hosts: websrvsremote_user: rootgather_facts: notasks:- name: "Add Nginx Group"group: name=nginx state=present- name: "Add Nginx User"user: name=nginx state=present group=nginx- name: "Install Nginx"yum: name=nginx state=present- name: "Copy Nginx Config File"copy: src=files/nginx.conf dest=/etc/nginx/nginx.confnotify: Restart Nginx Service    # 定义 notify 触发器- name: "Copy Web Page File"copy: src=files/index.html dest=/usr/share/nginx/html/index.html- name: "Start Nginx Service"service: name=nginx state=started enabled=yeshandlers:    # 触发如下操作- name: "Restart Nginx Service"service: name=nginx state=restarted enabled=yes[root@ansible ansible] ansible-playbook install_nginx.yml

范例: 强制执行 handlers

- hosts: websrvsforce_handlers: yes # 无论 task 中的任何一个 task 失败, 仍强制执行 handlerstasks:- name: config filecopy: src=nginx.conf dest=/etc/nginx/nginx.confnotify: restart nginx- name: install packageyum: name=no_exist_packagehandlers:- name: "restart nginx"service: name=nginx state=restarted

4.8)Playbook 中使用 tags 组件

官方文档:https://docs.ansible.com/ansible/latest/user_guide/playbooks_tags.html
参考文档:https://blog.csdn.net/weixin_42171272/article/details/135268747
如果写了一个很长的 PlayBook,其中有很多的任务,这并没有什么问题,不过在实际使用这个剧本时,可能只是想要执行其中的一部分任务。
或者,你只想要执行其中一类任务而已,而并非想要执行整个剧本中的全部任务,这个时候我们就可以借助 tags 标签实现这个需求。

tags 可以帮助我们对任务进行 打标签 的操作,与模块名同级,当任务存在标签以后,我们就可以在执行 PlayBook 时,借助标签,指定执行哪些任务,或者指定不执行哪些任务了。

在 PlayBook 文件中,利用 tags 组件,为特定 task 指定标签。
当在执行 PlayBook 时,可以只执行特定 tags 的 task,而非整个 PlayBook 文件。可以一个 task 对应多个 tag,也可以多个 task 对应一个 tag。
还有另外 3 个特殊关键字用于标签,tagged,untagged 和 all,它们分别是仅运行已标记,只有未标记和所有任务。

[root@ansible ~] vim httpd.yml
---
# tags example
- hosts: websrvsremote_user: rootgather_facts: notasks:- name: "Install httpd"yum: name=httpd state=present- name: "Install configure file"copy: src=files/httpd.conf dest=/etc/httpd/conf/tags: [ conf,file ]    # 写在一行- conf               # 写成多行- file- name: "start httpd service"tags: service          # 写在一行service: name=httpd state=started enabled=yes# 查看标签
[root@ansible ~] ansible-playbook --list-tags httpd.yml# 仅执行标签动作
[root@ansible ~] ansible-playbook -t conf,service httpd.yml# 跳过标签动作 
[root@ansible ~] ansible-playbook --skip-tags conf httpd.yml
[root@ansible ~] ansible-playbook httpd.yml --skip-tags untagged

4.9)Playbook 中 使用变量

Playbook 中同样也支持变量

变量名: 仅能由字母、数字和下划线组成,且只能以字母开头

// 变量定义
# variable=value
variable: value    # 建议

范例:

# http_port=80
http_port: 80    # 建议

变量调用方式:
通过 {{ variable_name }} 调用变量,且变量名前后建议加空格,
有时用 "{{ variable_name }}" 才生效

变量来源:

  1. ansible 的 setup facts 远程主机的所有变量 都可直接调用
  2. 通过命令行指定变量,优先级最高
ansible-playbook -e varname=value test.yml
  1. 在 PlayBook 文件中定义
vars:var1: value1var2: value2
  1. 在独立的变量 YAML 文件中定义
- hosts: allvars_files:- vars.yml
  1. 在主机清单文件中定义
  • 主机(普通)变量:主机组中主机单独定义,优先级高于公共变量
  • 组(公共)变量:针对主机组中所有主机定义统一变量
  1. 在项目中针对主机和主机组定义

在项目目录中创建 host_vars 和 group_vars 目录

  1. 在 role 中定义

变量的优先级从高到低如下

-e 选项定义变量 > playbook 中 vars_files > playbook 中 vars 变量定义 > host_vars/主机名 文件 > 主机清单中主机变量 > group_vars/主机组名文件 > group_vars/all文件 > 主机清单组变量

4.9.1)使用 setup 模块中变量

本模块自动在 PlayBook 调用,不要用 ansible 命令调用,生成的系统状态信息,并存放在 facts 变量中。
facts 包括的信息很多,**如: **主机名,IP,CPU,内存,网卡等
facts 变量的实际使用场景案例

  • 通过 facts 变量获取被控端 CPU 的个数信息,从而生成不同的 Nginx 配置文件
  • 通过 facts 变量获取被控端内存大小信息,从而生成不同的 memcached 的配置文件
  • 通过 facts 变量获取被控端主机名称信息,从而生成不同的 Zabbix 配置文件

**案例:**使用 setup 变量

[root@centos8 ~] ansible 192.168.80.18 -m setup -a "filter=ansible_nodename"
[root@centos8 ~] ansible 192.168.80.18 -m setup -a 'filter="ansible_default_ipv4"'

范例:

[root@ansible ~] vim var.yml
---
# var1.yml
- hosts: websrvsremote_user: rootgather_facts: yes    # 注意: 这个需要 yes 启用tasks:- name: "create log file"file: name=/root/{{ ansible_nodename }}.log state=touch owner=wangj mode=600[root@ansible ~] ansible-playbook var.yml

范例: 显示 ens33 网卡的 IP 地址

[root@ansible ansible] vim show_ip.yml 
- hosts: websrvstasks:- name: show eth0 ip address {{ ansible_facts["ens33"]["ipv4"]["address"] }}    # name 中也可以调用变量debug:msg: IP address {{ ansible_ens33.ipv4.address }}    # 注意: 网卡名称# msg: IP address {{ ansible_facts["eth0"]["ipv4"]["address"] }}# msg: IP address {{ ansible_facts.eth0.ipv4.address }}# msg: IP address {{ ansible_default_ipv4.address }}# msg: IP address {{ ansible_eth0.ipv4.address }}# msg: IP address {{ ansible_eth0.ipv4.address.split('.')[-1] }} # 取 IP 中的最后一个数字[root@ansible ansible] ansible-playbook -v show_ip.yml

范例:

[root@ansible ~] vim test.yml
---
- hosts: websrvstasks:- name: test varfile: path=/root/{{ ansible_facts["ens33"]["ipv4"]["address"] }}.log state=touch    # 注意: 网卡名称信息# file: path=/root/{{ ansible_ens33.ipv4.address }}.log state=touch # 和上面效果一样[root@ansible ~] ansible-playbook test.yml

4.9.2)在 PlayBook 命令行中定义变量

范例:

[root@ansible ~] vim var2.yml
---
- hosts: websrvsremote_user: roottasks:- name: "install package"yum: name={{ pkname }} state=present    # 调用变量# 在 PlayBook 命令行中定义变量
[root@ansible ~] ansible-playbook -e pkname=vsftpd var2.yml

范例:
也可以将多个变量放在一个文件中

# 也可以将多个变量放在一个文件中
[root@ansible ~] cat vars
pkname1: memcached
pkname2: redis[root@ansible ~] vim var2.yml
---
- hosts: websrvsremote_user: roottasks:- name: install package {{ pkname1 }}    # 名称也调用变量 ( 利于我们清楚正在安装什么软件包 )yum: name={{ pkname1 }} state=present- name: install package {{ pkname2 }}yum: name={{ pkname2 }} state=present# 方式一
[root@ansible ~] ansible-playbook -e pkname1=memcached -e pkname2=redis var2.yml# 方式二 ( 指定存放着变量的文件 )
[root@ansible ~] ansible-playbook -e '@vars' var2.yml

4.9.3)在 PlayBook 文件中定义变量

范例: 也可以在 PlayBook 文件中定义变量

[root@ansible ~] vim var3.yml
---
- hosts: websrvsremote_user: rootvars:username: user1        # 定义变量groupname: group1      # 定义变量tasks:- name: "create group {{ groupname }}"group: name={{ groupname }} state=present- name: "create user {{ username }}"user: name={{ username }} group={{ groupname }} state=present# 执行 PlayBook 文件
[root@ansible ~] ansible-playbook var3.yml# 验证
[root@ansible ~] ansible websrvs -m shell -a 'id user1'

范例:变量之间的相互调用

[root@ansible ~] vim var4.yaml
---
- hosts: websrvsremote_user: rootvars:collect_info: "/data/test/{{ansible_default_ipv4['address']}}/"	# 基于默认变量定义了一个新的变量tasks:- name: "Create IP directory"file: name="{{collect_info}}" state=directory		# 引用变量# 执行结果
tree /data/test/
/data/test/
└── 192.168.80.181 directory, 0 files

范例: 变量之间的 相互调用

[root@ansible ansible] cat var2.yml
---
- hosts: websrvsvars:suffix: "txt"file: "{{ ansible_nodename }}.{{suffix}}"		# 基于默认变量定义了一个新的变量tasks:- name: test varfile: path="/data/{{file}}" state=touch		# 引用变量

范例:安装多个包

# 实例一
[root@ansible ~] cat install.yml 
- hosts: websrvsvars:web: httpddb: mariadb-servertasks:- name: install {{ web }} {{ db }}yum:name:- "{{ web }}"- "{{ db }}"state: latest
# 实例二      
[root@ansible ~] cat install2.yml 
- hosts: websrvstasks:- name: install packagesyum: name={{ pack }}vars:pack:- httpd- memcached

范例: 安装指定版本的 MySQL
新增 PlayBook 定义变量功能

[root@ansible ansible] cat install_mysql.yml 
---
# install mysql-5.6.46-linux-glibc2.12-x86_64.tar.gz
- hosts: dbsrvsremote_user: rootgather_facts: novars:version: "mysql-5.6.46-linux-glibc2.12-x86_64"suffix: "tar.gz"file: "{{version}}.{{suffix}}"tasks:- name: "install packages"yum: name=libaio,perl-Data-Dumper,perl-Getopt-Long- name: "create mysql group"group: name=mysql gid=306- name: "create mysql user"user: name=mysql uid=306 group=mysql shell=/sbin/nologin system=yes create_home=no home=/data/mysql- name: "copy tar to remote host and file mode"unarchive: src=/data/ansible/files/{{file}} dest=/usr/local/ owner=root group=root- name: "create linkfile /usr/local/mysql"file: src=/usr/local/{{version}} dest=/usr/local/mysql state=link- name: "data dir"shell: chdir=/usr/local/mysql/ ./scripts/mysql_install_db --datadir=/data/mysql --user=mysqltags: data- name: "config my.cnf"copy: src=/data/ansible/files/my.cnf  dest=/etc/my.cnf- name: "service script"shell: /bin/cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld- name: "enable service"shell: /etc/init.d/mysqld start;chkconfig --add mysqld;chkconfig mysqld ontags: service- name: "PATH variable"copy: content='PATH=/usr/local/mysql/bin:$PATH' dest=/etc/profile.d/mysql.sh- name: "secure script"script: /data/ansible/files/secure_mysql.shtags: script

4.9.4)使用变量文件

可以在一个 独立的 PlayBook 文件 中定义变量,在另一个 PlayBook 文件中引用变量文件中的变量,比 PlayBook 中定义的变量优化级高

# 编写变量文件
vim vars.yml
---
# variables filepackage_name: mariadb-serverservice_name: mariadb
# 在 PlayBook 调用变量文件
vim var5.yml
---
# install package and start service
- hosts: dbsrvsremote_user: rootvars_files:            # 在 PlayBook 调用变量文件- vars.ymltasks:- name: "install package"yum: name={{ package_name }}tags: install- name: "start service"service: name={{ service_name }} state=started enabled=yes

范例:

cat vars2.yml
---
var1: httpd
var2: nginx
cat var6.yml
---
- hosts: webremote_user: rootvars_files:- vars2.ymltasks:- name: create httpd logfile: name=/app/{{ var1 }}.log state=touch- name: create nginx logfile: name=/app/{{ var2 }}.log state=touch

4.9.5)针对主机和主机组 定义变量

4.9.5.1)在主机清单中 针对所有项目的主机和主机分组对应变量

所有项目的 主机变量
在 inventory 主机清单文件中 为指定的主机定义变量 以便于在 PlayBook 中使用

// 范例: 定义主机变量
[websrvs]
www1.magedu.com http_port=80 maxRequestsPerChild=808
www2.magedu.com http_port=8080 maxRequestsPerChild=909

所有项目的组(公共)变量
在 inventory 主机清单文件中 赋予给指定组内所有主机上
在 PlayBook 中可用的变量,如果和主机变量是同名,优先级低于主机变量

// 范例: 公共变量
[websrvs:vars]
http_port=80
ntp_server=ntp.magedu.com
nfs_server=nfs.magedu.com
-- K8S 案例 --
[all:vars]
# --------- Main Variables ---------------
# Cluster container-runtime supported: docker, containerd
CONTAINER_RUNTIME="docker"# Network plugins supported: calico, flannel, kube-router, cilium, kube-ovn
CLUSTER_NETWORK="calico"# Service proxy mode of kube-proxy: 'iptables' or 'ipvs'
PROXY_MODE="ipvs"# K8S Service CIDR, not overlap with node(host) networking
SERVICE_CIDR="192.168.0.0/16"# Cluster CIDR (Pod CIDR), not overlap with node(host) networking
CLUSTER_CIDR="172.16.0.0/16"# NodePort Range
NODE_PORT_RANGE="20000-60000"# Cluster DNS Domain
CLUSTER_DNS_DOMAIN="magedu.local."

范例:

[root@ansible ~] vim /etc/ansible/hosts
[websrvs]
192.168.80.18 hname=www1 domain=magedu.io    # 定义主机变量 ( 主机变量 优先级高 )
192.168.80.28 hname=www2[websrvs:vars]        # 定义分组变量
mark="-"[all:vars]            # 定义公共变量 ( 公共变量优先级低 )
domain=magedu.org# 调用变量 ( 修改主机名 )
[root@ansible ~] ansible websrvs -m hostname -a 'name={{ hname }}{{ mark }}{{ domain }}'

# 命令行指定变量:
# -e 定义变量的优先级更高
[root@ansible ~] ansible websrvs -e domain=magedu.cn -m hostname -a 'name={{ hname }}{{ mark }}{{ domain }}'

范例: K8S 的 ansible 变量文件

[etcd]
10.0.0.104 NODE_NAME=etcd1
10.0.0.105 NODE_NAME=etcd2
10.0.0.106 NODE_NAME=etcd3[kube-master]
10.0.0.103 NEW_MASTER=yes
10.0.0.101
10.0.0.102[kube-node]
10.0.0.109 NEW_NODE=yes
10.0.0.107
10.0.0.108[harbor][ex-lb]
10.0.0.111 LB_ROLE=master EX_APISERVER_VIP=10.0.0.100 EX_APISERVER_PORT=8443
10.0.0.112 LB_ROLE=backup EX_APISERVER_VIP=10.0.0.100 EX_APISERVER_PORT=8443[chrony][all:vars]
CONTAINER_RUNTIME="docker"
CLUSTER_NETWORK="calico"
PROXY_MODE="ipvs"
SERVICE_CIDR="192.168.0.0/16"
CLUSTER_CIDR="172.16.0.0/16"
NODE_PORT_RANGE="20000-60000"
CLUSTER_DNS_DOMAIN="magedu.local."
bin_dir="/usr/bin"
ca_dir="/etc/kubernetes/ssl"
base_dir="/etc/ansible"
4.9.5.2)针对当前项目的主机和主机组的变量

上面的方式是针对所有项目都有效,而官方更建议的方式是使用 ansible 特定项目的主机变量和组变量。生产建议在项目目录中创建额外的两个变量目录,分别是 host_vars 和 group_vars。
host_vars: 下面的文件名和主机清单主机名一致,针对单个主机进行变量定义,格式:host_vars/hostname( 主机变量 )
group_vars: 下面的文件名和主机清单中组名一致,针对单个组进行变量定义,格式:gorup_vars/groupname( 分组变量 )
group_vars/all: 文件内定义的变量对所有组都有效( 公共变量 )

范例: 特定项目的主机变量和分组变量
建议: 主机清单不定义变量( 仅存放主机分组信息 )
变量统一定义在项目目录下的变量目录中( 条理非常清晰 )

# 创建项目目录
[root@ansible ansible] mkdir /data/ansible/test_project -p
[root@ansible ansible] cd /data/ansible/test_project# 编写项目主机清单文件 ( 仅存放主机分组信息 )
[root@ansible test_project] vim hosts
[websrvs]
192.168.80.18
192.168.80.28# 创建项目主机变量目录
[root@ansible test_project] mkdir host_vars# 创建项目分组变量目录
[root@ansible test_project] mkdir group_vars# 定义项目主机变量信息
[root@ansible test_project] vim host_vars/192.168.80.18
id: 1
[root@ansible test_project] vim host_vars/192.168.80.28
id: 2# 定义项目分组变量信息
[root@ansible test_project] vim group_vars/websrvs 
name: web
[root@ansible test_project] vim group_vars/all
domain: magedu.org# 验证项目变量文件
[root@ansible test_project] tree host_vars/ group_vars/
host_vars/
├── 192.168.80.18
└── 192.168.80.28
group_vars/
├── all
└── websrvs0 directories, 4 files# 定义 PlayBook 文件
[root@ansible test_project] vim test.yml
- hosts: websrvstasks:- name: get variablecommand: echo "{{name}}{{id}}.{{domain}}"register: result- name: print variabledebug:msg: "{{result.stdout}}"# 执行
[root@ansible test_project] ansible-playbook test.yml

4.9.6)register 注册变量( 重要 )

参考:https://blog.csdn.net/byygyy/article/details/105624602
在 PlayBook 中可以使用 register 将捕获命令的输出 保存在临时变量中
然后使用 debug 模块进行显示输出
范例: 利用 debug 模块输出变量
作用: 将 Shell 模块中命令的输出信息赋值给 register 注册变量中
注意: ansible 执行结果一般都会返回一个字典类型的数据,你会看到很多你不关心的字段,可以通过指定字典的 key,例如 stdout 或 stdout_lines,只看到你关心的数据。

[root@ansible ~] vim register1.yml
- hosts: 192.168.80.18tasks:- name: "get variable"shell: hostnameregister: name- name: "print variable"debug:msg: "{{ name }}"                   # 输出 register 注册的 name 变量的全部信息, 注意: 变量要加 "" 引起来# msg: "{{ name.cmd }}"             # 显示命令# msg: "{{ name.rc }}"              # 显示命令成功与否# msg: "{{ name.stdout }}"          # 显示命令的输出结果为字符串形式# msg: "{{ name.stdout_lines }}"    # 显示命令的输出结果为列表形式# msg: "{{ name.stdout_lines[0] }}" # 显示命令的输出结果的列表中的第一个元素# msg: "{{ name['stdout_lines'] }}" # 显示命令的执行结果为列表形式// 说明
在第一个 task 中, 使用了 register 注册变量名为 name;
当 Shell 模块执行完毕后, 会将数据放到该
变量中.
在第二个 task 中, 使用了 debug 模块, 并从变量 name 中获取数据.// 注意:
# 输出的 name 实际上相当于是一个字典
# 里面包含很多个键值对信息 ( 我们需要哪个键值对信息,需要指定性选择该键值 )
# 比如: name.stdout ( 在 name 变量后调用键信息 )
[root@centos8 ~] ansible-playbook register1.yml

ansible 执行结果一般都会返回一个字典类型的数据,以此你会看到很多你不关心的字段,我们可以通过指定字典的 key,例如 stdout 或 stdout_lines,只看到你关心的数据。

[root@ansible ~] vim register1.yml
- hosts: 192.168.80.18tasks:- name: "get variable"shell: hostnameregister: name- name: "print variable"debug:msg: "{{ name.stdout }}"            # 取 name 变量的 stdout 键值[root@centos8 ~] ansible-playbook register1.yml

**范例:**使用 register 注册变量 创建文件

[root@ansible ~] vim register2.yml 
- hosts: websrvstasks:- name: "get variable"shell: hostnameregister: name- name: "create file"file: dest=/root/{{ name.stdout }}.log state=touch[root@ansible ~] ansible-playbook register2.yml
[root@centos8 ~] ll /root | grep log

范例: register 和 debug 模块
参考:https://www.cnblogs.com/dgp-zjz/p/15683546.html
自定义 debug 模块的输出结果( 默认输出的 msg 键内容 )

[root@ansible ~] vim debug_test.yml
---
- hosts: 192.168.80.8tasks:- shell: echo "hello world"register: say_hi- shell: "awk -F: 'NR==1{print $1}' /etc/passwd"register: user- debug:var: say_hi.stdout   # 自定义输出变量代替 msg- debug:var: user.stdout     # 自定义输出变量代替 msg[root@ansible ~] ansible-playbook debug_test.yml

范例: 安装启动服务并检查

[root@ansible ansible] vim service.yml
---
- hosts: websrvsvars:package_name: nginxservice_name: nginxtasks:- name: "install {{ package_name }}"yum: name={{ package_name }}- name: "start {{ service_name }}"service: name={{ service_name }} state=started enabled=yes- name: "check service status"shell: ps aux | grep {{ service_name }}register: check_service- name: debugdebug:msg: "{{ check_service.stdout_lines }}"[root@ansible ansible] ansible-playbook service.yml

范例: 批量修改主机名

[root@ansible ansible] vim hostname.yml
- hosts: websrvsvars:host: webdomain: wuhanjiayou.cntasks:- name: "get variable"shell: echo $RANDOM | md5sum | cut -c 1-8register: get_random- name: "print variable"debug:msg: "{{ get_random.stdout }}"- name: "set hostname"hostname: name={{ host }}-{{ get_random.stdout }}.{{ domain }}[root@ansible ansible] ansible-playbook hostname.yml     

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/752894.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux之shell变量

华子目录 什么是变量&#xff1f;变量的名称示例 变量的类型变量的定义示例 自定义变量查看变量&#xff08;自定义变量和全局变量&#xff09; 环境变量定义环境变量&#xff08;全局变量&#xff09;法一法二法三env&#xff0c;printenv&#xff0c;export注意 C语言与shell…

upload-labs 0.1 靶机详解

下载地址https://github.com/c0ny1/upload-labs/releases Pass-01 他让我们上传一张图片&#xff0c;我们先尝试上传一个php文件 发现他只允许上传图片格式的文件&#xff0c;我们来看看源码 我们可以看到它使用js来限制我们可以上传的内容 但是我们的浏览器是可以关闭js功能的…

蓝桥杯-粘木棍-DFS

题目 思路 --有n根木棍&#xff0c;需要将其粘成m根木棍&#xff0c;并求出最小差值&#xff0c;可以用DFS枚举出所有情况。粘之前有n根短木棍&#xff0c;粘之后有m根长木棍&#xff0c;那么让长木棍的初始长度设为0。外循环让所有的短木棍都参与粘&#xff0c;内循环让要粘的…

windows 11访问Debian10上的共享目录

步骤 要在Windows 11上访问Debian 10.0.0的共享目录&#xff0c;可以通过以下步骤来实现&#xff1a; 1. 设置Samba服务&#xff1a;在Debian系统上&#xff0c;需要安装并配置Samba服务&#xff0c;以便能够实现文件夹共享。Samba是一个允许Linux/Unix服务器与Windows操作系…

2024年阿里云数据库价格_云数据库收费标准最新

2024年阿里云数据库价格查询&#xff0c;云数据库优惠活动MySQL版2核2GB 50GB配置99元一年&#xff0c;续费不涨价&#xff0c;续费也是99元1年&#xff0c;云数据库MySQL基础系列经济版 2核4GB 100GB配置227元1年&#xff0c;RDS SQL Server云数据库2核4G配置299元1年&#xf…

【CSS】Vue2使用TailwindCSS方法及相关问题

一.安装 1.npm安装TailwindCSS npm install tailwindcssnpm:tailwindcss/postcss7-compat tailwindcss/postcss7-compat postcss^7 autoprefixer^9 2.创建配置文件 npx tailwindcss init 3.创建postcss.config.js文件 // postcss.config.js module.exports {plugins: {t…

git的下载与安装

下载 首先&#xff0c;打开您的浏览器&#xff0c;并输入Git的官方网站地址 点击图标进行下载 下载页面会列出不同操作系统和平台的Git安装包。根据您的操作系统&#xff08;Windows、macOS、Linux等&#xff09;和位数&#xff08;32位或64位&#xff09;&#xff0c;选择适…

vue使用element-ui 实现自定义分页

可以通过插槽实现自定义的分页。在layout里面进行配置。 全部代码 export default { name:Cuspage, props:{total:Number, }, data(){return {currentPage:1,pageSize:10,} } methods: {setslot (h) {return(<div class"cusPage"›<span on-click{this.toBe…

E4-R升级固件方法 RockChip 3562

芯片&#xff1a;RockChip 3562 开发板 先安装驱动&#xff1a;DriverAssitant_v5.1.1 下载工具&#xff1a;RKDevTool_v3.13_for_window 烧录完整的update.img固件 1.选择update.img 2.关机下&#xff0c;同时Update和Power进入maskrom模式。界面会显示设备 3.点击升级 …

avue-crud顶部操作按钮插槽;avue-crud列数据插槽;avue-crud行操作按钮插槽

1.avue-crud顶部操作按钮插槽&#xff1b; <template slot"menuLeft" slot-scope"{ size }"><div class"left"><div class"btn"><el-button type"primary" size"small" click"onBatchR…

新能源汽车小三电系统

小三电系统 新能源电动汽车的"小三电"系统&#xff0c;一般指车载充电机(OBC)、车载 DC/DC 变换器&#xff0c;和高压直流配电盒(PDU)。一辆纯电动汽车一般配备一台OBC 和一台车载 DC/DC 变换器。OBC将外部输入的交流电转化为直流电输出给电池&#xff0c;DC/DC衔接…

zabbix配置

1 下载zabbix 1 配置yum源 rpm -Uvh https://repo.zabbix.com/zabbix/5.0/rhel/7/x86_64/zabbix-release- 5.0-1.el7.noarch.rpm yum clean all yum makecache fast 完成后会出现zabbix.repo文件 2安装zabbix服务 yum -y install zabbix-server-mysql zabbix-web-mysql z…

使用stream流合并多个List(根据实体类特定属性合并)

开发情景 现有多个List集合,其中都是一样的实体类,这里我想根据实体类的特定属性将它们合并在一起,形成一个最终的List集合。 这里主要用到了Stream流的flatMap方法与reduce方法。 flatMap:可以将多个Stream流合并在一起,形成一个Stream流。 reduce:可以将Stram流中的元…

初级爬虫实战——哥伦比亚大学新闻

文章目录 发现宝藏一、 目标二、简单分析网页1. 寻找所有新闻2. 分析模块、版面和文章 三、爬取新闻1. 爬取模块2. 爬取版面3. 爬取文章 四、完整代码五、效果展示 发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不…

力扣经典题:删除字符使字符串变好

char* makeFancyString(char* s) {int sizestrlen(s);char*arr(char*)malloc(sizeof(char)*size1);if(size<3){return s;}arr[0]s[0];arr[1]s[1];int p2;for(int j2;j<size;j){if(s[j]!s[j-1]||s[j]!s[j-2]){arr[p]s[j];p;}}arr[p]\0;return arr; } 此代码的细节很多&am…

大模型训练准备工作

一、目录 1 大模型训练需要多少算力&#xff1f; 2. 大模型训练需要多少显存&#xff1f; 3. 大模型需要多少数据量训练&#xff1f; 4. 训练时间估计 5. epoch 选择经验 6. 浮点计算性能测试 二、实现 1 大模型训练需要多少算力&#xff1f; 训练总算力&#xff08;Flops&…

python知识点总结(三)

python知识点总结三 1、有一个文件file.txt大小约为10G&#xff0c;但是内存只有4G&#xff0c;如果在只修改get_lines 函数而其他代码保持不变的情况下&#xff0c;应该如何实现? 需要考虑的问题都有那些?2、交换2个变量的值3、回调函数4、Python-遍历列表时删除元素的正确做…

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:TextPicker)

滑动选择文本内容的组件。 说明&#xff1a; 该组件从API Version 8开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 子组件 无 接口 TextPicker(options?: {range: string[] | string[][] | Resource | TextPickerRangeContent[] | Te…

深度解读:如何解决Image-to-Video模型视频生成模糊的问题?

Diffusion Models视频生成-博客汇总 前言&#xff1a;目前Image-to-Video的视频生成模型&#xff0c;图片一般会经过VAE Encoder和Image precessor&#xff0c;导致图片中的信息会受到较大损失&#xff0c;生成的视频在细节信息上与输入的图片有较大的出入。这篇博客结合最新的…

怎么在电脑上记录每日事项,并在桌面上显示便签记事本?

作为一名教师兼班主任&#xff0c;我每天的工作繁忙且多样。从早晨的课程准备&#xff0c;到课间的学生辅导&#xff0c;再到课后的作业批改和家长沟通&#xff0c;每一项工作都需要我细心且有条理地完成。在这样的工作节奏下&#xff0c;如何高效管理每日事项&#xff0c;确保…