Ansible架构

  • Inventory   主机清单,可以对主机分组
  • ansible-hoc   ansible的命令,适用临时场景
  • ansible-playbook   ansible是一个场景的集合,是YAML语言
  • 被控端: 被管理的主机
  • 连接协议:ansible是用的ssh协议,所以被控端不需要安装额外的agent,这也是

ansible-galaxy

连接https://galaxy.ansible.com 下载对应的Role,相当于仓库。从仓库里拉取相关应用

让我们获取一个nginx的role

1、安装

通过Yum安装RPMs适用于 EPEL 6, 7, 以及仍在支持中的Fedora发行版.这里我们直接安装就行。

sudo yum install ansible

配置文件

  • /etc/ansible/ansible.cfg   主配置文件,配置ansible工作特性
  • /etc/ansible/hosts   主机清单
  • /etc/ansible/roles/  存放角色目录

程序

  • /usr/bin/ansible   主程序,临时命令执行工具
  • /usr/bin/ansible-doc  查看配置文档,模块文档
  • /usr/bin/ansible-galaxy  下载\上传优秀代码或role模块的官方平台
  • /usr/bin/ansible-playbook  定制自动化任务,编排剧本工具
  • /usr/bin/ansible-pull  远程执行命令工具
  • /usr/bin/ansible-vault  文件加密工具
  • /usr/bin/ansible-console  基于Console界面与用户交互的执行工具

ansible配置文件详解

  • inventory      = /etc/ansible/hosts   主机列表配置文件
  • library        = /usr/share/my_modules/   库文件存放目录
  • remote_tmp     = ~/.ansible/tmp  临时py命令文件存放在远程主机上的目录
  • local_tmp      = ~/.ansible/tmp  本机的临时命令执行目录
  • forks          = 5    默认并发数
  • sudo_user      = root   默认sudo用户
  • ask_sudo_pass = True  默认sudo用户是否需要密码
  • ask_pass      = True  每次执行ansible命令询问是否需要密码
  • remote_port    = 22   默认ssh端口
  • host_key_checking = False  检查对应主机的host_key,建议取消注释
  • logpath =/var/log/ansible.log 日志文件存放位置

ansible-doc

  • -a 列出所有模块文档(太多不建议)
  • -l  --list 列出所有模块
  • -s --snippet 显示指定模块的playbook模块

示例

  • ansible-doc -l   列出所有模块
  • ansible-doc ping   查看ping模块文档
  • ansible-doc -s  ping   查看ping模块帮助用法

ansible命令用法

ansible <host-pattern> [-m module_name] [-a args]

  • --version 查看版本
  • -m   指定模块
  • -v  详细过程 -vv -vvv更详细
  • --list-hosts  显示主机列表,可简写--list
  • -k  提示输入ssh连接密码,默认key验证
  • -K 提示输入sudo时候的口令
  • -C --check 检查,但不执行
  • -T 执行超时时间,默认10s
  • -u 指定远程执行的用户
  • -b 代替旧版本的sudo切换

ansible <host-pattern>的格式

配置主机列表

  • all 表现所有的主机: ansible all -m ping
  • * 通配符(要加引号):  ansible "*" -m ping  ansible "10.10.3.*" -m ping
  • 或关系: ansible "monserver:ceph*" -m ping
  • 与关系:ansible "monserver:&ceph*" -m ping
  • 非关系(要用‘’号): ansible 'cephserver:!monserver' -m ping

ansible-galaxy

连接https://galaxy.ansible.com下载对应的Role,相当于仓库,可以找到自己想要的应用的role。

下载一个nginx的role

$ ansible-galaxy install nginxinc.nginx
- downloading role 'nginx', owned by nginxinc
- downloading role from https://github.com/nginxinc/ansible-role-nginx/archive/0.11.0.tar.gz

列出相关的本地的role

$ ansible-galaxy list
- nginxinc.nginx, 0.11.

删除一个role

$ ansible-galaxy remove nginxinc.nginx
- successfully removed nginxinc.nginx

ansible密钥分发

这里我们需要准备两台主机,我们需要在主机A上生成秘钥

 ssh-keygen -t rsa

主机清单分组

普通分组
[monserver]
10.10.3.150
10.10.3.151
10.10.3.152
[osdserver]
10.10.3.153
10.10.3.154
10.10.3.155
嵌套分组
[cephserver]
10.10.3.15[:]

测试cephserver 主机组是否可用

ansible cephserver -m ping -k
SSH password:
10.10.3.150 | SUCCESS => {
"changed": false,
"ping": "pong"
}
10.10.3.152 | SUCCESS => {
"changed": false,
"ping": "pong"
}
10.10.3.151 | SUCCESS => {
"changed": false,
"ping": "pong"
}
10.10.3.153 | SUCCESS => {
"changed": false,
"ping": "pong"
}
10.10.3.154 | SUCCESS => {
"changed": false,
"ping": "pong"
}
10.10.3.155 | SUCCESS => {
"changed": false,
"ping": "pong"
}

分发密钥

我们怕密码不同,我们可以把密码配置到主机清单的变量里。

#方法1
[cephserver:vars]
ansible_ssh_user=root
ansible_ssh_pass=
ansible_ssh_port=
#方法2
[osdserver]
10.10.3.153 ansible_ssh_user=root ansible_ssh_pass= ansible_ssh_port=
10.10.3.154 ansible_ssh_user=root ansible_ssh_pass= ansible_ssh_port=
10.10.3.155 ansible_ssh_user=root ansible_ssh_pass= ansible_ssh_port=

这里我们用方法一,我们使用了authorized_key模块

 ansible cephserver -m  authorized_key -a "user=root key='{{lookup('file','/root/.ssh/id_rsa.pub')}}'"
10.10.3.150 | CHANGED => {
    "changed": true,
    "comment": null,
    "exclusive": false,
    "follow": false,
    "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCuimpsq0vBZHHR9ypSlQjucyliwNQUppIkimDcTYiYg9ttRf0A3foPd01nXiez8TP52csdrEDUnZsy85fugtvRatu9eWi8BWXzVm0/9m7NuCDzyOqeoBHgiPPqdOwX7Djp4D0BRiu4YqhzTTjC+dkMvxJAxVpx6eyJglfPL7fII3iL0b45F812de869rqgP6CFIkNuiZGPtxCa/ngyP/ILCmhLRSOddflE1QKviV6J7+VHPOtvI1iK0TQMI2HZolf9sj7nzzUE0lH8gH4PLh8OF6Yup8QoBvHv6Y+EN3z7ORLEji1Sv2iUClQHgwcd6CWfAgy1NNURCyl92/t8D54f root@ceph-moni-0",
    "key_options": null,
    "keyfile": "/root/.ssh/authorized_keys",
    "manage_dir": true,
    "path": null,
    "state": "present",
    "unique": false,
    "user": "root",
    "validate_certs": true
}
10.10.3.152 | CHANGED => {
    "changed": true,
    "comment": null,
    "exclusive": false,
    "follow": false,
    "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCuimpsq0vBZHHR9ypSlQjucyliwNQUppIkimDcTYiYg9ttRf0A3foPd01nXiez8TP52csdrEDUnZsy85fugtvRatu9eWi8BWXzVm0/9m7NuCDzyOqeoBHgiPPqdOwX7Djp4D0BRiu4YqhzTTjC+dkMvxJAxVpx6eyJglfPL7fII3iL0b45F812de869rqgP6CFIkNuiZGPtxCa/ngyP/ILCmhLRSOddflE1QKviV6J7+VHPOtvI1iK0TQMI2HZolf9sj7nzzUE0lH8gH4PLh8OF6Yup8QoBvHv6Y+EN3z7ORLEji1Sv2iUClQHgwcd6CWfAgy1NNURCyl92/t8D54f root@ceph-moni-0",
    "key_options": null,
    "keyfile": "/root/.ssh/authorized_keys",
    "manage_dir": true,
    "path": null,
    "state": "present",
    "unique": false,
    "user": "root",
    "validate_certs": true
}
......

