admin管理员组文章数量:1530845
1.应用场景
公司计划在年底做一次大型市场促销活动,全面冲刺下交易额,为明年的上市做准备。公司要求各业务组对年底大促做准备要求所有业务容量进行三倍的扩容,并搭建出多套环境可以共开发和测试人员做测试,运维老大为了在年底有所表现,要求运门同学尽快实现,当你接到这个任务时,有没有更快的解决方案?
2.常用的自动化运维工具
- Ansible:python,Agentless,中小型应用环境
- Saltstack:python,一般需部署agent,执行效率更高
- Puppetruby,功能强大,配置复杂,重型,适合大型环境
- Fabric : python, agentless
- Chef:ruby,国内应用少
- Cfengine
- func
3.ansible发展史
- 创始人,Michael DeHaan ( Cobbler与Func的作者)
- 2012-O3-09,发布o.o.1版,红帽收购
- 2015-10-17 ,Red Hat宣布收购
4.特性
- 模块化:调用特定的模块,完成特定任务
- 有Paramiko,PyYAML,Jinja2(模版语言)三个关键模块
- 支持自定义模块
- 基于Python语言实现
- 部署简单,基于python和SSH(默认已安装),agentless
- 安全,基于OpenSSH
- 支持playbook编排任务
- 幂等性:一个任务执行1遍和执行n遍效果一样,不因重复执行带来意外情况
- 无需代理不依俩PKI(无需ssl)
- YAML格式,编排任务,支持丰富的数据结构
- 较强大的多层解决方案
5.ansible架构
Host Inventory(主机清单) ansible怎么知道那些主机是被控制的。
通过ssh协议
6.ansible工作原理
- INVENTORY:主机清单
- 被管理端可以是主机 也可以是网络设备
- CMDB 配值管理数据库
- 我们用的最多的是 playsbook是 进行管理
- 路由器 和交换机 都可以进行管理
- 公有云私有云的开发接口也可以
- 也可以二次开发
7.ansible主要组成部分
Ad-Hoc是执行单条命令
getenforce :查看是否开启selinux
asible是基于linux开发的 不支持在windows里面安装ansbile
8.安装
ansible已经被红帽收购
官方地址
- rpm包安装:EPEL源
yum -y install ansible
- 编译安装
yum -y install python-jinja2 PyYAML python-paramiko python-babel python-cryto
tar xf ansible-1.2.4.tar.gz
cd ansible-1.5.4
python setup.py build
python setup.py install
mkdir -p /etc/ansible
cp -r examples/* /etc/ansible
- Git安装
git clone git://github/ansible/ansible.git --recursive
cd ./ansible
source ./hacking/env-setup
- pip安装:pip安装Python包的管理器,类似yum
yum install python-pip python-devel
yum install gcc glibc-devel zibl-devel rpm-build openssl-devel
pip install --upgrade pip
piup install ansible --upgrade
- 确认安装
ansbile --version
2
1.安装
yum -y install ansible
yum info ansible #查看ansible的信息
# ansible --version #验证是否安装成功
ansible 2.9.10
config file = /etc/ansible/ansible.cfg
configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python2.7/site-packages/ansible #对应的模板路径
executable location = /usr/bin/ansible # 对应的二进制模板文件在哪
python version = 2.7.5 (default, Aug 7 2019, 00:51:29) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]
# file /usr/bin/ansible
/usr/bin/ansible: symbolic link to `/usr/bin/ansible-2.7'
#这是一个软链接 用起来更方便
2.主要文件介绍
rpm -ql ansible | less
- 配置文件
/etc/ansible/ansible.cfg #主配置文件
/etc/ansible/hosts #主机清单
/etc/ansible/roles #角色的目录
- 程序
/usr/bin/ansible #主程序 临时命令执行工具
/usr/bin/ansible-doc #查看配置文档,模块功能查看工具
/usr/bin/ansible-galaxy #下载/上传优秀代码或Roles模块的官网平台
/usr/bin/ansible-playbook #定制自动化任务,编排剧本工具/usr/bin/ansible-pull远程执行命令的工具
/usr/bin/ansible-vault #文件加密工具
/usr/bin/ansible-console #基于console界面与用户交互的执行工具
- 管理模块的文件
rpm -ql ansible | grep file.py
/usr/lib/python2.7/site-packages/ansible/modules/windows/win_file.py
-
主机清单
-
Inventory主机清单
ansible的主要功用在于批量主机操作,为了便捷地使用其中的部分主机,可以在inventory file中将其分组命名 -
默认的inventory file为/etc/ansible/hosts
-
inventory file可以有多个,且也可以通过Dynamic Inventory来动态生成
3.语法
[root@ansible ~]# ansible --help
usage: ansible [-h] [--version] [-v] [-b] [--become-method BECOME_METHOD]
ansible -m ping
-m 使用模块 ping
4.使用
1.尝试一下
- 没有任何操作前 :失败
[root@ansible ~]# ansible 10.0.0.48 -m ping
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not
match 'all'
[WARNING]: Could not match supplied host pattern, ignoring: 10.0.0.48 #提示为空
- 加入主机列表后
cat >> /etc/ansible/hosts << EOF
10.0.0.48
10.0.0.49
EOF
#也是提示错误 因为没有key验证
[root@ansible ~]# ansible 10.0.0.48 -m ping #探测以下
The authenticity of host '10.0.0.48 (10.0.0.48)' can't be established.
ECDSA key fingerprint is SHA256:Zp63J/kTvnYc3to3flnLUoagIIVYMYA3hwcDdjoPFdA.
ECDSA key fingerprint is MD5:af:6d:49:41:09:7b:a5:e9:13:e1:51:1f:20:fc:31:17.
Are you sure you want to continue connecting (yes/no)? yes
10.0.0.48 | UNREACHABLE! => { #不可到达
"changed": false,
"msg": "Failed to connect to the host via ssh: Warning: Permanently added '10.0.0.48' (ECDSA) to the list of known hosts.\r\nPermission denied (publickey,gssapi-keyex,gssapi-with-mic,password).",
"unreachable": true
}
- 使用参数 -k 基于密码登录:成功
[root@ansible ~]# ansible 10.0.0.48 -m ping -k
SSH password: #输入密码
10.0.0.48 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
- 多个密码不一致主机的ping
# 修改48的密码使48.49 密码不一致
[root@c7-48 ~]# passwd
Changing password for user root.
New password:12345678
BAD PASSWORD: The password fails the dictionary check - it is too simplistic/systematic
Retype new password:12345678
passwd: all authentication tokens updated successfully.
#毫无顺序可言
[root@ansible ~]# ansible 10.0.0.48,10.0.0.49 -m ping -k
SSH password:
10.0.0.49 | FAILED! => {
"msg": "Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support this. Please add this host's fingerprint to your known_hosts file to manage this host."
}
10.0.0.48 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
- 修改48.49密码一致
[root@ansible ~]# ansible 10.0.0.48,10.0.0.49 -m ping -k
SSH password:
10.0.0.49 | FAILED! => {
"msg": "Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support this. Please add this host's fingerprint to your known_hosts file to manage this host."
}
10.0.0.48 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
#查看已知主机目录
[root@ansible ~]# cd .ssh/
[root@ansible .ssh]# ls
known_hosts
[root@ansible .ssh]# cat known_hosts
10.0.0.48 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBI/gOEa/2bc0EAi3sG8Wrt94I5j+Ln5/k15je1cQCq97d1aoC2I1lNdq5qelONBCRjbEjsKeVtRUe/foBuK6BII=
[root@ansible .ssh]# ssh 10.0.0.49 #进行登录 加入信任主机
The authenticity of host '10.0.0.49 (10.0.0.49)' can't be established.
ECDSA key fingerprint is SHA256:Zp63J/kTvnYc3to3flnLUoagIIVYMYA3hwcDdjoPFdA.
ECDSA key fingerprint is MD5:af:6d:49:41:09:7b:a5:e9:13:e1:51:1f:20:fc:31:17.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '10.0.0.49' (ECDSA) to the list of known hosts.
root@10.0.0.49's password:
Last login: Wed Aug 12 23:31:25 2020 from 10.0.0.1
[root@c7-49 ~]# exit
logout
Connection to 10.0.0.49 closed.
[root@ansible .ssh]# ansible 10.0.0.48,10.0.0.49 -m ping -k #success
SSH password:
10.0.0.48 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
10.0.0.49 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
- 全部
[root@ansible ~]# ansible all -m ping -k #提供用户名指令
SSH password:
10.0.0.49 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
10.0.0.48 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
2. 分组
cat >> /etc/ansible/hosts <<EOF
[webserver]
10.0.0.48
[dbserver]
10.0.0.49
EOF
3.主机清单 inventory
1. /etc/ansible/hosts文件格式
-
- inventory文件遵循INI文件风格,中括号中的字符为组名。可以将同一个主机
同时归并到多个不同的组中;此外,当如若目标主机使用了非默认的SSH端口,
还可以在主机名称之后使用冒号加端口号来标明
- inventory文件遵循INI文件风格,中括号中的字符为组名。可以将同一个主机
ntp.magedu
[webservers]
www1.magedu:2222 #指定端口
www2.magedu
[dbservers]
db1.magedu
db2.magedu
db3.magedu
- 如果主机名称遵循相似的命名模式,还可以使用列表的方式标识各主机
示例︰
[websrvs]
www[01:100].example
[dbsrvs]
db-[a:f].example
3
1.主配置文件介绍
ansible配置文件 /etc/ansible/ansible.cfg(一般保持默认)
[defaults] #默认值
#inventory = /etc/ansible/hosts #主机列表配置文件
#library = /usr/share/my_modules/ #库文件存放目录
#module_utils = /usr/share/my_module_utils/
#remote_tmp = ~/.ansible/tmp #在被控制上执行 并删除
#local_tmp = ~/.ansible/tmp #两个搭配使用 执行完命令后会自动生成脚本 到远程主机 执行完即删除
#plugin_filters_cfg = /etc/ansible/plugin_filters.yml
#forks = 5 #并发执行5次
#poll_interval = 15 #15秒拉取一次数据
#sudo_user = root #普通用户无法在远程主机管理root 所以要使用sudo
#ask_sudo_pass = True #每次执行ansible命令是否询问ssh密码
#ask_pass = True
#transport = smart
#remote_port = 22 #远程主机默认端口号
#module_lang = C
#module_set_locale = False
#host_key_checking = False #检查对应服务器的host_key,建议取消注释 这个如果不取消就会出现 2情况
#log_path=/var/log/ansible.log #日志文件 (取消注释,建议开启)
2.没有建立连接 所以无法ping 通
[root@ansible ~]# cd .ssh/
[root@ansible .ssh]# ls
known_hosts #这是信任文件 我们ssh之后就出产生记录 才能ping 要不然注释下面的默认值
[root@ansible .ssh]# rm -rf known_hosts
[root@ansible .ssh]# ansible all -m ping -k
SSH password:
10.0.0.48 | FAILED! => {
"msg": "Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support this. Please add this host's fingerprint to your known_hosts file to manage this host."
}
10.0.0.49 | FAILED! => {
"msg": "Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support this. Please add this host's fingerprint to your known_hosts file to manage this host."
}
所有的主机都要手动ssh连接一遍才行
所以
#host_key_checking = False #检查对应服务器的host_key,建议取消注释
#注释后
[root@ansible .ssh]# ansible all -m ping -k
SSH password:
10.0.0.49 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
10.0.0.48 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
3.ansible系列命令
[root@ansible ~]# ansible # tab
ansible ansible-console ansible-doc-2.7 ansible-playbook ansible-pull-2.7
ansible-2 ansible-console-2 ansible-galaxy ansible-playbook-2 ansible-test
ansible-2.7 ansible-console-2.7 ansible-galaxy-2 ansible-playbook-2.7 ansible-vault
ansible-config ansible-doc ansible-galaxy-2.7 ansible-pull ansible-vault-2
ansible-connection ansible-doc-2 ansible-inventory ansible-pull-2 ansible-vault-2.7
Ansible系列命令
ansible ansible-doc ansible-playbookansible-vault
ansible-consoleansible-galaxyansible-pull
ansible-doc:显示模块帮助
ansible-doc [options][module...]
显示所有模块的文档
-a
-l,--list列出可用模块
-s, --snippet显示指定模块的playbook片段
示例:
ansible-docl列出所有模块
ansible-doc ping查看指定模块帮助用法
ansible-doc -s ping查看指定模块帮助用法
[root@ansible ~]# ansible doc ping #加上模块名 查看怎么使用
usage: ansible [-h] [--version] [-v] [-b] [--become-method BECOME_METHOD]
[--become-user BECOME_USER] [-K] [-i INVENTORY] [--list-hosts]
[-l SUBSET] [-P POLL_INTERVAL] [-B SECONDS] [-o] [-t TREE] [-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] [-C] [--syntax-check] [-D]
[-e EXTRA_VARS] [--vault-id VAULT_IDS]
[--ask-vault-pass | --vault-password-file VAULT_PASSWORD_FILES]
[-f FORKS] [-M MODULE_PATH] [--playbook-dir BASEDIR]
[-a MODULE_ARGS] [-m MODULE_NAME]
pattern
ansible: error: unrecognized arguments: ping
#统计ansible模块数量
[root@ansible ~]# ansible-doc -l | wc -l
3387
[root@ansible ~]# ansible-doc -s ping
- name: Try to connect to host, verify a usable python and return `pong' on success
ping:
data: # Data to return for the `ping' return value. If this parameter is set to `crash', the
module will cause an exception.
ansible通过ssh实现配置管理、应用部署、任务执行等功能,建议配置ansible
端能基子密钥认证的方式联系各被管理节点
ansible <host-pattern?[-m module_name] [-a args]
–version显示版本
-m module指定模块,默认为command
-v详细过程→vv -vv更详细
–list-hosts显示主机列表,可简写—list
[root@ansible ~]# ansible all --list-hosts
hosts (2):
10.0.0.48
10.0.0.49
-k,–ask-pass提示输入ssh连接密码,默认Key验证
-K,–ask-become-pass提示输入sudo时的口令
-C,–check检查,并不执行
-T,–timeout=TIMEOUT 执行命令的超时时间,默认10s
-u,–user=REMOTE_USER执行远程执行的用户
[root@ansible ~]# ansible webserver -m ping -u y -k
SSH password:
10.0.0.48 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
[root@ansible ~]# ansible webserver -u y -k -m command -a'ls /root'
SSH password:
10.0.0.48 | FAILED | rc=2 >>
ls: cannot open directory /root: Permission deniednon-zero return code
#做不了权限以外的事
-b,–become代替l旧版的sudo切换
实战
1.生成密钥
[root@ansible ansible]# ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:jd0oYIQ0Ms/MYd5V3mV3W3DEr4xfOHbP2dCV3ZIATv0 root@ansible
The key's randomart image is:
+---[RSA 2048]----+
| o.=.. ..+o ++*|
| X.= . + .oo o=|
| * + o .o o=|
| . . + o E.=|
| S + .o =.|
| . . B +|
| o *+|
| ..+|
| |
+----[SHA256]-----+
2.拷贝到目标主机
[root@ansible ansible]# ssh-copy-id 10.0.0.48
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
root@10.0.0.48's password:
Number of key(s) added: 1
Now try logging into the machine, with: "ssh '10.0.0.48'"
and check to make sure that only the key(s) you wanted were added.
[root@ansible ansible]# ssh-copy-id 10.0.0.49
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
root@10.0.0.49's password:
Number of key(s) added: 1
Now try logging into the machine, with: "ssh '10.0.0.49'"
and check to make sure that only the key(s) you wanted were added.
3.ansible的Host-pattern
3.1 all
ansible all -m ping
表示所有Inventory中的所有主机
[root@ansible ansible]# ansible all -m ping
10.0.0.49 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
10.0.0.48 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
[root@ansible ansible]#
3.2支持分组
ansible webserver -m ping
[root@ansible ansible]# ansible webserver -m ping
10.0.0.48 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
[root@ansible ansible]# ansible dbserver -m ping
10.0.0.49 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
3.3 * :通配符
ansible *server -m ping
[root@ansible ansible]# ansible *server -m ping
10.0.0.49 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
10.0.0.48 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
ansible “10.0.0.*” -m ping
[root@ansible ansible]# ansible "10.0.0.*" -m ping
10.0.0.49 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
10.0.0.48 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
ansible “*” -m ping
[root@ansible ansible]# ansible "*" -m ping
10.0.0.49 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
10.0.0.48 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
3.4 关系
: 逻辑或
[root@ansible ansible]# ansible webserver:dbserver -m ping
10.0.0.49 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
10.0.0.48 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
:& 逻辑与
#必须是两个分组里有相同的主机 才可以使用
ansible 'webserver:&dbserver' -m ping
:!逻辑非
#使用单引号
ansible 'webserver:!dbserver' -m ping
综合逻辑
#既在webserver和dbserver里面并且在appserver里面 不在ftpserver里面
ansible 'webserver:dbserver:&appservers:!ftpserver' -m ping
3.5正则表达式
ansible "webserver:&dbserver" -m ping
ansible "~(web|db).*\.magedu\" -m ping
~ :表示主机里面是web|db开头的
. 结尾包含的magedu
[root@ansible ansible]# ansible '~(web|db)' -m ping
10.0.0.49 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
10.0.0.48 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
[root@ansible ansible]# ansible '~(web|db)server' -m ping
10.0.0.49 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
10.0.0.48 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
4.ansible命令执行的过程
ansible命令执行过程
1. 加载自己的配置文件默认/etc/ansible/ansible.cfg
2. 加载自己对应的模块文件,如command
3. 通过ansible将模块或命令生成对应的临时py文件,并将该文件传输至远程服务器
的对应执行用户$HOME/.ansible/tmp/ansible-tmp-数字/xxX.PY文件
4. 给文件+x执行
5. 执行并返回结果
6. 删除临时py文件,sleep o退出
执行状态︰
- 绿色∶执行成功并且不需要做改变的操作
- 黄色︰执行成功并且对目标主机做变更
- 红色:执行失败
查看详细的执行命令
ansible all -m ping -vvv
5.ansible使用示例
#以wang用户执行ping存活检测
ansible all -m ping-u wang -k
#以wang sudo至root执行ping存活检测
ansible all -m ping -u wang-b-k
#以wang sudo至mage用户执行ping存活检测
ansible all -m|ping-u wang -b-k --become-user mage
#以wang sudo至root用户执行ls
ansible all -m command -u wang --become-user=root -a 'ls /root' -b -k -K
6.ansible常见模块
1.简介
- Command:在远程主机执行命令,默认模块,可忽略-m选项
```bash
ansible srvs -m command -a 'service vsftpd start'
ansible srvs-m command -a 'echo magedu |passwd --stdin wang’不成功
>此命令不支持$VARNAME< > |;&等,用shell模块实现
- Shell :和command相似,用shell执行命令
ansible srv-m shell -a 'echo magedu |passwd -stdin wang'
调用bash执行命令类似cat/tmp/stanley.md | awk -F'I'‘iprint $1,$2y&>
/tmp/example.txt这些复杂命令,即使使用shell也可能会失败,解决办法∶写到脚本
时,copy到远程,执行,再把需要的结果拉回执行命令的机器
- Script:运行脚本
-a "/PATH/TO/SCRIPT_FILE“
snsible websrvs -m script -a f1.sh
- Copy:从服务器复制文件到客户端
ansible all -m copy -a "src=/root/f1.sh dest=/tmp/f2.sh owner=wang mode=600 backup=yes"
如果目标存在,默认覆盖,此处指定先备份
ansible all -m copy -a "content='test content\n' dest=/tmp/f1.txt" 利用内容,直接生成目标文件
- Fetch:从客户端取文件至服务器端,copy相反,目标可先tar
ansible all -m fetch -a 'src=/root/a.sh dest=/data/scripts'
File: 设置文件属性
ansible all -m file -a "path=/root/a.sh owner=wang mode=755"
ansible web -m file -a 'src=/app/testfile dest=/app/testfile-link state=link'
2.示例
1.默认command模块
1.条件判断
removes 如果存在 执行
creates 如果不存在 执行
#如果存在/etc/fs 文件 则执行cat
ansible all -a 'removes=/etc/fs cat /etc/fstab'
#如果不存在 所以要执行
ansible all -a 'creates=/etc/fs cat /etc/fstab'
2.切换目录
ansible all -a 'chdir=/boot ls'
3.创建用户
[root@ansible ansible]# ansible 10.0.0.48 -a 'useradd test1'
10.0.0.48 | CHANGED | rc=0 >>
[root@ansible ansible]# ansible 10.0.0.48 -a 'getent passwd test1'
10.0.0.48 | CHANGED | rc=0 >>
test1:x:1002:1002::/home/test1:/bin/bash
4mand对特殊符号有bug
建议用shell模块
[root@ansible ansible]# ansible 10.0.0.48 -a 'echo magedu|passwd --stdin test1'
10.0.0.48 | CHANGED | rc=0 >>
magedu|passwd --stdin test1
[root@ansible ansible]# ansible 10.0.0.48 -a 'getent shadow test1'
10.0.0.48 | CHANGED | rc=0 >>
test1:!!:18488:0:99999:7::: #!! 提示为空
[root@ansible ansible]# ansible 10.0.0.48 -a 'echo $HOSTNAME'
10.0.0.48 | CHANGED | rc=0 >>
$HOSTNAME #直接打印了$HOSTNAME
2.shell模块
shell 比command强
[root@ansible ansible]# ansible 10.0.0.48 -m shell -a 'echo $HOSTNAME'
10.0.0.48 | CHANGED | rc=0 >>
c7-48 #输出成功
#修改密码 也是成功的
[root@ansible ansible]# ansible 10.0.0.48 -m shell -a "echo magedu|passwd --stdin test1"
10.0.0.48 | CHANGED | rc=0 >>
Changing password for user test1.
passwd: all authentication tokens updated successfully.
[root@ansible ansible]# ansible 10.0.0.48 -m shell -a "getent shadow test1" 10.0.0.48 | CHANGED | rc=0 >>
test1:$6$2zu5Lawc$5UgDQI8CR7cImwOu.AcTzM9pnM4UjW.svTM9mY3h3HI4nX4ECMEnoVzzwY0kWPaYVRRLL1p/FFzQQEsvaD.hU/:18488:0:99999:7:::
script模块
## 在本地新建一个脚本
[root@ansible ansible]# vim host.sh
#!/bin/bash
hostname
[root@ansible ansible]# chmod +X host.sh
[root@ansible ansible]# pwd
/etc/ansible
使用script的模块能使远程主机执行本地脚本
[root@ansible ansible]# ansible all -m script -a "/etc/ansible/host.sh"
10.0.0.48 | CHANGED => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to 10.0.0.48 closed.\r\n",
"stderr_lines": [
"Shared connection to 10.0.0.48 closed."
],
"stdout": "c7-48\r\n",
"stdout_lines": [
"c7-48"
]
}
10.0.0.49 | CHANGED => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to 10.0.0.49 closed.\r\n",
"stderr_lines": [
"Shared connection to 10.0.0.49 closed."
],
"stdout": "c7-49\r\n", #标准输出
"stdout_lines": [
"c7-49"
]
}
copy模块
查找copy选项
ansible-doc -s copy
- 将文件复制到目标主机
ansible all -m copy -a 'src=/root/ansible/selinux dest=/etc/selinux/config backup=yes'
ansible all -a 'cat /etc/selinux/config' #验证
ansible all -a 'ls /etc/selinux' #查看复制文件
ansible all -m shell -a 'rm -f /etc/selinux/config.*' #删除复制的文件
ansible all -m shell -a 'reboot'
#更改为selinux后需要重启生效
ansible all -m shell -a 'getenforce' #验证
#复制完更改权限
ansible all -m copy -a 'src=/etc/shadow dest=/data/ mode=000 owner=wang'
ansible all -a 'ls -l /data/' #查看
#编辑文件发送到目标主机
ansible all -m copy -a 'content="hello\nthanks\n" dest=/data/f2'
ansible all -m ping -a 'cat /data/f2'
#content里面是文件内容
src是本机源文件
dest是目标文件
backup=yes 是在推送是进行复制 保留源文件
mode= 权限可以设置
owner= 所有者也可以设置
ansible all -a ‘cat /etc/selinux/config’
4
默认使用shell 的配置方法
vim /etc/ansible/ansible.cfg
取消注释 使用shell模块
module_name = shell
1.模块使用
1.2cpoy:拷贝
[root@ansible ~]# ansible-doc -s copy
content: 写入
#content可以新建文件内容 并发送到目标主机
# 执行命令
[root@ansible ~]# ansible all -m copy -a "content='hello\nthanks\n' dest=/root/f2"
#在目标主机查看
[root@c7-48 ~]# cat f2
hello
thanks
1.2 fetch:抓取
[root@ansible ~]# ansible-doc -s fetch
单个文件
#只能抓取单个文件
[root@ansible ~]# ls /data
[root@ansible ~]# ansible all -m fetch -a 'src=/var/log/messages dest=/data'
[root@ansible ~]# ls /data/
10.0.0.44 10.0.0.48 10.0.0.49
[root@ansible ~]# tree /data/
/data/
├── 10.0.0.44
│ └── var
│ └── log
│ └── messages
├── 10.0.0.48
│ └── var
│ └── log
│ └── messages
└── 10.0.0.49
└── var
└── log
└── messages
目录(多个文件)
1.先对目标主机的文件进行打包
[root@ansible data]# ansible 10.0.0.44 -m shell -a 'tar jcf log.tar.xz /var/log/*.log'
2.查看(默认在root下)
[root@c7-44 ~]# ls /root
log.tar.xz f2
3.抓取
[root@ansible data]# ansible 10.0.0.44 -m fetch -a 'src=/root/log.tar.xz dest=/data'
#查看
[root@ansible ~]# tree /data/
/data/
├── 10.0.0.44
│ ├── root
│ │ └── log.tar.xz #在这
│ └── var
│ └── log
│ └── messages
#验证
[root@ansible ~]# cd /data/10.0.0.44/root/
[root@ansible root]# ls
log.tar.xz
[root@ansible root]# tar tvf log.tar.xz #预览
1.3unarchive:解包
[root@ansible ~]# ansible-doc -s unarchive
1.4archive:压缩包
[root@ansible ~]# ansible-doc -s archive
1.5file :设置文件属性
[root@ansible ~]# ansible-doc -s file
文件
name | path|src是等价的
新建新文件 touch
ansible all -m file -a 'name=/data/f3 state=touch'
ansible all -m file -a 'path=/data/f3 state=touch'
删除文件 absent
[root@ansible ~]# ansible all -m file -a 'name=/data/f3 state=absent'
[root@ansible ~]# ansible all -m file -a 'path=/data/f3 state=absent'
文件夹
新建文件夹 directory
[root@ansible ~]# ansible all -m file -a 'path=/data/dir2 state=directory'
[root@ansible ~]# ansible all -m file -a 'name=/data/dir1 state=directory'
删除文件夹 absent
[root@ansible ~]# ansible all -m file -a 'name=/data/dir1 state=absent'
[root@ansible ~]# ansible all -m file -a 'path=/data/dir2 state=absent'
软连接
创建软连接
[root@ansible ~]# ansible all -m file -a 'src=/etc/fstab dest=/data/fstab.link state=link'
#查看
[root@ansible ~]# ansible all -a 'ls -l /data'
删除软连接
[root@ansible ~]# ansible all -m file -a 'dest=/data/fstab.link state=absent'
#查看
[root@ansible ~]# ansible all -a 'ls -l /data'
删除目录
[root@ansible ~]# ansible all -m file -a 'dest=/data/ state=absent'
ps:挂在点的目录无法删除
#查看挂载点
[root@c7-48 ~]# df
Filesystem 1K-blocks Used Available Use% Mounted on
devtmpfs 1500376 0 1500376 0% /dev
tmpfs 1512380 0 1512380 0% /dev/shm
tmpfs 1512380 19616 1492764 2% /run
tmpfs 1512380 0 1512380 0% /sys/fs/cgroup
/dev/mapper/centos-root 28289540 2177492 26112048 8% /
/dev/sda1 1038336 139480 898856 14% /boot
tmpfs 302480 0 302480 0% /run/user/0
挂载点介绍
删除所有文件
ansible all -m shell -a "rm -rf /data/*"
1.6 hostname:更改主机名
[root@ansible ~]# ansible 10.0.0.48 -m hostname -a "name=node1"
已经生效并改名
[root@c7-48 ~]# bash
[root@node1 ~]# ls
anaconda-ks.cfg f1.txt f2
[root@node1 ~]# cat /etc/hostname #centos-7的主机名的配置文件
node1
#centos6的主机名在
/etc/sysconfig/network
缺点:
#没有改 手动更改建议修改
[root@node1 ~]# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 ==localhost4.localdomain4==
::1 localhost localhost.localdomain localhost6 ==localhost6.localdomain6==
==之间的部分 ==
1.7cron:计划任务
支持时间: minute,hour,day,month,weekday
*/1 每1分钟
1-5 范围
1,3,6 隔开
#广播位置
[root@ansible ~]# which wall
/usr/bin/wall
添加报警任务
[root@ansible ~]# ansible all -m cron -a 'minute=* weekday=1,7,6 job="/usr/bin/wall FBI warning" name=warningcron'
删除任务
[root@ansible ~]# ansible all -m cron -a 'job="/usr/bin/wall FBI warning" name=warningcron state=absent'
禁用任务
[root@ansible ~]# ansible all -m cron -a 'disabled=true job="/usr/bin/wall FBI warning" name=warningcron'
[root@ansible ~]# ansible all -m cron -a 'disabled=no job="/usr/bin/wall FBI warning" name=warningcron'
[root@node1 ~]# contab -l
bash: contab: command not found
[root@node1 ~]# crontab -l
*/5 * * * * /usr/sbin/ntpdate ntp1.aliyun >/dev/null 2>&1
#Ansible: warningcron
#* * * * * /usr/bin/wall FBI warning #已注释
启用任务
[root@ansible ~]# ansible all -m cron -a 'disabled=false job="/usr/bin/wall FBI warning" name=warningcron'
[root@ansible ~]# ansible all -m cron -a 'disabled=yes job="/usr/bin/wall FBI warning" name=warningcron'
[root@node1 ~]# crontab -l
*/5 * * * * /usr/sbin/ntpdate ntp1.aliyun >/dev/null 2>&1
#Ansible: warningcron
* * * * * /usr/bin/wall FBI warning
1.8yum:管理包
安装
install (present' or
installed’,`latest’),
卸载
remove (absent' or
removed’)
安装包
[root@ansible ~]# ansible all -m yum -a 'name=vsftpd'
查看所有装好的包
ansible all -m yum -a 'list=installed'
卸载包
ansible all -m yum -a 'name=vsftpd state=removed'
#验证
ansible all -m shell -a 'rpm -q vsftpd'
安装多个包 ,隔开
ansible all -m yum -a 'name=vsftpd,memcached state=latest'
卸载多个包
ansible all -m yum -a 'name=vsftpd,memcached state=absent'
安装已经下载好的包
#先copy到远程主机
[root@ansible data]# ansible 10.0.0.44,10.0.0.48 -m copy -a 'src=/data/jdk-8u131-linux-x64_.rpm dest=/root/'
#然后安装
[root@ansible data]# ansible 10.0.0.44,10.0.0.48 -m yum -a 'name=/root/jdk-8u131-linux-x64_.rpm state=installed'
#禁用gpg检查
[root@ansible data]# ansible 10.0.0.44,10.0.0.48 -m yum -a 'name=/root/jdk-8u131-linux-x64_.rpm state=installed disabled_gpg_check=yes'
#边清楚更新缓存 一边去装包
[root@ansible data]# ansible 10.0.0.44,10.0.0.48 -m yum -a 'name=dstat update_cache=yes'
gpg_check简介
dtsta是一款监控工具
1.9service:管理服务
[root@ansible ~]# ansible all -m service -a 'name=nginx state=started enabled=yes'
ansible all-m service -a 'name=httpd state=stopped'
ansible all -m service -a 'name=httpd state=started'
ansible all -m service -a 'name=httpd state=reloaded'
ansible all -m service -a 'name=httpd state=restarted'
2.0 user
#查看nginx账号有没有
getent passwd nginx
id nginx
[root@ansible ~]# ansible all -m user -a 'name=nginx shell=/sbin/nologin system=yes home=/var/system groups=root,bin uid=808 comment="system service"'
#system=yes 表示系统账号
# shell=/sbin/nologin 系统用户的shell类型
#comment 描述
#groups 附加组
新建账号
[root@ansible ~]# ansible all -m user -a 'name=ylm shell=/sbin/nologin system=yes home=/var/ylm groups=root,bin uid=88 comment="nginx service"'
[root@ansible ~]# ansible all -m shell -a 'getent passwd ylm'
删除账号
[root@ansible ~]# ansible all -m user -a 'name=ylm state=absent remove=yes'
#removes=yes 是确认删除家目录
[root@ansible ~]# ansible all -m shell -a 'getent passwd ylm'
2.1group :组管理
新建组
[root@ansible ~]# ansible all -m group -a 'name=ylm system=yes gid=800'
#验证
[root@ansible ~]# ansible all -a 'getent group ylm'
删除组
[root@ansible ~]# ansible all -m group -a 'name=ylm state=absent'
5
1.ansible系列命令
1.1 ansible-galaxy
连接https://galaxy.ansible下载相应的roles(角色)
- 列出所有已安装的galaxy
ansible-galaxy list
- 安装galaxy
ansible-galaxy install geerlingguy.redis
- 删除galaxy
ansible-galaxy remove geerlingguy.redis
1.1.2安装Nginx角色
[root@ansible ~]# ansible-galaxy install geerlingguy.nginx
#下载到隐藏目录.asnible目录
[root@ansible ~]# tree .ansible/roles/
.ansible/roles/
└── geerlingguy.nginx
├── defaults
│ └── main.yml
├── handlers
│ └── main.yml
├── LICENSE
├── meta
│ └── main.yml
├── molecule
│ └── default
│ ├── converge.yml
│ └── molecule.yml
├── README.md
├── tasks
│ ├── main.yml
│ ├── setup-Archlinux.yml
│ ├── setup-Debian.yml
│ ├── setup-FreeBSD.yml
│ ├── setup-OpenBSD.yml
│ ├── setup-RedHat.yml
│ ├── setup-Ubuntu.yml
│ └── vhosts.yml
├── templates
│ ├── nginx.conf.j2
│ ├── nginx.repo.j2
│ └── vhost.j2
└── vars
├── Archlinux.yml
├── Debian.yml
├── FreeBSD.yml
├── OpenBSD.yml
└── RedHat.yml
角色就是多个playbook
[root@ansible tasks]# pwd
/root/.ansible/roles/geerlingguy.nginx/tasks
[root@ansible tasks]# cat main.yml
---
# Variable setup.
- name: Include OS-specific variables.
include_vars: "{{ ansible_os_family }}.yml"
- name: Define nginx_user.
set_fact:
nginx_user: "{{ __nginx_user }}"
when: nginx_user is not defined
# Setup/install tasks.
- include_tasks: setup-RedHat.yml
when: ansible_os_family == 'RedHat'
- include_tasks: setup-Ubuntu.yml
when: ansible_distribution == 'Ubuntu'
- include_tasks: setup-Debian.yml
when: ansible_os_family == 'Debian'
- include_tasks: setup-FreeBSD.yml
when: ansible_os_family == 'FreeBSD'
- include_tasks: setup-OpenBSD.yml
when: ansible_os_family == 'OpenBSD'
- include_tasks: setup-Archlinux.yml
when: ansible_os_family == 'Archlinux'
# Vhost configuration.
- import_tasks: vhosts.yml
# Nginx setup.
- name: Copy nginx configuration in place.
template:
src: "{{ nginx_conf_template }}"
dest: "{{ nginx_conf_file_path }}"
owner: root
group: "{{ root_group }}"
mode: 0644
notify:
- reload nginx
- name: Ensure nginx service is running as configured.
service:
name: nginx
state: "{{ nginx_service_state }}"
enabled: "{{ nginx_service_enabled }}"
1.1.3查看角色
[root@ansible tasks]# ansible-galaxy list geerlingguy.nginx
# /root/.ansible/roles
- geerlingguy.nginx, 2.8.0
1.1.4复制角色
[root@ansible roles]# cp geerlingguy.nginx/ wang.nginx -rp
[root@ansible roles]# ansible-galaxy list
# /root/.ansible/roles
- geerlingguy.nginx, 2.8.0
- wang.nginx, 2.8.0
# /usr/share/ansible/roles
# /etc/ansible/roles
1.1.5删除角色
[root@ansible ~]# ansible-galaxy remove geerlingguy.nginx
#验证
#说白了 删除目录就可以
[root@ansible ~]# cd .ansible/roles/
[root@ansible roles]# ls
wang.nginx
1.2ansible-pull
推送至远程,效率无线提升,对运维要求较高
1.3ansible-playbook
1.用法
useage: ansible-playbook [optinon] playbook.yml [playbook2...]
#可以跟很多playbook
.yaml 后缀
2.格式
[root@ansible ansible]# cat hello.yaml
--- #表示开头
- hosts: webserver #操作的哪些主机
remote_user: root #默认使用什么用户
tasks: #任务
- name: hello #任务名称
command: hostname #执行操作
1.3ansible-vault
== 功能︰管理加密解密yml文件==
ansible-vault[create|decrypt|edit|encrypt|rekey|view]
ansible-vault encrypt hello.yml加密
ansible-vault decrypt hello.yml解密
ansible-vault view hello.yml查看
ansible-vault edit hello.yml编辑加密文件
ansible-vault rekey hello.yml修改口令
ansible-vault create new.yml创建新文件
1.encrypt :加密
[root@ansible ansible]# ansible-vault encrypt hello.yaml #加密
New Vault password:
Confirm New Vault password:
Encryption successful
[root@ansible ansible]# cat hello.yaml
$ANSIBLE_VAULT;1.1;AES256
62303934313466613534656430353834353434636532643439633634636434346462366537626365
3037313238336431643961323631333334663035653762650a663738316336333263383465343734
36323363636166316635396433646563383162653831323037646661313336303439303235313766
3433613735313237340a616264666464616334393033343138323539373764303734366538316439
31623730366338636438366363396538313966643539363737386264366639336238396635633130
39643264623730303435666431303232633062643439356238663333323333303766336665363661
38303535306565373131626163626466333439386265343837643034373461666534656364363730
36616665343862326537666333623266313538366262323430333832656465636531343862643738
6632
#加密后playbook不能直接使用
[root@ansible ansible]# ansible-playbook hello.yaml
ERROR! Attempting to decrypt but no vault secrets found
2.decrypt:解密
[root@ansible ansible]# ansible-vault decrypt hello.yaml
Vault password:
Decryption successful
[root@ansible ansible]# cat hello.yaml
---
- hosts: webserver
remote_user: root
tasks:
- name: hello
command: hostname
3.view :查看
使用口令进行查看加密的yml
[root@ansible ansible]# ansible-vault view hello.yaml
Vault password:
---
- hosts: webserver
remote_user: root
tasks:
- name: hello
command: hostname
4.edit :编辑
[root@ansible ansible]# ansible-vault edit hello.yaml
Vault password:
5.rekey: 修改口令
[root@ansible ansible]# ansible-vault rekey hello.yaml
Vault password:
New Vault password:
Confirm New Vault password:
Rekey successful
6.create :创建
[root@ansible ansible]# ansible-vault create hello2.yml
New Vault password:
Confirm New Vault password:
1.4 ansible-console
Ansible-console : 2.0+新增,可交互执行命令,支持tab
root@test(2)[f:10]$
执行用户@当前操作的主机组(当前组的主机数量)[f:并发数]$
设置并发数:forks n例如: forks 10
切换组:cd主机组例如: cd web
列出当前组主机列表:list
列出所有的内置命令∶?或help
用法示例︰
root@all(2)[f:5]$ list #查看主机
root@all (2)[f:5]$ cd appsrvs #进入主机清单
root@appsrvs (2)[f:5]$ list #查看主机
root@appsrvs (2)[f:5]$ yum name=httpd state=present #执行命令
root@appsrvs (2)[f:5]$ service name=httpd state=started
实践
[root@ansible ~]# ansible-console
Welcome to the ansible console.
Type help or ? to list commands.
root@all (3)[f:5]$
#root 用户
# all 所有人
(3)表示几个主机
[f:5] 并发5执行5个
1.进入主机目录
[root@ansible ~]# ansible-console
Welcome to the ansible console.
Type help or ? to list commands.
root@all (3)[f:5]$ cd webserver
2.更改并发数
root@webserver (1)[f:5]$ forks 10
3.查看模板
root@webserver (1)[f:10]$ ?
4.执行命令:查看主机名
root@webserver (1)[f:10]$ command hostname
10.0.0.48 | CHANGED | rc=0 >>
node1.ylm
5.更改主机名
root@webserver (1)[f:10]$ cd 10.0.0.48
root@10.0.0.48 (1)[f:10]$ hostname name=48
10.0.0.48 | CHANGED => {
"ansible_facts": {
"ansible_domain": "",
"ansible_fqdn": "48",
"ansible_hostname": "48",
"ansible_nodename": "48"
},
"changed": true,
"name": "48"
}
root@10.0.0.48 (1)[f:1
playbook
1.简介
- playbook是由一个或多个“play*组成的列表
- play的主要功能在于将事先归并为一组的主机装扮成事先通过ansible中的task
定义好的角色。从根本上来讲,所谓task无非是调用ansible的一个module。
将多个play组织在一个playbook中,即可以让它们联同起来按事先编排的机制
同唱一台夭戏 - Playbook采用YAML语言编写
2.工作流程
在playbook里面写好多 play 用户用ansible命令去调用执行的play,每个play里面有自己的任务,任务和任务之间有先后顺序,本质上调底层模块(开发 ,核心,插件),也得看主机清单 ,也通过ssh连接到远程主机上。
3.YAML介绍
-
YAML是一个可读性高的用来表达资料序列的格式。YAML参考了其他多种语言,包括:XML.
C语言、Python、Perl以及电子邮件格式RFC2822等。ClarkEvans在2001年在首次发表了这种
语言,另外Ingy dot Net与Oren Ben-Kikit也是这语言的共同设计者 -
YAML Ain’t Markup Language(不是标记语言),即YAML不是XML。不过,在开发的这种语言时,YAML的意
思其实是:“Yet Another Markup Language”(仍是一种标记语言) -
特性
1. YAML的可读性好
2. YAML和脚本语言的交互性好
3. YAML使用实现语言的数据类型
4. YAML有一个一致的信息模型
5. YAML易于实现
6. YAML可以基于流来处理
7. YAML表达能力强,扩展性好 -
内容及规范参见http://www.yaml
-
在单一挡案中,可用连续三个连字号(——)区分多个档案。另外,还有选择性的连续三个点号
(…)用来表示档案结尾 -
次行开始正常写Playbook的内容,一般建议写明该Playbook的功能
-
使用#号注释代码
-
缩进必须是统一的,不能空格和tab混用
-
缩进的级别也必须是一致的,同样的缩进代表同样的级别,程序判别配置的级别是通过缩进结
合换行来实现的 -
YAML文件内容和Linux系统大小写判断方式保持一致,是区别大小写的,k/v的值均需大小写敏
感 -
k/v的值可同行写也可换行写。同行使用:分隔
-
v可是个字符串,也可是另一个列表
-
一个完整的代码块功能需最少元素需包括name: task
-
一个name只能包括一个task
-
YAML文件扩展名通常为yml或yaml
3.1YAML语法简介
- List:列表,其所有元素均使用“”打头
- 示例∶
#A list of tasty fruits
-Apple
-orange
-strawberry
-Mango
-
Dictionary :字典,通常由多个key与value构成(键值对)
-
示例:
#An employee record
name: Example Developer
job: Developer
skill:Elite
也可以将key:value放置于{f}中进行表示,用,分隔多个key:value
- 示例:
--
# An employee record
{name:Example Developer,job: Developer,skill:Elite}
3.2YAML语法范例
- YAML的语法和其他高阶语言类似,并且可以简单表达清单、散列表、标量等数据结构。其结构
(Structure )通过空格来展示,序列(Sequence)里的项用-来代表,Map里的键值对用"∵"分隔 - 示例
name: John Smith
age;41
gender: Male
spouse:
name: lane Smith
age: 37
gender: Female
children:
- name: Jimmy Smith
age: 17
gender:Malc
- name: Jenny Smith
age 13
gender: Female
4.playbook核心元素
ansible中文权威指南
- Hosts执行的远程主机列表
- Tasks任务集
- Varniables内置变量或自定义变量在playbook中调用
- Templates模板,可替换模板文件中的变量并实现一些简单逻辑的文件
- Handlers和notity结合使用,由特定条件触发的操作,满足条件方才执行,否
则不执行 - tags标签指定某条任务执行,用于选择运行playbook中的部分代码。ansible
具有幂等性,因此会自动跳过没有变化的部分,即便如此,有些代码为测试其
确实没有发生变化的时间依然会非常地长。此时,如果确信其没有变化,就可
以通过tags跳过此些代码片断
ansible-playbook -t tagsname useradd.yml
5.playbook基础组件
-
Hosts;:
- playbook中的每一个play的目的都是为了让某个或某些主机以某个指定的用户
身份执行任务。hosts用于指定要执行指定住务的主机,须事宪定义在主机清
单中 - 可以是如下形式∶
one.example
one.example:two.example
192.168.1.50
192.168.1.*
- playbook中的每一个play的目的都是为了让某个或某些主机以某个指定的用户
-
Websrvs:dbsrvs两个组的并集
-
Websrvs:&dbsrvs两个组的交集
-
webservers:!phoenix在websrvs组,但不在dbsrvs组
示例: - hosts: websrvs : dbsrvs -
remote_user:可用于Host和task中。也可以通过指定其通过sudo的方式在远
程主机上执行任务,其可用于play全局或某任务;此外,甚至可以在sudo时使
用sudo_user指定sudo时切换的用户
- hosts: websrvs
remote_user: root
tasks:
- name: test connection
ping:
remote_user: magedu
sudo: yes #默认sudo为root
sudo_user:wang #sudo为wang
-
task列表和actioh
-
play的主体部分是tasklist。task list中的各任务按次序逐个在hosts中指定的所
有主机上执行,即在所有主机上完成第一个任务后再开始第二个。在运行自
下而下某playbook时,如果中途发生错误,所有已执行任务都将回滚,因此,
在更正playbook后重新执行一次即可 -
task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模
块执行是幂等的,这意味着多次执行是安全的,因为其结果均一致 -
每个task都应该有其name,用于playbook的执行结果输出,建议其内容尽可
能清晰地描述任务执行步骤。如果未提供name,则action的结果将用于输出 -
tasks:任务列表
格式∶(1)action: module arguments
(2) module: arguments # 建议使用
- 注意: shell和command模块后面跟命令,而非key=value -
某任务的状态在运行后为changed时,可通过“notify”通知给相应的
handlers -
任务可以通过"tags“打标签,而后可在ansible-playbook命令上使用-t指定进
行调用
示例:
tasks:
- name: disable selinux
command: /sbin/setenforce o
- 如果命令或脚本的退出码不为零,可以使用如下方式替代
tasks:
- name: run this command and ignore the result
shell: /usr/bin/somecommand || /bin/true
- 或者使用ignore_errors来忽略错误信息∶
tasks:
- name: run this command and ignore the result
shell: /usr/bin/somecommand
ignore_errors: True
5.1新建
[root@ansible ansible]# cat file.yml
---
- hosts: webserver
remote_user: root
tasks:
- name: create new file
file: name=/data/newfile state=touch
- name: create new user
user: name=test2 system=yes shell=/sbin/nologin
- name: install package
yum: name=httpd
- name: copy html
copy: src=/var/www/html/index.html dest=/var/www/html
- name: start service
service: name=httpd state=started enabled=yes
[root@ansible ansible]#
ps:新建用户使用user命令之前 一定要查看 用户是否存在
[root@ansible ~]# ansible webserver -a 'getent passwd'
5.2 -C 检查语法
[root@ansible ansible]# ansible-playbook -C file.yml
5.3运行playbook
1.运行playbook的方式
ansible-playbook <filename.yml> ... [options]
2.常见选项
--check只检测可能会发生的改变,但不真正执行操作
--list-hosts列出运行任务的主机
--limit主机列表只针对主机列表中的主机执行
-v 显示过程 -vv -v 更详细
- 示例
ansible-playbook file.yml --check只检测
ansible-playbook file.yml
ansible-playbook file.yml --limit websrvs
[root@ansible ansible]# ansible all -a 'getent passwd test2' --limit 10.0.0.48 只看48的
10.0.0.48 | CHANGED | rc=0 >>
test2:x:807:807::/home/test2:/sbin/nologin
3.查看文件针对那个主机执行的
[root@ansible ansible]# ansible-playbook file.yml --list-hosts
playbook: file.yml
play #1 (webserver): webserver TAGS: []
pattern: [u'webserver']
hosts (1):
10.0.0.48
4.查看几个任务
[root@ansible ansible]# ansible-playbook file.yml --list-tasks
playbook: file.yml
play #1 (webserver): webserver TAGS: []
tasks:
create new file TAGS: []
create new user TAGS: []
install package TAGS: []
copy html TAGS: []
start service TAGS: []
5.playbook VS shellscript
- 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,并设置开机启动
service httpd start
chkconfig httpd on
- Playbook定义
hosts: all
tasks:
- name:"安装Apache"
yum: name=httpd
- name:"复制配置文件”
copy: src=ftmp/httpd.conf dest=/etc/httpd/conf/
copy: src=/tmp/vhosts.conf dest=fetc/httpd/conf/ #不可用 一个name 使用一个copy
- name:"启动Apache ,并设置开机启动”
service: name=httpd state=started enabled=yes
相对路径☞的是playbook 的目录下
[root@ansible ansible]# cat file.yml
---
- hosts: webserver
remote_user: root
tasks:
- name: create new file
file: name=/data/newfile state=touch
- name: create new user
user: name=test2 system=yes shell=/sbin/nologin
- name: install package
yum: name=httpd
- name: copy html
copy: src=file/index.html dest=/var/www/html/
- name: copy test.html
copy: src=file/test.html dest=/var/www/html/
- name: start service
service: name=httpd state=started enabled=yes
6
1.handlers和notify结合使用触发条件
- Handlers(触发器)
是task列表,这些task与前述的task并没有本质上的不同,用于当关注的资源发生变化时,才会采取一定的操作 - Notify(通知)此action可用于在每个play的最后被触发,这样可避免多次有改变发生时每次都执行指定的操作,仅在所有的变化发生完成后一次性地执行指定操作。在notify中列出的操作称为handler,也即notify中调用handler中定义的操作。
示例:
执行一遍:
[root@ansible ansible]# cat files.yml
---
- hosts: webserver
remote_user: root
tasks:
- name: create new file
file: name=/root/newfile state=touch
- name: create new user
user: name=test2 system=yes shell=/sbin/nologin
- name: install package
yum: name=httpd
- name: copy html
copy: src=files/index.html dest=/var/www/html/
- name: start service
service: name=httpd state=started enabled=yes
如果我们在复制一个html 看看效果
[root@ansible ansible]# cat files.yml
---
- hosts: webserver
remote_user: root
tasks:
- name: create new file
file: name=/root/newfile state=touch
- name: create new user
user: name=test2 system=yes shell=/sbin/nologin
- name: install package
yum: name=httpd
- name: copy html
copy: src=files/index.html dest=/var/www/html/
- name: copy test html #增加了这一行 有拷贝了同一个文件
copy: src=files/test.html dest=/var/www/html/index.html
- name: start service
service: name=httpd state=started enabled=yes
我们发现 访问的时候 并没有更新页面 是因为 服务是启动的所以 必须重启 才可以
这就用到了 handler 和notify
[root@ansible ansible]# cat files.yml
---
- hosts: webserver
remote_user: root
tasks:
- name: create new file
file: name=/root/newfile state=touch
- name: create new user
user: name=test2 system=yes shell=/sbin/nologin
- name: install package
yum: name=httpd
- name: copy html
copy: src=files/index.html dest=/var/www/html/
- name: copy test html
copy: src=files/test.html dest=/var/www/html/index.html
notify: restart httpd
- name: start service
service: name=httpd state=started enabled=yes
handlers:
- name: restart httpd
service: name=httpd state=restarted enabled=yes
示例:
更改80端口为800
[root@ansible ansible]# cat http.yml
---
- hosts: webserver
remote_user: root
tasks:
- name: install package
yum: name=httpd
- name: copy conf file
copy: src=files/httpd.conf dest=/etc/httpd/conf backup=yes #将配置文件更改后
notify: restart service #重启服务
- name: start service
service: name=httpd state=started enabled=yes
handlers: #触发器可以定义多个
- name: restart service
service: name=httpd state=restarted
2.tags:标签
- 可以用==-t== 去执行某一个动作
[root@ansible ansible]# cat http.yml
---
- hosts: webserver
remote_user: root
tasks:
- name: install package
yum: name=httpd
- name: copy conf file
copy: src=files/httpd.conf dest=/etc/httpd/conf backup=yes
notify: restart service
- name: start service
service: name=httpd state=started enabled=yes
tags: rshttpd #打上标签
handlers:
- name: restart service
service: name=httpd state=restarted
[root@ansible ansible]# ansible-playbook -t rshttpd http.yml
- 也可以执行2个动作
[root@ansible ansible]# cat http.yml
---
- hosts: webserver
remote_user: root
tasks:
- name: install package
yum: name=httpd
tags: inshttpd
- name: copy conf file
copy: src=files/httpd.conf dest=/etc/httpd/conf backup=yes
notify: restart service
- name: start service
service: name=httpd state=started enabled=yes
tags: rshttpd
handlers:
- name: restart service
service: name=httpd state=restarted
[root@ansible ansible]#
[root@ansible ansible]# ansible-playbook -t inshttpd,rshttpd http.yml
- 多个动作共用一个标签
[root@ansible ansible]# cat http.yml
---
- hosts: webserver
remote_user: root
tasks:
- name: install package
yum: name=httpd
tags: httpd
- name: copy conf file
copy: src=files/httpd.conf dest=/etc/httpd/conf backup=yes
notify: restart service
- name: start service
service: name=httpd state=started enabled=yes
tags: httpd
handlers:
- name: restart service
service: name=httpd state=restarted
[root@ansible ansible]# ansible-playbook -t httpd http.yml
- 查看playbook里面的标签信息
[root@ansible ansible]# ansible-playbook http.yml --list-tags
playbook: http.yml
play #1 (webserver): webserver TAGS: []
TASK TAGS: [httpd]
3.playbook中变量的使用
- 变量名:仅能由字母、数字、和下划线组成。且只能以字母开头
- 变量来源:
1. ansible setup facts 远程主机的所有变量都可直接调用
2. 在/etc/ansible/hosts中定义
普通变量:主机组中主机单独定义,。优先级高于公共变量
公共(组)变量:针对主机组中所有主机同一变量
3. 通过命令行指定变量,优先级最高
ansible-playbook -e varname=value
4. 在playbook中定义
vars:
- var1:value1
- var2: value2
5. 在role中定义
3.1 setup
[root@ansible ansible]# ansible webserver -m setup #查看系统信息
[root@ansible ansible]# ansible webserver -m setup | less
[root@ansible ansible]#
[root@ansible ansible]# ansible 10.0.0.48 -m hostname -a 'name=node1'
10.0.0.48 | CHANGED => {
"ansible_facts": {
"ansible_domain": "",
"ansible_fqdn": "node1",
"ansible_hostname": "node1",
"ansible_nodename": "node1",
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"name": "node1"
}
[root@ansible ansible]# ansible webserver -m setup | grep ansible_fqdn
"ansible_fqdn": "c7-49.shared",
"ansible_fqdn": "node1",
[root@ansible ansible]# ansible webserver -m setup | grep ansible_hostname
"ansible_hostname": "c7-49",
"ansible_hostname": "node1",
[root@ansible ansible]# ansible webserver -m setup -a 'filter=ansible_hostname' #使用filter去过滤
10.0.0.49 | SUCCESS => {
"ansible_facts": {
"ansible_hostname": "c7-49",
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false
}
10.0.0.48 | SUCCESS => {
"ansible_facts": {
"ansible_hostname": "node1",
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false
}
3.2变量赋值
[root@ansible ansible]# cat app.yml
---
- hosts: webserver
remote_user: root
tasks:
- name: install package
yum: name={{ pkname }}
- name: start service
service: name={{ pkname }} state=started enabled=yes
使用==-e==去执行
[root@ansible ansible]# ansible-playbook -e 'pkname=httpd' app.yml
- 使用变量安装两个包
[root@ansible ansible]# cat app.yml
---
- hosts: webserver
remote_user: root
tasks:
- name: install package
yum: name={{ pkname1 }} #变量名
- name: install package
yum: name={{ pkname2 }} #变量名
[root@ansible ansible]# ansible-playbook -e 'pkname1=vsftpd pkname2=memcached' app.yml
[root@ansible ansible]# ansible webserver -m shell -a 'rpm -q vsftpd memcached' #查看安装的包
[root@ansible ansible]# ansible webserver -m shell -a 'yum -y remove vsftpd memcached' #卸载安装的包
3.3示例:安装两个包(使用var)
[root@ansible ansible]# cat app.yml
---
- hosts: webserver
remote_user: root
vars:
- pkname1: httpd
- pkname2: vsftpd
tasks:
- name: install package
yum: name={{ pkname1 }}
- name: install package
yum: name={{ pkname2 }}
[root@ansible ansible]# ansible-playbook app.yml
[root@ansible ansible]# ansible webserver -m shell -a 'rpm -q httpd vsftpd'
3.4针对单一主机的变量
vim /etc/ansible/hosts
[webserver]
10.0.0.48 http_port=81
10.0.0.49 http_port=82
[root@ansible ansible]# cat hostname.yml
---
- hosts: webserver
remote_user: root
tasks:
- name: set hostaname
hostname: name=www{{http_port}}.node
[root@ansible ansible]# ansible-playbook hostname.yml
10.0.0.49 | CHANGED | rc=0 >>
www82.node
10.0.0.48 | CHANGED | rc=0 >>
www81.node
3.5针对组的变量
[webserver]
10.0.0.48 http_port=81
10.0.0.49 http_port=82
[webserver:vars]
nodename=www
domainname=liming
[root@ansible ansible]# cat hostname.yml
---
- hosts: webserver
remote_user: root
tasks:
- name: set hostaname
hostname: name={{nodename}}{{http_port}}.{{domainname}}
[root@ansible ansible]# ansible-playbook hostname.yml
[root@ansible ansible]# ansible webserver -m shell -a 'hostname'
10.0.0.48 | CHANGED | rc=0 >>
www81.liming
10.0.0.49 | CHANGED | rc=0 >>
www82.liming
3.6命令行优先级最高
[root@ansible ansible]# ansible-playbook -e 'nodename=web domainname=example' hostname.yml
[root@ansible ansible]# ansible webserver -a 'hostname'
10.0.0.49 | CHANGED | rc=0 >>
web82.example
10.0.0.48 | CHANGED | rc=0 >>
web81.example
#命令行优先级大于配置文件
3.7普通变量优先级比分组的要高
7
1.在playbook中去定义变量
变量的优先级 -e > playbook > 主机清单
普通变量比分组里面的公共变量优先级高
1.1使用变量查看主机名
[root@ansible ansible]# ansible all -m setup -a 'filter="ansible_fqdn"'
10.0.0.50 | SUCCESS => {
"ansible_facts": {
"ansible_fqdn": "c7-50.shared",
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false
}
10.0.0.49 | SUCCESS => {
"ansible_facts": {
"ansible_fqdn": "web82.example",
"discovered_interpreter_python": "/usr/bin/python"
},
---
"changed": false
}
10.0.0.48 | SUCCESS => {
"ansible_facts": {
"ansible_fqdn": "web81.example",
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false
}
1.2新建playbook
[root@ansible ansible]# cat var.yml
---
- hosts: webserver
remote_user: root
tasks:
- name: create log file
file: name=/data/{{ ansible_fqdn }}.log state=touch #直接只是setup的变量
1.3启动
[root@ansible ansible]# ansible-playbook var.yml
1.4验证
[root@ansible ~]# ansible all -a 'ls /data -l'
10.0.0.49 | CHANGED | rc=0 >>
总用量 0
-rw-r--r-- 1 root root 0 8月 20 05:41 web82.example.log
10.0.0.48 | CHANGED | rc=0 >>
总用量 0
-rw-r--r-- 1 root root 0 8月 20 05:41 web81.example.log
10.0.0.50 | CHANGED | rc=0 >>
总用量 0
2.在独立的变量YAML文件中定义
2.1新建变量文件
[root@ansible ansible]# cat vars.yml
var1: httpd
var2: vsftpd
2.2新建playbook剧本
[root@ansible ansible]# cat testvar.yml
---
- hosts: webserver
remote_user: root
vars_files: #定义变量文件
- vars.yml #文件名
tasks:
- name: install package
yum: name={{ var1 }}
- name: cretate file
file: name=/data/{{ var2 }}.log state=touch
2.3执行
[root@ansible ansible]# ansible-playbook testvar.yml
2.4验证
#验证
[root@ansible ansible]# ansible webserver -m shell -a 'rpm -q httpd'
[WARNING]: Consider using the yum, dnf or zypper module rather than running
'rpm'. If you need to use command because yum, dnf or zypper 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.
10.0.0.48 | CHANGED | rc=0 >>
httpd-2.4.6-93.el7.centos.x86_64
10.0.0.49 | CHANGED | rc=0 >>
httpd-2.4.6-93.el7.centos.x86_64
[root@ansible ansible]# ansible webserver -m shell -a 'ls /data'
10.0.0.48 | CHANGED | rc=0 >>
vsftpd.log
10.0.0.49 | CHANGED | rc=0 >>
vsftpd.log
3.模版templates
- 只用于playbook
[root@ansible ansible]# ansible-doc -s template
- name: Template a file out to a remote server
#拿一个文件当模板传到远程主机上去
- 文本文件,嵌套有脚本(使用模板编程语言编写)
- Jinja2语言,使用字面量,有下面格式
字符串:使用单引号或双引号
数字: 整数,浮点数
列表:[iterm1,iterm2,…]
元组:(iterm1,iterm2,…)
字典:{key1:value1,key2:value2,…}
布尔型:true/false - 算术匀运算:+,-,/,//,%,**
- 比较操作:==,!=,>,>=,<,<=
- 逻辑运算:and,or,not
- 流表达式:For If When
3.1安装nginx
[root@ansible ~]# yum -y install nginx
3.2查看配置文件
root@ansible ~]# cat /etc/nginx/nginx.conf
worker_processes auto; #根据CPU核数自动生成work进程数
3.3启动nginx
[root@ansible ~]# systemctl start nginx
3.4查看进程数
[root@ansible ~]# ps aux | grep nginx
root 22038 0.0 0.2 120900 2096 ? Ss 21:21 0:00 nginx: master process /usr/sbin/nginx
nginx 22039 0.0 0.3 121296 3052 ? S 21:21 0:00 nginx: worker process #只有一个进程表示一个CPU
root 22041 0.0 0.0 112824 980 pts/2 S+ 21:21 0:00 grep --color=auto nginx
3.5查看CPU
[root@ansible ~]# lscpu #查看CPU 只有一个
CPU(s): 1
ansible_processor_vcpus": 1
3.6定义进程数
[root@ansible templates]# cat nginx.conf.j2
# For more information on configuration, see:
# * Official English Documentation: http://nginx/en/docs/
# * Official Russian Documentation: http://nginx/ru/docs/
user nginx;
worker_processes {{ansible_processor_vcpus*4}}; #使用变量*4
3.7编辑playbook
[root@ansible templates]# cat templat.yml
---
- hosts: webserver
remote_user: root
tasks:
- name: install package
yum: name=nginx
- name: copy template
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf #使用template模块 且只能在playbook中使用
notify: restart service
- name: start service
service: name=nginx state=started enabled=yes
handlers:
- name: restart service
service: name=nginx state=restarted
3.8执行
[root@ansible templates]# ansible-playbook templat.yml
3.9查看进程数
#因为是1核所以*4是4个进程
[root@ansible templates]# ansible webserver -m shell -a 'ps aux| grep nginx'
10.0.0.49 | CHANGED | rc=0 >>
root 7061 0.0 0.2 120900 2244 ? Ss 01:10 0:00 nginx: master process /usr/sbin/nginx
nginx 7063 0.0 0.3 121296 3256 ? S 01:10 0:00 nginx: worker process
nginx 7064 0.0 0.3 121296 3256 ? S 01:10 0:00 nginx: worker process
nginx 7065 0.0 0.3 121296 3256 ? S 01:10 0:00 nginx: worker process
nginx 7066 0.0 0.3 121296 3052 ? S 01:10 0:00 nginx: worker process
root 7215 0.0 0.1 113280 1204 pts/1 S+ 01:10 0:00 /bin/sh -c ps aux| grep nginx
root 7217 0.0 0.0 112828 960 pts/1 S+ 01:10 0:00 grep nginx
10.0.0.48 | CHANGED | rc=0 >>
root 7445 0.0 0.2 120900 2244 ? Ss 01:10 0:00 nginx: master process /usr/sbin/nginx
nginx 7447 0.0 0.3 121296 3052 ? S 01:10 0:00 nginx: worker process
nginx 7448 0.0 0.3 121296 3052 ? S 01:10 0:00 nginx: worker process
nginx 7449 0.0 0.3 121296 3052 ? S 01:10 0:00 nginx: worker process
nginx 7450 0.0 0.3 121296 3052 ? S 01:10 0:00 nginx: worker process
root 7580 0.0 0.1 113280 1204 pts/1 S+ 01:10 0:00 /bin/sh -c ps aux| grep nginx
root 7582 0.0 0.0 113280 188 pts/1 R+ 01:10 0:00 /bin/sh -c ps aux| grep nginx
4.0更改端口
4.0.1使用主机清单的变量
[root@ansible ~]# cat /etc/ansible/hosts
[webserver]
10.0.0.48 http_port=81
10.0.0.49 http_port=82
4.0.2修改配置文件
[root@ansible ansible]# cd templates/
[root@ansible templates]# cat nginx.conf.j2
# For more information on configuration, see:
# * Official English Documentation: http://nginx/en/docs/
# * Official Russian Documentation: http://nginx/ru/docs/
user nginx;
worker_processes {{ ansible_processor_vcpus*4 }}; #将auto改成变量
server {
listen {{ http_port }} default_server; #将80改成变量
4.0.3playbook
[root@ansible templates]# cat template.yml
---
- hosts: webserver
remote_user: root
tasks:
- name: install package
yum: name=nginx
- name: copy template
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf #推送到目标主机
notify: restart service
- name: start service
service: name=nginx state=started enabled=yes
handlers:
- name: restart service
service: name=nginx state=restarted
4.0.4验证
#更改为4个进程
[root@ansible templates]# ansible webserver -m shell -a 'ps aux| grep nginx'
10.0.0.49 | CHANGED | rc=0 >>
root 9665 0.0 0.2 120900 2244 ? Ss 01:48 0:00 nginx: master process /usr/sbin/nginx
nginx 9667 0.0 0.3 121296 3256 ? S 01:48 0:00 nginx: worker process
nginx 9668 0.0 0.3 121296 3256 ? S 01:48 0:00 nginx: worker process
nginx 9669 0.0 0.3 121296 3256 ? S 01:48 0:00 nginx: worker process
nginx 9670 0.0 0.3 121296 3048 ? S 01:48 0:00 nginx: worker process
root 9800 0.0 0.1 113280 1204 pts/1 S+ 01:48 0:00 /bin/sh -c ps aux| grep nginx
root 9802 0.0 0.0 112824 960 pts/1 R+ 01:48 0:00 grep nginx
10.0.0.48 | CHANGED | rc=0 >>
root 10378 0.0 0.2 120900 2248 ? Ss 01:48 0:00 nginx: master process /usr/sbin/nginx
nginx 10380 0.0 0.3 121296 3260 ? S 01:48 0:00 nginx: worker process
nginx 10381 0.0 0.3 121296 3260 ? S 01:48 0:00 nginx: worker process
nginx 10382 0.0 0.3 121296 3260 ? S 01:48 0:00 nginx: worker process
nginx 10383 0.0 0.3 121296 3056 ? S 01:48 0:00 nginx: worker process
root 10513 0.0 0.1 113280 1204 pts/1 S+ 01:48 0:00 /bin/sh -c ps aux| grep nginx
root 10515 0.0 0.0 112824 960 pts/1 S+ 01:48 0:00 grep nginx
[root@ansible templates]# ansible webserver -m shell -a 'ss -ntlp | grep nginx'
10.0.0.49 | CHANGED | rc=0 >>
LISTEN 0 128 *:82#已更改 *:* users:(("nginx",pid=9670,fd=6),("nginx",pid=9669,fd=6),("nginx",pid=9668,fd=6),("nginx",pid=9667,fd=6),("nginx",pid=9665,fd=6))
LISTEN 0 128 [::]:80 [::]:* users:(("nginx",pid=9670,fd=7),("nginx",pid=9669,fd=7),("nginx",pid=9668,fd=7),("nginx",pid=9667,fd=7),("nginx",pid=9665,fd=7))
10.0.0.48 | CHANGED | rc=0 >>
LISTEN 0 128 *:81 #已更改 *:* users:(("nginx",pid=10383,fd=6),("nginx",pid=10382,fd=6),("nginx",pid=10381,fd=6),("nginx",pid=10380,fd=6),("nginx",pid=10378,fd=6))
LISTEN 0 128 [::]:80 [::]:* users:(("nginx",pid=10383,fd=7),("nginx",pid=10382,fd=7),("nginx",pid=10381,fd=7),("nginx",pid=10380,fd=7),("nginx",pid=10378,fd=7))
[root@ansible templates]#
when
- 条件测试:如果需要根据变量、facts或之前任务的执行结果来做为某task执行与否的前提时要用到条件测试,通过when语句实现,在task中使用,Jinja2的语法格式
- when语句
- 在task后添加when子句即可使用条件测试;when语句支持Jinja2表达式语法
- 示例:
- tasks:
- name: “shutdown RedHat flavored systems”
command: /sbin/shutdown -h now
when: ansible_os_family == “RedHat”
- name: “shutdown RedHat flavored systems”
根据版本号 来推送不同的模板文件
8
1.迭代:with_itrems
迭代:当有需要重复执行的任务时,可以使用迭代机制
- 对迭代项的引用,固定变量名为 “itrem”
- 要在task中使用with_itrems给定要迭代的元素列表
- 列表格式:
字符串
字典
YAML文件在线测试
环境
[webserver]
10.0.0.48 http_port=81
10.0.0.49 http_port=82
[webserver:vars]
nodename=www
domainname=liming
[logserver]
10.0.0.49
10.0.0.54 #新建的虚拟机6已经搭好了
示例1
1.1.2查看表示版本的变量
[root@ansible ansible]# ansible all -m setup | grep version
"ansible_bios_version": "15.1.4 (47270)",
"ansible_distribution_major_version": "6",
"ansible_distribution_version": "6.9",
"ansible_kernel_version": "#1 SMP Tue Mar 21 19:29:05 UTC 2017",
"ansible_product_version": "None",
"version": {
"version_info": [
"ansible_python_version": "2.6.6",
"ansible_bios_version": "15.1.4 (47270)",
"ansible_distribution_major_version": "7",
"ansible_distribution_version": "7.7",
"ansible_kernel_version": "#1 SMP Wed Aug 7 18:08:02 UTC 2019",
"ansible_product_version": "None",
"version": {
"version_info": [
"ansible_python_version": "2.7.5",
"ansible_bios_version": "15.1.4 (47270)",
"ansible_distribution_major_version": "7",
"ansible_distribution_version": "7.7",
"ansible_kernel_version": "#1 SMP Wed Aug 7 18:08:02 UTC 2019",
"ansible_product_version": "None",
"version": {
"version_info": [
"ansible_python_version": "2.7.5",
1.1.3新建yaml文件
[root@ansible ansible]# cat testiterm.yml
---
- hosts: all
remote_user: root
tasks:
- name: create some file
file: name=/data/{{ item }} state=touch
when: ansible_distribution_major_version == "7"
with_items:
- file1
- file2
- file3
- name: install some packages
yum: name={{ item }}
with_items:
- htop
- sl
- hping3
1.1.4验证
#因为有条件判断 所以54 是6的机器 没有创建文件
[root@ansible ansible]# ansible all -m shell -a 'ls /data'
10.0.0.54 | FAILED | rc=2 >> #已经跳过54 没有文件
ls: 无法访问/data: 没有那个文件或目录non-zero return code
10.0.0.49 | CHANGED | rc=0 >>
file1 #安装了三个文件
file2
file3
vsftpd.log
web82.example.log
10.0.0.48 | CHANGED | rc=0 >>
file1
file2
file3
vsftpd.log
web81.example.log
#没有条件判断所以都安装上了
[root@ansible ansible]# ansible all -m shell -a "rpm -q htop sl hping3"
[WARNING]: Consider using the yum, dnf or zypper module rather than running 'rpm'. If you need to use command
because yum, dnf or zypper 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.
10.0.0.54 | CHANGED | rc=0 >>
htop-1.0.3-1.el6.x86_64
sl-5.02-1.el6.x86_64
hping3-0.0.20051105-16.el6.x86_64
10.0.0.49 | CHANGED | rc=0 >>
htop-2.2.0-3.el7.x86_64
sl-5.02-1.el7.x86_64
hping3-0.0.20051105-24.el7.x86_64
10.0.0.48 | CHANGED | rc=0 >>
htop-2.2.0-3.el7.x86_64
sl-5.02-1.el7.x86_64
hping3-0.0.20051105-24.el7.x86_64
示例2
1.新建yaml文件
[root@ansible ansible]# cat testiterm2.yml
---
- hosts: all
remote_user: root
tasks:
- name: create some groups
group: name={{ item }}
when: ansible_distribution_major_version == "7"
with_items:
- g1
- g2
- g3
2 .验证组是否被创建成功
ansible all -m shell -a 'getent group'
2.迭代嵌套子变量
- 将每个用户加入到每个组
[root@ansible ansible]# cat testiterm3.yml
---
- hosts: webserver
remote_user: root
tasks:
- name: create some groups
group: name={{ item }}
when: ansible_distribution_major_version == "7"
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'}
3.playbook中template for if
1.示例1:列表
1.1新建配置文件
[root@ansible ansible]# cat testiterm4.yml
---
- hosts: webserver
remote_user: root
vars:
ports:
- 81
- 82
- 83
tasks:
- name: cp conf
template: src=for1.conf.j2 dest=/data/for1.conf
1.2 在templates文件夹里新建模版文件
[root@ansible ansible]# cat templates/for1.conf.j2
{% for port in ports %}
server{
listen {{ port }} #port从yaml文件中来
}
{% endfor %}
1.3 验证
[root@ansible ansible]# ansible webserver -m shell -a 'ls /data'
10.0.0.48 | CHANGED | rc=0 >>
file1
file2
file3
for1.conf
vsftpd.log
web81.example.log
10.0.0.49 | CHANGED | rc=0 >>
file1
file2
file3
for1.conf
vsftpd.log
web82.example.log
[root@ansible ansible]# ansible webserver -m shell -a 'cat /data/for1.conf'
10.0.0.48 | CHANGED | rc=0 >>
server{
listen 81
}
server{
listen 82
}
server{
listen 83
}
10.0.0.49 | CHANGED | rc=0 >>
server{
listen 81
}
server{
listen 82
}
server{
listen 83
}
2.示例2:键值对
2.1新建配置文件
[root@ansible ansible]# cat for2.yml
---
- hosts: webserver
remote_user: root
vars:
ports:
- listen_port: 81
- listen_port: 82
- listen_port: 83
tasks:
- name: cp conf
template: src=for2.conf.j2 dest=/data/for2.conf
2.2新建配置文件
[root@ansible ansible]# cat templates/for2.conf.j2
{% for port in ports %}
server{
listen {{ port.listen_port }}
}
{% endfor %}
2.3验证
[root@ansible ansible]# ansible webserver -m shell -a 'ls /data'
10.0.0.48 | CHANGED | rc=0 >>
file1
file2
file3
for1.conf
for2.conf
vsftpd.log
web81.example.com.log
10.0.0.49 | CHANGED | rc=0 >>
file1
file2
file3
for1.conf
for2.conf
vsftpd.log
web82.example.com.log
[root@ansible ansible]# ansible webserver -m shell -a 'cat /data/for2.conf'
10.0.0.49 | CHANGED | rc=0 >>
server{
listen 81
}
server{
listen 82
}
server{
listen 83
}
10.0.0.48 | CHANGED | rc=0 >>
server{
listen 81
}
server{
listen 82
}
server{
listen 83
}
示例3: 多个键值对
[root@ansible ansible]# cat for3.yml
---
- hosts: webserver
remote_user: root
vars:
ports:
- web1:
port: 81
name: web1.node
rootdir: /data/website1
- web2:
port: 82
name: web2.node
rootdir: /data/website2
- web3:
port: 83
name: web3.node
rootdir: /data/website3
tasks:
- name: cp conf
template: src=for3.conf.j2 dest=/data/for3.conf
[root@ansible ansible]# cat templates/for3.conf.j2
{% for p in ports %}
server{
listen {{ p.port }}
servername {{ p.name }}
documentroot {{ p.rootdir }}
}
{% endfor %}
[root@ansible ansible]# ansible webserver -m shell -a 'ls /data'
10.0.0.49 | CHANGED | rc=0 >>
file1
file2
file3
for1.conf
for2.conf
for3.conf
vsftpd.log
web82.example.log
10.0.0.48 | CHANGED | rc=0 >>
file1
file2
file3
for1.conf
for2.conf
for3.conf
vsftpd.log
web81.example.log
[root@ansible ansible]# ansible webserver -m shell -a 'cat /data/for3.conf'
10.0.0.49 | CHANGED | rc=0 >>
server{
listen 81
servername web1.node
documentroot /data/website1
}
server{
listen 82
servername web2.node
documentroot /data/website2
}
server{
listen 83
servername web3.node
documentroot /data/website3
}
10.0.0.48 | CHANGED | rc=0 >>
server{
listen 81
servername web1.node
documentroot /data/website1
}
server{
listen 82
servername web2.node
documentroot /data/website2
}
server{
listen 83
servername web3.node
documentroot /data/website3
}
示例4: 加上if条件判断
[root@ansible ansible]# cat for4.yml
---
- hosts: webserver
remote_user: root
vars:
ports:
- web1:
port: 81
#name: web1.node
rootdir: /data/website1
- web2:
port: 82
name: web2.node
rootdir: /data/website2
- web3:
port: 83
#name: web3.node
rootdir: /data/website3
tasks:
- name: cp conf
template: src=for4.conf.j2 dest=/data/for4.conf
[root@ansible ansible]# cat templates/for4.conf.j2
{% for p in ports %}
server{
listen {{ p.port }}
{% if p.name is defined %}
servername {{ p.name }}
{% endif %}
documentroot {{ p.rootdir }}
}
{% endfor %}
[root@ansible ansible]# ansible webserver -m shell -a 'ls /data'
10.0.0.48 | CHANGED | rc=0 >>
file1
file2
file3
for1.conf
for2.conf
for3.conf
for4.conf
vsftpd.log
web81.example.log
10.0.0.49 | CHANGED | rc=0 >>
file1
file2
file3
for1.conf
for2.conf
for3.conf
for4.conf
vsftpd.log
web82.example.log
[root@ansible ansible]# ansible webserver -m shell -a 'cat /data/for4.conf'
10.0.0.48 | CHANGED | rc=0 >>
server{
listen 81
documentroot /data/website1
}
server{
listen 82
servername web2.node.com
documentroot /data/website2
}
server{
listen 83
documentroot /data/website3
}
10.0.0.49 | CHANGED | rc=0 >>
server{
listen 81
documentroot /data/website1
}
server{
listen 82
servername web2.node.com
documentroot /data/website2
}
server{
listen 83
documentroot /data/website3
}
[root@ansible ansible]#
roles
- roles
ansible自1.2版本引入的新特性,用于层次性、结构化地组织playbook。roles能够根据层次性结构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include(即将过期)指令即可。简单来讲,roles就是通过分别将变量、文件、模板以及处理器放置于单独的目录中,并可以便捷地include它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以使用用于构建守护进程等场景中 - 复杂场景:建议使用roles,代码复用度高
- 变更指定主机或主机组
- 如命名不规范维护和传承成本大
- 某些功能需多个playbook,通过includes实现
roles使用
- 角色(roles):角色集合
roles/
mysql/
httpd/
nginx/
memcached/
[root@ansible ansible]# cd /etc/ansible/ #官方推荐路径
[root@ansible ansible]# ls
ansible.cfg hosts roles #this
部署nginx服务
1.思路
- group: nginx
- user: nginx(要加入到nginx组)
- yum: nginx
- template:nginx.conf.j2
- service: nginx
2.查看用户和组是否存在
[root@ansible ansible]# ansible all -m shell -a 'getent group nginx'
[root@ansible ansible]# ansible all -m shell -a 'getent passwd nginx'
[root@ansible ansible]# ansible all -m shell -a 'userdel -r nginx' #删除
3. ansible roles目录编排
4.roles目录结构
- 每个角色,以特定的层级目录结构进行组织
- roles目录结构
playbook.yml
roles/
project/
tasks/
files/
vars/ 不常用
default/ 不常用
templates/
handlers/
meta/ 不常用
5.roles各目录作用
- /roles/project/: 项目名称,有以下子目录
- files/ :存放由copy或script模块等调用的文件
- templates/ : template模块查找所需模板文件的目录
- tasks/: 定义task.role的基本元素,至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含
- handers/ :至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含
- vars/: 定义变量,至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含
- meta/:定义当前角色的特殊设定及其依赖关系,至少应该包含一个名为main.yml的文件,其它文件需在此文件中通过include进行包含
- default/: 设定默认变量时使用此目录中的main.yml文件
6.🌲状图
[root@ansible ansible]# pwd
/root/ansible
[root@ansible ansible]# tree
.
├── nginx_roles.yml #ansible执行的文件 要和角色目录平行
└── roles #角色目录
├── httpd
├── memcache
├── mysql
└── nginx #新建nginx角色
├── tasks #包含任务目录
│ ├── group.yml
│ ├── main.yml
│ ├── restart.yml
│ ├── start.yml
│ ├── template.yml
│ ├── user.yml
│ └── yum.yml
└── templates 包含模板目录
└── nginx.conf.j2
7.tasks目录下
[root@ansible tasks]# ls
group.yml main.yml restart.yml start.yml template.yml user.yml yum.yml
[root@ansible tasks]# cat main.yml #设置启动顺序的目录
- include: group.yml
- include: user.yml
- include: yum.yml
- include: template.yml
- include: start.yml
[root@ansible tasks]# cat group.yml
- name: create group
group: name=nginx gid=80
[root@ansible tasks]# cat user.yml
- name: creat user
user: name=nginx uid=80 group=nginx system=yes shell=/sbin/nologin
[root@ansible tasks]# cat yum.yml
- name: install package
yum: name=nginx
[root@ansible tasks]# cat template.yml
- name: copy conf
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
[root@ansible tasks]# cat start.yml
- name: start service
service: name=nginx state=started enabled=yes
[root@ansible tasks]# cat restart.yml
- name: start service
service: name=nginx state=restarted enabled=yes
templates目录下
[root@ansible templates]# ls
nginx.conf.j2
9
1.创建httpd的角色
1.1检查目标主机有没有apache用户
[root@c7-47 ~]# ansible all -m shell -a 'getent passwd apache'
[root@c7-47 ~]# ansible all -m shell -a 'yum -y remove httpd'
[root@c7-47 ~]# ansible all -m user -a 'name=apache state=absent'
1.2httpd角色树状图
[root@c7-47 ansible]# pwd
/root/ansible
[root@c7-47 ansible]# ls
httpd_role.yml roles #playbook剧本应该和roles目录平行
[root@c7-47 ansible]# tree
.
├── httpd_role.yml #playbook文件
└── roles #角色目录
├── httpd #httpd的角色目录 playbook调用它
│ ├── files
│ │ └── httpd.conf
│ └── tasks
│ ├── copy.yml
│ ├── main.yml
│ └── user.yml
[root@c7-47 ansible]# cat roles/httpd/tasks/main.yml #定义任务使用的顺序
- include: user.yml
- include: copy.yml
[root@c7-47 ansible]# cat roles/httpd/tasks/copy.yml
- name: copy files
copy: src=httpd.conf dest=/data/ owner=apache
[root@c7-47 ansible]# cat roles/httpd/tasks/user.yml
- name: create user
user: name=apache system=yes shell=/sbin/nologin
1.3执行
[root@c7-47 ansible]# ansible-playbook -C httpd_role.yml
[root@c7-47 ansible]# ansible-playbook httpd_role.yml
[root@c7-47 httpd]# ansible all -m shell -a 'ls /data'
[root@c7-47 httpd]# ansible all -m shell -a 'getent passwd apache'
2.调用多个角色
[root@c7-47 ansible]# tree .
.
├── httpd_role.yml
├── nginx_roles.yml
├── roles
│ ├── httpd
│ │ ├── files
│ │ │ └── httpd.conf
│ │ └── tasks
│ │ ├── copy.yml
│ │ ├── main.yml
│ │ └── user.yml
│ ├── memcache
│ ├── mysql
│ └── nginx
│ ├── tasks
│ │ ├── group.yml
│ │ ├── main.yml
│ │ ├── restart.yml
│ │ ├── start.yml
│ │ ├── template.yml
│ │ ├── user.yml
│ │ └── yum.yml
│ └── templates
│ └── nginx.conf.j2
└── some_roles.yml
[root@c7-47 ansible]# cat some_roles.yml
- hosts: webserver
remote_user: root
roles:
- role: httpd #调用两个模块
- role: nginx
[root@c7-47 ansible]# ansible-playbook some_roles.yml
3.引用另外角色的任务
[root@c7-47 ansible]# cat roles/nginx/tasks/main.yml
- include: group.yml
- include: user.yml
- include: yum.yml
- include: template.yml
- include: start.yml
- include: roles/httpd/tasks/copy.yml #使用其它任务角色时 要加路径
#调用的相对应模块也要写绝对路径
[root@c7-47 ansible]# cat roles/httpd/tasks/copy.yml
- name: copy files
copy: src=/etc/httpd/conf/httpd.conf dest=/data/ owner=apache
4.根据标签执行任务
[root@c7-47 ansible]# cat some_roles.yml
- hosts: webserver
remote_user: root
roles:
- { role: httpd,tags: ['web','httpd']}
- { role: nginx,tags: ['web','nginx']}
- { role: app,tags: 'app' }
[root@c7-47 ansible]# ansible-playbook -t web some_roles.yml
#-t 选择相对应的标签
5.添加条件判断
[root@c7-47 ansible]# cat some_role.yml
- hosts: all
remote_user: root
roles:
- { role: httpd, tags: ['web','httpd'] }
- { role: nginx, tags: ['web','nginx'],when: ansible_distribution_major_version == "7" }
- { role: app, tags: "app" }
综合实践
[root@c7-47 ansible]# tree
.
├── app_role.yml
├── roles
│ ├── app
│ │ ├── files
│ │ │ └── vhosts.conf
│ │ ├── handlers
│ │ │ └── main.yml
│ │ ├── tasks
│ │ │ ├── copy.yml
│ │ │ ├── group.yml
│ │ │ ├── main.yml
│ │ │ ├── start.yml
│ │ │ ├── template.yml
│ │ │ ├── user.yml
│ │ │ └── yum.yml
│ │ ├── templates
│ │ │ └── httpd.conf.j2
│ │ └── vars
│ │ └── main.yml
[root@c7-47 ansible]# cat app_role.yml
- hosts: webserver
remote_user: root
roles:
- app
[root@c7-47 ansible]# cat roles/app/handlers/main.yml
- name: restart service
service: name=httpd state=restarted
[root@c7-47 ansible]# cat roles/app/tasks/copy.yml
- name: copy config
copy: src=vhosts.conf dest=/etc/httpd/conf.d/ owner=app
[root@c7-47 ansible]# cat roles/app/tasks/group.yml
- name: create group
group: name=app system=yes gid=123
[root@c7-47 ansible]# cat roles/app/tasks/main.yml
- include: group.yml
- include: user.yml
- include: yum.yml
- include: template.yml
- include: copy.yml
- include: start.yml
[root@c7-47 ansible]# cat roles/app/tasks/start.yml
- name: start service
service: name=httpd state=started enabled=yes
[root@c7-47 ansible]# cat roles/app/tasks/template.yml
- name: copy conf
template: src=httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
notify: restart service
[root@c7-47 ansible]# cat roles/app/tasks/user.yml
- name: create user
user: name=app group=app system=yes shell=/sbin/nologin uid=123
[root@c7-47 ansible]# cat roles/app/tasks/yum.yml
- name: install packages
yum: name=httpd
[root@c7-47 ansible]# cat roles/app/vars/main.yml
username: app
groupname: app
- 验证
[root@c7-47 ansible]# ansible webserver -m shell -a 'ss -ntlp'
[root@c7-47 ansible]# ansible webserver -m shell -a 'getent passwd app'
[root@c7-47 ansible]# ansible webserver -m shell -a 'ps aux | grep app'
[root@c7-47 ansible]# ansible webserver -m shell -a 'ls /etc/httpd/conf.d'
根据服务器内存安装软件
[root@c7-47 ansible]# pwd
/root/ansible
[root@c7-47 ansible]# tree
.
├── memcache_role.yml
├── roles
│ ├── memcached
│ │ ├── handlers
│ │ │ └── main.yml
│ │ ├── tasks
│ │ │ ├── main.yml
│ │ │ ├── start.yml
│ │ │ ├── template.yml
│ │ │ └── yum.yml
│ │ └── templates
│ │ └── memcached.j2
[root@c7-47 ansible]# cat memcache_role.yml
- hosts: webserver
remote_user: root
roles:
- memcached
[root@c7-47 ansible]# cat roles/memcached/handlers/main.yml
- name: restart service
service: name=memcached state=restarted
[root@c7-47 ansible]# cat roles/memcached/tasks/main.yml
- include: yum.yml
- include: template.yml
- include: start.yml
[root@c7-47 ansible]# cat roles/memcached/tasks/start.yml
- name: start service
service: name=memcached state=started enabled=yes
[root@c7-47 ansible]# cat roles/memcached/tasks/template.yml
- name: copy conf
template: src=memcached.j2 dest=/etc/sysconfig/memcached
notify: restart service
[root@c7-47 ansible]# cat roles/memcached/tasks/yum.yml
- name: install packages
yum: name=memcached
[root@c7-47 ansible]# cat roles/memcached/templates/memcached.j2
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="{{ ansible_memtotal_mb//4 }}"
OPTIONS=""
验证
[root@c7-47 ansible]# ansible webserver -m shell -a 'ss -ntlp' #判断服务是否启动
[root@c7-47 ansible]# ansible webserver -m shell -a 'cat /etc/sysconfig/memcached' #查看文件 是否生效
版权声明:本文标题:ansible入门与实践 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://m.elefans.com/dianzi/1725736806a1039819.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论