34-Ansible常用playbook和大型项目role角色拆分

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了34-Ansible常用playbook和大型项目role角色拆分相关的知识,希望对你有一定的参考价值。

yaml简单示例

#格式要求
在单一文件第一行,用连续三个连字号"-" 开始,还有选择性的连续三个点号( ... )用来表示文件的结尾
次行开始正常写Playbook的内容,一般建议写明该Playbook的功能
使用#号注释代码
缩进的级别也必须是一致的,同样的缩进代表同样的级别,程序判别配置的级别是通过缩进结合换
行来实现的
缩进不支持tab,必须使用空格进行缩进
缩进的空格数不重要,只要相同层级的元素左对齐即可
YAML文件内容是区别大小写的,key/value的值均需大小写敏感
多个key/value可同行写也可换行写,同行使用,分隔
key后面冒号要加一个空格 比如: key: value
value可是个字符串,也可是另一个列表
YAML文件扩展名通常为yml或yaml

案例:palybook 配置nginx服务到被控制端
[root@ubuntu2204 ~]#cat test.yaml
---
#This is a test yaml

-hosts: webservers

tasks:
- name: install package
apt: name=nginx
- name: config
copy: src=/data/files/nginx.conf dest=/etc/nginx/nginx.conf
notify: restart service
- name: sub config
copy:
src: /data/files/www.mooreyxia.conf
dest: /etc/nginx/conf.d/www.mooreyxia.conf
notify: restart service
- name: create data file
file:
path: /data/mooreyxiasite
state: directory
- name: html page file
copy:
src: /data/files/index.html
dest: /data/mooreyxiasite
- name: create group
group: name=www gid=88 system=yes
- name: create user
user: name=www group=www system=yes shell=/sbin/nologin
- name: start service
service:
name: nginx
state: started
enabled: yes

handlers:
- name: restart service
service:
name: nginx
state: restarted

Playbook调用

[root@ubuntu2204 ~]#ansible-playbook  --help
usage: ansible-playbook [-h] [--version] [-v] [-k] [--private-key PRIVATE_KEY_FILE] [-u REMOTE_USER] [-c CONNECTION] [-T TIMEOUT] [--ssh-common-args SSH_COMMON_ARGS]
[--sftp-extra-args SFTP_EXTRA_ARGS] [--scp-extra-args SCP_EXTRA_ARGS] [--ssh-extra-args SSH_EXTRA_ARGS] [--force-handlers] [--flush-cache] [-b]
[--become-method BECOME_METHOD] [--become-user BECOME_USER] [-K] [-t TAGS] [--skip-tags SKIP_TAGS] [-C] [--syntax-check] [-D] [-i INVENTORY]
[--list-hosts] [-l SUBSET] [-e EXTRA_VARS] [--vault-id VAULT_IDS] [--ask-vault-password | --vault-password-file VAULT_PASSWORD_FILES] [-f FORKS]
[-M MODULE_PATH] [--list-tasks] [--list-tags] [--step] [--start-at-task START_AT_TASK]
playbook [playbook ...]

Runs Ansible playbooks, executing the defined tasks on the targeted hosts.

positional arguments:
playbook Playbook(s)

options:
--ask-vault-password, --ask-vault-pass
ask for vault password
--flush-cache clear the fact cache for every host in inventory
--force-handlers run handlers even if a task fails
--list-hosts outputs a list of matching hosts; does not execute anything else
--list-tags list all available tags
--list-tasks list all tasks that would be executed
--skip-tags SKIP_TAGS
only run plays and tasks whose tags do not match these values
--start-at-task START_AT_TASK
start the playbook at the task matching this name
--step one-step-at-a-time: confirm each task before running
--syntax-check perform a syntax check on the playbook, but do not execute it
--vault-id VAULT_IDS the vault identity to use
--vault-password-file VAULT_PASSWORD_FILES, --vault-pass-file VAULT_PASSWORD_FILES
vault password file
--version show programs version number, config file location, configured module search path, module location, executable location and exit
-C, --check dont make any changes; instead, try to predict some of the changes that may occur
-D, --diff when changing (small) files and templates, show the differences in those files; works great with --check
-M MODULE_PATH, --module-path MODULE_PATH
prepend colon-separated path(s) to module library (default=~/.ansible/plugins/modules:/usr/share/ansible/plugins/modules)
-e EXTRA_VARS, --extra-vars EXTRA_VARS
set additional variables as key=value or YAML/JSON, if filename prepend with @
-f FORKS, --forks FORKS
specify number of parallel processes to use (default=5)
-h, --help show this help message and exit
-i INVENTORY, --inventory INVENTORY, --inventory-file INVENTORY
specify inventory host path or comma separated host list. --inventory-file is deprecated
-l SUBSET, --limit SUBSET
further limit selected hosts to an additional pattern
-t TAGS, --tags TAGS only run plays and tasks tagged with these values
-v, --verbose verbose mode (-vvv for more, -vvvv to enable connection debugging)

Connection Options:
control as whom and how to connect to hosts

--private-key PRIVATE_KEY_FILE, --key-file PRIVATE_KEY_FILE
use this file to authenticate the connection
--scp-extra-args SCP_EXTRA_ARGS
specify extra arguments to pass to scp only (e.g. -l)
--sftp-extra-args SFTP_EXTRA_ARGS
specify extra arguments to pass to sftp only (e.g. -f, -l)
--ssh-common-args SSH_COMMON_ARGS
specify common arguments to pass to sftp/scp/ssh (e.g. ProxyCommand)
--ssh-extra-args SSH_EXTRA_ARGS
specify extra arguments to pass to ssh only (e.g. -R)
-T TIMEOUT, --timeout TIMEOUT
override the connection timeout in seconds (default=10)
-c CONNECTION, --connection CONNECTION
connection type to use (default=smart)
-k, --ask-pass ask for connection password
-u REMOTE_USER, --user REMOTE_USER
connect as this user (default=None)

