从入门到精通Ansible Playbook,一篇就够了

一、Host Inventory(主机清单)

在这里插入图片描述

1.1 简介

Inventory支持对主机进行分组每个组内可以定义多个主机,每个主机都可以定义在任何一个或多个主机组内。

1.2 inventory 文件

默认路径为/etc/ansible/hosts

Ansible Inventory 文件是一个纯文本文件,用于定义 Ansible 执行命令的目标主机和组,以及这些主机和组的变量和属性

Inventory 文件的构成包括:

1)主机与组

  • 主机:一个主机就是目标机器,可以是 IP 地址、域名或在 SSH 配置中定义的别名,也可以使用 ansible_host 指定。

  • 组:可以将多个主机划分到同一个组中,并可以对组进行操作。

    示例:

[WebServer]
192.168.1.10
192.168.1.11
192.168.1.12

[DatabaseServer]
192.168.1.20
192.168.1.21

注意:组名不能包含空格,并且主机和组名必须放在方括号中

2)变量

  • 主机变量:为单个主机指定变量,使用主机名或 IP 地址作为标识符,变量可以设置为一个或多个值。

    示例:

[ServerA]
192.168.1.10 http_port=80 https_port=443

[ServerB]
serverb.example.com ansible_user=admin ansible_password=1234
  • 组变量:在组名之后,使用 vars 关键字设置变量,可以在组间共享变量。示例:
#所有主机指定 `ansible_ssh_user` 变量,这意味着每个主机都具有该变量。
#为每个主机定义唯一的 `name` 变量。
[WebServer]
192.168.1.10 name=webserver1
192.168.1.11 name=webserver2
192.168.1.12 name=webserver3

[DatabaseServer]
192.168.1.20 name=dbserver1
192.168.1.21 name=dbserver2

[all:vars]
ansible_ssh_user=centos

3)组的嵌套
将一个组嵌套到另一个组中,在 Inventory 文件中使用 :children 关键字。

示例:

#将 `WebServer` 和 `DatabaseServer` 组嵌套到 `Production` 组中。
[WebServer]
192.168.1.10
192.168.1.11
192.168.1.12

[DatabaseServer]
192.168.1.20

[Production:children]
WebServer
DatabaseServer

4)别名
使用 Alias(别名)来引用 Inventory 中的主机。

示例:

#为 `WebServer` 和 `DatabaseServer` 组定义别名,并将它们作为两个分离的组 `Web` 和 `Db` 的成员
#创建了一个名为 `Production` 的组,该组由这两个组的别名组成。
[WebServer]
192.168.1.10
192.168.1.11
192.168.1.12

[DatabaseServer]
192.168.1.20

[Web:children]
WebServer

[Db:children]
DatabaseServer

[Production]
@Web
@Db

1.2 inventory 中的变量

hosts 文件中为主机或组定义变量,在 playbook 中可以直接调用变量。

Inventory变量名 含义
ansible_host ansible连接节点时的IP地址
ansible_port 连接对方的端口号,ssh连接时默认为22
ansible_user 连接对方主机时使用的用户名。不指定时,将使用执行ansible或ansible-playbook命令的用户
ansible_password 连接时的用户的ssh密码,仅在未使用密钥对验证的情况下有效
ansible_ssh_private_key_file 指定密钥认证ssh连接时的私钥文件
ansible_ssh_common_args 提供给ssh、sftp、scp命令的额外参数
ansible_become 允许进行权限提升
ansible_become_method 指定提升权限的方式,例如可使用sudo/su/runas等方式
ansible_become_user 提升为哪个用户的权限,默认提升为root
ansible_become_password 提升为指定用户权限时的密码

举个例子

1)首先定义一个 my_port 变量,其值为 http_port 变量;

2)然后使用 uri 模块检查 defined myserver 主机上特定端口的服务是否运行,并将结果存储在 result 变量中;

3)最后使用 debug 模块输出该服务的响应内容。

#编辑清单文件,定义变量
vim /etc/ansible/hosts

[webservers]
192.168.2.102 ansible_host=192.168.2.102 http_port=8080
#在 playbook 中,用 `vars` 字段来使用变量:
- name: Example playbook using inventory variable
  hosts: webservers
  tasks:
    - name: Ping the web server
      uri:
        url: "http://{
    
    {inventory_hostname}}:{
    
    {http_port}}"
        return_content: yes
      register: result
    - name: Show the response
      debug:
        var: result.content