authorized_key

  • - exclusive [default: no]: 是否移除 authorized_keys 文件中其它非指定 key
  • - key: SSH public key(s) 可以是字符串或 url,如:https://github.com/username.keys
  • - key_options [Default: None]: 附加到 key 中的字符串,该字符串会加到 key 的开头
  • - path [Default: (homedir)+/.ssh/authorized_keys]: 指定 authorized_keys 文件存放的位置
  • - state (Choices: present, absent) [Default: present]: present 添加指定 key 到 authorized_keys 文件中;absent 从 authorized_keys 文件中移除指定 key
  • - user: 指定修改远端服务器上哪个用户的 authorized_keys
  • - manage_dir (Choices: yes, no) [Default: yes]: 指定模块是否应该管理 authorized key 文件所在的目录。如果设置为 yes,模块会创建目录,以及设置一个已存在目录的拥有者和权限。如果通过 path 选项,重新指定了一个 authorized key 文件所在目录,那么应该将该选项设置为 no

2、远程执行命令

ansible all -m ping
172.16.138.40 | SUCCESS => {
"changed": false,
"ping": "pong"
}
172.16.138.41 | SUCCESS => {
"changed": false,
"ping": "pong"
}

我们也可以通过主机组执行命令

$ ansible webhost -m command -a  "w"
172.16.138.41 | CHANGED | rc= >>
:: up days, :, users, load average: 0.24, 0.33, 0.27
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
root pts/ 172.16.40.86 : .00s .00s .00s -bash
root pts/ k8s-master : .00s .06s .00s w 172.16.138.40 | CHANGED | rc= >>
:: up days, :, users, load average: 0.98, 0.88, 0.86
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
root pts/ 172.16.40.86 : :08m .29s .29s -bash
root pts/ 172.16.40.86 : .00s .11s .00s ssh -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout= -o ControlPath=/root/.ansible/cp/2c6989e158 -tt 172.16.138.40 /bin/sh -c '/usr/bin/python /root/.ansible/tmp/ansible-tmp-1553146517.04-153785974352870/AnsiballZ_command.py && sleep 0'
root pts/ k8s-master : .00s .10s .01s w
  • webhost 是指定的主机组
  • -m 是指定模块
  • -a 是执行的命令

这里还有一个shell模块。同样也支持写一个命令。

3、管理文件和目录

ansible 172.16.138.41 -m copy -a "src=/etc/ansible dest=/tmp/ansible_test owner=root group=root mode=755"
172.16.138.41 | CHANGED => {
"changed": true,
"dest": "/tmp/ansible_test/",
"src": "/etc/ansible"
}

我们看一下目标主机下/tmp目录

[root@node02 tmp]# ls
ansible_test
[root@node02 tmp]# ls ansible_test/
ansible
[root@node02 tmp]#
  • src 指定源目录
  • dest 指定目标目录

需要注意的是,如果目标主机没有这个目录会自动创建这个目录,如果拷贝是文件,目标主机指定的名字和源如果不同,并且不是已经存在的目录,相当于copy过去又重命名。但相反,如果目标主机上已经处在的目录,则会直接把文件copy到该目录下。

Fetch模块

抓取远程节点上的文件,只能复制远程单个文件,不能复制目录

$ ansible all -m fetch -a "src=/var/log/messages dest=/root/logs"
10.10.3.150 | CHANGED => {
"changed": true,
"checksum": "1e74d4714c730e75b453868a1a842e05b5e1504a",
"dest": "/root/logs/10.10.3.150/var/log/messages",
"md5sum": "32f20a6108ec6a30e5a81435b329c690",
"remote_checksum": "1e74d4714c730e75b453868a1a842e05b5e1504a",
"remote_md5sum": null
}
.....
我们用tree查看一下目录
$ tree
.
├── 10.10.3.150
│   └── var
│   └── log
│   └── messages
├── 10.10.3.151
│   └── var
│   └── log
│   └── messages
├── 10.10.3.152
│   └── var
│   └── log
│   └── messages
├── 10.10.3.153
│   └── var
│   └── log
│   └── messages
├── 10.10.3.154
│   └── var
│   └── log
│   └── messages
└── 10.10.3.155
└── var
└── log
└── messages

File模块

创建一个文件夹

ansible all -m file -a "path=/data state=directory"
10.10.3.154 | CHANGED => {
"changed": true,
"gid": ,
"group": "root",
"mode": "",
"owner": "root",
"path": "/data",
"size": ,
"state": "directory",
"uid":
}
.........

创建文件

 ansible all -m file -a "path=/data/zzk state=touch"
10.10.3.150 | CHANGED => {
"changed": true,
"dest": "/data/zzk",
"gid": ,
"group": "root",
"mode": "",
"owner": "root",
"size": ,
"state": "file",
"uid":
}
..........

删除文件

ansible all -m file -a "path=/data/zzk state=absent"
10.10.3.153 | CHANGED => {
"changed": true,
"path": "/data/zzk",
"state": "absent"
}

3、脚本管理

我们先随便写一个脚本

#!/bin/bash
date >> /tmp/data.txt

ansible需要先把脚本copy到对应主机上

$ ansible 172.16.138.41 -m copy  -a "src=/tmp/1.sh dest=/tmp/test.sh owner=root group=root mode=755"
172.16.138.41 | CHANGED => {
    "changed": true,
    "checksum": "a0d6b0777539641b9aab412a0297b1273e836bbb",
    "dest": "/tmp/test.sh",
    "gid": 0,
    "group": "root",
    "md5sum": "fc416150a5e218531c550b98e6ea35b6",
    "mode": "0755",
    "owner": "root",
    "size": 36,
    "src": "/root/.ansible/tmp/ansible-tmp-1553151731.05-254487603693246/source",
    "state": "file",
    "uid": 0
}

执行远程脚本

ansible 172.16.138.41 -m shell -a "/tmp/test.sh"
172.16.138.41 | CHANGED | rc= >>

4、管理任务计划