Privilege Escalation Options:
control how and which user you become as on target hosts

--become-method BECOME_METHOD
privilege escalation method to use (default=sudo), use `ansible-doc -t become -l` to list valid choices.
--become-user BECOME_USER
run operations as this user (default=root)
-K, --ask-become-pass
ask for privilege escalation password
-b, --become run operations with become (does not imply password prompting)

Playbook核心组件

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

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

hosts 组件

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

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

案例:
- hosts: webservers:appservers

remote_user 组件

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

案例:
- hosts: webservers
remote_user: root
tasks:
- name: test connection
ping:
remote_user: moore
sudo: yes #默认sudo为root
sudo_user:mooreyxia #sudo为mooreyxia

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.yml
---
#first yaml文件
#
- hosts: webservers
remote_user: root

gather_facts: no
tasks:
- name: task1
debug: msg="task1 running"
- name: task2
debug: msg="task2 running"
- hosts: appservers
remote_user: root

gather_facts: no
tasks:
- name: task3
debug: msg="task3 running"
- name: task4
debug: msg="task4 running"

其它组件说明 tags notify

  • 某任务的状态在运行后为changed时,可通过"notify"通知给相应的handlers任务
  • 还可以通过"tags"给task 打标签,可在ansible-playbook命令上使用-t指定进行调用
ShellScripts 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: webservers
remote_user: root
gather_facts: no
tasks:
- name: "安装Apache"
yum: name=httpd
- name: "复制配置文件"
copy: src=/tmp/httpd.conf dest=/etc/httpd/conf/
notify: restart service
tags: config
- name: "复制配置文件"
copy: src=/tmp/vhosts.conf dest=/etc/httpd/conf.d/
notify: restart service
tags: config
- name: "启动Apache,并设置开机启动"
service: name=httpd state=started enabled=yes

handlers:
- name: restart service
service: httpd
state: restarted

#调用
格式:ansible-playbook <filename.yml> ... [options]

ansible-playbook install-apache.yaml
或者只执行tag部分
ansible-playbook -t config install-apache.yaml

force_handlers

如果不论前面的task成功与否,都希望handlers能执行, 可以使用force_handlers: yes 强制执行handler

案例: 强制调用handlers
- hosts: webservers
force_handlers: yes #无论task中的任何一个task失败,仍强制调用handlers
tasks:
- name: config file
copy: src=nginx.conf dest=/etc/nginx/nginx.conf
notify: restart nginx
- name: install package
yum: name=no_exist_package

handlers:
- name: restart nginx
service: name=nginx state=restarted

Playbook中使用tags组件

在playbook文件中,可以利用tags组件,为特定 task 指定标签,当在执行playbook时,可以只执行特定tags的task,而非整个playbook文件

  • 可以一个task对应多个tag,也可以多个task对应同一个tag
  • 还有另外3个特殊关键字用于标签, tagged, untagged 和 all,它们分别是仅运行已标记,只有未标记和所有任务
  • tags 主要用于调试环境
范例: tag 标签
vim httpd.yml
---
# tags example
- hosts: webservers
remote_user: root
gather_facts: no
tasks:
- 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
#忽略执行指定标签的task
[root@ansible ~]#ansible-playbook --skip-tags conf httpd.yml
#忽略执行没有标签的任务,即只执行有标签的任务
[root@ansible ~]#ansible-playbook httpd.yml --skip-tags untagged

Playbook中使用变量

变量定义:
variable=value
variable: value

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

变量来源:
1. ansible 的 setup facts 远程主机的所有变量都可直接调用
2. 通过命令行指定变量,优先级最高
ansible-playbook -e varname=value test.yml
3. 在playbook文件中定义
vars:
var1: value1
var2: value2
4. 在独立的变量YAML文件中定义
- hosts: all
vars_files:
- vars.yml
5. 在主机清单文件中定义
主机(普通)变量:主机组中主机单独定义,优先级高于公共变量组(公共)变量:针对主机组中所有主机定义统一变量
6. 在项目中针对主机和主机组定义
在项目目录中创建 host_vars和group_vars目录
7. 在role中定义

变量的优先级从高到低如下
-e 选项定义变量 -->playbook中vars_files --> playbook中vars变量定义 -->host_vars/主机名文件 -->主机清单中主机变量
--> group_vars/主机组名文件-->group_vars/all文件--> 主机清单组变量

使用 setup 模块中变量

#使用 facts 变量
facts 包括的信息很多,如: 主机名,IP,CPU,内存,网卡等
facts 变量的实际使用场景案例
通过facts变量获取被控端CPU的个数信息,从而生成不同的Nginx配置文件
通过facts变量获取被控端内存大小信息,从而生成不同的memcached的配置文件
通过facts变量获取被控端主机名称信息,从而生成不同的Zabbix配置文件
通过facts变量获取被控端网卡信息,从而生成不同的主机名
......