在这里插入图片描述

二、Playbook 剧本

在这里插入图片描述

2.1 简介

Playbook 剧本是由一个或多个play组成的列表。

play的主要功能在于将预定义的一组主机,装扮成事先通过ansible中的task定义好的角色。

Task实际是调用ansible的一个module,将多个play组织在一个playbook中,即可以让它们联合起来,按事先编排的机制执行预定义的动作

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

2.2 Playbook的组成部分

1)Tasks:任务,即通过 task 调用 ansible 的模板将多个操作组织在一个 playbook 中运行;

2)Variables:变量;

3)Templates:模板;

4)Handlers:处理器,当changed状态条件满足时,(notify)触发执行的操作;

5)Roles:角色。

2.3 如何编写Playbook?

2.3.1 基本格式

  • 在单一文件第一行,用连续三个连字号“-” 开始,还有选择性的连续三个点号( … )用来表示文件的结尾;
  • 次行开始正常写Playbook的内容,一般建议写明该Playbook的功能;
  • 使用#号注释代码;
  • 缩进必须是统一的,不能空格和tab混用;
  • 缩进的级别也必须是一致的,同样的缩进代表同样的级别,程序判别配置的级别是通过缩进结合换行来实现的;
    YAML文件内容是区别大小写的,key/value的值均需大小写敏感;
  • 多个key/value可同行写也可换行写,同行使用,分隔;
  • v可是个字符串,也可是另一个列表;
  • 一个完整的代码块功能需最少元素需包括 name 和 task;
  • 一个name只能包括一个task;
  • YAML文件扩展名通常为yml或yaml
xxx.yaml/xxx.yml
--- #表示开始
- name:  #指定play的名称
  hosts: #指定主机清单中定义的主机组名
  remote_user: #指定远程主机的执行用户
  grather_facts: ture|fales #指定是否要收集远程主机的facts信息
  vars:   #自定义变量,只能在当前play有效
    - 变量1: 值1  #格式为key: value
    - 变量2: 值2
  tasks: #定义任务列表,默认从上往下依次执行
    - name: #定义任务的名称
      模块名: 模块参数        
      ignore errors: true  #忽略任务的失败
    - name: #可以定义多个任务
      模块名: 模块参数  
      notify: 任务名  #如以上操作后为changed的状态时,会通过notify指定的名称触发对应名称的handlers操作
      ##条件判断##
     - name:
       模块名: 模块参数
       when: #定义条件表达式(== != > < >= <=),条件成立时执行此task任务,否则不执行任务
       ##循环##
     - name:
       模块名: 模块参数={
    
    {
    
    item}}
       with_items: #定义循环列表
     ##tags模块,标签## 
     - name: 
       模块名: 模块参数 
       tags:
       - 标签1
       - 标签2
        
  handlers: 
    - name: 任务名  #和notify中的任务名相同
      模块名: 模块参数

#无注释版
---
- name: 
  hosts: 
  remote_user:
  grather_facts: ture|fales 
  vars:
    - 变量1: 值1
    - 变量2: 值2
  tasks:
    - name:
      模块名: 模块参数        
      ignore errors: true
    - name:
      模块名:
      notify: 任务名
     - name:
       模块名:
       when:
     - name:
       模块名: 模块参数={
    
    {
    
    item}}
       with_items:
  handlers: 
    - name: 任务名
      模块名: 模块参数

Ansible在执行完某个任务之后并不会立即去执行对应的handler,而是在当前play中所有普通任务都执行完后再去执行handler。

这样的好处是可以多次触发notify,但最后只执行一次对应的handler,从而避免多次重启。

2.3.2 语句的横向/纵向写法

横向写法一般是数组类型

纵向写法一般是列表类型

task任务的模块语法格式
横向格式:
模块名: 参数1=值 参数2={
    
    {
    
    变量名}} ...

纵向格式:
模块名:
  参数1: 值
  参数2: "{
    
    {变量名}}"
  ...
  
with_items 和 vars 的语法格式
横向格式:
with_items: ["值1", "值2", "值3", ...]

值为对象(键值对字段)时:
with_items:
- {
    
    key1: "值1", key2: "值2"}
- {
    
    key1: "值3", key2: "值4"}
