ansible完全攻略
ansible安装:
apt安装:
apt install ansible #安装ansible
ansible --version #ansible
ansible简单使用:
ansible 主机列表 参数
主机列表默认值得是 /etc/ansible/hosts
可默认指定为仅可以用localhost但是不隐式指定
ansible localhost -m command -a "参数" #-m指定模块,默认为command
ex:
ansible localhost -m command -a "ls" #在本机执行ls命令,可以用-v,-vv,-vvv来显示更加详细的命令执行信息
ansible localhost -m ping #执行ping命令操作
ansible-doc -l #列出所有模块,按Q退出
ansible-doc -h #ansible-doc帮助命令
ansible-doc -s [模块] #显示某个模块的简单参数信息
ex:
root@dokcer:~# ansible localhost -m command -a "chdir=/tmp pwd" #使用command的chdir参数改变执行命令的目录
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit
localhost does not match 'all'
localhost | SUCCESS | rc=0 >>
/tmp #显示已经更改了执行命令的目录
ansible-config -h #显示配置的帮助信息
ansible-config list #以yaml的格式来显示配置信息
ansible-config view #以json的格式来显示配置信息
ansible-config dump #显示所有配置的变量信息
主机清单:
主机清单文件:
文件位置:/etc/ansible/hosts
主机属性:(用于过滤主机)
all 所有主机
ungrouped 所有没有组的主机
localhost 表示本机
主机格式:
散列主机列表
主机名/IP地址:[ssh端口]
主机组列表
[主机组名]
主机列表1
[主机组:children]
子组1
子组2
...
主机范围
主机域名[001:006]
IP地址[01:60]
如果连接过主机但是失败了,会在~/.ssh/known_hosts中有记录,删除之后重新连接就可以了。
报错:
to use the 'ssh' connection type with passwords, you must install the sshpass program
sudo apt-get install sshpass #安装sshpass模块
PermitRootLogin yes #ansible默认执行命令的用户为root,设置为root可以登录
ansible连接主机的属性
192.168.0.50 ansible_connection=local #设置主机连接方式为本地连接
ansible 192.168.0.50 -a "ls" #不用输入密码就可以连接,相当于localhost方式
192.168.0.50 ansible_ssh_pass=ssh登录密码
ansible 192.168.0.50 -a "ls" #不用输入ssh密码就可以输入命令了
ansible免密钥认证:
1.生成密钥对
root@dokcer:~# ssh-keygen -t rsa
2.发送控制端的公钥到目标主机
ssh-copy-id -i /root/.ssh/id_rsa.pub lion@192.168.0.50 #输入lion用户的密码就传输完成了
error:
No such file or directory #没有.ssh文件夹
lion@dokcer:~$ ssh localhost #连接本地生成ssh文件夹
3.实现免密码登录
ansible配置文件:
配置文件目录:
root@dokcer:/root/.ssh# tree /etc/ansible/
/etc/ansible/
├── ansible.cfg #核心配置文件
└── hosts #主机列表文件
└── roles #角色管理文件
核心配置文件为ansible.cfg
通过修改
1.环境变量$ANSIBLE_CONFIG #通过环境变量来定义配置文件的位置
2.工作目录 #仅限当前目录
3.用户家目录 #仅限当前系统用户
4.软件目录 #全局生效
配置格式:
[配置段]
配置项:属性值
root@dokcer:~# egrep -v '^$|^#' /etc/ansible/ansible.cfg #过滤掉空格和#号显示
[defaults]
[inventory]
[privilege_escalation]
[paramiko_connection]
[ssh_connection]
[persistent_connection]
[accelerate]
[selinux]
[colors]
[diff]
[defaults] #默认配置
# some basic default values...
#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
#poll_interval = 15
#sudo_user = root
#ask_sudo_pass = True
#ask_pass = True
#transport = smart
#remote_port = 22 #ssh端口
#remote_user = root #远程登录用户
#module_lang = C
#module_set_locale = False
ansilbe利用指定用户提权执行命令
ansible localhost -u lion -a "ls /root" -b -K #输入sudo密钥后执行超级管理员命令
设置某一个用户拥有root权限
root@dokcer:~# cat /etc/sudoers
#
# This file MUST be edited with the 'visudo' command as root.
#
# Please consider adding local content in /etc/sudoers.d/ instead of
# directly modifying this file.
#
# See the man page for details on how to write a sudoers file.
#
Defaults env_reset
Defaults mail_badpass
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"
# Host alias specification
# User alias specification
# Cmnd alias specification
# User privilege specification
root ALL=(ALL:ALL) ALL
# Members of the admin group may gain root privileges
%admin ALL=(ALL) ALL #admin组用用户拥有root权限
# Allow members of group sudo to execute any command
%sudo ALL=(ALL:ALL) ALL #sudo组用户拥有sudo来执行任何命令
# See sudoers(5) for more information on "#include" directives:
#includedir /etc/sudoers.d
root@dokcer:~# grep sudo /etc/gshadow #在gshandown文件中查看sudo组的成员
sudo:*::lion
root@dokcer:~# usermod -G sudo lion #增加某一用户到sudo组中
%sudo ALL=(ALL:ALL) ALL / %sudo ALL=(ALL:ALL) NOPASSWD:ALL #默认切换sudo执行命令时不需要输入密码
root@dokcer:~# ansible localhost -u lion -a "ls /root" -b #不用-K输入密码就可以执行超级命令
localhost | SUCCESS | rc=0 >>
snap
ansible主机匹配:
匹配所有: all
正则匹配 *(通配符)
逻辑或 :(并集),一般由于主机组
逻辑或 :&(交集),一般由于主机组
逻辑非 :!(补集),一般由于主机组
root@dokcer:/root/.ssh# ansible '*' -m ping -k #匹配所有主机进行ping,用单引号括住主机列表部分
SSH password:
192.168.0.50 | SUCCESS => {
"changed": false,
"ping": "pong"
}
ansible命令模块:
命令模块
command:默认模块,可以远程权限运行所有的shell命令,不支持特殊符号,但是支持系统变量,不支持命令别名
shell:用于执行某些带特殊符号的命令<>!#$
scripts:可以执行脚本文件,也可以从控制主机的脚本运行到远程主机
**command模块:**
root@dokcer:~# ansible localhost -a "chdir=/tmp ls" #切换执行命令的目录
root@dokcer:~# ansible localhost -a 'chdir=/tmp creates=1.txt ls' #如果creates文件存在,则跳过命令执行,反之亦然
localhost | SUCCESS | rc=0 >>
skipped, since 1.txt exists
root@dokcer:~# ansible localhost -a 'chdir=/tmp removes=1.txt ls' #如果removes的文件存在则执行命令,反之亦然
localhost | SUCCESS | rc=0 >>
1.txt
ansible_VtVGmv
snap.docker
systemd-private-66d00680e20c4dba801130d9387e8e6f-systemd-resolved.service-KVfCH2
systemd-private-66d00680e20c4dba801130d9387e8e6f-systemd-timesyncd.service-xhgHcZ
root@dokcer:~# ansible localhost -a 'echo $SHELL' #command值支持系统变量不支持自定义变量
localhost | SUCCESS | rc=0 >>
/bin/bash
root@dokcer:~# ansible localhost -a 'la=lala; echo $la'
localhost | FAILED | rc=2 >>
[Errno 2] No such file or directory
root@dokcer:~# ansible localhost -a 'env | grep 1' #command不支持特殊管道命令
localhost | FAILED | rc=127 >>
env: ‘|’: No such file or directorynon-zero return code
**shell模块**:
root@dokcer:~# ansible localhost -m shell -a "la=lala; echo $la" #双引号有特殊符号时不生效
localhost | SUCCESS | rc=0 >>
root@dokcer:~# ansible localhost -m shell -a 'la=lala; echo $la' #单引号命令成功
localhost | SUCCESS | rc=0 >>
lala
root@dokcer:~# ansible localhost -m shell -a 'env | grep $SHELL' #shell执行管道符命令
localhost | SUCCESS | rc=0 >>
SUDO_COMMAND=/bin/bash
SHELL=/bin/bash
root@dokcer:~# ansible localhost -m shell -a '/bin/bash /tmp/1.sh admin' #shell执行远程脚本
localhost | SUCCESS | rc=0 >>
user is admin
**script模块:**
root@dokcer:~# ansible 192.168.0.50 -m script -a '/bin/bash /tmp/1.sh amdin' -kSSH password:
192.168.0.50 | SUCCESS => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to 192.168.0.50 closed.\r\n",
"stdout": "user is amdin\r\n",
"stdout_lines": [
"user is amdin" #可以执行存在于控制端,但是不存在被控端的脚本文件
]
}
#script使用executable参数来指定不存在于被控端的脚本文件
root@dokcer:~# ansible 192.168.0.50 -m script -a 'executable=/bin/bash /tmp/1.sh amdin' -k
SSH password:
192.168.0.50 | SUCCESS => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to 192.168.0.50 closed.\r\n",
"stdout": "user is amdin\r\n",
"stdout_lines": [
"user is amdin"
]
}
ansible系统模块:
hostname模块
修改主机名,立刻生效,并且永久生效,hostname只会修改/etc/hostname,而不会修改/etc/hosts
root@dokcer:~# ansible localhost -m hostname -a 'name=lion' #修改hostname
localhost | SUCCESS => {
"ansible_facts": {
"ansible_domain": "",
"ansible_fqdn": "lion",
"ansible_hostname": "lion",
"ansible_nodename": "lion"
},
"changed": true,
"name": "lion"
}
root@dokcer:~# ansible localhost -a 'hostname' #修改成功
localhost | SUCCESS | rc=0 >>
docker
user
创建一个用户,name lion2 系统输入,用户组是root, uid 10010 注释是lion2 禁止登录 state=presen状态为存在
root@dokcer:~# ansible localhost -m user -a 'name=lion2 system=yes groups=root uid=10010 comment=lion2 shell=/sbin/nologin state=present'
localhost | SUCCESS => {
"changed": true,
"comment": "lion2",
"create_home": true,
"group": 999,
"groups": "root",
"home": "/home/lion2",
"name": "lion2",
"shell": "/sbin/nologin",
"state": "present",
"system": true,
"uid": 10010
}
root@dokcer:~# ansible localhost -a "id lion2" #创建用户成功,要注意uid
localhost | SUCCESS | rc=0 >>
uid=10010(lion2) gid=999(lion2) groups=999(lion2),0(root)
root@dokcer:~# ansible localhost -a "getent passwd lion2" #查看lion2用户的密码
localhost | SUCCESS | rc=0 >>
lion2:x:10010:999:lion2:/home/lion2:/sbin/nologin
#创建带ssh私钥的用户
root@dokcer:~# ansible localhost -m user -a 'name=lion2 system=yes generate_ssh_key=yes ssh_key_bits=2048 ssh_key_file=.ssh/id_ras'
localhost | SUCCESS => {
"append": false,
"changed": true,
"comment": "lion2",
"group": 999,
"home": "/home/lion2",
"move_home": false,
"name": "lion2",
"shell": "/sbin/nologin",
"ssh_fingerprint": "2048 SHA256:9hjxzWM3jQFqBIqhEceXCdWMRv94CYthiSTB3PoPnCg ansible-generated on docker (RSA)",
"ssh_key_file": "/home/lion2/.ssh/id_ras",
"ssh_public_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD0LwW+HVOsSCjDMX9U64ugIU+P6O+NWmly4Dy+XHXPShYumFUxAFe7WIq000YBOQgFbrTreOzoGkH5712uZIiUll3Gmbq+zNgY2231KrkpxsVAMjcjq8VidsiOihUaO3CgZAwsIUucuYZo19UTZTThl7h3i28xtaGXbJaWNbC9Xhx2Jrs+QU904JnVWxw8jmDJkePSDiasYsagpICHOL6LpKNUB4QUSnhwwk02wxyIWhAxVEFf59Ub6FCvp77a3K/vBeFoLDlMkySqYoCbieT943ibmBhiNWDkF//YNYlnIa9Fjb5tx3bovic3Br8vgh47PkaE937OY8+6gU3hPTjj ansible-generated on docker",
"state": "present",
"uid": 10010
}
#删除用户state=absent remove=ye 用户禁用和删除
root@dokcer:~# ansible localhost -m user -a 'name=lion2 state=absent remove=yes'
localhost | SUCCESS => {
"changed": true,
"force": false,
"name": "lion2",
"remove": true,
"state": "absent",
"stderr": "userdel: lion2 mail spool (/var/mail/lion2) not found\n",
"stderr_lines": [
"userdel: lion2 mail spool (/var/mail/lion2) not found"
]
}
group模块:
#创建和删除用户组,gid要唯一
#创建用户组
root@dokcer:~# ansible localhost -m group -a 'name=admin system=yes gid=10010'
localhost | SUCCESS => {
"changed": true,
"gid": 10010,
"name": "admin",
"state": "present",
"system": true
}
root@dokcer:~# ansible localhost -a 'getent group admin' #获取用户组
localhost | SUCCESS | rc=0 >>
admin:x:10010:
#删除用户组
root@dokcer:~# ansible localhost -m group -a 'name=admin state=absent'
localhost | SUCCESS => {
"changed": true,
"name": "admin",
"state": "absent"
}
root@dokcer:~# ansible localhost -a 'getent group admin' localhost | FAILED | rc=2 >>
non-zero return code
cron模块:
#指定定时任务,禁用定时任务,启用定时任务,删除定时任务
#指定定时任务
root@dokcer:~# ansible localhost -m cron -a 'name="cron_test" minute=*/1 hour=* day=* month=* weekday=* state=present job="/usr/sbin/ntpdate 192.168.0.5" '
localhost | SUCCESS => {
"changed": true,
"envs": [],
"jobs": [
"cron_test"
]
}
root@dokcer:~# ansible localhost -a 'crontab -l'
localhost | SUCCESS | rc=0 >>
#Ansible: cron_test
*/1 * * * * /usr/sbin/ntpdate 192.168.0.5
#禁用定时任务
root@dokcer:~# ansible localhost -m cron -a 'disabled=yes name="cron_test" minute=*/1 hour=* day=* month=* weekday=* state=present job="/usr/sbin/ntpdate 192.168.0.5" '
localhost | SUCCESS => {
"changed": true,
"envs": [],
"jobs": [
"cron_test"
]
}
root@dokcer:~# ansible localhost -a 'crontab -l' localhost | SUCCESS | rc=0 >>
#Ansible: cron_test
#*/1 * * * * /usr/sbin/ntpdate 192.168.0.5
#启用定时任务
root@dokcer:~# ansible localhost -m cron -a 'disabled=no name="cron_test" minute=*/1 hour=* day=* month=* weekday=* state=present job="/usr/sbin/ntpdate 192.168.0.5" '
localhost | SUCCESS => {
"changed": true,
"envs": [],
"jobs": [
"cron_test"
]
}
root@dokcer:~# ansible localhost -a 'crontab -l' localhost | SUCCESS | rc=0 >>
#Ansible: cron_test
*/1 * * * * /usr/sbin/ntpdate 192.168.0.5
#删除定时任务
root@dokcer:~# ansible localhost -m cron -a 'state=absent name="cron_test" job="/usr/sbin/ntpdate 192.168.0.5" ' localhost | SUCCESS => {
"changed": true,
"envs": [],
"jobs": []
}
root@dokcer:~# ansible localhost -a 'crontab -l'
localhost | SUCCESS | rc=0 >>
setup模块:
收集目标主机的属性信息
root@dokcer:~# ansible localhost -m setup #获取主机所有属性信息
用filter获取被控主机的内存信息,filter支持正则表达式
root@dokcer:~# ansible localhost -m setup -a 'filter=ansible_memtotal_mb'
localhost | SUCCESS => {
"ansible_facts": {
"ansible_memtotal_mb": 1993
},
"changed": false
}
ansible文件模块:
copy模块:
#文件纯拷贝,拷贝时更改属性,拷贝时备份,根据内容增加文件
#文件复制,src控制端源路径,dest为被控端目标路径,目标和源路径最好一致
root@docker:~# ansible localhost -m copy -a 'src=/home/lion/1.txt dest=/tmp/1.txt'
localhost | SUCCESS => {
"changed": false,
"checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
"dest": "/tmp/1.txt",
"gid": 0,
"group": "root",
"mode": "0644",
"owner": "root",
"path": "/tmp/1.txt",
"size": 0,
"state": "file",
"uid": 0
}
root@docker:~# ansible localhost -a 'ls /tmp -l' -o #-o参数代表一行输出
localhost | CHANGED | rc=0 | (stdout) total 20\n-rw-r--r-- 1 root root 30 Jul 8 13:24 1.sh\n-rw-r--r-- 1 root root 0 Jul 8 13:08 1.txt\ndrwx------
#拷贝时更改属主和文件权限 owner属主 group组 mode文件模式
root@docker:~# ansible localhost -m copy -a 'src=/home/lion/1.txt dest=/tmp/1.txt owner=root group=sudo mode=666'
localhost | SUCCESS => {
"changed": true,
"checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
"dest": "/tmp/1.txt",
"gid": 27,
"group": "sudo",
"md5sum": "d41d8cd98f00b204e9800998ecf8427e",
"mode": "0666",
"owner": "root",
"size": 0,
"src": "/home/lion/.ansible/tmp/ansible-tmp-1657418921.53-172677670998462/source",
"state": "file",
"uid": 0
}
root@docker:~# ansible localhost -a 'ls /tmp -l'
localhost | SUCCESS | rc=0 >>
total 20
-rw-r--r-- 1 root root 30 Jul 8 13:24 1.sh
-rw-rw-rw- 1 root sudo 0 Jul 10 02:08 1.txt #属性666 2-4-1 #读写执行
#文件备份 backup=yes,备份时文件一点要有变化否则copy失败,
root@docker:~# ansible localhost -m copy -a 'src=/home/lion/1.txt dest=/tmp/1.txt owner=root group=sudo mode=666 backup=yes'
localhost | SUCCESS => {
"backup_file": "/tmp/1.txt.8363.2022-07-10@02:15:01~", #备份文件包含时间戳
"changed": true,
"checksum": "a48f53309f72df9fe7124c65605c328c0c4dd415",
"dest": "/tmp/1.txt",
"gid": 27,
"group": "sudo",
"md5sum": "6e5599d95ad03eb9ead7390bd1be4146",
"mode": "0666",
"owner": "root",
"size": 7,
"src": "/home/lion/.ansible/tmp/ansible-tmp-1657419301.17-100695084433159/source",
"state": "file",
"uid": 0
}
content模块:
#利用content直接把字符串写入文件
root@docker:~# ansible localhost -m copy -a 'content="hello world" dest=/tmp/content.txt'
localhost | SUCCESS => {
"changed": true,
"checksum": "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed",
"dest": "/tmp/content.txt",
"gid": 0,
"group": "root",
"md5sum": "5eb63bbbe01eeed093cb22bb8f5acdc3",
"mode": "0644",
"owner": "root",
"size": 11,
"src": "/home/lion/.ansible/tmp/ansible-tmp-1657419516.99-173271494695010/source",
"state": "file",
"uid": 0
}
root@docker:~# ansible localhost -a 'cat /tmp/content.txt'
localhost | SUCCESS | rc=0 >>
hello world
fetch模块:
fetch模块与copy模块正好相反,是从远程主机被控端传输文件到控制端的本地主机
#拉取文件
#localhost上的/tmp/2.txt文件拉取到/home/lion/localhost/tmp/2.txt
#目录为dest/[主机]/src
root@docker:~# ansible localhost -m fetch -a 'src=/tmp/2.txt dest=/home/lion'
localhost | SUCCESS => {
"changed": true,
"checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
"dest": "/home/lion/localhost/tmp/2.txt",
"md5sum": "d41d8cd98f00b204e9800998ecf8427e",
"remote_checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
"remote_md5sum": null
}
root@docker:~# ls /home/lion
1.txt localhost
root@docker:~# ls /home/lion/localhost/
tmp
root@docker:~# ls /home/lion/localhost/tmp
2.txt
#多文件拷贝通过压缩包的方式
#添加/tmp文件下的所有文件到压缩包
root@docker:~# ansible localhost -a 'tar zcf tmp.tar.gz /tmp'
#拉取压缩包文件
root@docker:~# ansible localhost -m fetch -a 'src=tmp.tar.gz dest=/tmp'
localhost | SUCCESS => {
"changed": true,
"checksum": "385215126769067cd0ea21c9a4461458f52d2344",
"dest": "/tmp/localhost/tmp.tar.gz",
"md5sum": "819dee6bdbd3fef5707637139d0dff6a",
"remote_checksum": "385215126769067cd0ea21c9a4461458f52d2344",
"remote_md5sum": null
}
file模块:
文件创建,设置属性,文件删除
#创建目录
root@docker:~# ansible localhost -m file -a 'path=/file/ state=directory'
localhost | SUCCESS => {
"changed": true,
"gid": 0,
"group": "root",
"mode": "0755",
"owner": "root",
"path": "/file/",
"size": 4096,
"state": "directory",
"uid": 0
}
#创建文件 state=touch
root@docker:~# ansible localhost -m file -a 'path=/file/1.txt state=touch'
localhost | SUCCESS => {
"changed": true,
"dest": "/file/1.txt",
"gid": 0,
"group": "root",
"mode": "0644",
"owner": "root",
"size": 0,
"state": "file",
"uid": 0
}
#创建link文件
root@docker:~# ansible localhost -m file -a 'src=/etc/fstab dest=/file/1.fstab state=link'
localhost | SUCCESS => {
"changed": true,
"dest": "/file/1.fstab",
"gid": 0,
"group": "root",
"mode": "0777",
"owner": "root",
"size": 10,
"src": "/etc/fstab",
"state": "link",
"uid": 0
}
#file模块修改文件属主和权限
root@docker:~# ansible localhost -m file -a 'path=/file/1.txt owner=root mode=777'
localhost | SUCCESS => {
"changed": true,
"gid": 0,
"group": "root",
"mode": "0777",
"owner": "root",
"path": "/file/1.txt",
"size": 0,
"state": "file",
"uid": 0
}
#file删除文件,要确保文件没有正在被使用
root@docker:~# ansible localhost -m file -a 'path=/file/1.txt state=absent'
localhost | SUCCESS => {
"changed": true,
"path": "/file/1.txt",
"state": "absent"
}
#file查看文件属性
root@docker:~# ansible localhost -m stat -a 'path=/tmp/1.txt'
ansible应用模块:
apt模块
#安装软件
ansible localhost -m apt -a 'package=wget state=present'
#卸载软件
ansible localhost -m apt -a 'package=wget state=absent'
#更新软件
root@docker:~# ansible localhost -m apt -a 'package=wget state=latest'
#更新软件
#root@docker:~# ansible localhost -m apt -a 'upgrade=yes'
server模块使用:
#开机自启动,服务重启,启动,停止
#服务自启动
root@docker:~# ansible localhost -m service -a 'name=nginx enabled=yes'
#验证服务是否自启动
root@docker:~# ansible localhost -a 'systemctl is-enabled nginx'
localhost | SUCCESS | rc=0 >>
enabled #服务已设置自启动
#服务启动
root@docker:~# ansible localhost -m service -a 'name=nginx state=started'
#服务停止
root@docker:~# ansible localhost -m service -a 'name=nginx state=stopped'
#服务重载
root@docker:~# ansible localhost -m service -a 'name=nginx state=reloaded'
#服务重启
root@docker:~# ansible localhost -m service -a 'name=nginx state=restarted'
debug模块:
#查看帮助信息,主要在playbook中使用
#显示默认debug信息
root@docker:~# ansible localhost -m debug
localhost | SUCCESS => {
"msg": "Hello world!"
}
#设置debug信息输出
root@docker:~# ansible localhost -m debug -a 'msg='ss''
localhost | SUCCESS => {
"msg": "ss"
}
ansible命令:
ansible-doc
-t 指定特殊的插件类型来显示,默认为module
ansible-glaxy
官方的模板网站
ansible-playbook #执行playbook脚本
ansible-vault
采用安全加密的方式来操作文件
#创建文件,输入密码和确认密码
root@docker:~# ansible-vault create 1.txt
#输入密码查看文件
root@docker:~# ansible-vault view 12.txt
#编辑文件
root@docker:~# ansible-vault edit 12.txt
#解密文件
root@docker:~# ansible-vault decrypt 12.txt
#加密文件
root@docker:~# ansible-vault encrypt 12.txt
#重新设置密钥
root@docker:~# ansible-vault rekey 12.txt
ansible-console
#可交互式终端执行命令
root@docker:~# ansible-console
Welcome to the ansible console.
Type help or ? to list commands.
root@all (1)[f:5]$ list #主机数为1 fork数量为5
192.168.0.50
root@192.168.0.50 -k (1)[f:5]$ cd localhost #进入主机列表中的主机
root@localhost (1)[f:5]$ ls #就和一样执行命令
localhost | SUCCESS | rc=0 >>
12.txt
1.txt
localhost
tmp.tar.gz
root@localhost (1)[f:5]$
#apt模块安装wget软件
wget -o /文件/ /http路径
root@localhost (1)[f:5]$ apt package=wget state=present
ansible-inventory #获取主机清单信息的专用命令
#列出所有主机
root@docker:~# ansible-inventory --export --list
#列出所有主机
root@docker:~# ansible-inventory --vars --list
ansible-playbook模块:
playbook其实就是一个自动化执行ansible的命令方式罢了
使用ansible-playbook执行playbook文件,playbook文件
使用yaml语言编写
ansible在执行playbook的时候,执行效果具有幂等性(即一个命令执行多次与执行一次效果一样)
playbook文件内容组成
组成 | 功能 | 常见属性 | 备注 |
---|---|---|---|
Target section | 执行playbook的目标主机 | hosts remote_user order | 必备内容 |
Variable section | 执行playbook的需要的变量 | vars | 可选内容 |
Task section | playbook中的功能任务 | task(name 模块名称) | 必备内容 |
Handler section | 各种任务之间的关联关系 | handler(name 模块名称) | 可选内容 |
YAML语法:
YAML文件示例:
---
- hosts: 192.168.0.50
remote_user: root
tasks:
- name: hello world
command: wall 'hello world'
tags:
- hello world
YAML语法特点
大小写敏感
使用缩进表示层级关系
缩进时不允许使用TAB键,**只允许使用空格**
缩进的空格不重要,只要**相同层级的元素左侧对齐**即可
#表示注释
---表示分割符,是多个文件合并在一个文件中的分割效果
playbook文件实例:
1.安装httpd
服务
2.开启httpd server
- hosts: 192.168.0.50,localhost
remote_user: root
tasks:
- name: install httpd_package
apt: package=nginx state=present
- name: start service
service: name=nginx state=started enabled=yes
root@docker:~# ansible-playbook test.yaml --syntax-check #语法检测
root@docker:~# ansible-playbook test.yaml -C test.yaml #模拟执行
root@docker:~# ansible-playbook test.yaml -l#执行playbook文件
#-***l表示指定某一台主机执行playbook文件***
root@docker:~# netstat -tnulp #查看端口监听状态
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 14869/nginx: master
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN 885/systemd-resolve
playbook host属性:
单个主机:
-hosts: 192.168.0.50
-hosts: master.ansible.com
多个主机:
-hosts: 192.168.0.*
-hosts: *.ansible.com
特定主机:(交集,并集,补集)
-hosts: web:mysql
-hosts: web:&mysql
-hosts: web:!mysql
playbook remote_user属性:
remote_user作用相当于-u(登录用户)+ -k(登录密码) + -K(提权密码)
默认登录用户(全局用户),用于所有task任务的默认执行用户
- hosts: localhost
remote_user: root
或者
- hosts: localhost
remote_user: otheruser
特殊登录用户:
- hosts: localhost
remote_user: root
tasks:
- name test
ping:
remote_user: lion
sudo: yes #sudo切换到root用户
sudo_user: otheruser #sudo切换到其他用户身份
#在task中sudoh和sudo_user只存在一个即可
#子任务在切换任务时候,要和全局默认的登录用户识别清楚
playbook tasks:
playbook文件只要就是实现各种功能,每一个tasks代表一个实现功能,playbook中的功能具有幂等特性
tasks根据顺序从上到下依次执行,如果中途某一个tasks出现错误,那么整个任务就会中断
tasks格式
tasks:
- name: install_nginx #名称
ping: #执行的动作,也就是ansible模块命令,格式二
- name: ping
action: ping #格式一
ansible模块的动作分为两种格式
1: action: 模块 具体动作
2: 模块: 具体动作
对于
shell和command模块来说具体动作就是可执行命令,对于其他模块,具体动作就是参数key=value格式
**在一个tasks中有多个action动作,只有最后一个action动作生效
如果想要执行多条命令,只有写多个子任务,也就是多个name
不过如果想要用shell模块执行多个命令,可以使用&;之类的命令连接符号,但是动作只能有一个
可以使用
-v,-vv,-vvvv参数查看执行过程**
playbook异常中断
playbook是从上到下依次执行的,如果中间出现异常就会中断执行,必须要解决中断
palybook的任务能否按顺序执行下去,主要是依据任务之间的指令的执行状态返回码来
判断的,正常执行为0否则为非0,可以通过||逻辑符号来强制让指令返回0
1:强制正确(|| /bin/true)
2:忽略错误,并抛出异常
- hosts: localhost
remote_user: root
tasks:
- name: touch1
shell: rm 4.txt || /bin/true #4.txt文件不存在,所以会报错,/bin/true强制执行正确
playbook有一种专门在处理任务列表意外中断的属性值ignore_erros,用于判断任务是否异常
- hosts: localhost
remote_user: root
tasks:
- name: touch1
shell: rm 4.txt
ignore_errors: True #使用ignore_errors值为true,这样就可忽略异常然后抛出错误
playbook任务依赖:
playbook中存在一种依赖关系,分为监控器和触发器
notify: notify是task中的一个子属性,监控我们指定的动作涉及的内容是否发生了变化,比如配置文件
notify: handler名称
handlers: 接收到变化的动作后,自动执行的其他操作命令
应该先写handlers,然后再在notify中调用,要先写handlers
- hosts: localhost
remote_user: root
tasks:
- name: copy4
copy: src=/home/lion/4.txt dest=/tmp/4.txt
notify: touch5 #监听器当4.txt出现修改时就会执行handlers中的touch5子任务
ignore_errors: True
handlers: #触发器
- name: touch5
shell: touch 5.txt
让一个notify执行多个触发器
- hosts: localhost
remote_user: root
tasks:
- name: copy4
copy: src=/home/lion/4.txt dest=/tmp/4.txt
notify:
- touch5 #监听器当4.txt文件出现修改时,会同时触发touch5和touch6两个动作
- touch6
ignore_errors: True
handlers:
- name: touch5 #触发器动作
shell: touch 5.txt
- name: touch6
shell: touch 6.txt
playbook标签:
通过playbook标签可以在playbook中执行某一个任务,或者让某一个主机执行任务
- hosts: localhost
tags: localhost #localhost主机
remote_user: root
tasks:
- name: touch1
shell: touch 7.txt
tags: touch #标签为touch,可以直接用-t参数来执行touch任务
ignore_errors: True
- name: touch2
command: ls
root@docker:~# ansible-playbook 4.yaml --list-tags #查看yaml文件中的标签
playbook: 4.yaml
play #1 (localhost): localhost TAGS: [localhost]
TASK TAGS: [localhost, touch]
root@docker:~# ansible-playbook 4.yaml -t touch #执行taskz中的标签任务
root@docker:~# ansible-playbook 4.yaml -t localhost #用localhost主机执行任务
#可以在不同的动作下添加同一个标签,这样就可以在执行同一个标签的同时在执行同一个标签的任务,
实现任务分割同时来增加文件层次
- hosts: localhost
remote_user: root
tasks:
- name: touch1
shell: touch 11.txt
tags: touch
- name: touch2
shell: touch 10.txt
tags: touch
root@docker:~# ansible-playbook 4.yaml -t touch #同时执行touch1和touch2两个动作
playbook变量:
变量实现方式 | 优先级 | 编号 |
---|---|---|
目标主机默认属性 | 最低 | 1 |
主机清单中的特有属性 | 次低 | 2 |
命令行定义的特定属性 | 最高 | 3 |
playbook通过vars定义的属性 | 低 | 4 |
专用yaml文件定义的属性文件 | 次高 | 5 |
1<2<4<5<3 |
我们可以基于获取目标主机的主机属性来定制化yaml文件
可以用setup的方式来获取主机属性
root@docker:~# ansible localhost -m setup | grep ' "' | wc -l
847 #默认情况下
#获取cpu型号 -o输出通过一行
root@docker:~# ansible localhost -m setup -a 'filter=ansible_processor' -o
localhost | SUCCESS => {"ansible_facts": {"ansible_processor": ["0", "AuthenticAMD", "AMD Athlon(tm) X4 870K Quad Core Processor"]}, "changed": false}
#playbook变量实例
通过ansible setup模块获取cpu信号并且写入cpu.txt
- hosts: localhost
remote_user: root
tasks:
- name: get_cpu_name
shell: echo '{{ ansible_processor[2] }}' >> cpu.txt
- name: debug
debug: msg='{{ ansible_processor[2] }}' #通过debug模块打印出获取的变量,方便调试
#效果:
TASK [debug]
ok: [localhost] => {
"msg": "AMD Athlon(tm) X4 870K Quad Core Processor" #debug模块显示
}
root@docker:~# cat cpu.txt #把cpu型号写入cpu.txt,查看cpu.txt
AMD Athlon(tm) X4 870K Quad Core Processor
play变量种类和优先级
在/etc/ansible/host文件中定义主机变量有两种样式:
公共变量和普通变量
**普通变量比公共变量的优先级高,如果普通变量不存在然后才会使用公共变量**
**普通变量**
root@docker:~#cat /etc/ansible/hosts
[nginx]
192.168.0.50 ansible_connection=local hostname=localhost #定义普通变量,ansible定义为本地连接
root@docker:~# cat local.yaml #打印获取到的hosts文件中的普通变量
- hosts: all
tasks:
- name: print_hostname
debug: msg='{{ hostname }}'
#效果:
ok: [192.168.0.50] => {
"msg": "localhost" #打印了获取到的localhost变量
}
**公共变量**
/etc/ansible/hosts
****root@docker:~# tail -n 4 /etc/ansible/hosts
[nginx]
192.168.0.50 ansible_connection=local hostname=localhost
[nginx:vars] #公共变量
hostname=local
ok: [192.168.0.50] => { #由于普通变量优先级更高,所以变量仍然等于localhost
"msg": "localhost"
}
root@docker:~# tail -n 4 /etc/ansible/hosts
[nginx]
192.168.0.50 ansible_connection=local #删除了普通变量,所以所以hostname等于local
[nginx:vars] #[主机组:vars]定义变量
hostname=local
ok: [192.168.0.50] => {
"msg": "local"
}
**playbook命令行变量:**
通过-e 参数在命令行指定变量,所有变量用单引号括住,多个变量用空格隔开
****root@docker:~# ansible all -e host='localhost' -m debug -a "msg='this is {{ host }}'"
192.168.0.50 | SUCCESS => {
"msg": "this is localhost"
}
通过命令行定义多个变量:
root@docker:~# ansible all -e 'host=localhost user=lion' -m debug -a "msg='this is {{ host }} user is {{ user }}'"
192.168.0.50 | SUCCESS => {
"msg": "this is localhost user is lion"
}
**playbook yaml文件中定义变量**:
通过vars列表的方式来定义变量
root@docker:~# cat var.yaml
- hosts: all
remote_user: root
vars:
- user: root
- hostname: master
tasks:
- name: print_user_hostname
debug: msg='user is {{ user }} hostname is {{ hostname }}'
ok: [192.168.0.50] => {
"msg": "user is root hostname is master" #打印出定义的变量
}
#命令行的变量优先级高于yaml文件中的变量
root@docker:~# ansible-playbook -e user='lion' -C var.yaml
TASK [print_user_hostname]
ok: [192.168.0.50] => {
"msg": "user is lion hostname is master" #打印出命令行中定义的user变量
}
PLAY RECAP
192.168.0.50 : ok=2 changed=0 unreachable=0 failed=0
ansible专用yaml变量文件
可以在专用的yaml文件中定义统一变量,可以应用多个变量文件,推荐用绝对路径,一般情况下
放到和yaml执行文件的同一路径下,使用相对路径
**vars.yaml专用变量文件**
root@docker:~# cat vars.yaml
user: lion
hostname: localhost
root@docker:~# cat var.yaml
- hosts: all
remote_user: root
vars_files:
- vars.yaml #变量文件
vars: #playbook中定义的变量
- user: root
- hostname: master
tasks:
- name: print_user_hostname
debug: msg='user is {{ user }} hostname is {{ hostname }}'
执行结果:
变量文件中的变量的优先级大于yaml文件中的变量
ok: [192.168.0.50] => {
"msg": "user is lion hostname is localhost"
}
**#显示root组是否存在**
root@docker:~# getent group | grep root
root:x:0:
ansible模板模块:
ansible可以通过jinja2模块来实现主机配置文件的灵活定制
使用jinja2模板语言来定制配置文件,j2模板文件推荐使用相对目录,文件路径在playbook文件下的
template目录下
root@docker:~# cat template.yaml
- hosts: all
remote_user: root
vars:
- cpu: 'x4 870k'
tasks:
- name: get_cpu_model
template: src=./template/cpu.txt.j2 dest=/tmp/cpu.txt #使用j2模板文件,生成/tmp/cpu.txt文件
root@docker:~# cat /tmp/cpu.txt
#cpu model
CPU Model is x4 870k
#模板语法条件判断
**when支持算数运算符和比较运算符和逻辑运算符**
- hosts: all
remote_user: root
tasks:
- name: AMD
debug: msg='CPU is AMD'
when: ansible_processor[1] == 'AuthenticAMD' #当cpu为AMD时
- name: INTEL
debug: msg='CPU is INTEL'
when: ansible_processor[1] != 'AuthenticAMD' #当cpu不是AMD时
#执行结果:
ok: [192.168.0.50] => {
"msg": "CPU is AMD"
}
TASK [INTEL]
skipping: [192.168.0.50] #跳过执行
#模板迭代执行
with_itmes可以是列表和字典
一个任务中一个action动作只能执行一个,所以可以通过类似于循环的方式通过一个action执行多个动作
- hosts: all
remote_user: root
tasks:
- name: print_process_info
debug: msg='{{ item }}' #把item替换成with_items列表中的每一项,with_items可以是列表和字典
with_items:
- '{{ ansible_processor[0] }}'
- '{{ ansible_processor[1] }}'
- '{{ ansible_processor[2] }}'
打印结果:
ok: [192.168.0.50] => (item=None) => {
"msg": "0"
}
ok: [192.168.0.50] => (item=None) => {
"msg": "AuthenticAMD" #打印cpu种类
}
ok: [192.168.0.50] => (item=None) => {
"msg": "AMD Athlon(tm) X4 870K Quad Core Processor" #打印cpu型号
}
#迭代和流程流程判断结合
- hosts: all
remote_user: root
tasks:
- name: AMD
debug: msg='CPU is AMD'
when: ansible_processor[1] == 'AuthenticAMD'
- name: INTEL
debug: msg='CPU is INTEL'
when: ansible_processor[1] != 'AuthenticAMD'
- name: AMD_OR_INTEL
debug: msg='{{ item }}'
when: ansible_processor[1] == 'AuthenticAMD' #当when成立时,才执行迭代操作
with_items:
- the cpu is AMD_CPU
- AMD_yyds!
#迭代进阶
使用多值迭代,通过类似python字典的方式来,使用多个字段来多值迭代
- hosts: all
remote_user: root
tasks:
- name: AMD_OR_INTEL
debug: msg='the cpu is {{ item.model }} {{ item.cpu_info }}'
with_items:
- { model: 'AMD', cpu_info: 'AMD YYDS!!' }
#模板流程控制
{{}} #用于表达式,变量
{% %} #流程控制,if,for
{# #} #用于注释内容
条件控制语句
{% if 条件 %} 执行语句 {% endif %}
条件判断 {%if 变量 is denfind %}
循环语句
{% for 条件 %} 执行语句 {% end for %}
fo循环 {% for 变量 in 变量列表 %}
只有当条件成立时,执行语句才会执行
#模板文件:
#cpu_info
{%if cpu is defined %}
the cpu is {{ cpu }};
{% endif %}
#yaml文件
- hosts: all
remote_user: root
tasks:
- name: cpu_info
template: src=./template/cpuz.txt.j2 dest=/tmp/cpuz.txt
#/etc/ansible/hosts
192.168.0.50 ansible_connection=local cpu=AMD #定义了cpu变量
#cpu_info for循环实例
yaml文件
- hosts: all
remote_user: root
vars:
cpu_info:
- INTEL
- AMD
tasks:
- name: cpu_info
template: src=./template/cpus.txt.j2 dest=/tmp/cpus.txt
模板文件
#cpu_info
{% for cpu in cpu_info %}
{%if cpu is defined %}
the cpu is {{ cpu }};
{% endif %}
{% endfor%}
执行结果:
cpus.txt
root@docker:~# cat /tmp/cpus.txt
#cpu_info
the cpu is INTEL;
the cpu is AMD;
ansible role:
ansible role角色
ansible role可以将不同的功能的yaml文件整合在一起,比如tasks,template,file,等不同功能的模块
分割成单个yaml文件,然后再在入口的yaml(mian.yaml)文件中导入其他的功能模块(include)。这样就可以实现更加灵活的管理和增加功能,实现模块化管理。
role不适用中小场景管理环境,不复杂的场景不必应用role,role适用于大型业务管理
#创建roles文件夹
root@docker:~# mkdir test_role
root@docker:~# cd test_role/
root@docker:~/test_role# mkdir roles
root@docker:~/test_role# mkdir roles/role_cpu
root@docker:~/test_role# tree
.
└── roles
└── role_cpu
2 directories, 0 files
root@docker:~/test_role# mkdir roles/role_cpu/{tasks,vars} #创建tasks,vars模块文件夹
root@docker:~/test_role# tree
.
└── roles
└── role_cpu
├── tasks
└── vars
4 directories, 0 files
root@docker:~/test_role# touch roles/role_cpu/tasks/{main,debug}.yaml #创建子任务的yaml文件
root@docker:~/test_role# tree
.
└── roles
└── role_cpu
├── tasks
│ ├── debug.yaml
│ └── main.yaml
└── vars
4 directories, 2 files
root@docker:~/test_role# touch roles/role_cpu/vars/main.yaml #创建变量main目录
root@docker:~/test_role# tree
.
└── roles
└── role_cpu
├── tasks
│ ├── debug.yaml
│ └── main.yaml
└── vars
└── main.yaml
4 directories, 3 files
#test_role.yaml
- hosts: all
remote_user: root
roles:
- role: role_cpu #引入角色,标准写法
------------------------------------------------------------------------------------
- hosts: all
remote_user: root
roles:
- role_cpu #引入角色,简写
#tasks/main.yaml
- include: debug.yaml #导入其他task模块,在项目中使用相对路径以main.yaml目录为准
(./main.yaml 当前目录,../ main.yaml的上一级目录)
#tasks/debug.yaml
- name: cpu_info
debug: msg={{ ansible_processor[1] }} #打印出cpu型号
- name: os
debug: msg={{ systeminfo[0] }} #在var/main.yaml中定义的变量
- name: hostname
debug: msg='hostname is {{ ansible_facts['nodename'] }}' #打印hostname
#vars/main.yaml
systeminfo:
- '{{ ansible_os_family }}' #变量定于格式必须时变量字典的形式,否则会报错
执行结果:
root@docker:~/test_role# ansible-playbook -C test_role.yaml
ok: [192.168.0.50]
TASK [role_cpu : cpu_info]
"msg": "AuthenticAMD"
}
TASK [role_cpu : os]
ok: [192.168.0.50] => {
"msg": "Debian"
}
TASK [role_cpu : hostname]
ok: [192.168.0.50] => {
"msg": "hostname is docker"
}
#可以在role主yaml文件中定义变量,执行role时引用定义的变量
{ role: role角色目录,变量:变量值}
- hosts: all
remote_user: root
roles:
- { role: role_cpu, user: root }
#在debug目录中使用user变量
- name: cpu_info
debug: msg={{ ansible_processor[1] }}
- name: os
debug: msg={{ systeminfo[0] }}
- name: hostname
debug: msg='hostname is {{ ansible_facts['nodename'] }}'
- name: user
debug: msg='{{ user }}' #使用定义的变量
#roles结合条件判断,只有当when条件判断成立时,才可以定义变量,才会执行roles角色tasks
#执行roles角色
- hosts: all
remote_user: root
roles:
- { role: role_cpu, user: root, when: ansible_facts.nodename == 'docker' }
#不执行roles角色
- hosts: all
remote_user: root
roles:
- { role: role_cpu, user: root, when: ansible_facts.nodename == 'doc' }
#定义多个role角色,用标签的方式调用不同的roles,执行不同的tasks
- hosts: all
remote_user: root
roles:
- { role: role_cpu, user: root, tags: ['cpu_info', 'localhost'] }
#用-t运行指定标签的role,用-l指定执行的主机
root@docker:~/test_role# ansible-playbook -C test.yaml -t cpu_info -l all
ansible示例:
ansbile部署prometheus,并创建prometheus service,设置开机启动
prometheus.yml:
- hosts: localhost
remote_user: root
vars:
- version: 2.37.0 #下载的版本
tasks:
- name: downlaod prometheus
command: wget https://github.com/prometheus/prometheus/releases/download/v{{ version }}/prometheus-{{ version }}.linux-amd64.tar.gz
- debug: msg='wget https://github.com/prometheus/prometheus/releases/download/v{{ version }}/prometheus-{{ version }}.linux-amd64.tar.gz'
- name: tar prometheus
shell: tar -xzvf prometheus-{{ version }}.linux-amd64.tar.gz -C /usr/local/
- name: link
shell: ln -sv /usr/local/prometheus-{{ version }}.linux-amd64/prometheus /usr/local/bin/prometheus
- name: touch prometheus service
template: src=./prometheus.service dest=/etc/systemd/system/prometheus.service
tags: prometheus_service
- name: start prometheus service
shell: systemctl start prometheus.service
- name: enable prometheus service
shell: systemctl enable prometheus.service
prometheus.service文件模板:
[Unit]
Description=prometheus
[Service]
Restart=on-failure
ExecStart=/usr/local/bin/prometheus --config.file=/usr/local/prometheus-{{ version }}.linux-amd64/prometheus.yml
[Install]
WantedBy=multi-user.target