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

news2024/9/24 1:20:07

Playbook

  • 一、Host Inventory(主机清单)
    • 1.1 简介
    • 1.2 inventory 文件
    • 1.2 inventory 中的变量
  • 二、Playbook 剧本
    • 2.1 简介
    • 2.2 Playbook的组成部分
    • 2.3 如何编写Playbook?
      • 2.3.1 基本格式
      • 2.3.2 语句的横向/纵向写法
  • 三、Playbook实例和知识点补充
    • 3.1 编写yum安装nginx的playbook
    • 3.2 参数补充
    • 3.3 变量的定义和引用
    • 3.4 指定远程主机sudo切换用户
    • 3.5 when条件判断
      • 3.5.1 用法
      • 3.5.2 实例
    • 3.6 迭代(循环结构)
  • 四、Playbook的模块
    • 4.1 Template配置模板模块
      • 4.1.1 怎么使用?
      • 4.1.2 实例
    • 4.2 tags模块
    • 4.3 Roles模块
      • 4.3.1 Roles模块的作用(重要)
      • 4.3.2 roles 的目录结构
      • 4.3.3 roles 内各目录含义解释
      • 4.3.3 在一个 playbook 中使用 roles 的步骤
      • 4.3.4 实例

一、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_hostansible连接节点时的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组的主机
在这里插入图片描述
在这里插入图片描述

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

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

相关文章

si24r1/nrf24l01

Si24R1 可配置为 Shutdown、 Standby、 Idle-TX、 TX 和 RX 五种工作模式。 芯片上电后为shutdown模式。此模式下不可以通过芯片收发数据&#xff0c;但MCU和芯片可以通过spi协议通信&#xff0c;更改内部寄存器的状态&#xff08;如设置 CONFIG 寄存器下的 PWR_UP 位的值为 1&…

Java练习题2020 -1

统计1到N的整数中&#xff0c;被A除余A-1的偶数的个数 输入说明&#xff1a;整数 N(N<10000), A, (A 输出说明&#xff1a;符合条件的数的个数 输入样例&#xff1a;10 3 输出样例&#xff1a;2 (说明&#xff1a;样例中符合条件的2个数是 2、8) import java.util.Scanner;p…

Java SE 学习笔记(十四)—— IO流(3)

目录 1 缓冲流1.1 缓冲流概述1.2 字节缓冲流1.3 字符缓冲流 2 转换流2.1 字符输入转换流2.1 字符输出转换流 3 序列化3.1 对象序列化3.2 对象反序列化 4 打印流5 与Properties结合使用6 IO 框架 1 缓冲流 1.1 缓冲流概述 我们之前学习的字节流、字符流属于基础流、原始流&…

引流大法,助你销量翻倍!亚马逊新卖家必备的六种流量来源!

作为亚马逊的一个新卖家&#xff0c;我们在新店上传产品之后&#xff0c;第一个目标就是引流&#xff0c;因为流量是支撑店铺销量的重要环节&#xff0c;那么我们引流的方式都有哪些呢&#xff1f; ​首先我们要知道亚马逊的一些流量来源分别有哪几块&#xff01; 一、平台自…

计算机网络重点概念整理-第五章 传输层【期末复习|考研复习】

第五章 传输层 【期末复习|考研复习】 计算机网络系列文章传送门&#xff1a; 第一章 计算机网络概述 第二章 物理层 第三章 数据链路层 第四章 网络层 第五章 传输层 第六章 应用层 第七章 网络安全 计算机网络整理-简称&缩写 文章目录 第五章 传输层 【期末复习|考研复习…

通过宏定义解决编程难题

大家好&#xff0c;我们今天来通过我们的define定义宏解决C语言上的难题。 实例一&#xff1a; offsetof这个宏我们在学习结构体的时候就已经了解过了&#xff0c;这个宏是我们在计算结构体大小的时候来查看每个结构体成员的偏移量的&#xff0c;那么我们在这里就来模拟实现一…

【LeetCode:2558. 从数量最多的堆取走礼物 | 大根堆】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

面试算法43:在完全二叉树中添加节点

题目 在完全二叉树中&#xff0c;除最后一层之外其他层的节点都是满的&#xff08;第n层有2n-1个节点&#xff09;。最后一层的节点可能不满&#xff0c;该层所有的节点尽可能向左边靠拢。例如&#xff0c;图7.3中的4棵二叉树均为完全二叉树。实现数据结构CBTInserter有如下3种…

线程状态,BLOCKED和WAITING 有什么区别

BLOCKED 和 WAITING 都是属于线程的阻塞等待状态。 BLOCKED BLOCKED 状态是指线程在等待监视器锁的时候的阻塞状态。 也就是在多个线程去竞争 Synchronized 同步锁的时候&#xff0c;没有竞争到锁资源的 线程&#xff0c;会被阻塞等待&#xff0c;这个时候线程状态就是 BLOCK…