...

纵向格式:
with_items:
- 值1
- 值2
- 值3
...

值为对象(键值对字段)时:
with_items:
- key1: "值1"
  key2: "值2"
- key1: "值3"
  key2: "值4"
...

三、Playbook实例和知识点补充

3.1 编写yum安装nginx的playbook

1.先更新主机清单

在这里插入图片描述

2.编写剧本

cd /etc/ansible
#编写yaml文件,安装nginx的剧本
vim test.yaml

---
 - name: first play
   hosts: dbservers
   remote_user: root
   gather_facts: false
   tasks:
     - name: firewalld
       service: name=firewalld state=stopped enabled=no
     - name: selinux
       command: '/usr/sbin/setenforce 0 '
       ignore_errors: true
     - name: mount
       mount: src=/dev/sr0 path=/mnt state=mounted fstype=iso9660
     - name: local.repo
       copy: src=/etc/yum.repos.d/local.repo dest=/etc/yum.repos.d/
     - name: epel.repo
       copy: src=/etc/yum.repos.d/epel.repo dest=/etc/yum.repos.d/
     - name: nginx install
       yum: name=nginx state=latest
     - name: configuration file
       copy: src=/usr/local/nginx/conf/nginx.conf dest=/etc/nginx/nginx.conf
       notify: "reload nginx"
     - name: start nginx
       service: name=nginx state=started enabled=yes
   handlers:
     - name: reload nginx
       service: name=nginx state=reloaded

在这里插入图片描述

3.运行剧本

ansible-playbook test.yaml

在这里插入图片描述

4.查看db服务器组的主机

systemctl status firewalld
getenforce

systemctl status nginx

在这里插入图片描述

3.2 参数补充

#执行playbook
ansible-playbook xx.yaml/yml [参数]
常用参数 描述
--syntax-check 检查yaml文件的语法是否正确
--list-task 检查tasks任务
--list-hosts 检查生效的主机
--start-at-task=' name ' 指定从某个task开始运行 一般用于剧本较长且不想从头重复执行的场景
-k 用来交互输入ssh密码 -ask-pass
-K 用来交互输入sudo密码 -ask-become-pass
-u 指定用户
#检查yaml文件的语法是否正确
ansible-playbook test.yaml --syntax-check    

在这里插入图片描述

#检查tasks任务
ansible-playbook test.yaml --list-task      

在这里插入图片描述

#检查生效的主机
ansible-playbook test.yaml --list-hosts      

在这里插入图片描述

#指定从 nginx install 开始运行
ansible-playbook test.yaml --start-at-task='nginx install'

在这里插入图片描述

3.3 变量的定义和引用

  vars:   #自定义变量,只能在当前play有效
    - 变量1: 值1  #格式为key: value
    - 变量2: 值2
  tasks:  #在任务列表中引用变量
    -name:
     module: {
    
    {
    
    变量1}}

方式一:在yaml文件中定义和引用

vim test2.yml

---
 - name: second play
   hosts: dbservers
   remote_user: root
   gather_facts: true
   vars: 
     - groupname: mysql 
     - username: nginx
   tasks:
     - name: create group
       group: name={
    
    {
    
    groupname}} system=yes gid=306    #使用 {
    
    {key}} 引用变量的值
     - name: create user
       user: name={
    
    {
    
    username}} uid=306 group={
    
    {
    
    groupname}} 
     - name: copy file
       copy: content="{
    
    {
    
    ansible_default_ipv4.network}}" dest=/opt/vars.txt    #在setup模块中可以获取facts变量信息
       
#ansible_default_ipv4为facts变量信息中的字段
#ansible_default_ipv4.network中的 .network表示只提取信息中network部分
ansible-play test2.yml

在这里插入图片描述

方式二:在命令行定义

ansible-playbook test1.yaml -e "username=nginx"
#通过 -e 参数传递一个额外的变量 "username=nginx" 给 playbook
#playbook 将会使用变量 "username" 的值设置为 "nginx"

3.4 指定远程主机sudo切换用户

使用-k-K 参数实现。

1)先编写剧本

vim test2.yaml

---
- hosts: webservers
  remote_user: test2            
  become: yes	                 #2.6版本以后的参数,之前是sudo,意思为切换用户运行
  become_user: root              #指定sudo用户为root
  tasks: 
    - name: ts
      command: ls ./