案例:使用setup变量
[root@ubuntu2204 ~]#ansible localhost -m setup -a filter="ansible_default_ipv4"
localhost | SUCCESS =>
"ansible_facts":
"ansible_default_ipv4":
"address": "10.0.0.200",
"alias": "eth0",
"broadcast": "10.0.0.255",
"gateway": "10.0.0.2",
"interface": "eth0",
"macaddress": "00:0c:29:df:99:92",
"mtu": 1500,
"netmask": "255.255.255.0",
"network": "10.0.0.0",
"type": "ether"

,
"changed": false

性能优化

每次执行playbook,默认会收集每个主机的所有facts变量,将会导致速度很慢,可以采用下面方法加速

方法1 - 关闭facts采集加速执行,此方法将导致无法使用facts变量
- hosts: all
gather_facts: no

方法2 - 设置facts 的缓存,将facts变量信息存在redis服务器中
[root@ansible ~]# cat /etc/ansible/ansible.cfg
[defaults]
# smart 表示默认收集 facts,但 facts 已有的情况下不会收集,即使用缓存 facts
# implicit 表示默认收集 facts,要禁止收集,必须使用 gather_facts: False
# explicit 则表示默认不收集,要显式收集,必须使用gather_facts: True
gathering = smart #在使用 facts 缓存时设置为smart
fact_caching_timeout = 86400 #缓存时长
fact_caching = redis #缓存存在redis中
fact_caching_connection = 10.0.0.100:6379:0 #0表示redis的0号数据库
#若redis设置了密码
fact_caching_connection = 10.0.0.100:6379:0:password

register 注册变量 - 使用register将捕获命令的输出保存在临时变量中

案例: 利用debug 模块输出变量
[root@ubuntu2204 ~]#cat register1.yaml
---
#register 模块测试

- hosts: webservers

tasks:
- name: get variable
shell: hostname
register: name1
- name: "print variable"
debug:
msg: " name1 "

[root@ubuntu2204 ~]#ansible-playbook register1.yaml

PLAY [webservers] *****************************************************************************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************************************************************************
[WARNING]: Platform linux on host 10.0.0.8 is using the discovered Python interpreter at /usr/bin/python3.9, but future installation of another Python interpreter could change
the meaning of that path. See https://docs.ansible.com/ansible/2.10/reference_appendices/interpreter_discovery.html for more information.
ok: [10.0.0.8]
ok: [10.0.0.200]

TASK [get variable] ***************************************************************************************************************************************************************
changed: [10.0.0.200]
changed: [10.0.0.8]

TASK [print variable] *************************************************************************************************************************************************************
ok: [10.0.0.8] =>
"msg":
"changed": true,
"cmd": "hostname",
"delta": "0:00:00.003766",
"end": "2022-12-21 11:12:26.361378",
"failed": false,
"rc": 0,
"start": "2022-12-21 11:12:26.357612",
"stderr": "",
"stderr_lines": [],
"stdout": "rocky8.mooreyxia.org",
"stdout_lines": [
"rocky8.mooreyxia.org"
]


ok: [10.0.0.200] =>
"msg":
"changed": true,
"cmd": "hostname",
"delta": "0:00:00.029575",
"end": "2022-12-21 11:12:26.283027",
"failed": false,
"rc": 0,
"start": "2022-12-21 11:12:26.253452",
"stderr": "",
"stderr_lines": [],
"stdout": "ubuntu2204.mooreyxia.org",
"stdout_lines": [
"ubuntu2204.mooreyxia.org"
]



PLAY RECAP ************************************************************************************************************************************************************************
10.0.0.200 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
10.0.0.8 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

将多个变量放在一个文件中

[root@ansible ~]#cat vars
pkname1: memcached
pkname2: vsftpd
[root@ansible ~]#vim var2.yml
---
- hosts: webservers
remote_user: root
tasks:
- 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=httpd var2.yml
[root@ansible ~]#ansible-playbook -e @vars var2.yml

案例: 安装指定版本的mysql - 格式需要调整

[root@ansible ansible]#cat install_mysql.yml
---
# install mysql-5.6.46-linux-glibc2.12-x86_64.tar.gz
- hosts: dbservers
remote_user: root
gather_facts: no
vars:
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=mysql
tags: 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 on
tags: 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.sh
tags: script

使用专用的公共的变量文件

可以在一个独立的playbook文件中定义公共变量,在其它的playbook文件中可以引用变量文件中的变量,此方式比playbook中定义的变量优化级高

vim vars.yml
---
# variables file
package_name: mariadb-server
service_name: mariadb

vim var5.yml
---
#install package and start service
- hosts: dbservers
remote_user: root
vars_files:
- vars.yml
tasks:
- name: install package
yum: name= package_name
tags: install
- name: start service
service: name= service_name state=started enabled=yes

所有项目的组(公共)变量

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

案例1:
[root@ansible ~]#vim /etc/ansible/hosts
[webservers]
10.0.0.8 hname=www1 domain=moore.io
10.0.0.7 hname=www2
[webservers:vars]
mark="-"
[all:vars]
domain=mooreyxia.org
[root@ansible ~]#ansible webservers -m hostname -a name= hname mark
domain
#命令行指定变量:
[root@ansible ~]#ansible webservers -e domain=magedu.cn -m hostname -a name=
hname mark domain

