方法一:
pip install ansible
方法二:
yum -y install ansible
方法三:
git clone git://github.com/ansible/ansible.git
cd ./ansible
source ./hacking/env-setup
ansible配置文件有多个位置:按照下面顺序查找
1、环境变量 ANSIBLE_CONFIG 所指向的位置
2、当前目录下的 ansible.cfg
3、HOME目录下的配置文件 ~/.ansible.cfg
4、/etc/ansible/ansible.cfg
ansible 常见配置参数如下:
● inventory=~/ansible_hosts: 表示主机清单 inventory 文件位置
● forks = 5 : 并发连接数,默认为5
● sudo_user = root : 设置默认执行命令的用户
● remote_port = 22 : 指定被管理节点的连接端口,默认为22,。建议修复,能够更加安全
● host_key_checking = False : 设置是否安全检查ssh主机的秘钥,值为True/False。关闭后第一次连接不会提示配置实例
● timeout = 60 :设置SSH连接的超时时间,单位为秒
● log_path = /var/log/ansible.log :指定一个存储ansible日志的文件(默认不记录日志)
3.1、对主机进行分组
[]中的字符串代表组名,便于对主机进行分组管理
[group01]
192.168.0.11
192.168.1.20
foo.example.com
bar.example.com
3.2、分配变量给主机
分配变量给不同主机,在后面使用palybook中会用到
格式:主机地址 变量名=变量值 (多个变量以空格隔开)
[group02]
host1 http_port=80 maxRequestsPerChild=808
host2 http_port=303 maxRequestsPerChild=999
3.3、定义组变量
组变量可以定义属于整个组的变量
[group03:vars]
ntp_server=ntp.example.com
proxy=proxy.example.com
3.4、将组作为另一个组的子成员
可以将一个组定义为另一个组的子成员,以及分配变量给整个组使用,这些变量可以给/usr/bin/ansible-playbook使用,但是不能给/usr/bin/ansible使用
[root@localhost ~]# vim /etc/ansible/hosts
[atlanta]
host1
host2
[raleigh]
host2
host3
[southeast:children]
some_server= foo.southeast.example.com
halon_system_timeout = 30
self_destruct_countdown = 60
escape_pods = 2
[usa:children]
southeast
northeast
southwest
northwest
3.5、给每个主机选择连接类型和连接用户名
[targets]
localhost ansible_connection=local
other.example.com other.example.com=ssh ansible_ssh_user=test
other2.example.com other2.example.com=ssh ansible_ssh_user=test2
3.6、设置inventory参数
通过设置inventory参数,可以控制Ansible与远程主机的交互方式
ansible_ssh_host # 如果将要连接的远程主机名与你想要设定的主机的别名不同的话,可以通过此变量来控制
ansible_ssh_port # ssh的端口号,如果不是默认端口号,就通过此变量来设置
ansible_ssh_user # 默认ssh的用户名
ansible_pass # ssh的密码(这种方式不建议,很不安全,建议使用秘钥)
ansible_sudo_pass # sudo的密码(建议使用 --ask-sudo-pass)
ansible_sudo_exe # sudo的命令路径
ansible_connection # 与主机连接的类型。比如:local,ssh 或者 parmaiko
ansible_ssh_private_key_file # ssh 使用的私钥文件,适用于有多个密钥,而你不想使用ssh代理的情况下
ansible_shell_type # 目标系统的shell类型,默认情况下使用“sh”,也可以设置成"csh"或"fish"
ansible_python_interpreter # 目标主机python的路径,使用情况:系统中有多个python,或者路径不是/usr/bin/python等
# -------------------------以下是一个主机文件示例-----------------------
some_host absible_ssh_port=2222 ansible_ssh_user=test1
one_host absible_ssh_port=2222 ansible_ssh_user=test2
秘钥上传前
[root@localhost ~]# ansible master -m ping
192.168.10.10 | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).",
"unreachable": true
}
可以加上–ask-pass来手动输入密码
[root@localhost ~]# ansible master -m "ping" --ask-pass
SSH password: # 输入密码
192.168.10.10 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
上传秘钥
# 生成秘钥
[root@localhost ~]# ssh-keygen -t rsa
……省略部分
+---[RSA 2048]----+
| ++=Eo |
|oo..= |
| o.. . . |
| o * = . |
| = + * S |
| . * . |
|. +.*.. . |
| =*=+= o. o |
| .=@=o=..o |
+----[SHA256]-----+
# 查看公钥文件
[root@localhost ~]# ls -ltr /root/.ssh/
总用量 12
-rw-r--r--. 1 root root 396 5月 23 19:23 id_rsa.pub
-rw-------. 1 root root 1679 5月 23 19:23 id_rsa
-rw-r--r--. 1 root root 175 5月 23 19:24 known_hosts
# 上传公钥
[root@localhost ~]# ansible all -m authorized_key -a "user=root key='{{lookup('file', '/root/.ssh/id_rsa.pub')}}' path=/root/.ssh/id_rsa.pub manage_dir=yes" --ask-pass
SSH password:
192.168.10.10 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"comment": null,
"exclusive": false,
"follow": false,
"gid": 0,
"group": "root",
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDmZ3VmXIZRL2W2INKz8iZV/DBLcfyoPhciAQKJJKLNdpKDcHwsT33WgDioVunk1qgwPVi79PZZtl/4sSmo1ZJt1sQ4W37Y9a8ad4jMuQW2JhD/TWfYFKsQgisgSE9YgdTkEZv7T5/Fuqpa0RgblLnqZ0pv3Kb/OweHZIWsieVGZ9pom+MQ3f06mngPRpQIxCDiUHdoAvCRCvk3TXMbggOhg2R8BpZLmPzbu8rR9UOEezT03+nS3gQGuhtJvz3iOBEqLgN80FtsLBm812Vbxjj97ZCu+Dc8kMhtwaOs/GZtH3IMACmAd5chj4ZJomV1EY22eWPslRuceIGOv9QovALT root@localhost",
"key_options": null,
"keyfile": "/root/.ssh/id_rsa.pub",
"manage_dir": true,
"mode": "0600",
"owner": "root",
"path": "/root/.ssh/id_rsa.pub",
"size": 396,
"state": "file",
"uid": 0,
"user": "root",
"validate_certs": true
}
# 测试是否已实现免密
[root@localhost ~]# ansible all -m ping
192.168.10.10 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
[root@localhost ~]# ansible 分组名 --list-hosts ##查看分组中的主机列表
[root@localhost ~]# ansible work --list-host
hosts (40):
192.168.2.115
192.168.2.116
192.168.2.202
192.168.2.204
192.168.2.207
……
[root@localhost ~]# ssh-keygen -t rsa ##生成秘钥
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): ##直接回车
Enter passphrase (empty for no passphrase): ##输入密码123123
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.
[root@localhost ~]# ssh-copy-id root@192.168.10.30
[root@localhost ~]# ssh-copy-id root@192.168.10.170 //配置密钥对验证
------------免交互代理--------------(设置代理可以让主机不要再输入密码)
ssh-agent bash ## 开启代理功能
ssh-add ## 添加秘钥给代理
ansible-doc -l # 列出所有已安装的模块 注:按q退出
ansible-doc -s yum #-s列出yum模块描述信息和操作动作
## -m:指定模块;-a:指定参数(如-m command:指定命令模块;-a date:命令模块参数为date,相当于在对方执行了date命令)
------------------ ansible指定ip执行命令 ----------------
方法1:
[root@localhost ~]# ansible all -i "IP地址," -m shell -a "free -m"
方法2:
[root@localhost ~]# ansible ip地址 -m command -a 'date'
----------------- ansible指定分组批量执行命令 -----------
[root@localhost ~]# ansible 分组名 -m command -a 'date'
命令格式:ansible [主机] [-m 模块] [-a args]
ansible mysql -m command -a 'date'
ansible all -m command -a 'date' //所有hosts主机执行date命令
ansible all -a 'ls /' ##如果不加-m模块,则默认运行command模块,all:表示所有的分类
## 报错信息:"changed": false, ##########################################################
[root@localhost ~]# ansible all -a 'ls /'
192.168.10.30 | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).",
"unreachable": true
}
192.168.10.170 | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).",
"unreachable": true
}
报错原因:ssh秘钥错误
ssh-keygen -t rsa ##生成秘钥
ssh-copy-id root@192.168.10.30
ssh-copy-id root@192.168.10.170 //配置密钥对验证
ssh-agent bash ##开启代理功能
ssh-add ##添加秘钥给代理
########################################################################
两种状态(state):present表示添加(可以省略),absent表示移除
[root@localhost ~]# ansible-doc -s cron # 查看cron模块信息,帮助文档
[root@localhost ~]# ansible webserver -m cron -a 'minute="*/1" job="/usr/bin/echo heihei" name="test cron job"'
# 选项解释:
# -m:指定模块;
# -a:指定参数;minute="*/1":表示每分钟执行计划任务;
# job="/bin/echo heihei":表示执行echo的动作;
# 最后name表示定义的计划任务的名称(自定义)
[root@localhost ~]# ansible webserver -a 'crontab -l' # 查看设置的计划任务
192.168.10.30 | CHANGED | rc=0 >>
#Ansible: test cron job
*/1 * * * * /usr/bin/echo heihei
[root@localhost ~]# crontab -l # 去192.168.10.30(即webserver)上查看计划任务
#Ansible: test cron job
*/1 * * * * /usr/bin/echo heihei # 可以查看到计划任务
You have new mail in /var/spool/mail/root # 执行的结果生成在/var/spool/mail/root文件内
[root@localhost ~]# ansible webserver -m cron -a 'name="test cron job" state=absent' //指定计划任务名称,结合state=absent参数,移除计划任务
[root@localhost ~]# ansible webserver -a 'crontab -l' # 再次查看,计划任务消失了
192.168.10.30 | CHANGED | rc=0 >>
# user模块是请求的是useradd,userdel,usermod三个指令
[root@localhost ~]# ansible-doc -s user # 查看user模块参数说明
[root@localhost ~]# ansible mysql -m user -a 'name="test01"' # 创建用户test01
[root@localhost ~]# id test01 # 到192.168.10.170(即mysql上)查看用户是否建立
uid=1001(test01) gid=1001(test01) 组=1001(test01)
[root@localhost ~]# ansible mysql -m command -a 'tail -1 /etc/passwd' # 同样可以查看到新用户test01
192.168.10.170 | CHANGED | rc=0 >>
test01:x:1001:1001::/home/test01:/bin/bash
[root@localhost ~]# ansible mysql -m user -a 'name="test01" state=absent' # 删除用户test01,state=absent参数用于删除
# group模块请求的是groupadd,groupdel,groupmod 三个指令。
[root@localhost ~]# ansible-doc -s group # 查看group模块参数说明
[root@localhost ~]# ansible mysql -m group -a 'name=mysql gid=306 system=yes' # 创建用户组mysql,指定uid,system=yes代表创建的是系统组
[root@localhost ~]# ansible mysql -a 'tail -1 /etc/group' # 查看到新建的用户组
192.168.10.170 | CHANGED | rc=0 >>
mysql:x:306:
[root@localhost ~]# ansible mysql -m user -a 'name=test01 uid=306 system=yes group=mysql' # 创建test01用户,指定uid,和ground组名,添加到mysql组
[root@localhost ~]# ansible mysql -a 'tail -1 /etc/passwd' # 查看,mysql组中多了test01用户成员
192.168.10.170 | CHANGED | rc=0 >>
test01:x:306:306::/home/test01:/bin/bash
[root@localhost ~]# ansible mysql -a 'id test01' # 查看test01用户,标明了所在组
192.168.10.170 | CHANGED | rc=0 >>
uid=306(test01) gid=306(mysql) groups=306(mysql)
[root@localhost ~]# ansible-doc -s copy # 查看copy模块参数说明
[root@localhost ~]# ansible mysql -m copy -a 'src=/etc/fstab dest=/opt/fstab.back owner=root mode=640'
# 参数解释:
# src:源文件(被copy的文件);
# dest:目标文件;
# owner:属主属性;
# mode:文件权限属性
[root@localhost ~]# ansible mysql -a 'ls -l /opt' # 查看copy过去的文件,属主root,权限640
192.168.10.170 | CHANGED | rc=0 >>
total 4
-rw-r-----. 1 root root 465 Nov 29 22:34 fstab.back
[root@localhost ~]# ansible mysql -a ' cat /opt/fstab.back' # 查看内容
[root@localhost ~]# ansible mysql -m copy -a 'content="hello heihei !" dest=/opt/fstab.back' # 将hello heihei!写入/opt/fstab.back
[root@localhost ~]# ansible mysql -a 'cat /opt/fstab.back' # 查看到写入的内容
192.168.10.170 | CHANGED | rc=0 >>
hello heihei !
1、修改文件属性, ansible all -m file -a “path=/root/test.sh owner=test group=test mode=0644”
2、生成链接文件:ansible all -m file -a “src=/root/test.sh dest=/root/testlink.sh owner=root group=root state=link”
3、创建空文件:ansible all -m file -a “path=/root/testtouch.sh state=touch mode=0644”
4、创建空目录: ansible all -m file -a “path=/root/testdirectory state=directory mode=0644”
5、删除目录或文件,强制执行:ansible all -m file -a “path=/root/testdirectory state=absent force=yes”
[root@localhost ~]# ansible-doc -s file # 查看file模块参数说明
[root@localhost ~]# ansible mysql -m user -a ' name=mysql system=yes'
[root@localhost ~]# ansible mysql -m group -a ' name=mysql system=yes'
[root@localhost ~]# ansible mysql -m file -a 'owner=mysql group=mysql mode=644 path=/opt/fstab.back' # 修改文件属主、属组、权限
[root@localhost ~]# ansible mysql -m file -a ' src=/opt/fstab.back path=/opt/fstab.link state=link' # 给原文件/opt/fstab.back建立软连接,利用state=link参数
[root@localhost ~]# ansible mysql -m file -a "path=/opt/fstab.back state=absent" # 删除一个文件或目录
[root@localhost ~]# ansible mysql -m file -a "path=/opt/test state=touch" # 创建一个空文件
[root@localhost ltp]# ansible 192.168.2.100 -m file -a "name=/abc state=directory" # 创建一个目录
[root@localhost ~]# ansible all -m ping ## ping所有分类
192.168.10.30 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong" ## "pong" 表示能ping通
}
192.168.10.170 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
[root@localhost ~]# ansible-doc -s yum # 查看模块帮助文档
[root@localhost ~]# ansible webserver -m yum -a 'name="httpd"' //yum安装httpd服务
[root@localhost ~]# rpm -q httpd ##到192.168.10.20上查看,安装成功了
httpd-2.4.6-97.el7.centos.x86_64
[root@localhost ~]# ansible webserver -m yum -a 'name=httpd state=absent' //卸载httpd
[root@localhost ~]# rpm -q httpd ##再到192.168.10.20上查看,被卸载了
package httpd is not installed
[root@localhost ~]# ansible-doc -s service
[root@localhost ~]# ansible webserver -m yum -a 'name="httpd"'
[root@localhost ~]# ansible webserver -a 'systemctl status httpd' // 查看web服务器httpd运行状态
192.168.10.30 | FAILED | rc=3 >>
● httpd.service - The Apache HTTP Server
Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; vendor preset: disabled)
Active: inactive (dead)
Docs: man:httpd(8)
man:apachectl(8)non-zero return code
[root@localhost ~]# ansible webserver -m service -a 'enabled=true name=httpd state=started' //启动httpd服务,并且开机自启
[root@localhost ~]# ansible webserver -a 'systemctl status httpd' //查看是否开启,成功开启了
192.168.10.30 | CHANGED | rc=0 >>
● httpd.service - The Apache HTTP Server
Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
Active: active (running) since Sun 2020-11-29 23:30:11 CST; 8s ago
Docs: man:httpd(8)
man:apachectl(8)
[root@localhost ~]# ansible-doc -s shell
[root@localhost ~]# ansible webserver -m user -a 'name=jack' ##创建一个用户
[root@localhost ~]# ansible webserver -m shell -a 'echo abc123 | passwd --stdin jack' ##使用无交互模式给用户设置密码
192.168.10.30 | CHANGED | rc=0 >>
Changing password for user jack.
passwd: all authentication tokens updated successfully. ##免密设置成功
ansible-doc -s script
[root@localhost ~]# vim /opt/test.sh ##写一个脚本
#!/bin/bash
echo "hello ansible from script"> /opt/script.txt
[root@localhost ~]# chmod +x test.sh ##给执行权限
[root@localhost ~]# ansible mysql -m script -a '/opt/test.sh' ##指定script模块和脚本位置,执行脚本
[root@localhost ~]# cat /opt/script.txt ##到192.168.10.170上查看,脚本是否执行成功
hello ansible from script
ansible-doc -s setup
ansible mysql -m setup //获取mysql组主机的facts信息(包含ip信息、版本信息等等)
[root@localhost ~]# ansible-playbook -h
usage: ansible-playbook [-h] [--version] [-v] [-k]
[--private-key PRIVATE_KEY_FILE] [-u REMOTE_USER]
[-c CONNECTION] [-T TIMEOUT]
[--ssh-common-args SSH_COMMON_ARGS]
[--sftp-extra-args SFTP_EXTRA_ARGS]
[--scp-extra-args SCP_EXTRA_ARGS]
[--ssh-extra-args SSH_EXTRA_ARGS] [--force-handlers]
[--flush-cache] [-b] [--become-method BECOME_METHOD]
[--become-user BECOME_USER] [-K] [-t TAGS]
[--skip-tags SKIP_TAGS] [-C] [--syntax-check] [-D]
[-i INVENTORY] [--list-hosts] [-l SUBSET]
[-e EXTRA_VARS] [--vault-id VAULT_IDS]
[--ask-vault-pass | --vault-password-file VAULT_PASSWORD_FILES]
[-f FORKS] [-M MODULE_PATH] [--list-tasks]
[--list-tags] [--step] [--start-at-task START_AT_TASK]
playbook [playbook ...]
……
YAML支持的数据结构:
1.对象:键值对的集合,又称为映射(mapping)/哈希(hashes)/字
例如:
name: Example Developer
键 值
2.数组:一组按次序排列的值,又称为序列(sequence)/列表(list)
例如:
- Apple
- Orange
3.纯量:单个的、不可再分的值
例如:
number: 12.30
sure: true
yaml示例:
---
# 一个美味的水果列表
- Apple
- Oranage
- Strawebrry
- Mango
一个字典是由一个简单的 键: 值 的形式组成(注意:这个":"冒号后面必须是一个空格)
---
# 一个职工的记录
name: Example Developer
job: Developer
skill: Elite
字典也可以使用缩进形式来表示(这种格式在ansible中不经常使用)
---
# 一个职工记录
{name: Example Developer, job: Developer, skill: Elite}
可以通过下面格式指定一个布尔值
---
create_key: yes
need_agent: no
knows_oop: True
likes_emacs: TRUE
uses_cvs: False
示例:将上面的示例整合到一个yaml中
---
# 一个职工记录
name: Example Developer
job: Developer
skill: Elite
employed: True
foods:
- Apple
- Orange
- Strawberry
- Mango
# 相当于{foods:[Apple, Orange, Strawberry, Mango]}
languages:
ruby: Elite
python: Elite
dotnet: Lame
# 相当于{languages:{ruby: Elite, python: Elite, dotnet: Lame}}
playbooks本身由以下各部分组成
示例1:
[root@localhost ~]# cat /etc/ansible/hosts |grep -Ev "^$|^#"
[work]
master
node
[master]
192.168.10.10
[node]
192.168.10.20
[root@localhost ~]# vim MyPlaybook.yaml
- shosts: master
remote_user: root
task:
- name: read sys time
shell: echo "$(date +'%Y-%m-%d %T')" > time.txt
- hosts: slave
remote_user: root
task:
- name: list file
shell: ls -ltr > list.txt
执行结果:
[root@localhost ~]# ansible-playbook MyPlaybook.yaml --ask-pass
SSH password:
PLAY [master] ********************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************
ok: [192.168.10.10]
TASK [read sys time] *************************************************************************************************
changed: [192.168.10.10]
PLAY [node] **********************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************
ok: [192.168.10.20]
TASK [list file] *****************************************************************************************************
changed: [192.168.10.20]
PLAY RECAP ***********************************************************************************************************
192.168.10.10 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
192.168.10.20 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
# 查看执行后生成的文件
[root@localhost ~]# ansible all -m shell -a "ls -ltr |tail -1"
192.168.10.10 | CHANGED | rc=0 >>
-rw-r--r-- 1 root root 20 5月 23 21:14 time.txt
192.168.10.20 | CHANGED | rc=0 >>
-rw-r--r-- 1 root root 1051 5月 23 21:14 list.txt
-f :可以指定并发进程数
例如:ansible-playbook MyPlaybook.yaml --ask-pass -f 3 # 表示由3个并发进程来执行
示例2
下面是一个playbook的示例:
# 查看模板内容,模板中用{{变量名}}来调用playbook.yaml中的变量值,如下
[root@localhost temp]# vim httpd-temp.conf
Listen {{http_port}}
MaxClients {{max_clients}}
[root@localhost temp]# vim HttpPlaybook.yaml
- hosts: node # 定义的主机组,即应用的主机,前面的(- hosts:)不能更改,指明在/etc/ansible/hsots中声明的组
vars: # 定义变量
http_port: 80
max_clients: 200
user: root # 在远程执行时建议使用remote_user远程用户
tasks: # 执行的任务
- name: ensure apache is at the latest version # 指定任务名称,会在执行任务时显示出来的内容(自定义),有利于定位错误发生位置
yum: pkg=httpd state=latest # yum是模块,pkg指定检测软件包,state=latest是否为最新的
- name: write the apache config file
template: src=httpd-temp.conf dest=/etc/httpd/conf/httpd.conf # 定义配置文件模板
notify: # 调用下面自定义的restart apache(restart apache在handlers中定义了具体内容)
- restart apache
- name: ensure apache is running
service: name=httpd state=started
handlers: # 处理器,当某条件满足时,触发执行的操作,和notify结合使用,被notify调用;
- name: restart apache
service: name=httpd state=restarted
执行结果:
[root@localhost temp]# ansible-playbook HttpPlaybook.yaml
PLAY [node] **********************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************
ok: [192.168.10.20]
TASK [ensure apache is at the latest version] ************************************************************************
ok: [192.168.10.20]
TASK [write the apache config file] **********************************************************************************
ok: [192.168.10.20]
TASK [ensure apache is running] **************************************************************************************
changed: [192.168.10.20]
PLAY RECAP ***********************************************************************************************************
192.168.10.20 : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@localhost temp]# ansible node -m shell -a "systemctl status httpd"
192.168.10.20 | CHANGED | rc=0 >>
● httpd.service - The Apache HTTP Server
Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; vendor preset: disabled)
Active: active (running) since 日 2021-05-23 21:30:07 CST; 21s ago
Docs: man:httpd(8)
man:apachectl(8)
Main PID: 7544 (httpd)
Status: "Total requests: 0; Current requests/sec: 0; Current traffic: 0 B/sec"
Memory: 3.3M
CGroup: /system.slice/httpd.service
├─7544 /usr/sbin/httpd -DFOREGROUND
├─7545 /usr/sbin/httpd -DFOREGROUND
├─7546 /usr/sbin/httpd -DFOREGROUND
├─7547 /usr/sbin/httpd -DFOREGROUND
├─7548 /usr/sbin/httpd -DFOREGROUND
└─7549 /usr/sbin/httpd -DFOREGROUND
5月 23 21:30:07 node01 systemd[1]: Starting The Apache HTTP Server...
5月 23 21:30:07 node01 httpd[7544]: AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using fe80::20c:29ff:fe47:c5d7. Set the 'ServerName' directive globally to suppress this message
5月 23 21:30:07 node01 systemd[1]: Started The Apache HTTP Server.
执行一个playbook
语法:ansible-playbook [yaml文件名]
例如: ansible-playbook ping.yml
参数:-k(-ask-pass):用来交互输入ssh密码
-K(-ask-become-pass):用来交互输入sudo密码(提权)…
-u:指定用户
补充命令:
# 检查yaml文件的语法
ansible-playbook nginx.yaml --syntax-check
# 检查tasks任务
ansible-playbook nginx. yaml --list-task
# 检查生效的主机
ansible-playbook nginx. yaml --list-hosts
# 指定playbook中的task执行,检查效果
ansible-playbook nginx.yaml --start-at-task=‘Copy Nginx.conf’
# 指定执行playbook的并行线程数
ansible-playbook nginx.yaml -f 线程数
- hosts: webserver # 指定主机组,可以是一个或多个组。
remote_user: root # 指定远程主机执行的用户名,注意,用户一定要有执行权限
还可以为每个任务定义远程执行用户:
- hosts: mysql
remote_user: root
tasks:
-name: test connection
ping:
remote_user: mysql # 指定远程主机执行tasks的运行用远程指定的用户
执行playbook时: ansible-playbook ping. yml -k
指定远程主机sudo切换用户:
-hosts: mysql
remote_user: root
become: yes ## 2.6版本以后的参数,之前是sudo,意思相同
become_user: mysql ## 指定sudo用户为mysql,之后执行任务的用户就变为mysql了
执行playbook时 : ansible-playbook ping. yml -K
1、Play的主体部分是task列表,task列表中的各任务按次序逐个在hosts中指定的主机上执行
2、每一个task必须有一个名称name,这样在运行playbook时,从其输出的任务执行信息中可以很好的辨别出是属于那一部分的任务
3、定义一个task,常见的格式:”module: options”是"模块对应参数"的形式,例如: yum: name=htttpd
4、ansible的自带模块中,command模块和shel1模块无需使用key=value格式
示例:
- hosts: 192.168.10.20
remote_user: root
tasks:
- name: disable selinux
command: '/sbin/setenforce o'
- name: make sure apache is running
service: name=httpd state=started
playbook中只要执行命令的返回值不为0,就会报错,tasks停止
要想报错不停止执行tasks,修改如下 ignore_errors: True
- hosts: webserver
remote_user: root
tasks:
- name: disable selinux
command: '/sbin/setenforce 0'
ignore_errors: True #忽略错误,强制返回成功,继续执行,true这个布尔值不区分大小写的
- name: make sure apache is running
service: name=httpd state=started
以下是另外一个示例,可以读一读
- hosts: webserver
remote_user: root
tasks:
- name: create nginx group
group: name=nginx system=yes gid=208
- name: create nginx user
user: name=nginx uid=208 group=nginx system=yes
- hosts: mysql
remote_user: root
tasks:
- name: copy file to mysql
copy : src=/etc/inittab dest=/opt/inittab.back
示例1
- hosts: webserver
remote_user: root
tasks:
- name: install httpd package
yum: name=httpd state=latest
- name: install configuration file for httpd
copy: src=/opt/httpd.conf dest=/etc/httpd/conf/httpd.conf
notify:
- restart httpd
- name: start httpd service
service: enabled=true name=httpd state=started
handlers:
- name: restart httpd
service: name=httpd state=restarted
示例2:测试notify所在task执行失败,是否会继续执行notify
[root@localhost temp]# vim testvarPlaybook.yaml
- hosts: node
remote_user: root
vars: # 定义变量
- path: /root/
- filename: test.txt
tasks:
- name: delete file
file: path=/root/test.txt state=absent
ignore_errors: True
notify:
- modify file
handlers:
- name: modify file
shell: echo "123" >{{path}}{{filename}}
# 目标及其没有test.txt文件
[root@localhost temp]# ansible node -m shell -a "cat test.txt"
192.168.10.20 | FAILED | rc=1 >>
cat: test.txt: 没有那个文件或目录non-zero return code
# 执行playbook
[root@localhost temp]# ansible-playbook testvarPlaybook.yaml
PLAY [node] **********************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************
ok: [192.168.10.20]
TASK [delete file] ***************************************************************************************************
ok: [192.168.10.20]
PLAY RECAP ***********************************************************************************************************
192.168.10.20 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
# 再次查看,依旧没有test.txt文件
[root@localhost temp]# ansible node -m shell -a "cat test.txt"
192.168.10.20 | FAILED | rc=1 >>
cat: test.txt: 没有那个文件或目录non-zero return code
# 首先在目标机器上创建test.txt文件
[root@localhost temp]# ansible node -m file -a "path=/root/test.txt state=touch"
192.168.10.20 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"dest": "/root/test.txt",
"gid": 0,
"group": "root",
"mode": "0644",
"owner": "root",
"size": 0,
"state": "file",
"uid": 0
}
# 查看文件内容为空
[root@localhost temp]# ansible node -m shell -a "cat test.txt"
192.168.10.20 | CHANGED | rc=0 >>
# 执行playbook
[root@localhost temp]# ansible-playbook testvarPlaybook.yaml
PLAY [node] **********************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************
ok: [192.168.10.20]
TASK [delete file] ***************************************************************************************************
changed: [192.168.10.20]
RUNNING HANDLER [modify file] ****************************************************************************************
changed: [192.168.10.20]
PLAY RECAP ***********************************************************************************************************
192.168.10.20 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
# 查看test.txt文件,handler的action被调用执行
[root@localhost temp]# ansible node -m shell -a "cat test.txt"
192.168.10.20 | CHANGED | rc=0 >>
123
playbook使用变量的方法:
1、在yml文件中使用vars来设置变量
2、在/etc/ansible/hosts文件中主机名后面声明变量(如:变量username=lisi)
3、在执行ansible-playbook时,后面加上 -e 变量名=值 的方式给变量赋值;如 ansible-playbook test.yml -e “service=httpd”
示例1
- hosts: webserver
remote_user: root
vars:
- package: httpd
- service: httpd
tasks:
- name: install httpd package
yum: name={{package}} state=latest
- name: install configuration file for httpd
copy: src=/opt/httpd.conf dest=/etc/httpd/conf/httpd.conf
notify:
- restart httpd
- name: start httpd service
service: enabled=true name={{service}} state=started
handlers:
- name: restart httpd
service: name={{service}} state=restarted
示例
[root@localhost temp]# vi test.yml
- hosts: node
remote_user: root
tasks:
- name: copy filel
# {{ansible_all_ipv4_addresses}}是引用ip的固定变量
copy: content="{{ansible_all_ipv4_addresses}}," dest=/opt/iplist.txt
执行结果
[root@localhost temp]# ansible-playbook test.yaml
PLAY [node] **********************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************
ok: [192.168.10.20]
TASK [copy filel] ****************************************************************************************************
changed: [192.168.10.20]
PLAY RECAP ***********************************************************************************************************
192.168.10.20 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@localhost temp]# ansible node -m shell -a "cat /opt/iplist.txt"
192.168.10.20 | CHANGED | rc=0 >>
([u'192.168.122.1', u'192.168.10.20'],)
# 查看目标机器ip,确实有192.168.122.1 和 192.168.10.20两个ip
[root@localhost temp]# ansible node -m shell -a "ip a"
192.168.10.20 | CHANGED | rc=0 >>
……
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:0c:29:47:c5:d7 brd ff:ff:ff:ff:ff:ff
inet 192.168.10.20/24 brd 192.168.10.255 scope global ens33
……
3: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN qlen 1000
link/ether 52:54:00:13:da:e3 brd ff:ff:ff:ff:ff:ff
inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
……
[root@localhost temp]# vim test.yaml
- hosts: node
remote_user: root
tasks:
- name: "look os"
shell: echo {{ansible_distribution}} >os.txt
when: ansible_distribution == "CentOS"
执行结果
[root@localhost temp]# ansible-playbook test.yaml
PLAY [node] **********************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************
ok: [192.168.10.20]
TASK [look os] *******************************************************************************************************
changed: [192.168.10.20]
PLAY RECAP ***********************************************************************************************************
192.168.10.20 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
# 查看os.txt文件
[root@localhost temp]# ansible node -m shell -a "cat os.txt"
192.168.10.20 | CHANGED | rc=0 >>
CentOS
[root@localhost temp]# cat test.yaml
- hosts: node
remote_user: root
tasks:
- name: "look os"
shell: echo "{{ansible_distribution}}.{{ansible_distribution_major_version}}" >os.txt
when:
- ansible_distribution == "CentOS"
- ansible_distribution_major_version == "7"
执行结果
[root@localhost temp]# ansible-playbook test.yaml
PLAY [node] **********************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************
ok: [192.168.10.20]
TASK [look os] *******************************************************************************************************
changed: [192.168.10.20]
PLAY RECAP ***********************************************************************************************************
192.168.10.20 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@localhost temp]# ansible node -m shell -a "cat os.txt"
192.168.10.20 | CHANGED | rc=0 >>
CentOS.7
[root@localhost temp]# cat test.yaml
- hosts: node
remote_user: root
tasks:
- name: "look os"
shell: echo "{{ansible_distribution}}.{{ansible_distribution_major_version}}" >os.txt
when: (ansible_distribution == "CentOS" and ansible_distribution_major_version == "7") or (ansible_distribution == "CentOS" and ansible_distribution_major_version == "6")
## 满足系统为centos且为6版本,或者系统文centos且是6版本,则执行命令
执行结果
[root@localhost temp]# ansible-playbook test.yaml
PLAY [node] **********************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************
ok: [192.168.10.20]
TASK [look os] *******************************************************************************************************
changed: [192.168.10.20]
PLAY RECAP ***********************************************************************************************************
192.168.10.20 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@localhost temp]# ansible node -m shell -a "cat os.txt"
192.168.10.20 | CHANGED | rc=0 >>
CentOS.7
[root@localhost temp]# vi test.yaml
- hosts: node
remote_user: root
vars:
msg: 'hellow world'
exist: True
flag: None
tasks:
- name: "existed file"
shell: rm -rf os.txt
when:
- exist == False
- name: 'look file'
shell: echo "{{msg}}" >os.txt
when: flag == "None"
执行结果
[root@localhost temp]# ansible-playbook test.yaml
PLAY [node] **********************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************
ok: [192.168.10.20]
TASK [existed file] **************************************************************************************************
skipping: [192.168.10.20]
TASK [look file] *****************************************************************************************************
changed: [192.168.10.20]
PLAY RECAP ***********************************************************************************************************
192.168.10.20 : ok=2 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
[root@localhost temp]# ansible node -m shell -a "cat os.txt"
192.168.10.20 | CHANGED | rc=0 >>
hellow world
[root@localhost temp]# vim test.yaml
- hosts: node
remote_user: root
vars:
path: /ltp/
msg: "hellow world"
tasks:
- name: "Save Msg"
shell: echo {{msg}} > {{path}}{{item}} # 固定变量item,值为下面with_items:下的参数,遍历执行
with_items: # 定义了item的值
- first.txt
- second.txt
- third.txt
register: shell_result # registe用于储存执行结果,调试阶段使用,利用下面的debug返回结果
- debug: var=shell_result.stdout verbosity=0
执行结果
# 查看文件内容
[root@localhost temp]# ansible node -m shell -a "cat /ltp/first.txt"
192.168.10.20 | CHANGED | rc=0 >>
I am the first
[root@localhost temp]# ansible node -m shell -a "cat /ltp/second.txt"
192.168.10.20 | CHANGED | rc=0 >>
I am the second
[root@localhost temp]# ansible node -m shell -a "cat /ltp/third.txt"
192.168.10.20 | CHANGED | rc=0 >>
I am the third
# 执行playbook
[root@localhost temp]# ansible-playbook test.yaml
PLAY [node] **********************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************
ok: [192.168.10.20]
TASK [Save Msg] ******************************************************************************************************
changed: [192.168.10.20] => (item=first.txt)
changed: [192.168.10.20] => (item=second.txt)
changed: [192.168.10.20] => (item=third.txt)
TASK [debug] *********************************************************************************************************
ok: [192.168.10.20] => {
"shell_result.stdout": "VARIABLE IS NOT DEFINED!"
}
PLAY RECAP ***********************************************************************************************************
192.168.10.20 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
# 再次查看文件内容,全部被改变了
[root@localhost temp]# ansible node -m shell -a "cat /ltp/first.txt"
192.168.10.20 | CHANGED | rc=0 >>
hellow world
[root@localhost temp]# ansible node -m shell -a "cat /ltp/second.txt"
192.168.10.20 | CHANGED | rc=0 >>
hellow world
[root@localhost temp]# ansible node -m shell -a "cat /ltp/third.txt"
192.168.10.20 | CHANGED | rc=0 >>
hellow world
也可以自己定义迭代器属性
[root@localhost temp]# vim item.yaml
- hosts: node
remote_user: root
tasks:
- name: "Add users"
# with_items:下每一行就是item的一个值,item.name指其值得name字段的值,如test1
user: name={{item.name}} state=present groups={{item.groups}}
with_items:
- {name: 'test1',groups: 'wheel'}
- {name: 'test2',groups: 'root'}
# 执行效果就是创建两个用户,并且分别指定了属主和属组
示例:
[root@localhost temp]# vim host.yaml
- hosts: webserver
remote_user: root
tasks:
- name: touch file
file: path=/opt/host01 state=touch
- name: Copy hosts file
copy : src=/etc/hosts dest=/opt/hosts
tags:
- abc
- name: touch file
file: path=/opt/host02 state=touch
ansible-playbook hosts.yml --tags="abc"
# 加上"–tags=标签" ,就只执行打上标签的这段操作语句ansible-playbook hosts.yml
# 若不加上"–tags=标签" ,那么将会执行全部的task示例
[root@localhost temp]# wim host.yaml
- hosts: mysql
remote_user: root
tasks:
- name: Copy hosts file
copy: src=/etc/hosts dest=/opt/hosts
tags:
- only
- name: touch file
file: path=/opt/host1 state=touch
tags:
- always
执行命令
ansible-playbook host.yaml --tags="only"
# 指定执行带有only标签的命令,结果发现带有always标签的也会跟着执行
示例:
[root@master01 ~]# ansible all -m shell -a "echo {% if 'a' == 'b' %} a {% endif %}"
192.168.2.210 | CHANGED | rc=0 >>
192.168.2.203 | CHANGED | rc=0 >>
192.168.2.99 | CHANGED | rc=0 >>
[root@master01 ~]# ansible all -m shell -a "echo {% for i in range(3) %} {{i}} {% endfor %}"
192.168.2.210 | CHANGED | rc=0 >>
0 1 2
192.168.2.203 | CHANGED | rc=0 >>
0 1 2
192.168.2.99 | CHANGED | rc=0 >>
0 1 2