2)执行剧本

#执行playbook,加上参数-k和-K
ansible-playbook test2.yml -k -K 

3.5 when条件判断

3.5.1 用法

在Ansible中,提供的唯一一个通用的条件判断when指令

当when指令的值为true时,则该任务执行否则不执行该任务。

When指令一个比较常见的应用场景是实现跳过某个主机不执行任务 或者 只有满足条件的主机执行任务。

3.5.2 实例

1.编写剧本,使用条件判断语句

#如果条件判断成功,则对应主机关机
vim test3.yaml

---
- hosts: all
  remote_user: root
  tasks:
   - name: poweroff host 
     command: /usr/sbin/poweroff -r now
     when: ansible_default_ipv4.address == "192.168.2.102"      
     #when指令中的变量名不需要手动加上 {
    
    {}}when: inventory_hostname == "<主机名>"

2.执行剧本

#执行剧本
ansible-playbook test3.yaml

在这里插入图片描述

3.6 迭代(循环结构)

Ansible提供了很多种循环结构,一般都命名为with_items,作用等同于 loop 循环

vim test4.yaml
---
- name: play1
  hosts: dbservers
  gather_facts: false
  tasks: 
    - name: create file
      file:
        path: "{
    
    {item}}"
        state: touch
      with_items: [ /opt/a, /opt/b, /opt/c, /opt/d ]


- name: play2
  hosts: dbservers
  gather_facts: false		
  vars:
    test:
    - /tmp/test1
    - /tmp/test2
    - /tmp/test3
    - /tmp/test4
  tasks: 
    - name: create directories
      file:
        path: "{
    
    {item}}"
        state: directory
      with_items: "{
    
    {test}}"
		
- name: play3
  hosts: dbservers
  gather_facts: false
  tasks:
    - name: add users
      user: name={
    
    {
    
    item.name}} state=present groups={
    
    {
    
    item.groups}}
      with_items:
        - name: test1
          groups: wheel
        - name: test2
          groups: root
或
      with_items:
        - {
    
    name: 'test1', groups: 'wheel'}
        - {
    
    name: 'test2', goups: 'root'}


ansible-playbook test3.yaml

四、Playbook的模块

4.1 Template配置模板模块

用于生成配置模板文件,配合hosts中定义的变量,或者剧本中定义的变量,为不同主机生成不同的配置参数。

Jinja是基于Python的模板引擎。

Template类是Jinja的一个重要组件,可以看作是一个编译过的模板文件,用来产生目标文本,传递Python的变量给模板去替换模板中的标记。

4.1.1 怎么使用?

1)先准备一个xxx.j2配置模板文件,在文件中使用{ {变量名}} 引用主机变量或者vars字段自定义的变量 以及 facts信息字段做变量的值;

2)在playbook剧本中的task任务定义template模块配置。

template: src--xxx.j2 文件路径 dest-远程主机文件路径

4.1.2 实例

1)先准备一个以 .j2 为后缀的 template 模板文件,设置引用的变量

mkdir /etc/ansible/playbook
cp /usr/local/nginx/conf/nginx.conf /etc/ansible/playbook/nginx.conf.j2

在这里插入图片描述

vim /etc/ansible/playbook/nginx.conf.j2

在这里插入图片描述
在这里插入图片描述

2)修改主机清单文件,使用主机变量定义一个变量名相同,而值不同的变量

vim /etc/ansible/hosts

[webservers]
192.168.2.102 http_port=192.168.2.102:80 server_name=www.test1.com:80 root_dir=/var/www/html
192.168.2.103 http_port=192.168.2.103:80 server_name=www.test2.com:80 root_dir=/var/www/html

[dbservers]
192.168.2.106 http_port=192.168.2.103:80 server_name=www.test3.com:80 root_dir=/var/www/html

在这里插入图片描述

3)编写 playbook并执行