ansible 172.16.138.41 -m cron -a "name='test cron' job='touch /tmp/111.txt' weekday=6"
172.16.138.41 | CHANGED => {
"changed": true,
"envs": [],
"jobs": [
"test cron"
]
}
  • cron 定时任务模块
  • name 指定定时任务的名字
  • job 指定定时任务的内容
  • weekday 指定是时间计划,也可以使用*****表示

我们看一下目录主机的定时任务

$ crontab -l
#Ansible: test cron
* * * * touch /tmp/.txt

我们看到有个Ansible的表示,下面是定时任务的内容。

我们可以通过state=absent 来删除定时任务

$ ansible 172.16.138.41 -m cron -a "name='test cron' state=absent"
172.16.138.41 | CHANGED => {
"changed": true,
"envs": [],
"jobs": []
}

5、Playbook

playbook就是把一些模块的集合搞到一个文件里。play的主要功能在于将事先归为一组的主机装扮成事先通过ansible中的task定义好的角色,从根本来讲,所谓的task无非是调用ansible的一个module。将多个play组织在一个playbook中,既可以让他们连通起来按事先编排的机制同唱一台戏。

核心元素:

  • hosts  执行的主机列表
  • tasks  任务集
  • varniables  内置变量或者自定义变量在playbook中调用
  • templates  模板,可以替换模板中的变量并实现一些简单逻辑文件
  • handlers  和notity结合使用,由特定条件触发的操作,满足条件方可执行,否则不执行。
  • tags  标签  指定某条任务执行,用于选择运行playbook中的部分代码,ansible具有幂等性,因此会自动跳过没有变化的部分,即便如此,有些代码为测试其确实没有发生变化的时间依然会非常的长。此时,如果确信没有其他变化, 就可以通过tags跳过这些代码片段。

例如:

---   #表示开始
- hosts: 172.16.138.41 #指定远程主机
remote_user: root #指定远程用户
tasks: #任务
- name: test_playbook #任务名字
shell: touch /tmp/playbook.txt #具体的任务,核心

执行

ansible-playbook /etc/ansible/test.yaml

PLAY [172.16.138.41] ******************************************************************************************************************

TASK [Gathering Facts] ****************************************************************************************************************
ok: [172.16.138.41] TASK [test_playbook] ******************************************************************************************************************
[WARNING]: Consider using the file module with state=touch rather than running 'touch'. If you need to use command because file is
insufficient you can add 'warn: false' to this command task or set 'command_warnings=False' in ansible.cfg to get rid of this message. changed: [172.16.138.41] PLAY RECAP ****************************************************************************************************************************
172.16.138.41 : ok= changed= unreachable= failed=

在palybook中使用file模块和user模块

---
- host: monserver
remote_user: root tasks:
- name: create new file
file: name=/data/newfile state=touch
- name: create net user
user: name=test1

这里我们使用-C参数,-C 是测试一下,不执行真正的结果

ansible-playbook -C test.yaml

PLAY [monserver] ***************************************************************************************

TASK [Gathering Facts] *********************************************************************************
ok: [10.10.3.150]
ok: [10.10.3.152]
ok: [10.10.3.151] TASK [create new file] *********************************************************************************
ok: [10.10.3.150]
ok: [10.10.3.152]
ok: [10.10.3.151] TASK [create net user] *********************************************************************************
changed: [10.10.3.150]
changed: [10.10.3.152]
changed: [10.10.3.151] PLAY RECAP *********************************************************************************************
10.10.3.150 : ok= changed= unreachable= failed=
10.10.3.151 : ok= changed= unreachable= failed=
10.10.3.152 : ok= changed= unreachable= failed=

查看playbook执行文件中有哪些主机

ansible-playbook test.yaml --list-hosts

playbook: test.yaml

  play # (monserver): monserver    TAGS: []
pattern: [u'monserver']
hosts ():
10.10.3.152
10.10.3.150
10.10.3.151

查看playbook执行文件中,有哪些任务

ansible-playbook test.yaml --list-tasks

playbook: test.yaml

  play # (monserver): monserver    TAGS: []
tasks:
create new file TAGS: []
create net user TAGS: []

在指定主机下执行

ansible-playbook test.yaml --limit 10.10.3.152

PLAY [monserver] ***************************************************************************************

TASK [Gathering Facts] *********************************************************************************
ok: [10.10.3.152] TASK [create new file] *********************************************************************************
changed: [10.10.3.152] TASK [create net user] *********************************************************************************
changed: [10.10.3.152] PLAY RECAP *********************************************************************************************
10.10.3.152 : ok= changed= unreachable= failed=

6、Playbook变量

变量的来源:

  • ansible setup facts 来和获取系统变量,举例:ansible monserver  -m  setup  过滤:ansible monserver  -m  setup  -a "filter=ansible_hostname"
  • 在/etc/ansible/hosts中定义
  1. 普通变量:主机组中主机单独定义,优先级高于公共变量
  2. 公共(组)变量:针对主机组中所有主机定义统一变量
  • 通过命令行指定变量,优先级最高。 ansible-playbook -e varname=value
  • 在playbook中定义
  • 在role中定义

我们创建一个用户。通过变量传过去

---
- name: create_user
hosts: 172.16.138.41
remote_user: root
gather_facts: false
vars:
- user: "zzkk"
tasks:
- name: create-user
user: name="{{ user }}"

执行:

ansible-playbook /etc/ansible/user.yaml

PLAY [create_user] ********************************************************************************************************************

TASK [create-user] ********************************************************************************************************************
changed: [172.16.138.41] PLAY RECAP ****************************************************************************************************************************
172.16.138.41 : ok= changed= unreachable= failed=

测试

---
- hosts: monserver
remote_user: root tasks:
- name: install httpd package
yum: name={{ pkname }}
- name: start service
service: name={{ pkname }} state=started enabled=yes

执行

ansible-playbook -e 'pkname=vsftpd' app.yaml

PLAY [monserver] ***************************************************************************************

TASK [Gathering Facts] *********************************************************************************
ok: [10.10.3.152]
ok: [10.10.3.150]
ok: [10.10.3.151] TASK [install httpd package] ***************************************************************************
changed: [10.10.3.152]
changed: [10.10.3.150]
changed: [10.10.3.151] TASK [start service] ***********************************************************************************
changed: [10.10.3.150]
changed: [10.10.3.152]
changed: [10.10.3.151] PLAY RECAP *********************************************************************************************
10.10.3.150 : ok= changed= unreachable= failed=
10.10.3.151 : ok= changed= unreachable= failed=
10.10.3.152 : ok= changed= unreachable= failed=

palybook中定义变量

---
- hosts: monserver
remote_user: root
vars:
- pkname: vsftpd tasks:
- name: install httpd package
yum: name={{ pkname }}
- name: start service
service: name={{ pkname }} state=started enabled=yes

执行

$ ansible-playbook app.yaml

