ansible
基础知识:
批量管理服务器工具;
使用python编写;
基于ssh进行管理,所以不需要在被控端安装任何软件;
ansible在远程管理主机时,主要通过各种模块进行操作的
对主控端的要求:
配置域名解析,能够通过名字访问所有节点
配置可以通过ssh到所有节点免密登录
安装ansible_soft.tar.gz
ansible配置环境管理
# 创建ansible工作目录,目录名自己定义,不是固定的。
[root@control ~]# mkdir ansible
[root@control ~]# cd ansible
# 创建配置文件。默认的配置文件是/etc/ansible/ansible.cfg,但是一般不使用它,而是在工作目录下创建自己的配置文件
[root@control ansible]# vim ansible.cfg # 文件名必须是ansible.cfg
[defaults]
inventory = hosts # 管理的主机,配置在当前目录的hosts文件中,hosts名是自定义的。=号两边空格可有可无。
# 创建主机清单文件。写在[]里的是组名,[]下面的是组内的主机名
[root@control ansible]# vim hosts
[test]
node1
[proxy]
node2
[webserver]
node[3:4] # node3和node4的简化写法,表示从3到4
[database]
node5
# cluster是组名,自定义的;:children是固定写法,表示下面的组名是cluster的子组。
[cluster:children]
webserver
database
# 查看被管理的所有的主机。注意,一定在工作目录下执行命令。
[root@control ansible]# ansible all --list-hosts
hosts (5):
node1
node2
node3
node4
node5
# 查看webserver组中所有的主机
[root@control ansible]# ansible webserver --list-hosts
hosts (2):
node3
node4
ansible的两个管理办法:
adhoc临时命令(在命令行上执行管理命令)
playbook剧本 (把管理任务用特定格式写到文件里)
共同点:都是通过模块加参数进行管理
adhoc临时命令:
语法:ansible 主机或组列表 -m 模块 -a “参数” 【-a 是可选的】
如何测试远程主机的连通性: ansible all -m ping
ansible模块
模块基本信息查看:
ansible-doc -l | wc -l
列出ansible所有模块:
ansible-doc -l
查看和yum有关的模块:
ansible-doc -l | grep yum
查看yum模块的使用说明(专注于EXAMPLE):
ansible-doc yum
模块详细信息:
command模块:
ansible默认模块,用于在远程主机上执行任意命令;
command不支持shell特性,如管道,重定向
例:在被管主机上创建目录:ansible all -a “mkdir /tmp/demo”
shell模块
和command模块类似,但是支持shell特性,如管道,重定向。
例:查看node1的IP地址:ansible node1 -m shell -a “ip a s | head”
script模块
用于在远程主机上执行脚本
例:
在控制端创建脚本即可:vim test.sh
在test组主机上执行脚本:ansible test -m script -a “test.sh”
file模块
可以创建文件,目录,链接等,还可以修改权限、属性等
常用选项:
path:指定文件路径
owner:设置文件所有者
group:设置文件所属组
state:状态:touch表示创建文件;directory表示创建目录;link表示创建软连接;absent表示删除。
mode:设置权限
src:源
dest:目标
例:
在test主机上创建/tmp/file.txt:ansible test -m file -a “path=/tmp/file state=touch”【touch表示 文件若不存在则创建】
将test主机上将/tmp/file.txt的属主改为sshd,属主改为adm,权限改为0777:admin test -m file -a “path=/tmp/file.txt owner=sshd group=adm mode=’0777’”
在test主机上创建/etc/host 的软连接,目标是/tmp/host.txt:ansible test -m file -a “src=/etc/hosts dest=/tmp/hosts.txt state=link”
copy模块(从上往下)
将文件从控制端拷贝到被控端
常用选项:
src:源
dest:目标;被控制端的文件路径
content:内容;需要写到文件里的内容
例:
将a.txt拷贝到test主机上的/root/:ansible test -m copy -a “src=a3.txt dest=/root/”
在目标主机test上 创建/tmp/mytest.txt,内容是helloword: ansible test -m copy -a “content=’helloword’ dest=/tmp/mytest.txt”
fetch模块:(从下往上)
和copy模块相反,copy是上传,fetch是下载
常用选项:
src:源;被控制端的文件路径
desc:目标;控制端的文件路径
例:
将test主机上的/etc/hostname 下载到本地目录的家目录下
ansible test -m fetch -a “src=/etc/hostname desc=~/”
lineinfile模块
用于确保目标文件中有某一行neir
常用选项:
path:待修改文件的路径
line:写入文件的一行内容
regrxp:正正则表达式,用于查找文件内容
例:
test组的主机中,/etc/issue中一定有一行helloword,若不存在则默认添加到行尾:
ansible test -m lineinfile -a “path=/etc/issue line=’helloword’”
test组的主机中,把/etc/issue中有hello的行,替换成chilema:
ansible test -m linefinfile -a “path=/etc/issue line=’chilema’ regrxp=hello”
replace模块
lineinfile会替换一行,replace可以替换关键词
常用选项:
path:待修改的文件路径
replace:将正则表达式查到的内容,替换成replace的内容
regexp:正则表达式,用于查找文件的内容
例:
将test组中主机上的/etc/issue文件中的chi,替换成he
ansible test -m replace -a “path=/etc/issue regexp=’chji’ replace=’he’”
group模块
创建、删除组
常用选项:
name:待创建组名
gid:组的id号
state:present表示创建(默认);absent表示删除
user模块
实现linux用户管理
常用选项:
name:待创建的用户名
uid:用户id
group:设置主组
groups:设置附加组
home:设置家目录
password:设置用户密码
state:状态;present表示创建(默认选项);absent表示删除;
remove:删除家目录、邮箱等。值为yes或者true都可以
例:
在test组的主机上创建tom用户:ansible test -m user -a “name=tom”
在test组的主机上,创建jeerry用户。设置其uid为1010,主组啊是adm,附加组是daemon和root,家目录是/home/jerry:
ansible test -m user -a “uid=101 name=jerry group=adm groups=deamon,root home=/home/jerry”
设置tom的密码是123456:
【{{}}是一种固定格式,表示执行命令。password_hash是函数,sha512是一种加密算法,则password_hash函数将会把123456听过sha512加密变成tom的密码】
ansible test -m user -a “name=tom password={{‘123456|password_hash(‘sha512’)’}}”
删除tom用户,但不删除家目录:ansible test -m user -a “name=tom state=absent”
删除Jerry用户,删除家目录:ansible test -m user -a”name=jerry state=absent remove=yes”
yum_repository模块
用于配置yum
常用选项:
file:指定文件名
其他选项:需对照文件
例:
在test组主机上配置yum:
ansible test -m yum_repository -a “file=myrepo name=myapp description=’My App’ baseurl=ftp://192.168.4.254/rhel8/AppStream gpgcheck=no enabled=yes”
yum模块:
用于rpm包的管理,如安装、升级、卸载
常用选项:
name:包名
state:状态;present表示安装,如果已安装则忽略;latest表示安装或升级到最新版本;absent表示卸载
例:
在test组主机上安装tar: ansible test -m yum -a “name=tar state=present”
在test组主机上卸载tar:ansible test -m yum -a “name=tar state=absent”
service模块:
用于控制服务的启动,关闭,重启,开机自启。
常用选项:
name:控制的服务名
state:start表示启动;stopped表示关闭;restart表示重启
enabled:yes表示设置开机自启;no表示开机不要自启
例:
将test主机上的httpd启动,并设置他开机自启:ansible test -m service -a “name=httpd state=started enabled=yes”
常用于复杂的任务管理,以及管理经常要完成的任务
playbook也是通过模块和他的参数,在特定主机上执行任务
playbook是一个文件,该文件中需要通过yaml格式进行书写
yaml语法规范:
yaml文件的命名,一般以yml或者yaml作为扩展名
文件一般以---作为第一行,不是必须,但是常用
键值对使用冒号表示,冒号后面必须有空格
数组使用-表示,-后面必须有空格
相同层级必须有相同的缩进。如果缩进不对,则会有语法错误。每一级缩进,为两个空格。
全文不可以使用tab,必须使用空格(可以使用特殊设置来适应,方法如下)
让vim适应yaml语法:(首先进入到ansible文件内)
输入vim ~/.vimrc
在文件内输入:
set ai
set ts=2
set et
【完成后即可在vim内使用tab键】
编写playbook:
一个playbook可以包含多个play
每个play用于在指定主机上,通过模块和参数执行相应的任务
每个play可以包含多个任务
任务由模块和参数构成
编写用于测试连通性的playbook,相当于执行ansible all -m ping
---
hosts: all
tasks:
- ping:
执行playbook:ansible-playbook “yaml文件的名子 ”
更规范的写法如下:
---
- name: test network 【play的名字,可选项】
hosts: all 【作用于所有的主机】
tasks: 【任务】
- name: task 1 【第一个任务的名字,可选选项】
ping: 【第一个任务使用的模块】
执行playbook:ansible-playbook “yaml文件的名子 ”
例:在test主机和node2上创建/tmp/demo目录,权限是0755。将控制端的/etc/hosts拷贝到目标主机的/tmp/demo中。
---
- name: carete dir and copy file
host: test,node2
tasks:
- name: create dir
file:
path: /tmp/demo
state: direction
mode: ‘0755’
- name: copy file
copy:
src: /etc/hosts
dest: /tmp/demo/hosts
执行: ansible-playbook fileop.yaml
通过copy模块创建/tmp/1.txt,文件内容有两行,分别是helloworld和nihao
---
- name: play
hosts: test
tasks:
- name: mkfile 1.txt
copy:
dest: /tmp/1.txt
cintent: |
helloword
nihao
在test主机上创建见john用户,他的uid是1040,主组是daemon,密码为123
---
- name: create user
hosts: test
tasks:
- name: create user john
user:
name: john
uid: 1040
group: daemon
password: “{{‘123’|password_hash(‘sha512’)}}”
在test主机上,安装httpd,php,php-mysqlnd
---
- name: install pkgs
host: test
tasks:
- name: install web pkgs
yum:
name: httpd,php,php-mysqlnd 【也可以加个“[ ]”】
stste: present
或者:
---
- name: install pkgs
host: test
tasks:
- name: install web pkgs
yum:
name:
- httpd
- php
- php-mysqlnd
stste: present
安装软件包组:
列出所有的软件包组:yum grouplist
yum groupinstall "Development Tools"批量安装软件
【如果列出的组名为中文,可以:LANG=C yum grouplist】
在test组中的主机上安装Development Tools组
---
- name: install pkgs
host: test
tasks:
- name: install dev group
yum:
name: “@ Development Tools”
name: present
在test组的主机上升级所有的包到最新版本
---
- name: install web pkgs
hosts: test
tasks:
- name: updata system
yum:
name: ”*”
state: latest
ansible变量
facts变量
facts是ansible自带的预定义变量,用于描述被控端软件和硬件的信息
facts变量通过setup模块获得
通过setup查看所有的facts变量:ansible test -m setup
facts变量是一个大的由{}构成的键值对字典,在{}中,有很多层级的嵌套。可以通过参数过滤出第一个层级的内容。
查看所有ipv4的地址,filter是过滤的意思:ansible test -m setup -a “filter=ansible_all_ipv4_address”
查看可用内存:ansible test -m setup -a “filter=ansible_memfree_mb”
常用的facts变量
- ansible_all_ipv4_address:所有的ipv4地址
- ansible_bios_version:BIOS版本信息
- ansible_memotal_mb:总内存大小
- ansible_hostname:主机名
在playbook中使用变量:
显示远程主机的主机名和内存大小。在ansible中,变量使用{{}}表示
debug模块用于输出信息,常用的参数是msg,用于指定输出内容
---
- name: display host info
host: test
tasks:
- name: display hostname and memory
debug:
msg: “hostname: {{ansible_hostname}}; mem: {{ansible_memotal_mb}} MB”
自定义变量:
引入变量,可以方便playbook重复使用。比如装包的playbook,包名可以使用变量。多次执行playbook,只要改变变量名即可,无需重新编写新的playbook。
ansible支持10种以上的变量定义方式。常用的变量来源如下:
inventory变量。变量主要来自主机清单文件中.
facts变量。
playbook变量。变量主要在playbook定义。
变量文件。专门创建用于保存变量的文件。推荐变量写入单独的文件。
# 使用inventory变量。
[root@control ansible]# vim hosts
[test]
node1 iname="nb" # 主机变量定义的方法。iname是自定义名称
[proxy]
node2
[webserver]
node[3:4]
[database]
node5
[cluster:children]
webserver
database
[webserver:vars] # 组变量定义方法。:vars是固定格式
iname="dachui"
# 通过变量创建用户
[root@control ansible]# vim var1.yml
---
- name: test create user
hosts: test
tasks:
- name: create user
user:
name: "{{iname}}"
state: present
- name: create user in webserver
hosts: webserver
tasks:
- name: create some users
user:
name: "{{iname}}"
state: present
[root@control ansible]# ansible-playbook var1.yml
# 上述两个play也可以合并为一个,如下:
[root@control ansible]# vim var1.yml
---
- name: test create user
hosts: test,webserver # 指定执行的目标是test组和webserver组
tasks:
- name: create user
user:
name: "{{iname}}"
state: present
# 在playbook中定义变量
# 在test组中的主机上创建用户jack,他的密码是123456
[root@control ansible]# vim user_jack.yml
---
- name: create user
hosts: test
vars: # 固定格式,用于声明变量
username: "jack" # 此处引号可有可无
mima: "123456" # 此处引号是需要的,表示数字字符
tasks:
- name: create some users
user:
name: "{{username}}" # {}出现在开头,必须有引号
state: present
password: "{{mima|password_hash('sha512')}}"
[root@control ansible]# ansible-playbook user_jack.yml
# 将变量定义在文件中
[root@control ansible]# vim vars.yml # 文件名自定义
---
yonghu: rose
mima: abcd
[root@control ansible]# vim user_rose.yml
---
- name: create user
hosts: test
vars_files: vars.yml # vars_files用于声明变量文件
tasks:
- name: create some users
user:
name: "{{yonghu}}" # 这里的变量来自于vars.yml
state: present
password: "{{mima|password_hash('sha512')}}"
[root@control ansible]# ansible-playbook user_rose.yml
补充模块
firewalld模块
- 用于配置防火墙的模块
- 常用选项:
- port:声明端口
- permanent:永久生效,但不会立即生效
- immediate:立即生效,临时生效
- state:enabled,放行;disabled拒绝
- 防火墙一般默认拒绝,明确写入允许的服务。
- 有一些服务有名字,有些服务没有名字。但是最终都是基于TCP或UDP的某些端口。比如http服务基于TCP80端口。服务名和端口号对应关系的说明文件是:/etc/services
- 配置服务器的防火墙,一般来说只要配置开放哪些服务或端口即可。没有明确开放的,都默认拒绝。
- 应用
- 在test组中的主机上安装并启动httpd
- 客户端访问服务器的http服务
- 在test组中的主机上安装并启动firewalld
- 客户端访问服务器的http服务
- 在test组中的主机上开放http服务
# 配置httpd服务
[root@control ansible]# vim firewall.yml
---
- name: configure test
hosts: test
tasks:
- name: install httpd pkg # 这里通过yum模块装httpd
yum:
name: httpd
state: present
- name: start httpd service # 这里通过service模块启httpd服务
service:
name: httpd
state: started
enabled: yes
[root@control ansible]# ansible-playbook firewall.yml
[root@control ansible]# curl http://192.168.4.11/ # 可访问
# 安装并启动firewalld
[root@control ansible]# vim firewall.yml
---
- name: configure test
hosts: test
tasks:
- name: install httpd pkg # 这里通过yum模块装httpd
yum:
name: httpd
state: present
- name: start httpd service # 这里通过service模块启httpd服务
service:
name: httpd
state: started
enabled: yes
- name: install firewalld pkg # 这里通过yum模块装firewalld
yum:
name: firewalld
state: present
- name: start firewalld service # 这里通过service模块启firewalld服务
service:
name: firewalld
state: started
enabled: yes
[root@control ansible]# ansible-playbook firewall.yml
[root@control ansible]# curl http://192.168.4.11/ # 被拒绝
curl: (7) Failed to connect to 192.168.4.11 port 80: 没有到主机的路由
# 配置防火墙规则,放行http协议
[root@control ansible]# vim firewall.yml
---
- name: configure test
hosts: test
tasks:
- name: install httpd pkg # 这里通过yum模块装httpd
yum:
name: httpd
state: present
- name: start httpd service # 这里通过service模块启httpd服务
service:
name: httpd
state: started
enabled: yes
- name: install firewalld pkg # 这里通过yum模块安装firewalld
yum:
name: firewalld
state: present
- name: start firewalld service # 这里通过service模块启service服务
service:
name: firewalld
state: started
enabled: yes
- name: set firewalld rules # 通过firewalld模块开放80端口
firewalld:
port: 80/tcp
permanent: yes
immediate: yes
state: enabled
[root@control ansible]# ansible-playbook firewall.yml
[root@control ansible]# curl http://192.168.4.11/ # 可访问
template模块
- copy模块可以上传文件,但是文件内容固定
- template模块可以上传具有特定格式的文件(如文件中包含变量)
- 当远程主机接收到文件之后,文件中的变量将会变成具体的值
- template模块上传的文件,使用的语法叫Jinja2。
- 常用选项:
- src:要上传的文件
- dest:目标文件路径
# 使用template模块将含有变量的文件上传到test组中的主机
[root@control ansible]# vim index.j2
Welcome to {{ansible_hostname}} on {{ansible_eth0.ipv4.address}}
[root@control ansible]# vim templ.yml
---
- name: upload index
hosts: test
tasks:
- name: create web index
template:
src: index.j2
dest: /var/www/html/index.html
[root@control ansible]# ansible-playbook templ.yml
[root@control ansible]# curl http://192.168.4.11/
Welcome to node1 on 192.168.4.11
[root@node1 ~]# cat /var/www/html/index.html
Welcome to node1 on 192.168.4.11
进阶语法
错误处理
- 当Playbook中包含很多任务时,当某一个任务遇到错误,它将崩溃,终止执行
# 在test组中的主机上启动mysqld服务,然后创建/tmp/service.txt
# 因为目标主机上没有mysqld服务,所以它将崩溃,终止执行。即,不会创建/tmp/service.txt文件
[root@control ansible]# vim myerr.yml
---
- name: my errors
hosts: test
tasks:
- name: start mysqld service # 通过service模块启动mysqld服务
service:
name: mysqld
state: started
enabled: yes
- name: touch a file # 通过file模块创建文件
file:
path: /tmp/service.txt
state: touch
# 执行playbook,第1个任务就会失败
[root@control ansible]# ansible-playbook myerr.yml
# 到node1上查看,因为第2个任务没有执行,所以文件不会创建
[root@node1 ~]# ls /tmp/service.txt
ls: cannot access '/tmp/service.txt': No such file or directory
- 可以指定某一个任务如果出现错误,则忽略它
# 编辑myerr.yml,如果myslqd服务无法启动,则忽略它
[root@control ansible]# vim myerr.yml
---
- name: my errors
hosts: test
tasks:
- name: start mysqld service
service:
name: mysqld
state: started
enabled: yes
ignore_errors: yes # 即使这个任务失败了,也要继续执行下去
- name: touch a file
file:
path: /tmp/service.txt
state: touch
[root@control ansible]# ansible-playbook myerr.yml
[root@node1 ~]# ls /tmp/service.txt # 第2个任务已执行
/tmp/service.txt
- 通过全局设置,无论哪个任务出现问题,都要忽略
[root@control ansible]# vim myerr.yml
---
- name: my errors
hosts: test
ignore_errors: yes
tasks:
- name: start mysqld service
service:
name: mysqld
state: started
enabled: yes
- name: touch a file
file:
path: /tmp/mysql.txt
state: touch
[root@control ansible]# ansible-playbook myerr.yml
[root@node1 ~]# ls /tmp/mysql.txt
/tmp/mysql.txt
触发执行任务
- 通过handlers定义触发执行的任务
- handlers中定义的任务,不是一定会执行的
- 在tasks中定义的任务,通过notify关键通知handlers中的哪个任务要执行
- 只有tasks中的任务状态是changed才会进行通知。
# 下载node1上的/etc/httpd/conf/httpd.conf
[root@control ansible]# vim get_conf.yml
---
- name: download httpd.conf
hosts: test
tasks:
- name: get httpd.conf
fetch:
src: /etc/httpd/conf/httpd.conf
dest: ./
flat: yes # 直接下载文件,不要目录
[root@control ansible]# ansible-playbook get_conf.yml
# 修改httpd.conf的端口为变量
[root@control ansible]# vim +45 httpd.conf
... ...
Listen {{http_port}}
... ...
# 修改httpd服务的端口为8000,重启httpd
[root@control ansible]# vim trigger.yml
---
- name: configure httpd
hosts: test
vars:
http_port: "8000" # 定义httpd.conf中的变量和值
tasks:
- name: upload httpd.conf # 上传httpd.conf
template:
src: ./httpd.conf
dest: /etc/httpd/conf/httpd.conf
- name: restart httpd # 重启服务
service:
name: httpd
state: restarted
# 第一次执行trigger.yml,上传文件和重启服务两个任务的状态都是黄色changed
[root@control ansible]# ansible-playbook trigger.yml
# 第二次执行trigger.yml,上传文件的任务状态是绿色的ok,重启服务任务的状态是黄色changed
[root@control ansible]# ansible-playbook trigger.yml
# 既然配置文件没有改变,那么服务就不应该重启
# 修改Playbook,只有配置文件变化了,才重启服务
[root@control ansible]# vim trigger.yml
---
- name: configure httpd
hosts: test
vars:
http_port: "80"
tasks:
- name: upload httpd.conf
template:
src: ./httpd.conf
dest: /etc/httpd/conf/httpd.conf
notify: restart httpd # 通知restart httpd需要执行
handlers:
- name: restart httpd
service:
name: httpd
state: restarted
# 第一次运行Playbook,因为第1个任务是黄色的changed,所以handlers中的任务也被触发执行
[root@control ansible]# ansible-playbook trigger.yml
# 第二次运行Playbook,因为第1个任务是绿色的OK,也就不会再触发执行其他任务了
[root@control ansible]# ansible-playbook trigger.yml
when条件
- 只有满足某一条件时,才执行任务
- 常用的操作符:
- ==:相等
- !=:不等
- >:大于
- <:小于
- <=:小于等于
- >=:大于等于
- 多个条件或以使用and或or进行连接
- when表达式中的变量,可以不使用{{}}
# 当test组中的主机内存大于2G的时候,才安装mariadb-server
[root@control ansible]# vim when1.yml
---
- name: install mariadb
hosts: test
tasks:
- name: install mariadb pkg
yum:
name: mariadb-server
state: present
when: ansible_memtotal_mb>2048
# 如果目标主机没有2GB内存,则不会安装mariadb-server
[root@control ansible]# ansible-playbook when1.yml
# 多条件。系统发行版是RedHat8才执行任务
# /etc/motd中的内容,将会在用户登陆时显示在屏幕上
[root@control ansible]# vim motd
_____________
< hello world >
-------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
[root@control ansible]# vim when2.yml
---
- name: when condition
hosts: test
tasks:
- name: modify /etc/motd
copy:
dest: /etc/motd
src: motd
when: > # 以下三行合并成一行
ansible_distribution == "RedHat"
and
ansible_distribution_major_version == "8"
[root@control ansible]# ansible-playbook when2.yml
cowsay:
[root@node1 ~]# yum install -y cowsay-3.04-4.el7.noarch.rpm
[root@node1 ~]# cowsay hello world # 默认是奶牛形象
[root@node1 ~]# cowsay -l # 查看可用形象
[root@node1 ~]# cowsay -f sheep hello world
[root@node1 ~]# cowsay -l > ss.txt
[root@node1 ~]# vim ss.txt # 删除第1行的说明
[root@node1 ~]# for i in $(cat ss.txt)
> do
> echo "--------------$i----------------"
> cowsay -f $i hello
> sleep 3
> echo "--------------------------------"
> done
任务块
可以通过block关键字,将多个任务组合到一起
可以将整个block任务组,一起控制是否要执行‘
例:如果test组中的主机系统发行版是RedHat,则安装并启动httpd
---
- name: block tasks
hosts: test
tasks:
- name: define a group of tasks
block:
- name: install httpd # 通过yum安装httpd
yum:
name: httpd
state: present
- name: start httpd # 通过service启动httpd服务
service:
name: httpd
state: started
enabled: yes
when: ansible_distribution=="RedHat" # 条件为真才会执行上面的任务
rescue和always
block和rescue,always联合使用
block中的任务出现失败(failed),rescue中的任务执行
block中的任务都成功,rescue中的任务不执行
block中的任务不管怎样,always中的任务忠实执行
---
- name: block test
hosts: test
tasks:
- name: block / rescue / always test1
block:
- name: touch a file
file:
path: /tmp/test1.txt
state: touch
rescue:
- name: touch file test2.txt
file:
path: /tmp/test2.txt
state: touch
always:
- name: touch file test3.txt
file:
path: /tmp/test3.txt
state: touch
执行后将会出现/tmp/test1.txt和/tmp/test3.txt
loop循环
相当于shell里的for循环
ansible中循环用到的变量名是固定的,叫item
例:在test组中的主机上创建5个目录/tmp/{aaa,bbb,ccc,ddd,eee}
---
- name: use loop
hosts: test
tasks:
- name: create directory
file:
path: /tmp/{{item}}
state: directory
loop: [aaa,bbb,ccc,ddd,eee]
也可以改进为:
---
- name: use loop
hosts: test
tasks:
- name: create directory
file:
path: /tmp/{{item}}
state: directory
loop:
- aaa
- bbb
- ccc
- ddd
- eee
例:使用复杂变量。创建zhangsan用户,密码是123;创建lisi用户,密码是456
item是固定的,用于表示循环中的变量
循环时,loop中每个-后面的内容作为一个整体赋值给item。
loop中{}中的内容是自己定义的,写法为key:val
取值时使用句点表示。如下例中取出用户名就是{{item.uname}}
---
- name: create users
hosts: test
tasks:
- name: create multiple users
user:
name: "{{item.uname}}"
password: "{{item.upass|password_hash('sha512')}}"
loop:
- {"uname": "zhangsan", "upass": "123"}
- {"uname": "lisi", "upass": "456"}
role角色
- 为了实现playbook重用,可以使用role角色
- 角色role相当于把任务打散,放到不同的目录中
- 再把一些固定的值,如用户名、软件包、服务等,用变量来表示
- role角色定义好之后,可以在其他playbook中直接调用
# 使用常规playbook,修改/etc/motd的内容
# 1. 修改默认配置
[root@control ansible]# vim ansible.cfg
[defaults]
inventory = hosts
# 2. 创建motd模板文件
[root@control ansible]# vim motd.j2
Hostname: {{ansible_hostname}} # facts变量,主机名
Date: {{ansible_date_time.date}} # facts变量,日期
Contact to: {{admin}} # 自定义变量
# 3. 编写playbook
[root@control ansible]# vim motd.yml
---
- name: modifty /etc/motd
hosts: test
vars:
admin: root@tedu.cn # 自定义名为admin的变量
tasks:
- name: modify motd
template:
src: motd.j2
dest: /etc/motd
[root@control ansible]# ansible-playbook motd.yml
[root@node1 ~]# cat /etc/motd
Hostname: node1
Date: 2021-11-01
Contact to: root@tedu.cn
# 创建角色
# 1. 声明角色存放的位置
[root@control ansible]# vim ansible.cfg
[defaults]
inventory = hosts
roles_path = roles # 定义角色存在当前目录的roles子目录中
# 2. 创建角色目录
[root@control ansible]# mkdir roles
# 3. 创建名为motd的角色
[root@control ansible]# ansible-galaxy init roles/motd
[root@control ansible]# ls roles/
motd # 生成了motd角色目录
[root@control ansible]# yum install -y tree
[root@control ansible]# tree roles/motd/
roles/motd/
├── defaults # 定义变量的目录,一般不用,因为优先级太低
│ └── main.yml
├── files # 保存上传的文件(如copy模块用到的文件)
├── handlers # handlers任务写到这个目录的main.yml中
│ └── main.yml
├── meta # 保存说明数据,如角色作者、版本等
│ └── main.yml
├── README.md # 保存角色如何使用之类的说明
├── tasks # 保存任务
│ └── main.yml
├── templates # 保存template模块上传的模板文件
├── tests # 保存测试用的playbook。可选
│ ├── inventory
│ └── test.yml
└── vars # 定义变量的位置,推荐使用的位置
└── main.yml
# 4. 将不同的内容分别写到对应目录的main.yml中
# 4.1 创建motd.j2模板文件
[root@control ansible]# vim roles/motd/templates/motd.j2
Hostname: {{ansible_hostname}}
Date: {{ansible_date_time.date}}
Contact to: {{admin}}
# 4.2 创建变量
[root@control ansible]# vim roles/motd/vars/main.yml # 追加一行
admin: zzg@tedu.cn
# 4.3 创建任务
[root@control ansible]# vim roles/motd/tasks/main.yml # 追加
- name: modify motd
template:
src: motd.j2 # 这里的文件,自动到templates目录下查找
dest: /etc/motd
# 5. 创建playbook,调用motd角色
[root@control ansible]# vim role_motd.yml
---
- name: modify motd with role
hosts: test
roles:
- motd
# 6. 执行playbook
[root@control ansible]# ansible-playbook role_motd.yml
- ansible的公共角色仓库:https://galaxy.ansible.com/
# 在公共仓库中搜索与httpd相关的角色
[root@zzgrhel8 ~]# ansible-galaxy search httpd
# 如果找到相应的角色,如名字为myhttpd,可以下载它到roles目录
[root@zzgrhel8 ~]# ansible-galaxy install myhttpd -p roles/
role练习
- 创建名为pkgs的角色。用于装包。包名使用变量pkg代表
- 创建inst_http.yml,调用pkgs角色,安装httpd
- 创建inst_php.yml,调用pkgs角色,安装php
# 1. 创建名为pkgs的角色。
# 1.1 创建角色目录
[root@control ansible]# ansible-galaxy init roles/pkgs
# 1.2 创建装包的任务,包名使用变量pkg代表
[root@control ansible]# vim roles/pkgs/tasks/main.yml
---
# tasks file for roles/pkgs
- name: install rpm pkg
yum:
name: "{{pkg}}"
state: present
# 1.3 定义变量
[root@control ansible]# vim roles/pkgs/defaults/main.yml
---
# defaults file for roles/pkgs
pkg: httpd
# 2. 创建inst_http.yml,调用pkgs角色,安装httpd
[root@control ansible]# vim inst_httpd.yml
---
- name: install httpd pkg
hosts: test
roles:
- pkgs
[root@control ansible]# ansible-playbook inst_httpd.yml
# 3. 创建inst_php.yml,调用pkgs角色,安装php
[root@control ansible]# vim inst_php.yml
---
- name: install php pkg
hosts: node2
vars:
pkg: php
roles:
- pkgs
[root@control ansible]# ansible-playbook inst_php.yml
ansible加解密文件
- ansible加解密文件使用ansible-vault命令
[root@control ansible]# echo "Hi ni hao" > hello.txt
[root@control ansible]# cat hello.txt
Hi ni hao
# 加密文件
[root@control ansible]# ansible-vault encrypt hello.txt
New Vault password: 123456
Confirm New Vault password: 123456
Encryption successful
[root@control ansible]# cat hello.txt
$ANSIBLE_VAULT;1.1;AES256
37373366353566346235613731396566646533393361386131313632306563633336333963373465
6164323461356130303863633964393339363738653036310a666564313832316263393061616330
32373133323162353864316435366439386266616661373936363563373634356365326637336165
6336636230366564650a383239636230623633356565623461326431393634656666306330663533
6235
# 解密
[root@control ansible]# ansible-vault decrypt hello.txt
Vault password: 123456
Decryption successful
[root@control ansible]# cat hello.txt
Hi ni hao
# 加密后更改密码
[root@control ansible]# ansible-vault encrypt hello.txt
New Vault password: 123456
Confirm New Vault password: 123456
Encryption successful
[root@control ansible]# ansible-vault rekey hello.txt # 改密码
Vault password: 123456 # 旧密码
New Vault password: abcd # 新密码
Confirm New Vault password: abcd
Rekey successful
# 不解密文件,查看内容
[root@control ansible]# ansible-vault view hello.txt
Vault password: abcd
Hi ni hao
# 使用密码文件进行加解密
# 1. 将密码写入文件
[root@control ansible]# echo 'tedu.cn' > pass.txt
# 2. 创建明文文件
[root@control ansible]# echo 'hello world' > data.txt
# 3. 使用pass.txt中的内容作为密码加密文件
[root@control ansible]# ansible-vault encrypt --vault-id=pass.txt data.txt
Encryption successful
[root@control ansible]# cat data.txt # 文件已加密
# 4. 使用pass.txt中的内容作为密码解密文件
[root@control ansible]# ansible-vault decrypt --vault-id=pass.txt data.txt
Decryption successful
[root@control ansible]# cat data.txt
hello world
sudo命令
- 一般用于普通用户执行需要root权限的命令
- 在node1上配置zhangsan拥有sudo权限
# 如果没有zhangsan,手工创建
[root@node1 ~]# visudo # 将会打开vi,在尾部追加以下一行
zhangsan ALL=(ALL) ALL
# 中间的ALL=(ALL)在集中认证的域环境中才有效,单机忽略即可
# zhangsan是用户名,最后的ALL表示zhangsan可以以管理员的身份执行所有命令
# 切换成zhangsan用户,执行命令
[root@node1 ~]# su - zhangsan
[zhangsan@node1 ~]$ useradd wangwu # 失败,因为还是张三身份
[zhangsan@node1 ~]$ sudo useradd wangwu # 以管理员身份执行
... ...
[sudo] password for zhangsan: # 输入zhangsan的密码,不是root
# 配置lisi不输入密码可以直接运行sudo
[root@node1 ~]# visudo # 在最后追加一行
lisi ALL=(ALL) NOPASSWD: ALL
# 切换成lisi运行
[root@node1 ~]# su - lisi
[lisi@node1 ~]$ ls /root/ # 没权限
ls: cannot open directory '/root/': Permission denied
[lisi@node1 ~]$ sudo ls /root/ # 成功运行,无需输入密码
a3.txt anaconda-ks.cfg
特殊的主机清单变量
- 如果远程主机没有使用免密登陆,如果远程主机ssh不是标准的22端口,可以设置特殊的主机清单变量
ansible_ssh_user
:指定登陆远程主机的用户名ansible_ssh_pass
:指定登陆远程主机的密码ansible_ssh_port
:指定登陆远程主机的端口号
# 删除远程主机的/root/.ssh/authorized_keys,以便恢复通过密码登陆
[root@control ansible]# ansible all -m file -a "path=/root/.ssh/authorized_keys state=absent"
# 创建新的工作目录
[root@control ~]# mkdir myansible
[root@control ~]# cd myansible
[root@control myansible]# vim ansible.cfg
[defaults]
inventory = hosts
[root@control myansible]# vim hosts
[group1]
node1
node2
node3
[root@control myansible]# ansible all -m ping # 报错,因为无法免密执行
# 修改node1 ssh服务的端口为220
[root@node1 ~]# systemctl stop firewalld
[root@node1 ~]# vim +17 /etc/ssh/sshd_config
Port 220
[root@node1 ~]# systemctl restart sshd
# 退出再登陆时,需要指定端口号
[root@zzgrhel8 ~]# ssh -p220 192.168.4.11
# 配置ssh通过用户名、密码管理远程主机,通过220端口连接node1
[root@control myansible]# vim hosts
[group1]
node1 ansible_ssh_user=root ansible_ssh_pass=a ansible_ssh_port=220
node2 ansible_ssh_user=root ansible_ssh_pass=a
node3 ansible_ssh_user=root ansible_ssh_pass=a
[root@control myansible]# ansible all -m ping