#编写剧本
vim nginx1.yaml
---
- name: new play
  hosts: webservers:dbservers
  remote_user: root
  gather_facts: yes
  tasks:
  - name: disable firewalld
    systemd:
      name: firewalld
      state: stopped
      enabled: no
  - name: disable selinux
    command: '/usr/sbin/setenforce 0'
    ignore_errors: true
  - name: copy local repo file
    copy:
      src: /etc/yum.repos.d/repo.bak/local.repo
      dest: /etc/yum.repos.d/
  - name: mount cdrom
    mount: src=/dev/sr0 path=/mnt state=mounted fstype=iso9660
  - name: install dependent packages
    with_items:
    - gcc
    - gcc-c++
    - make
    - pcre-devel
    - zlib-devel
    - openssl-devel
    yum: name={
    
    {
    
    item}} state=present
      #name: "gcc,gcc-c++,make,pcre-devel,zlib-devel,openssl-devel"
      #state: present
  - name: unarchive nginx package
    unarchive: copy=yes src=/opt/nginx-1.24.0.tar.gz dest=/opt/
  - name: install nginx
    shell: chdir=/opt/nginx-1.24.0/ ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_stub_status_module && make && make install
  - name: copy nginx config file
    template: src=/etc/ansible/playbook/nginx.conf.j2 dest=/usr/local/nginx/conf/nginx.conf
    notify: "reload nginx"
  - name: copy nginx systemd control script
    copy: src=/etc/ansible/playbook/nginx.service dest=/usr/lib/systemd/system/
  - name: create nginx user
    user: name=nginx shell=/sbin/nologin create_home=no
  - name: start nginx
    service: name=nginx state=started enabled=yes
  - name: create root dir
    file: path={
    
    {
    
    root_dir}} state=directory
  - name: create index.html for 2.102
    copy: content="this is test1" dest={
    
    {
    
    root_dir}}/index.html
    when: ansible_default_ipv4.address == "192.168.2.102"
  - name: create index.html for 2.103
    copy: content="this is test2" dest={
    
    {
    
    root_dir}}/index.html
    when: ansible_default_ipv4.address == "192.168.2.103"
  - name: create index.html for 2.106
    copy: content="this is test3" dest={
    
    {
    
    root_dir}}/index.html
    when: ansible_default_ipv4.address == "192.168.2.106"
  handlers:
  - name: reload nginx
    service: name=nginx state=reloaded

``在这里插入图片描述

#执行剧本
ansible-playbook nginx1.yaml

在这里插入图片描述

4)切换到组内主机,查看是否配置了不同的参数

grep -v -e '^$' -e '#' /usr/local/nginx/conf/nginx.conf
#观察配置文件是否修改成功

在这里插入图片描述

4.2 tags模块

可以在一个playbook中为某个或某些任务定义“标签”,在执行此playbook时通过ansible-playbook命令使用–tags选项能实现仅运行指定的tasks。

playbook还提供了一个特殊的tags为always。

作用就是当使用always作为tags的task时,无论执行哪一个tags时,定义有always的tags都会执行。

4.3 Roles模块

Roles用于层次性、结构化地组织playbook,适用于代码复用度较高的场景。

4.3.1 Roles模块的作用(重要)

将playbook剧本中的各个play视作一个角色,将各个角色的tasks任务vars变量templates模板files文件等内容放置在指定角色的目录中统一管理。

需要的时候可以在playbook中使用roles角色直接调用,即roles角色可以在playbook中实现代码的复用

4.3.2 roles 的目录结构

cd /etc/ansible/
tree roles/
roles/
├── web/    #相当于 playbook 中的 每一个 play 主题
│   ├── files/
│   ├── templates/
│   ├── tasks/
│   ├── handlers/
│   ├── vars/
│   ├── defaults/
│   └── meta/
└── db/
    ├── files/
    ├── templates/
    ├── tasks/
    ├── handlers/
    ├── vars/
    ├── defaults/
    └── meta/

4.3.3 roles 内各目录含义解释

目录 含义
files 用来存放由 copy 模块或 script 模块调用的文件
templates 用来存放 jinjia2 模板,template 模块会自动在此目录中寻找 jinjia2 模板文件
tasks 此目录应当包含一个 main.yml 文件,用于定义此角色的任务列表,此文件可以使用 include 包含其它的位于此目录的 task 文件
handlers 此目录应当包含一个 main.yml 文件,用于定义此角色中触发条件时执行的动作
vars 此目录应当包含一个 main.yml 文件,用于定义此角色用到的变量
defaults 此目录应当包含一个 main.yml 文件,用于为当前角色设定默认变量。 这些变量具有所有可用变量中最低的优先级,并且可以很容易地被任何其他变量覆盖。所以生产中我们一般不在这里定义变量
meta 此目录应当包含一个 main.yml 文件,用于定义此角色的元数据信息及其依赖关系