众和策略:数据要素市场腾飞在即 游戏市场持续高增长

昨日&#xff0c;两市股指早盘弱势下探&#xff0c;午后沪指在银行、电力等板块的带动下发力拉升&#xff0c;深成指、创业板指均走高。到收盘&#xff0c;沪指涨0.48%报2988.3点&#xff0c;深成指涨0.4%报9566.1点&#xff0c;创业板指涨0.65%报1875.86点&#xff1b;两市合计…

[javaweb]——spring框架之控制反转(IOC)与依赖注入(DI)

&#x1f308;键盘敲烂&#xff0c;年薪30万&#x1f308; 目录 一、概念介绍 二、示例演示 2.1 代码高内聚问题 2.2 三层架构 2.3 分层解耦 2.4 分层解耦的实现 &#x1f4d5;总结 一、概念介绍 控制反转&#xff1a;简称IOC&#xff0c;对象的创建控制权由程序自身转…

vulnhub_DeRPnStiNK靶机渗透测试

VulnHub2018_DeRPnStiNK靶机 https://www.vulnhub.com/entry/derpnstink-1,221/ flag1(52E37291AEDF6A46D7D0BB8A6312F4F9F1AA4975C248C3F0E008CBA09D6E9166) flag2(a7d355b26bda6bf1196ccffead0b2cf2b81f0a9de5b4876b44407f1dc07e51e6) flag4(49dca65f362fee401292ed7ada96f9…

人工智能基础_机器学习006_有监督机器学习_正规方程的公式推导_最小二乘法_凸函数的判定---人工智能工作笔记0046

我们来看一下公式的推导这部分比较难一些, 首先要记住公式,这个公式,不用自己理解,知道怎么用就行, 比如这个(mA)T 这个转置的关系要知道 然后我们看这个符号就是求X的导数,X导数的转置除以X的导数,就得到单位矩阵, 可以看到下面也是,各种X的导数,然后计算,得到对应的矩阵结…

ADI模数转换AD7091的SPI驱动接口verilog,代码/视频

名称&#xff1a;ADI模数转换AD7091的SPI驱动 软件&#xff1a;QuartusII 语言&#xff1a;Verilog 代码功能&#xff1a; 完成ADI单通道模数转换器AD7091R的逻辑接口设计。1 MSPS、超低功耗、12-Bit ADC &#xff08;1&#xff09;实现全部逻辑接口功能&#xff0c;完成对…

云端代码编辑器Atheos

什么是 Atheos &#xff1f; Atheos是一个基于 Web 的 IDE 框架&#xff0c;占用空间小且要求最低&#xff0c;构建于 Codiad 之上&#xff0c;不过 Atheos 已从原始 Codiad 项目完全重写&#xff0c;以利用更现代的工具、更简洁的代码和更广泛的功能。 注意事项 群晖内核版本太…

系列二十、循环依赖(二)

一、请解释下Spring的三级缓存 所谓Spring的三级缓存是Spring内部解决循环依赖的三个Map&#xff0c;即DefaultSingletonBeanRegistry中的三个Map。 二、A、B两对象在三级缓存中的迁移过程 第一步&#xff1a;A创建过程中需要B&#xff0c;于是A将自己放到三级缓存里面&#x…

ubuntu安装nps客户端

Ubuntu安装nps客户端 1.什么是nps内网穿透&#xff1f;2.设备情况3.下载客户端3.链接服务端3.1、无配置文件模式3.2、注册到系统服务(启动启动、监控进程) 1.什么是nps内网穿透&#xff1f; nps是一款轻量级、高性能、功能强大的内网穿透代理服务器。目前支持tcp、udp流量转发…

vue笔记(三)

15、过滤器 过滤器 用法&#xff1a;对要显示的数据进行特定格式化后再显示&#xff08;用于一个简单的逻辑处理&#xff09;语法 1、注册过滤器&#xff1a;Vue.fillter(name,callback) &#xff08;全局&#xff09;或 new Vue{filters&#xff1a;{}}&#xff08;局部&…

Ubuntu20运行SegNeXt代码提取道路水体(四)——成功解决训练与推理自己的数据集iou为0的问题!!

在我的这篇博文里Ubuntu20运行SegNeXt代码提取道路水体(三)——SegNeXt训练与推理自己的数据集 经过一系列配置后 iou算出来是0 经过多次尝试后 终于让我试出来了正确配置方法&#xff01; 具体的配置细节请查看这篇文章 1、在mmseg/datasets下面对数据集进行初始定义 我新建…

使用baostock获取上市公司情况

起因是有个不知道什么专业的同学问了我一题 cs: import baostock as bs import pandas as pd import datetime 日线指标参数包括&#xff1a;date,code,open,high,low,close,preclose,volume,amount,adjustflag,turn,tradestatus,pctChg,peTTM,pbMRQ,psTTM,pcfNcfTTM,isST 周…