案例2:k8s 的ansible 变量文件
[kube-master]
10.0.0.101
10.0.0.102
10.0.0.103 NEW_MASTER=yes
[etcd]
10.0.0.104 NODE_NAME=etcd1
10.0.0.105 NODE_NAME=etcd2
10.0.0.106 NODE_NAME=etcd3
[kube-node]
10.0.0.107
10.0.0.108
10.0.0.109 NEW_NODE=yes
[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"

针对当前项目的主机和主机组的变量

生产建议在每个项目对应的目录中创建额外的两个变量目录,分别是host_vars和group_vars

  • host_vars下面的文件名和主机清单主机名一致,针对单个主机进行变量定义 - 格式:host_vars/hostname
  • group_vars下面的文件名和主机清单中组名一致, 针对单个组进行变量定义 - 格式: group_vars/groupname
  • group_vars/all文件内定义的变量对所有组都有效
案例:特定项目的主机和组变量
[root@ubuntu2204 ~]#mkdir -pv /data/ansible
mkdir: 已创建目录 /data/ansible
[root@ubuntu2204 ~]#cd /data/ansible/
[root@ubuntu2204 ansible]#mkdir host_vars
[root@ubuntu2204 ansible]#mkdir group_vars
[root@ubuntu2204 ansible]#vim host_vars/10.0.0.8
[root@ubuntu2204 ansible]#vim host_vars/10.0.0.200
[root@ubuntu2204 ansible]#cat host_vars/10.0.0.8
id: 2
[root@ubuntu2204 ansible]#cat host_vars/10.0.0.200
id: 1
[root@ubuntu2204 ansible]#vim group_vars/webservers
[root@ubuntu2204 ansible]#cat group_vars/webservers
name: web
[root@ubuntu2204 ansible]#vim group_vars/all
[root@ubuntu2204 ansible]#cat group_vars/all
domain: mooreyxia.org
[root@ubuntu2204 ansible]#tree host_vars/ group_vars/
host_vars/
├── 10.0.0.200
└── 10.0.0.8
group_vars/
├── all
└── webservers

0 directories, 2 files
[root@ubuntu2204 ansible]#vim test.yaml
[root@ubuntu2204 ansible]#cat test.yaml
- hosts: webservers

tasks:
- name: get variable
command: echo " name id . domain "
register: result
- name: print variable
debug:
msg: " result.stdout "

#执行结果
[root@ubuntu2204 ansible]#ansible-playbook test.yaml

PLAY [webservers] *****************************************************************************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************************************************************************
[WARNING]: Platform linux on host 10.0.0.8 is using the discovered Python interpreter at /usr/bin/python3.9, but future installation of another Python interpreter could change
the meaning of that path. See https://docs.ansible.com/ansible/2.10/reference_appendices/interpreter_discovery.html for more information.
ok: [10.0.0.8]
ok: [10.0.0.200]

TASK [get variable] ***************************************************************************************************************************************************************
changed: [10.0.0.200]
changed: [10.0.0.8]

TASK [print variable] *************************************************************************************************************************************************************
ok: [10.0.0.8] =>
"msg": "web2.mooreyxia.org"

ok: [10.0.0.200] =>
"msg": "web1.mooreyxia.org"


PLAY RECAP ************************************************************************************************************************************************************************
10.0.0.200 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
10.0.0.8 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

Template 模板

模板是一个文本文件,可以用于根据每个主机的不同环境而为生成不同的文件

template功能:可以根据和参考模块文件,动态生成相类似的配置文件

template文件存建议放于templates目录下,且命名为 .j2 结尾

yaml/yml 文件和templates目录平级,此时playbook中指定模板文件时可不用指定路径

案例:利用template 同步nginx配置文件

#准备templates/nginx.conf.j2文件
[root@ubuntu2204 ansible]#cat templates/nginx.conf.j2

user user;
worker_processes ansible_processor_vcpus*2;

#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;

#pid logs/nginx.pid;


events
worker_connections connection;



http
include mime.types;
default_type application/octet-stream;
...

#准备playbook
[root@ubuntu2204 ansible]#cat templates1.yaml
---
- hosts: webservers
vars:
nginx_ver: 1.22.1
nginx_file: "nginx-nginx_ver.tar.gz"
nginx_url: "http://nginx.org/download/nginx_file"
user: www
connection: "2048"
install_path: /tmp/nginx

tasks:
- name: download nginx src file
unarchive:
src: "nginx_url"
dest: /tmp/
remote_src: yes

- name: create install path
file:
path: "install_path"
state: directory

- name: create nginx config
template:
src: nginx.conf.j2
dest: "install_path/nginx.conf"
mode: 600
owner: bin
group: daemon

#执行
[root@ubuntu2204 ansible]#ansible-playbook templates1.yaml
[WARNING]: Found variable using reserved name: connection

PLAY [webservers] **********************************************************************************************

TASK [Gathering Facts] *****************************************************************************************
[WARNING]: Platform linux on host 10.0.0.8 is using the discovered Python interpreter at /usr/bin/python3.9,
but future installation of another Python interpreter could change the meaning of that path. See
https://docs.ansible.com/ansible/2.10/reference_appendices/interpreter_discovery.html for more information.
ok: [10.0.0.8]
ok: [10.0.0.200]

TASK [download nginx src file] *********************************************************************************
changed: [10.0.0.8]
changed: [10.0.0.200]

TASK [create install path] *************************************************************************************
changed: [10.0.0.200]
changed: [10.0.0.8]

TASK [create nginx config] *************************************************************************************
changed: [10.0.0.200]
changed: [10.0.0.8]

PLAY RECAP *****************************************************************************************************
10.0.0.200 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
10.0.0.8 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0


#查看10.0.0.8
[root@rocky8 ~]#ll /tmp/
total 0
[root@rocky8 ~]#ll /tmp/
total 0
drwxr-xr-x 2 root root 24 Dec 21 17:38 nginx
drwxr-xr-x 8 moore moore 158 Oct 19 16:02 nginx-1.22.1
[root@rocky8 ~]#cat /tmp/nginx/nginx.conf

user www;
worker_processes 4;

#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;

#pid logs/nginx.pid;


events
worker_connections 2048;



http
include mime.types;
default_type application/octet-stream;

#log_format main $remote_addr - $remote_user [$time_local] "$request"
# $status $body_bytes_sent "$http_referer"
# "$http_user_agent" "$http_x_forwarded_for";

#access_log logs/access.log main;

sendfile on;
#tcp_nopush on;

#keepalive_timeout 0;
keepalive_timeout 65;
....

10.0.0.200 也一样

template中也可以使用流程控制 for 循环和 if 条件判断,实现动态生成文件功能

案例:for 循环

#准备templates
[root@ubuntu2204 ~]#cat /data/ansible/templates/web.conf.j2
% for vhost in vhosts %
server
listen vhost.listen
server_name vhost.server_name
root vhost.root

% endfor %

#准备palybook 下载 创建存放文件 配置文件
[root@ubuntu2204 ~]#cat /data/ansible/templates.yaml
---
- hosts: webservers
vars:
nginx_ver: 1.22.1
nginx_file: "nginx-nginx_ver.tar.gz"
nginx_url: "http://nginx.org/download/nginx_file"
user: www
connection: "2048"
install_path: /tmp/nginx
vhosts:
- listen: 81
server_name: www.a.cn
root: web1

- listen: 82
server_name: www.b.com
root: web2

- listen: 83
server_name: www.c.org
root: web3

tasks:
- name: download nginx src file
unarchive:
src: "nginx_url"
dest: /tmp/
remote_src: yes

- name: create install path
file:
path: "install_path"
state: directory

- name: create nginx config
template:
src: nginx.conf.j2
dest: "install_path/nginx.conf"
mode: 600
owner: bin
group: daemon

#执行
[root@ubuntu2204 ansible]#ansible-playbook templates.yaml
[WARNING]: Found variable using reserved name: connection

PLAY [webservers] **********************************************************************************************

TASK [Gathering Facts] *****************************************************************************************
[WARNING]: Platform linux on host 10.0.0.8 is using the discovered Python interpreter at /usr/bin/python3.9,
but future installation of another Python interpreter could change the meaning of that path. See
https://docs.ansible.com/ansible/2.10/reference_appendices/interpreter_discovery.html for more information.
ok: [10.0.0.8]
ok: [10.0.0.200]

TASK [download nginx src file] *********************************************************************************
changed: [10.0.0.200]
changed: [10.0.0.8]

TASK [create install path] *************************************************************************************
changed: [10.0.0.200]
changed: [10.0.0.8]

TASK [create nginx config] *************************************************************************************
changed: [10.0.0.200]
changed: [10.0.0.8]

PLAY RECAP *****************************************************************************************************
10.0.0.200 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
10.0.0.8 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

#查看结果
10.0.0.200

[root@ubuntu2204 ansible]#ll /tmp/nginx
nginx/ nginx-1.22.1/
[root@ubuntu2204 ansible]#cat /tmp/nginx/nginx.conf
server
listen 81
server_name www.a.cn
root web1

server
listen 82
server_name www.b.com
root web2

server
listen 83
server_name www.c.org
root web3


10.0.0.8
[root@rocky8 ~]#ll /tmp/
total 0
drwxr-xr-x 2 root root 24 Dec 21 17:24 nginx
drwxr-xr-x 8 moore moore 158 Oct 19 16:02 nginx-1.22.1
[root@rocky8 ~]#cat /tmp/nginx/nginx.conf
server
listen 81
server_name www.a.cn
root web1

server
listen 82
server_name www.b.com
root web2

server
listen 83
server_name www.c.org
root web3
案例:if 条件判断

#templnginx6.yml
- hosts: webservers
remote_user: root
vars:
nginx_vhosts:
- web1:
listen: 8080
root: "/var/www/nginx/web1/"
- web2:
listen: 8080
server_name: "web2.mooreyxia.org"
root: "/var/www/nginx/web2/"
- web3:
listen: 8080
server_name: "web3.mooreyxia.org"
root: "/var/www/nginx/web3/"

tasks:
- name: template config to
template: src=nginx.conf5.j2 dest=/data/nginx5.conf

#templates/nginx.conf6.j2
% for vhost in nginx_vhosts %
server
listen vhost.listen
% if vhost.server_name is defined %
server_name vhost.server_name #注意缩进
% endif %
root vhost.root #注意缩进

% endfor %

#生成的结果
server
listen 8080
root /var/www/nginx/web1/

server
listen 8080
server_name web2.mooreyxia.org
root /var/www/nginx/web2/

server
listen 8080
server_name web3.mooreyxia.org
root /var/www/nginx/web3/

使用循环迭代

案例1:在task中使用with_items给定要迭代的元素列表
---
- hosts: webservers
remote_user: root

tasks:
- name: add several users
user: name= item state=present groups=wheel
with_items:
- testuser1
- testuser2
- testuser3
#上面语句的功能等同于下面的语句
- name: add several users
user: name=testuser1 state=present groups=wheel
- name: add several users
user: name=testuser2 state=present groups=wheel
- name: add several users
user: name=testuser3 state=present groups=wheel

案例2:迭代嵌套子变量
---
- hosts: webservers
remote_user: root
tasks:
- name: add some groups
group: name= item state=present
with_items:
- nginx
- mysql
- apache
- name: add some users
user: name= item.user group= item.group uid=item.uid state=present
with_items:
- user: nginx, group: nginx,uid: "80"
- user: mysql, group: mysql ,uid: "3306"
- user: apache, group: apache,uid: "8080"

条件判断 when

when语句可以实现条件测试。如果需要根据变量、facts或此前任务的执行结果来做为某task执行与否的前提时要用到条件测试,通过在task后添加when子句即可使用jinja2的语法格式条件测试

案例:判断OS版本
[root@ansible ansible]#cat when.yml
- hosts: all
tasks:
- name: install httpd
yum:
name: "httpd"
when:
- ansible_distribution_file_variety == "RedHat"
- name: install package
apt:
name: "apache2"
when:
- ansible_distribution_file_variety == "Debian"

分组 block

当想在满足同样条件下,执行多个任务时,就需要分组。而不再针对每个任务都是用 when

[root@ansible ansible]#cat block.yml
---
- hosts: localhost
tasks:
- block:
- debug: msg="first"
- debug: msg="second"
when:
- ansible_facts[distribution] == "CentOS"
- ansible_facts[distribution_major_version] == "8"
#相当于下面写法
---
- hosts: localhost
tasks:
- debug: msg="first"
when:
- ansible_facts[distribution] == "CentOS"
- ansible_facts[distribution_major_version] == "8"
- debug: msg="second"
when:
- ansible_facts[distribution] == "CentOS"
- ansible_facts[distribution_major_version] == "8"

changed_when

关闭 changed 状态 - 当确定某个task不会对被控制端做修改时但执行结果却显示是黄色的changed状态,可以通过 changed_when: false 关闭changed状态

案例:changed_when 检查task返回结果,决定是否继续向下执行
[root@ansible ansible]#cat test_changed_when.yml
---
- hosts: webservers
tasks:
- name: install nginx
yum: name=nginx
- name: config file
template: src="nginx.conf.j2" dest="/etc/nginx/nginx.conf"
notify: restart nginx
- name: check config
shell: /usr/sbin/nginx -t
register: check_nginx_config
changed_when:
- check_nginx_config.stdout.find(successful) #如果执行结果中有successful字符串,则继续执行,如果没有则停止向下执行
- false #nginx -t 每次成功执行是changed状态,关闭此changed状态
- name: start service
service: name=nginx state=started enabled=yes
handlers:
- name: restart nginx
service: name=nginx state=restarted

滚动执行

管理节点过多导致的超时问题解决方法

默认情况下,Ansible将尝试并行管理playbook中所有的机器。对于滚动更新用例,可以使用serial关键字定义Ansible一次应管理多少主机,还可以将serial关键字指定为百分比,表示每次并行执行的主机数占总数的比例

案例:
#vim test_serial.yml
---
- hosts: all
serial: 2 #每次只同时处理2个主机,将所有task执行完成后,再选下2个主机再执行所有task,直至所有主机
gather_facts: False

tasks:
- name: task one
comand: hostname
- name: task two
command: hostname

委派至其它主机执行

利用委托技术,可以在非当前被控主机的其它主机上执行指定操作

注意: 当前执行的被管理端主机需要实现到被委派主机的ssh key 验证才能实现委派

案例: 创建普通用户基于ssh key验证

[root@ansible ansible]#cat ssh_key_push.yml
---
# 创建普通用户管理ansible
- hosts: webservers
vars:
- user_name: ssh_demo

tasks:
# manage 节点执行
- name: Create Manager user_name
user:
name: " user_name "
generate_ssh_key: yes
ssh_key_bits: 2048
ssh_key_file: ".ssh/id_rsa"
register: user_message
delegate_to: localhost # 委派给管理端
run_once: true # 委派任务仅执行一次

# node 节点执行
- name: 打印管理用户的key结果
debug:
msg: " user_message.ssh_public_key "

- name: 在被控端上创建用户
user:
name: " user_name "

- name: 在被控端上创建用户.ssh目录
file:
path: "/home/ user_name /.ssh"
state: directory
owner: " user_name "
group: " user_name "
mode: "0700"

- name: 将管理端 user_name 用户的key存储到被控端
copy:
content: " user_message.ssh_public_key "
dest: "/home/ user_name /.ssh/authorized_keys"
owner: " user_name "
group: " user_name "
mode: "0600"

- name: 配置被控制端sudo提权
lineinfile:
path: /etc/sudoers
line: " user_name ALL=(ALL) NOPASSWD:ALL"

#执行
[root@ubuntu2204 ansible]#ansible-playbook ssh_key_push.yaml

PLAY [webservers] **********************************************************************************************

TASK [Gathering Facts] *****************************************************************************************
[WARNING]: Platform linux on host 10.0.0.8 is using the discovered Python interpreter at /usr/bin/python3.9,
but future installation of another Python interpreter could change the meaning of that path. See
https://docs.ansible.com/ansible/2.10/reference_appendices/interpreter_discovery.html for more information.
ok: [10.0.0.8]
ok: [10.0.0.200]

TASK [Create Manager ssh_demo] *********************************************************************************
changed: [10.0.0.8]

TASK [打印管理用户的key结果] ********************************************************************************************
ok: [10.0.0.8] =>
"msg": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCO72al73U2cAN6LjggrvY6ufhTf4m4IcR+ZkhHlk+NyFjYZ4aVNOmFRk1GZlNupMX2ZFe6BOXEPiKjLQHhYbrb7w29OAwq/IFhIzgLmURvn8yKcWV7+RAmJ6ZLbNw21ogqHAEOamUCvLi8GAnKPFFy+vcA86F6OQZjoP/GWA34r9ojjLHoQdxaokHujqzZZYbVMAKYEFSl6CHHoo14AIMiIoafchw8mgAyAr+uFRze5PJjNQ2o86jZUlBwBuHxrhyaYdx7p/sNRh/AjfVjZv5abHb4N5HzXofqjxOgsdgN9Ogm8yFt9gDypuVsb/8C1akiXG5o5aQhvYygG4xGtK7n ansible-generated on ubuntu2204.wang.org"

ok: [10.0.0.200] =>
"msg": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCO72al73U2cAN6LjggrvY6ufhTf4m4IcR+ZkhHlk+NyFjYZ4aVNOmFRk1GZlNupMX2ZFe6BOXEPiKjLQHhYbrb7w29OAwq/IFhIzgLmURvn8yKcWV7+RAmJ6ZLbNw21ogqHAEOamUCvLi8GAnKPFFy+vcA86F6OQZjoP/GWA34r9ojjLHoQdxaokHujqzZZYbVMAKYEFSl6CHHoo14AIMiIoafchw8mgAyAr+uFRze5PJjNQ2o86jZUlBwBuHxrhyaYdx7p/sNRh/AjfVjZv5abHb4N5HzXofqjxOgsdgN9Ogm8yFt9gDypuVsb/8C1akiXG5o5aQhvYygG4xGtK7n ansible-generated on ubuntu2204.wang.org"


TASK [在被控端上创建用户] ***********************************************************************************************
ok: [10.0.0.200]
changed: [10.0.0.8]

TASK [在被控端上创建用户.ssh目录] *****************************************************************************************
ok: [10.0.0.200]
changed: [10.0.0.8]

TASK [将管理端 ssh_demo 用户的key存储到被控端] ******************************************************************************
changed: [10.0.0.200]
changed: [10.0.0.8]

TASK [配置被控制端sudo提权] *************************************************************************************
changed: [10.0.0.200]
changed: [10.0.0.8]

PLAY RECAP *****************************************************************************************************
10.0.0.200 : ok=6 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
10.0.0.8 : ok=7 changed=5 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0


#查看10.0.0.200
[root@ubuntu2204 ansible]#getent passwd
[root@ubuntu2204 ansible]#su - ssh_demo
$ ssh 10.0.0.8
The authenticity of host 10.0.0.8 (10.0.0.8) cant be established.
ED25519 key fingerprint is SHA256:rziuY3aU2QPQ9Aj+y//KUMlP8fkRzlREsMZcUn2sRuk.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 10.0.0.8 (ED25519) to the list of known hosts.
[ssh_demo@rocky8 ~]$exit
logout
Connection to 10.0.0.8 closed.
$ ssh 10.0.0.8
Last login: Wed Dec 21 20:52:30 2022
[ssh_demo@rocky8 ~]$

[root@ubuntu2204 ansible]#cat /home/ssh_demo/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCO72al73U2cAN6LjggrvY6ufhTf4m4IcR+ZkhHlk+NyFjYZ4aVNOmFRk1GZlNupMX2ZFe6BOXEPiKjLQHhYbrb7w29OAwq/IFhIzgLmURvn8yKcWV7+RAmJ6ZLbNw21ogqHAEOamUCvLi8GAnKPFFy+vcA86F6OQZjoP/GWA34r9ojjLHoQdxaokHujqzZZYbVMAKYEFSl6CHHoo14AIMiIoafchw8mgAyAr+uFRze5PJjNQ2o86jZUlBwBuHxrhyaYdx7p/sNRh/AjfVjZv5abHb4N5HzXofqjxOgsdgN9Ogm8yFt9gDypuVsb/8C1akiXG5o5aQhvYygG4xGtK7n ansible-generated on ubuntu2204.mooreyxia.org


查看10.0.0.8
[root@rocky8 ~]#getent passwd
ssh_demo:x:1002:1002::/home/ssh_demo:/bin/bash
[root@rocky8 ~]#cat /home/ssh_demo/.ssh/authorized_keys
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCO72al73U2cAN6LjggrvY6ufhTf4m4IcR+ZkhHlk+NyFjYZ4aVNOmFRk1GZlNupMX2ZFe6BOXEPiKjLQHhYbrb7w29OAwq/IFhIzgLmURvn8yKcWV7+RAmJ6ZLbNw21ogqHAEOamUCvLi8GAnKPFFy+vcA86F6OQZjoP/GWA34r9ojjLHoQdxaokHujqzZZYbVMAKYEFSl6CHHoo14AIMiIoafchw8mgAyAr+uFRze5PJjNQ2o86jZUlBwBuHxrhyaYdx7p/sNRh/AjfVjZv5abHb4N5HzXofqjxOgsdgN9Ogm8yFt9gDypuVsb/8C1akiXG5o5aQhvYygG4xGtK7n ansible-generated on ubuntu2204.mooreyxia.org

Yaml 文件的相互调用

#利用include 或 include_tasks 可以在某个task中调用其它的只有task内容的yaml文件
案例:
[root@ansible ansible]#cat a.yml
---
- hosts: webservers
tasks:
- name: run a job
command: wall run a job
- name: excute b.yml
include: b.yml #调用另一个yaml文件
#include_tasks: b.yml #另一种写法
[root@ansible ansible]#cat b.yml
- name: run b job
command: wall run b job


#import_playbook 可以将多个包含完整内容的yml文件由一个yml统一调用
案例:
[root@ansible ansible]#cat main.yml
- import_playbook: tasks1.yml
- import_playbook: tasks2.yml
[root@ansible ansible]#cat tasks1.yml
---
- hosts: webservers
tasks:
- name: run task1 job
command: wall run task1 job
[root@ansible ansible]#cat tasks2.yml
---
- hosts: dbservers
tasks:
- name: run task2 job
command: wall run task2 job
[root@ansible ansible]#ansible-play main.yml

Roles 角色

34-Ansible常用playbook和大型项目role角色拆分_Roles

roles就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中,并可以便捷地include它们的一种机制

运维复杂的场景:建议使用 roles,代码复用度高

#roles:多个角色的集合目录, 可以将多个的role,分别放至roles目录下的独立子目录中,如下示例
roles/
mysql/
nginx/
tomcat/
redis/

#默认roles存放路径
/root/.ansible/roles
/usr/share/ansible/roles
/etc/ansible/roles

#roles目录结构:
playbook1.yml
playbook2.yml
roles/
project1/
tasks/
files/
vars/
templates/
handlers/
defaults/
meta/
project2/
tasks/
files/
vars/
templates/
handlers/
defaults/
meta/

Roles各目录作用

roles/project/ :项目名称,有以下子目录

  • files/ :存放由copy或script模块等调用的文件
  • templates/:template模块查找所需要模板文件的目录
  • tasks/:定义task,role的基本元素,至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含
  • handlers/:至少应该包含一个名为main.yml的文件;此目录下的其它的文件需要在此文件中通过include进行包含
  • vars/:定义变量,至少应该包含一个名为main.yml的文件;此目录下的其它的变量文件需要在此文件中通过include进行包含,也可以通过项目目录中的group_vars/all定义变量,从而实现角色通用代码和项目数据的分离
  • meta/:定义当前角色的特殊设定及其依赖关系,至少应该包含一个名为main.yml的文件,其它文件需在此文件中通过include进行包含defaults/:设定默认变量时使用此目录中的main.yml文件,比vars的优先级低

创建role的步骤

1 创建role的目录结构.在以roles命名的目录下分别创建以各角色名称命名的目录,如mysql等,在每个角色命名的目录中分别创建相关的目录和文件,比如tasks、files、handlers、templates和vars等目录;用不到的目录可以创建为空目录,也可以不创建
2 编写和准备指定role的功能文件,包括: tasks,templates,vars等相关文件
3 编写playbook文件调用上面定义的role,应用到指定的主机

针对大型项目使用Roles进行编排

案例:实现 Nginx 角色
[root@ansible ~]#mkdir -pv
/data/ansible/roles/nginx/tasks,handlers,templates,vars
#创建task文件
[root@ansible ~]#cd /data/ansible/roles/nginx/
[root@ansible nginx]#vim tasks/main.yml
- include: install.yml
- include: config.yml
- include: index.yml
- include: service.yml
[root@ansible nginx]#vim tasks/install.yml
- name: install
yum: name=nginx
[root@ansible nginx]#vim tasks/config.yml
- name: config file for centos7
template: src=nginx7.conf.j2 dest=/etc/nginx/nginx.conf
when: ansible_distribution_major_version=="7"
notify: restart
- name: config file for centos8
template: src=nginx8.conf.j2 dest=/etc/nginx/nginx.conf
when: ansible_distribution_major_version=="8"
notify: restart
#跨角色调用文件
[root@ansible nginx]#vim tasks/index.yml
- name: index.html
copy: src=roles/httpd/files/index.html dest=/usr/share/nginx/html/
[root@ansible nginx]#vim tasks/service.yml
- name: start service
service: name=nginx state=started enabled=yes
#创建handler文件
[root@ansible nginx]#cat handlers/main.yml
- name: restart
service: name=nginx state=restarted
#创建两个template文件
[root@ansible nginx]#cat templates/nginx7.conf.j2
...省略...
user user;
worker_processes ansible_processor_vcpus+3; #修改此行
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
...省略...
[root@ansible nginx]#cat templates/nginx8.conf.j2
...省略...
user user;
worker_processes ansible_processor_vcpus**3; #修改此行
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
...省略...
#创建变量文件
[root@ansible nginx]#vim vars/main.yml
user: daemon
#目录结构如下
[root@ansible ~]#tree /data/ansible/roles/nginx/
/data/ansible/roles/nginx/
├── handlers
│ └── main.yml
├── tasks
│ ├── config.yml
│ ├── file.yml
│ ├── install.yml
│ ├── main.yml
│ └── service.yml
├── templates
│ ├── nginx7.conf.j2
│ └── nginx8.conf.j2
└── vars
└── main.yml
4 directories, 9 files
#在playbook中调用角色
[root@ansible ~]#vim /data/ansible/role_nginx.yml
---
#nginx role
- hosts: webservers
roles:
- role: nginx
#运行playbook
[root@ansible ~]#ansible-playbook /data/ansible/role_nginx.yml

我是moore,大家一起加油!

以上是关于34-Ansible常用playbook和大型项目role角色拆分的主要内容,如果未能解决你的问题,请参考以下文章

Ansible playbooks入门和编写规范Ansible Playbooks常用模块介绍常用模块集合

Ansible playbooks入门和编写规范Ansible Playbooks常用模块介绍常用模块集合

playbook常用操作

Ansible7:Playbook常用模块

Asible常用的模块和简单的playbook使用

ansible-playbook-常用