4.3.3 在一个 playbook 中使用 roles 的步骤

1)创建以 roles 命名的目录;

#举个例子
mkdir /etc/ansible/roles/ -p    #yum装完默认就有

2)创建全局变量目录(可选);

#举个例子
mkdir /etc/ansible/group_vars/ -p
touch /etc/ansible/group_vars/all     #文件名自己定义,引用的时候注意

3)在 roles 目录中分别创建以各角色名称命名的目录,如 httpd、mysql;

#举个例子
mkdir /etc/ansible/roles/httpd
mkdir /etc/ansible/roles/mysql

4)在每个角色命名的目录中分别创建files、handlers、tasks、templates、meta、defaults和vars目录,用不到的目录可以创建为空目录,也可以不创建;

#举个例子
mkdir /etc/ansible/roles/httpd/{
    
    files,templates,tasks,handlers,vars,defaults,meta}
mkdir /etc/ansible/roles/mysql/{
    
    files,templates,tasks,handlers,vars,defaults,meta}

5)在每个角色的 handlers、tasks、meta、defaults、vars 目录下创建 main.yml 文件,千万不能自定义文件名

#举个例子
touch /etc/ansible/roles/httpd/{
    
    defaults,vars,tasks,meta,handlers}/main.yml
touch /etc/ansible/roles/mysql/{
    
    defaults,vars,tasks,meta,handlers}/main.yml

6)修改 site.yml 文件,针对不同主机去调用不同的角色;

#举个例子
vim /etc/ansible/site.yml
---
- hosts: webservers
  remote_user: root
  roles:
     - httpd
- hosts: dbservers
  remote_user: root
  roles:
     - mysql

7)ansible-playbook运行剧本。

#举个例子
cd /etc/ansible
ansible-playbook site.yml

4.3.4 实例

1) 创建各角色的目录和main.yaml文件

mkdir /etc/ansible/roles/httpd/{
    
    files,templates,tasks,handlers,vars,defaults,meta} -p
mkdir /etc/ansible/roles/mysql/{
    
    files,templates,tasks,handlers,vars,defaults,meta} -p
mkdir /etc/ansible/roles/php/{
    
    files,templates,tasks,handlers,vars,defaults,meta} -p

touch /etc/ansible/roles/httpd/{
    
    defaults,vars,tasks,meta,handlers}/main.yml
touch /etc/ansible/roles/mysql/{
    
    defaults,vars,tasks,meta,handlers}/main.yml
touch /etc/ansible/roles/php/{
    
    defaults,vars,tasks,meta,handlers}/main.yml

在这里插入图片描述

2)编写httpd模块

#写一个简单的tasks/main.yml
vim /etc/ansible/roles/httpd/tasks/main.yml
- name: install apache
  yum: name={
    
    {
    
    pkg}} state=latest
- name: start apache
  service: enabled=true name={
    
    {
    
    svc}} state=started
 

#定义变量:可以定义在全局变量中,也可以定义在roles角色变量中,一般定义在角色变量中存档
vim /etc/ansible/roles/httpd/vars/main.yml
pkg: httpd
svc: httpd

3)编写mysql模块

vim /etc/ansible/roles/mysql/tasks/main.yml
- name: install mysql
  yum: name={
    
    {
    
    pkg}} state=latest
- name: start mysql
  service: enabled=true name={
    
    {
    
    svc}} state=started
  
vim /etc/ansible/roles/mysql/vars/main.yml
pkg:
  - mariadb
  - mariadb-server
svc: mariadb

4)编写php模块

vim /etc/ansible/roles/php/tasks/main.yml
- name: install php
  yum: name={
    
    {
    
    pkg}} state=latest
- name: start php-fpm
  service: enabled=true name={
    
    {
    
    svc}} state=started

vim /etc/ansible/roles/php/vars/main.yml
pkg:
  - php
  - php-fpm
svc: php-fpm

5)编写roles示例

vim /etc/ansible/site.yml
---
- hosts: webservers
  remote_user: root
  roles:
   - httpd
   - mysql
   - php
cd /etc/ansible
ansible-playbook site.yml

在这里插入图片描述

6)效果测试

切换到webservers组的主机
在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/q2524607033/article/details/134089507