PLAY [monserver] **************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************
ok: [10.10.3.152]
ok: [10.10.3.150]
ok: [10.10.3.151] TASK [install httpd package] **************************************************************************************
changed: [10.10.3.150]
changed: [10.10.3.152]
changed: [10.10.3.151] TASK [start service] **********************************************************************************************
changed: [10.10.3.150]
changed: [10.10.3.152]
changed: [10.10.3.151] PLAY RECAP ********************************************************************************************************
10.10.3.150 : ok= changed= unreachable= failed=
10.10.3.151 : ok= changed= unreachable= failed=
10.10.3.152 : ok= changed= unreachable= failed=

主机清单中定义变量

普遍变量,就是定义单个主机的变量

[monserver]
10.10.3.150 http_port=
10.10.3.151 http_port=
10.10.3.152 http_port=
---
- hosts: monserver
remote_user: root tasks:
- name: hostname
hostname: name=user{{ http_port }}

执行

ansible-playbook -C host.yaml

PLAY [monserver] **************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************
ok: [10.10.3.150]
ok: [10.10.3.152]
ok: [10.10.3.151] TASK [hostname] ***************************************************************************************************
changed: [10.10.3.150]
changed: [10.10.3.151]
changed: [10.10.3.152] PLAY RECAP ********************************************************************************************************
10.10.3.150 : ok= changed= unreachable= failed=
10.10.3.151 : ok= changed= unreachable= failed=
10.10.3.152 : ok= changed= unreachable= failed=

公共变量

[cephserver:vars]
ansible_ssh_user=root
ansible_ssh_pass=
ansible_ssh_port=

7、playbook循环

创建三个文件,并修复其权限为600

---
- hosts: 172.16.138.41
user: root
task:
- name: "touch 1 2 3 file and change file mode"
file: path=/tmp/{{ item }} state=touch mode=
with_items:
- .txt
- .txt
- .txt

执行:

ansible-playbook /etc/ansible/while.yaml

PLAY [172.16.138.41] ******************************************************************************************************************

TASK [Gathering Facts] ****************************************************************************************************************
ok: [172.16.138.41] TASK [touch file and change file mode] ******************************************************************************************
changed: [172.16.138.41] => (item=.txt)
changed: [172.16.138.41] => (item=.txt)
changed: [172.16.138.41] => (item=.txt) PLAY RECAP ****************************************************************************************************************************
172.16.138.41 : ok= changed= unreachable= failed=

8、playbook 条件判断

我们查看一下gather_facts收集到的信息,来作为我们判断的条件,这里我们要获取IP地址。

ansible 172.16.138.41 -m setup
....
"ansible_ens160": {
"active": true,
"device": "ens160",
....
"ipv4": {
"address": "172.16.138.41",
"broadcast": "172.16.138.255",
"netmask": "255.255.255.0",
"network": "172.16.138.0"
},
....

我们写一个判断条件 当ansible_ens160.ipv4.address = 172.16.138.41 执行创建文件

---
- hosts: webhost
user: root
gather_facts: True
tasks:
- name: stady when
shell: touch /tmp/when.txt
when: ansible_ens160.ipv4.address == "172.16.138.41"

执行结果:

ansible-playbook /etc/ansible/when.yaml

PLAY [webhost] ************************************************************************************************************************

TASK [Gathering Facts] ****************************************************************************************************************
ok: [172.16.138.41]
ok: [172.16.138.40] TASK [stady when] *********************************************************************************************************************
skipping: [172.16.138.40]
[WARNING]: Consider using the file module with state=touch rather than running 'touch'. If you need to use command because file is
insufficient you can add 'warn: false' to this command task or set 'command_warnings=False' in ansible.cfg to get rid of this message. changed: [172.16.138.41] PLAY RECAP ****************************************************************************************************************************
172.16.138.40 : ok= changed= unreachable= failed=
172.16.138.41 : ok= changed= unreachable= failed=

这里我们看到跳过172.16.138.40,在172.16.138.41中执行。

8、playbook Handlers

module 具有”幂等”性,所以当远端系统被人改动时,可以重放 playbooks 达到恢复的目的. playbooks 本身可以识别这种改动,并且有一个基本的 event system(事件系统),可以响应这种改动.

(当发生改动时)’notify’ actions 会在 playbook 的每一个 task 结束时被触发,而且即使有多个不同的 task 通知改动的发生, ‘notify’ actions 只会被触发一次.

举例来说,比如多个 resources 指出因为一个配置文件被改动,所以 apache 需要重新启动,但是重新启动的操作只会被执行一次.

样例:

安装http服务,并将配置文件copy到远程服务里

---
- hosts: monserver
  remote_user: root   tasks:
    - name: install httpd package
      yum: name=httpd
    - name: copy conf file
      copy: src=files/httpd.conf dest=/etc/httpd/ backup=yes
    - name: start service
      service: name=httpd state=started enabled=yes

执行:

$ ansible-playbook httpd.yaml

PLAY [monserver] ***************************************************************************************

TASK [Gathering Facts] *********************************************************************************
ok: [10.10.3.152]
ok: [10.10.3.151]
ok: [10.10.3.150] TASK [install httpd package] ***************************************************************************
changed: [10.10.3.150]
changed: [10.10.3.152]
changed: [10.10.3.151] TASK [start service] ***********************************************************************************
changed: [10.10.3.150]
changed: [10.10.3.152]
changed: [10.10.3.151] PLAY RECAP *********************************************************************************************
10.10.3.150                : ok=3    changed=2    unreachable=0    failed=0
10.10.3.151                : ok=3    changed=2    unreachable=0    failed=0
10.10.3.152                : ok=3    changed=2    unreachable=0    failed=0

确认是否安装成功

ansible monserver -m shell -a "ss -ntlp | grep :80"
10.10.3.152 | CHANGED | rc= >>
LISTEN ::: :::* users:(("httpd",pid=,fd=),("httpd",pid=,fd=),("httpd",pid=,fd=),("httpd",pid=,fd=),("httpd",pid=,fd=),("httpd",pid=,fd=)) 10.10.3.151 | CHANGED | rc= >>
LISTEN ::: :::* users:(("httpd",pid=,fd=),("httpd",pid=,fd=),("httpd",pid=,fd=),("httpd",pid=,fd=),("httpd",pid=,fd=),("httpd",pid=,fd=)) 10.10.3.150 | CHANGED | rc= >>
LISTEN ::: :::* users:(("httpd",pid=,fd=),("httpd",pid=,fd=),("httpd",pid=,fd=),("httpd",pid=,fd=),("httpd",pid=,fd=),("httpd",pid=,fd=))

这里我们将配置文件的http端口改成81

.....
# directive.
#
# Change this to Listen on specific IP addresses as shown below to
# prevent Apache from glomming onto all bound IP addresses.
#
#Listen 12.34.56.78:
Listen .....

让我们重新执行palybook,看看会发生什么

$ ansible-playbook httpd.yaml

PLAY [monserver] ***************************************************************************************

TASK [Gathering Facts] *********************************************************************************
ok: [10.10.3.150]
ok: [10.10.3.152]
ok: [10.10.3.151] TASK [install httpd package] ***************************************************************************
ok: [10.10.3.150]
ok: [10.10.3.152]
ok: [10.10.3.151] TASK [copy conf file] **********************************************************************************
changed: [10.10.3.152]
changed: [10.10.3.150]
changed: [10.10.3.151] TASK [start service] ***********************************************************************************
ok: [10.10.3.152]
ok: [10.10.3.150]
ok: [10.10.3.151] PLAY RECAP *********************************************************************************************
10.10.3.150 : ok= changed= unreachable= failed=
10.10.3.151 : ok= changed= unreachable= failed=
10.10.3.152 : ok= changed= unreachable= failed=

其实这里我们发现,任务只执行了“copy conf file”这个task,我们再坚持一下远程端口看看有没有启动81

$ ansible monserver -m shell -a "ss -ntlp | grep :81"
10.10.3.150 | FAILED | rc= >>
non-zero return code 10.10.3.152 | FAILED | rc= >>
non-zero return code 10.10.3.151 | FAILED | rc= >>
non-zero return code

我们可以看到这里报错, 没有返回对应的端口,说明就没有启动81端口,我们需要的发现配置文件发送变化,就自动重启。这里我们使用handler来实现

---
- hosts: monserver
remote_user: root tasks:
- name: install httpd package
yum: name=httpd
- name: copy conf file
copy: src=files/httpd.conf dest=/etc/httpd/ backup=yes
notify: restart service
- name: start service
service: name=httpd state=started enabled=yes handlers:
- name: restart service
service: name=httpd state=restarted

执行验证:

$ ansible-playbook httpd.yaml

PLAY [monserver] ***************************************************************************************

TASK [Gathering Facts] *********************************************************************************
ok: [10.10.3.150]
ok: [10.10.3.151] ▽
ok: [10.10.3.152] TASK [install httpd package] ***************************************************************************
ok: [10.10.3.150]
ok: [10.10.3.152]
ok: [10.10.3.151] TASK [copy conf file] **********************************************************************************
changed: [10.10.3.152]
changed: [10.10.3.150]
changed: [10.10.3.151] TASK [start service] ***********************************************************************************
ok: [10.10.3.152]
ok: [10.10.3.150]
ok: [10.10.3.151] RUNNING HANDLER [restart service] **********************************************************************
changed: [10.10.3.152]
changed: [10.10.3.150]
changed: [10.10.3.151] PLAY RECAP *********************************************************************************************
10.10.3.150 : ok= changed= unreachable= failed=
10.10.3.151 : ok= changed= unreachable= failed=
10.10.3.152 : ok= changed= unreachable= failed=0 $ ansible monserver -m shell -a "ss -ntlp | grep :81"
10.10.3.150 | CHANGED | rc=0 >>
LISTEN     0      128         :::81                      :::*                   users:(("httpd",pid=6255,fd=4),("httpd",pid=6254,fd=4),("httpd",pid=6253,fd=4),("httpd",pid=6252,fd=4),("httpd",pid=6251,fd=4),("httpd",pid=6250,fd=4)) 10.10.3.151 | CHANGED | rc=0 >>
LISTEN     0      128         :::81                      :::*                   users:(("httpd",pid=21469,fd=4),("httpd",pid=21468,fd=4),("httpd",pid=21467,fd=4),("httpd",pid=21466,fd=4),("httpd",pid=21465,fd=4),("httpd",pid=21464,fd=4)) 10.10.3.152 | CHANGED | rc=0 >>
LISTEN     0      128         :::81                      :::*                   users:(("httpd",pid=9087,fd=4),("httpd",pid=9086,fd=4),("httpd",pid=9085,fd=4),("httpd",pid=9084,fd=4),("httpd",pid=9083,fd=4),("httpd",pid=9082,fd=4))

9、template模板

  • 文本文件
  • Jinjia2语言,有下面形式:
  1. 字符串:使用单引号或者双引号
  2. 数字:整数,浮点数
  3. 列表:[item1,item2....]
  4. 元组:(item1,item2...)
  5. 字典:{key1:value1,key2:value2....}
  6. 布尔型:true/false
  • 算术运算:“+”,“-”,“*”,“/”,“//”,“%”,“**”
  • 比较操作:==,!=,>,>=,<,<=
  • 逻辑运算:and,or,not
  • 流表达式:For If When

简单使用方法:

在当前目录下创建templates目录,下负责nginx的配置文件

创建一个playbook

---
- hosts: monserver
remote_user: root tasks:
- name: install nginx
yum: name=nginx
- name: copy template
template: src=templates/nginx.conf.j2 dest=/etc/nginx/nginx.conf
- name: start nginx
service: name=nginx state=started enabled=yes

执行:

ansible-playbook  temp.yaml

PLAY [monserver] **************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************
ok: [10.10.3.150]
ok: [10.10.3.151]
ok: [10.10.3.152] TASK [install nginx] **********************************************************************************************
changed: [10.10.3.150]
changed: [10.10.3.152]
changed: [10.10.3.151] TASK [copy template] **********************************************************************************************
ok: [10.10.3.150]
ok: [10.10.3.152]
ok: [10.10.3.151] TASK [start nginx] ************************************************************************************************
changed: [10.10.3.152]
changed: [10.10.3.151]
changed: [10.10.3.150] PLAY RECAP ********************************************************************************************************
10.10.3.150 : ok= changed= unreachable= failed=
10.10.3.151 : ok= changed= unreachable= failed=
10.10.3.152 : ok= changed= unreachable= failed=

我们使用系统变量修改nginx work进程数:

获取变量的方法,我们可以使用 ansible monserver -m setup | grep "processor" 获取CPU个数

修改nginx模板文件

$ vim templates/nginx.conf.j2
# For more information on configuration, see:
# * Official English Documentation: http://nginx.org/en/docs/
# * Official Russian Documentation: http://nginx.org/ru/docs/ user nginx;
worker_processes {{ ansible_processor_vcpus** }};
error_log /var/log/nginx/error.log;
.....

修改playbook使用handlers

---
- hosts: monserver
remote_user: root tasks:
- name: install nginx
yum: name=nginx
- name: copy template
template: src=templates/nginx.conf.j2 dest=/etc/nginx/nginx.conf
notify: restart nginx
- name: start nginx
service: name=nginx state=started enabled=yes handlers:
- name: restart nginx
service: name=nginx state=restarted

执行:

ansible-playbook temp.yaml

PLAY [monserver] **************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************
ok: [10.10.3.150]
ok: [10.10.3.151]
ok: [10.10.3.152] ▽ TASK [install nginx] **********************************************************************************************
ok: [10.10.3.150]
ok: [10.10.3.151]
ok: [10.10.3.152] TASK [copy template] **********************************************************************************************
changed: [10.10.3.150]
changed: [10.10.3.152]
changed: [10.10.3.151] TASK [start nginx] ************************************************************************************************
ok: [10.10.3.150]
ok: [10.10.3.152]
ok: [10.10.3.151] RUNNING HANDLER [restart nginx] ***********************************************************************************
changed: [10.10.3.150]
changed: [10.10.3.152]
changed: [10.10.3.151] PLAY RECAP ********************************************************************************************************
10.10.3.150 : ok= changed= unreachable= failed=
10.10.3.151 : ok= changed= unreachable= failed=
10.10.3.152 : ok= changed= unreachable= failed=

验证:

$ ansible monserver -m shell -a "ps -ef  | grep nginx "
10.10.3.151 | CHANGED | rc= >>
root : ? :: nginx: master process /usr/sbin/nginx
nginx : ? :: nginx: worker process
nginx : ? :: nginx: worker process
nginx : ? :: nginx: worker process
nginx : ? :: nginx: worker process
nginx : ? :: nginx: worker process
nginx : ? :: nginx: worker process
nginx : ? :: nginx: worker process
nginx : ? :: nginx: worker process
nginx : ? :: nginx: worker process
nginx : ? :: nginx: worker process
nginx : ? :: nginx: worker process
nginx : ? :: nginx: worker process
nginx : ? :: nginx: worker process
nginx : ? :: nginx: worker process
nginx : ? :: nginx: worker process
nginx : ? :: nginx: worker process
root : pts/ :: /bin/sh -c ps -ef | grep nginx
root : pts/ :: grep nginx ....

同样也可以引用主机清单、playbook等里面的变量。

when用法

when 既中文含义是“当”,当怎么怎么就怎么怎么

当hostname=ceph-osd-1的时候安装服务

---
- hosts: cephserver
remote_user: root
tasks:
- name: install nginx
when: ansible_hostname == "ceph-osd-1"
yum: name=nginx
- name: copy template
when: ansible_hostname == "ceph-osd-1"
template: src=templates/nginx.conf.j2 dest=/etc/nginx/nginx.conf
notify: restart nginx
- name: start nginx
when: ansible_hostname == "ceph-osd-1"
service: name=nginx state=started enabled=yes
handlers:
- name: restart nginx
service: name=nginx state=restarted

迭代机制, with_items

---
- hosts: monserver
remote_user: root tasks:
- name: create some file
file: name=/data/{{ item }} state=touch
with_items:
- file1
- file2
- file3
- name: install spme packages
yum: name= {{ item }}
with_items:
- htop
- sl
- hping3

执行:

ansible-playbook -C testitem.yaml

PLAY [monserver] **********************************************************************************************************

TASK [Gathering Facts] ****************************************************************************************************
ok: [10.10.3.150]
ok: [10.10.3.151]
ok: [10.10.3.152] TASK [create some file] ***************************************************************************************************
ok: [10.10.3.150] => (item=file1)
ok: [10.10.3.152] => (item=file1)
ok: [10.10.3.151] => (item=file1)
ok: [10.10.3.150] => (item=file2)
ok: [10.10.3.152] => (item=file2)
ok: [10.10.3.151] => (item=file2)
ok: [10.10.3.150] => (item=file3)
ok: [10.10.3.152] => (item=file3)
ok: [10.10.3.151] => (item=file3) TASK [install spme packages] **********************************************************************************************
ok: [10.10.3.152] => (item=htop)
ok: [10.10.3.150] => (item=htop)
ok: [10.10.3.151] => (item=htop)
ok: [10.10.3.152] => (item=sl)
ok: [10.10.3.150] => (item=sl)
ok: [10.10.3.151] => (item=sl)
ok: [10.10.3.152] => (item=hping3)
ok: [10.10.3.150] => (item=hping3)
ok: [10.10.3.151] => (item=hping3) PLAY RECAP ****************************************************************************************************************
10.10.3.150 : ok= changed= unreachable= failed=
10.10.3.151 : ok= changed= unreachable= failed=
10.10.3.152 : ok= changed= unreachable= failed= [root@ceph-moni- ansible]# ansible-playbook testitem.yaml PLAY [monserver] ********************************************************************************************************** TASK [Gathering Facts] ****************************************************************************************************
ok: [10.10.3.150]
ok: [10.10.3.152]
ok: [10.10.3.151] TASK [create some file] ***************************************************************************************************
changed: [10.10.3.152] => (item=file1)
changed: [10.10.3.151] => (item=file1) ▽
changed: [10.10.3.150] => (item=file1)
changed: [10.10.3.150] => (item=file2)
changed: [10.10.3.152] => (item=file2)
changed: [10.10.3.151] => (item=file2)
changed: [10.10.3.150] => (item=file3)
changed: [10.10.3.152] => (item=file3)
changed: [10.10.3.151] => (item=file3) TASK [install spme packages] **********************************************************************************************
ok: [10.10.3.152] => (item=htop)
ok: [10.10.3.151] => (item=htop)
ok: [10.10.3.150] => (item=htop)
ok: [10.10.3.151] => (item=sl)
ok: [10.10.3.152] => (item=sl)
ok: [10.10.3.150] => (item=sl)
ok: [10.10.3.151] => (item=hping3)
ok: [10.10.3.152] => (item=hping3)
ok: [10.10.3.150] => (item=hping3) PLAY RECAP ****************************************************************************************************************
10.10.3.150 : ok= changed= unreachable= failed=
10.10.3.151 : ok= changed= unreachable= failed=
10.10.3.152 : ok= changed= unreachable= failed=

验证:

ansible  monserver  -m shell -a "ls /data"
10.10.3.150 | CHANGED | rc= >>
file1
file2
file3 10.10.3.152 | CHANGED | rc= >>
file1
file2
file3
newfile 10.10.3.151 | CHANGED | rc= >>
file1
file2
file3

迭代嵌套子变量,使用字典

---
- hosts: monserver
remote_user: root tasks:
- name: create some group
group: name={{ item }}
with_items:
- g1
- g2
- g3
- name: create some users
user: name={{ item.name }} group={{ item.group }}
with_items:
- {name: 'user1',group: 'g1'}
- {name: 'user2',group: 'g2'}
- {name: 'user3',group: 'g3'}

执行:

$ ansible-playbook testitem2.yaml

PLAY [monserver] **********************************************************************************************************

TASK [Gathering Facts] ****************************************************************************************************
ok: [10.10.3.152]
ok: [10.10.3.150]
ok: [10.10.3.151] TASK [create some group] ************************************************************************************************** ▽
changed: [10.10.3.150] => (item=g1)
changed: [10.10.3.152] => (item=g1)
changed: [10.10.3.151] => (item=g1)
changed: [10.10.3.152] => (item=g2)
changed: [10.10.3.150] => (item=g2)
changed: [10.10.3.151] => (item=g2)
changed: [10.10.3.152] => (item=g3)
changed: [10.10.3.150] => (item=g3)
changed: [10.10.3.151] => (item=g3) TASK [create some users] **************************************************************************************************
changed: [10.10.3.152] => (item={u'group': u'g1', u'name': u'user1'})
changed: [10.10.3.151] => (item={u'group': u'g1', u'name': u'user1'})
changed: [10.10.3.150] => (item={u'group': u'g1', u'name': u'user1'})
changed: [10.10.3.152] => (item={u'group': u'g2', u'name': u'user2'})
changed: [10.10.3.150] => (item={u'group': u'g2', u'name': u'user2'})
changed: [10.10.3.151] => (item={u'group': u'g2', u'name': u'user2'})
changed: [10.10.3.152] => (item={u'group': u'g3', u'name': u'user3'})
changed: [10.10.3.150] => (item={u'group': u'g3', u'name': u'user3'})
changed: [10.10.3.151] => (item={u'group': u'g3', u'name': u'user3'}) PLAY RECAP ****************************************************************************************************************
10.10.3.150 : ok= changed= unreachable= failed=
10.10.3.151 : ok= changed= unreachable= failed=
10.10.3.152 : ok= changed= unreachable= failed=

for 循环在template模板中:

我们创建一个变量字段

---
- hosts: monserver
  remote_user: root
  vars:
    ports:
      - web1:
        name: webhs1
        port: 81
        rootdir: /data/web1
      - web2:
        name: webhs2
        port: 82
        rootdir: /data/web2
      - web3:
        name: webhs3
        port: 83
        rootdir: /data/web3
  tasks:
    - name: copy conf
      template: src=for3.conf.j2 dest=/data/for1.conf

创建template模板配置文件

{% for p in ports %}
server{
listen {{ p.port }}
servername {{ p.name }}
documentroot: {{ p.rootdir }}
}
{% endfor %}

执行:

ansible-playbook  for.yaml

PLAY [monserver] **********************************************************************************************************

TASK [Gathering Facts] ****************************************************************************************************
ok: [10.10.3.152]
ok: [10.10.3.150]
ok: [10.10.3.151] TASK [copy conf] **********************************************************************************************************
changed: [10.10.3.152]
changed: [10.10.3.151]
changed: [10.10.3.150] PLAY RECAP ****************************************************************************************************************
10.10.3.150 : ok= changed= unreachable= failed=
10.10.3.151 : ok= changed= unreachable= failed=
10.10.3.152 : ok= changed= unreachable= failed=

循环嵌套if判断

需求是,如果name有定义就添加这个配置,如果没有就不添加,这里我们在前面定义的变量里注释两个name

---
- hosts: monserver
remote_user: root
vars:
ports:
- web1:
# name: webhs1
port:
rootdir: /data/web1
- web2:
# name: webhs2
port:
rootdir: /data/web2
- web3:
name: webhs3
port:
rootdir: /data/web3
tasks:
- name: copy conf
template: src=for1.conf.j2 dest=/data/for3.conf

在template中增加判断

{% for p in ports %}
server{
listen {{ p.port }}
{% if p.name is defined %}
servername {{ p.name }}
{% endif %}
documentroot: {{ p.rootdir }}
}
{% endfor %}

执行:

ansible-playbook  for1.yaml

PLAY [monserver] **********************************************************************************************************

TASK [Gathering Facts] ****************************************************************************************************
ok: [10.10.3.150]
ok: [10.10.3.152]
ok: [10.10.3.151] TASK [copy conf] **********************************************************************************************************
changed: [10.10.3.152]
changed: [10.10.3.151]
changed: [10.10.3.150] PLAY RECAP ****************************************************************************************************************
10.10.3.150 : ok= changed= unreachable= failed=
10.10.3.151 : ok= changed= unreachable= failed=
10.10.3.152 : ok= changed= unreachable= failed=

查看结果:

ansible monserver -m shell -a "cat /data/for3.conf  "
10.10.3.150 | CHANGED | rc= >>
server{
listen
documentroot: /data/web1
}
server{
listen
documentroot: /data/web2
}
server{
listen
servername webhs3
documentroot: /data/web3
}
.......

Role

用于层次性,结构化地组织playbook,roles能够根据层次型结构自动装载变量文件,tasks以及handlers等。要使用roles只需要在playbook中使用include指令即可。简单讲,roles就是通过将变量、文件、任务、模板及处理器放置于单独的目录里。并可以便捷的include他们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中。

Role各目录作用:

  • files/ 存放由copy和script模块等调用文件
  • templates/ template模块查找所需要的模板目录
  • tasks/ 定义task,role的基本元素,至少应该包含一个名为main.yaml的文件,其他文件需要在此文件中通过include进行包含
  • handlers/ 至少包含一个名为main.yaml的文件,其他文件需要在此文件中通过include进行包含
  • vars/ 至少包含一个名为main.yaml的文件,其他文件需要在此文件中通过include进行包含
  • mete/ 定义当前角色的特殊设定及其依赖关系,至少包含一个名为main.yaml的文件,其他文件需要在此文件中通过include进行包含
  • default/ 设定默认变量时使用此目录中的main.yaml文件

需求:

通过role安装nginx,安装nginx的步骤:

  1. 创建nginx用户组,group:nginx
  2. 创建nginx用户,user:nginx
  3. yum安装nginx  yum:nginx
  4. 拷贝模板:template:nginx.conf.j2
  5. 启动服务,service:nginx

我们根据需求和上面的解释,场景对应的目录:

mkdir -p testroles/roles/nginx/{tasks,templates}

上面的1、2、3是tasks任务,所以我们会再tasks目录下一一创建

$ vim group.yaml
- name: create group
group: name=nginx
$ vim user.yaml
- name: create user
user: name=nginx group=nginx system=yes shell=/sbin/nologin
$ vim yum.yaml
- name: install package
yum: name=nginx
$ vim start.yaml
- name: start nginx
service: name=nginx state=started
$ vim restart.yaml
- name: restart nginx
service: name=nginx state=restarted
$ vim temp.yaml
- name: copy config
  template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf

创建配置文件模板

$ vim ../templates/nginx.conf.j2

 For more information on configuration, see:
# * Official English Documentation: http://nginx.org/en/docs/
# * Official Russian Documentation: http://nginx.org/ru/docs/ user nginx;
worker_processes {{ ansible_processor_vcpus** }};
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
........

这里我们的配置文件准备完成了。接下来是关键是怎么调用,这时候我们需要一个总的tasks文件(main.yaml)。

$ vim roles/nginx/tasks/main.yaml
- include: group.yaml
- include: user.yaml
- include: yum.yaml
- include: temp.yaml
- include: start.yaml

这里我们在role目录平级的目录创建一个剧本,写具体怎么调用:

$ vim nginx-role.yaml

- hosts: monserver
remote_user: root
roles:
- role: nginx

执行:

ansible-playbook -C  nginx-role.yaml

PLAY [monserver] *******************************************************************************

TASK [Gathering Facts] *************************************************************************
ok: [10.10.3.150]
ok: [10.10.3.152]
ok: [10.10.3.151] TASK [nginx : create group] ********************************************************************
changed: [10.10.3.152]
changed: [10.10.3.151]
changed: [10.10.3.150] TASK [nginx : create user] *********************************************************************
changed: [10.10.3.150]
changed: [10.10.3.152]
changed: [10.10.3.151] TASK [nginx : install package] *****************************************************************
changed: [10.10.3.151]
changed: [10.10.3.152]
changed: [10.10.3.150] TASK [nginx : copy config] *********************************************************************
changed: [10.10.3.152]
changed: [10.10.3.151]
changed: [10.10.3.150] TASK [nginx : start nginx] *********************************************************************
changed: [10.10.3.152]
changed: [10.10.3.151]
changed: [10.10.3.150] PLAY RECAP *************************************************************************************
10.10.3.150 : ok= changed= unreachable= failed=
10.10.3.151 : ok= changed= unreachable= failed=
10.10.3.152 : ok= changed= unreachable= failed= [root@ceph-moni- testroles]# ansible-playbook nginx-role.yaml PLAY [monserver] ******************************************************************************* TASK [Gathering Facts] *************************************************************************
ok: [10.10.3.150]
ok: [10.10.3.151]
ok: [10.10.3.152] TASK [nginx : create group] ********************************************************************
changed: [10.10.3.152]
changed: [10.10.3.150]
changed: [10.10.3.151] TASK [nginx : create user] *********************************************************************
changed: [10.10.3.152]
changed: [10.10.3.150]
changed: [10.10.3.151] TASK [nginx : install package] *****************************************************************
changed: [10.10.3.152]
changed: [10.10.3.150]
changed: [10.10.3.151] TASK [nginx : copy config] *********************************************************************
changed: [10.10.3.150]
changed: [10.10.3.152]
changed: [10.10.3.151] TASK [nginx : start nginx] *********************************************************************
changed: [10.10.3.152]
changed: [10.10.3.150]
changed: [10.10.3.151] PLAY RECAP *************************************************************************************
10.10.3.150 : ok= changed= unreachable= failed=
10.10.3.151 : ok= changed= unreachable= failed=
10.10.3.152 : ok= changed= unreachable= failed=

Ansible-基础的更多相关文章

  1. ansible基础-安装与配置

    一 安装 1.1 ansible架构 ansible是一个非常简单的自动化部署项目,由python编写并且开源.用于提供自动化云配置.配置文件管理.应用部署.服务编排和很多其他的IT自动化需求. an ...

  2. ansible基础-优化

    简介 当管理集群达到一定规模时,ansible达到性能瓶颈是难以避免的,此时我们可以通过一定手段提高ansible的执行效率和性能. 笔者虽未管理过超大规模服务器,但也通过查找资料和咨询大神了解了一些 ...

  3. ansible基础-Jinja2模版 | 过滤器

    Jinja2模版介绍 注:本文demo使用ansible2.7稳定版 在ansible基础-变量的「8.2 模版使用变量」章节中关于模版与变量也有所提及,有兴趣的同学可以去回顾一下. ansible通 ...

  4. ansible基础-理解篇

    1. 介绍 要说现在的部署工具,ansible可以说家喻户晓了. ansible是一个开源软件,用于软件供应.配置管理.应用部署.ansible可以通过SSH.remote PowerShell.其他 ...

  5. ansible基础-roles

    一 简介 注:本文demo使用ansible2.7稳定版 在我看来,role是task文件.变量文件.handlers文件的集合体,这个集合体的显著特点是:可移植性和可重复执行性. 实践中,通常我们以 ...

  6. ansible基础-playbooks

    1. playbooks介绍 如果说ansible的modules是工具,inventory配置文件是原材料,那么playbook就是一封说明书,这里会记录任务是如何如何执行的,当然如果你愿意,这里也 ...

  7. ansible基础-ansible角色的使用

    ansible基础-ansible角色的使用 作者:尹正杰  版权声明:原创作品,谢绝转载!否则将追究法律责任. 我们建议把多个节点都会用到的功能将其定义模块,然后谁要用到该模块就直接调用即可!而在a ...

  8. ansible基础-playbook剧本的使用

    ansible基础-playbook剧本的使用 作者:尹正杰  版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.YAML概述 1>.YAML的诞生 YAML是一个可读性高,用来表达数据序 ...

  9. 003.Ansible基础使用

    一 Ansible命令用法 Ansible命令行执行方式有:Ad-Hoc.Ansible-playbook两种,Web方式其官方提供付费产品Tower.Ad-Hoc主要用于临时命令的执行,Ansibl ...

  10. 自动化运维工具-Ansible基础

    目录 自动化运维工具-Ansible基础 什么是Ansible 同类型软件对比 Ansible的功能及优点 Ansible的架构 Ansible的执行流程 安装Ansible ansible配置文件 ...

随机推荐

  1. Java使用PipedStream管道流通信

    多线程使用PipedStream 通讯 Java 提供了四个相关的管道流,我们可以使用其在多线程进行数据传递,其分别是 类名 作用 备注 PipedInputStream 字节管道输入流 字节流 Pi ...

  2. vue 外部字体图标使用,无须绝对路径引入办法

    通常外部字体图标都在使用 iconfont ,这种图标在网上搜到一大把都是由于路径问题显示不出来,或者是显示个方块. 最近的项目中也碰到这个坑爸的问题,总结一下解决办法: 和 webpack.conf ...

  3. spark als scala实现(二)

    Vi  t1.txt1,101,5.01,102,3.01,103,2.52,101,2.02,102,2.52,103,5.02,104,2.03,101,2.53,104,4.03,105,4.5 ...

  4. eclipse 更改默认主题,重写默认滚动条样式(安装DevStyle主题插件)

    1.点击Help->Eclipse Marktplace 2.弹出窗口输入: DevStyle 3.点击安装,重启eclipse 4.可以设置黑色和浅色主题,个人比较喜欢浅色,重点式滚动条样式变 ...

  5. Swift 访问控制

    1.private private访问级别所修饰的属性或者方法只能在当前类里访问. 2.fileprivate fileprivate访问级别所修饰的属性或者方法在当前的Swift源文件里可以访问. ...

  6. 3星|《陈志武金融投资课》:金融改善社会,A股投资策略

    从历史上的金融说起,介绍金融的基本知识.理念.大事.重要人物.也有一些A股投资策略和A股政策点评. 引用了不少学术研究成果做证据.讲历史的部分,功力比专业历史学者稍逊,毕竟这不是作者的专业. 我读后认 ...

  7. Java基础系列--01_基础类型

    J2SE.J2ME.J2EE分别指什么? J2SE 基础版,桌面应用. J2ME 微型版,手机开发.(android,ios) J2EE 企业版,所有浏览器访问的应用程序. 注意:JDK5以后改名 J ...

  8. ASP.NET Core 2.2 十九. Action参数的映射与模型绑定

    前文说道了Action的激活,这里有个关键的操作就是Action参数的映射与模型绑定,这里即涉及到简单的string.int等类型,也包含Json等复杂类型,本文详细分享一下这一过程.(ASP.NET ...

  9. Swagger 报错 no mapping found for http request with uri [/***/swagger-ui.html] in dispatcherservlet with name '***'

    swagger报错: no mapping found for http request with uri [/***/swagger-ui.html] in dispatcherservlet wi ...

  10. dpdk-18.11开发库编译安装

    简介 dpdk官网 安装 下载 点击下载地址,选择合适的版本下载.这里下载DPDK 18.11.0 (LTS)版本. 编译 将下载的dpdk-18.11.tar.xz上传服务器,解压,这里放在了/op ...