前提提要:此文是https://blog.csdn.net/kali_yao/article/details/119983133进阶板
目录
5.always语句定义无论block任务是否成功,都要执行的任务
Ansible ad-hoc可以通过命令行形式远程管理其他主机,适合执行一些临时性简单任务。另外还有一种远程管理的方式叫Playbook,Ansible Playbook中文名称叫剧本,它将经常需要执行的任务写入一个文件,这个文件就叫剧本。
一.ploybook的介绍及用法介绍
1. Ploubook的概述:
剧本中可以包含多个任务
剧本写后,我们随时根据剧本,执行相关的任务命令
Playbook剧本要求按照YAML格式编写
适合执行周期性经常执行的复杂任务
2.YAML是什么?
YAML是一个可读性高、用来表达数据序列的格式语言
YAML:YAML Ain't a Markup Language
YAML以数据为中心,重点描述数据的关系和结构
YAML的格式要求如下:
"#"代表注释,一般第一行为三个横杠(---)
键值(key/value)对使用":"表示,数组使用"-"表示,"-"后面有空格
key和value之间使用":"分隔,":"后面必须有空格
一般缩进由两个或以上空格组成
相同层级的缩进必须对齐,缩进代表层级关系
全文不可以使用tab键
区分大小写
扩展名为yml或者yaml
跨行数据需要使用>或者|,其中|会保留换行符
YAML 官方网站:http://www.yaml.org
3.Playbook语法格式要求如下:
playbook采用YAML格式编写
playbook文件中由一个或多个play组成每个play中可以包含: hosts(主机)、tasks(任务)、vars(变量)等元素组成
使用ansible-playbook命令运行playbook剧本
二.用法案例
1.编写第一个Playbook(剧本)
hosts、tasks、name是关键词(不可修改),ping是模块,调用不同模块完成不同任务。
vim ~/ansible/test.yml --- - hosts: all #hosts定义要远程谁? tasks: #tasks定义远程后要执行的任务有哪些? - name: This is my first playbook #name后面的具体内容可以任意 ping:
ansible-playbook ~/ansible/test.yml #运行
ansible-playbook ~/ansible/test.yml --check #只检测不运行
2.用户管理,创建系统账户、账户属性、设置密码
vim ~/ansible/test_john.yml
---
- hosts: webserver
tasks:
- name: Add the user 'johnd'
user:
name: johnd
uid: 1040
group: daemon
shell: /bin/bash
groups: bin,adm
password: "{{ '123' | password_hash('sha512') }}"
3.使用playbook管理逻辑卷
vim ~/ansible/lvm.yml
---
- hosts: node2 #远程node2主机
tasks:
- name: Create a new primary partition with a size of 1GiB #任务的描述信息
parted: #调用parted模块进行分区
device: /dev/vdb #对/dev/vdb磁盘进行分区(磁盘名称不要照抄)
label: gpt #分区表类型为gpt,或msdos
number: 1 #分区编号(创建第几个分区)
state: present #present是创建分区,absent是删除分区
part_start: 1MiB #分区的开始位置(默认从最开始位置分区)
part_end: 1GiB #分区的结束位置(不写就分到磁盘最后位置)
- name: Create a volume group on top of /dev/vdb1 #第二个任务的描述信息
lvg: #调用lvg模块,创建VG卷组
vg: my_vg #要创建的卷组名称
pvs: /dev/vdb1 #使用哪个分区创建PV
- name: Create a logical volume of 512m #第三个任务的描述信息
lvol: #调用lvol模块创建LV
vg: my_vg #使用哪个VG创建LV
lv: my_lv #需要创建的LV名称
size: 512m #要创建的LV大小,可以不指定单位,默认单位m
- filesystem: #格式化分区
fstype: ext4 #格式化类型
dev: /dev/sdb1 #哪块磁盘
force: true #强制执行
4.使用playbook管理软件
---
- hosts: webserver #需要远程的主机是谁
tasks: #定义剧本需要执行的任务
- name: Install a list of packages #第一个任务的描述信息
yum: #调用yum模块安装软件
name: #安装软件的名字,它的值有多个,使用数组-
- httpd #安装httpd软件
- mariadb #安装mariadb软件
- mariadb-server #安装mariadb-server
- name: install the 'RPM Development Tools' package group #第二个任务的描述信息
yum: #调用yum模块安装软件组包
name: "@RPM Development Tools" #安装哪个组包,@是关键词
- name: update software #第三个任务的描述信息
yum: #调用yum模块升级软件
name: '*' #需要升级哪些软件
state: latest #latest代表升级软件
5.firewalld模块配置防火墙策略
---
- hosts: test #hosts定义需要远程的主机
tasks: #tasks定义需要执行哪些任务
- name: install firewalld. #name为第一个任务定义描述信息
yum: #第一个任务调用yum模块安装软件
name: firewalld #需要安装的软件名称为firewalld
state: present #state等于present代表安装软件
- name: run firewalld. #定义第二个任务的描述信息
service: #第二个任务调用service模块启动服务
name: firewalld #启动的服务名称为firewalld
state: started #state等于started代表启动服务
enabled: yes #enabled等于yes是设置服务为开机自启动
- name: set firewalld rule. #第三个任务的描述信息
firewalld: #第三个任务调用firewalld模块设置防火墙规则
port: 80/tcp #在防火墙规则中添加一个放行tcp,80端口的规则
permanent: yes #permanent 是设置永久规则
immediate: yes #immediate 是让规则立刻生效
state: enabled #state等于enabled是添加防火墙规则
6.template模块
copy模块可以将一个文件拷贝给远程主机,但是如果希望每个拷贝的文件内容都不一样呢?如何给所有web主机拷贝index.html内容是各自的IP地址?
Ansible可以利用Jinja2模板引擎读取变量,之前在playbook中调用变量,也是Jinja2的功能,Jinja2模块的表达式包含在分隔符"{{ }}"内。
vim ~/ansible/index.html #创建一个文件并写入内容 Welcome to {{ansible_hostname}} on {{ ansible_eth0.ipv4.address }}. vim ~/ansible/template.yml --- - hosts: webserver tasks: - name: use template copy index.html to webserver. template: #拷贝文件 src: ~/ansible/index.html #原文件 dest: /tmp/index.html #目标
7.Ansible变量应用案例
1)setup模块
ansible_facts用于采集被管理设备的系统信息,所有收集的信息都被保存在变量中,每次执行playbook默认第一个任务就是Gathering Facts,使用setup模块可以查看收集到的facts信息。也就是所有环境变量
ansible test -m setup
2)debug模块
debug模块可以显示变量的值,可以辅助排错,通过msg可以显示变量的值,变量需要使用{{}}扩起来。
--- - hosts: test tasks: - debug: msg: "主机名是:{{ ansible_hostname }}" - debug: msg: "总内存大小:{{ ansible_memtotal_mb }}"
8.定义变量的方法
Ansible支持十几种定义变量的方式,这里我们仅介绍其中一部分变量。
下面是根据优先级排序的定义方式:
Inventory变量 指定主机清单的变量
Host Facts变量 主机事实变量
Playbook变量 剧本里的变量
变量文件 优先集先从变量文件开始
1))Inventory变量(在主机清单配置文件中定义变量)清单不是yml格式。
vim ~/ansible/inventory [test] node1 iname="nb" [proxy] node2 [webserver] node[3:4] [webserver:vars](不可改变的变量) iname="dachui"
--- - hosts: node1,webserver #定义需要远程管理的主机是谁 tasks: #剧目要完成哪些任务 - name: create a user with var. #剧目中的第一个任务描述信息 user: #调用user模块创建用户 name: "{{ iname }}" #需要创建的用户名是iname这个变量
#在ansible剧本中当调用变量时,开始位置就调用变量,就需要在{{}}外面加双引号
#如果是在后面或者中间位置调用变量{{}}外面可以不加双引号,也可以加双引号
2)Host Facts变量(可以直接调用ansible收集的系统信息)
--- - hosts: test tasks: - name: create user. user: name: "{{ansible_hostname}}"
#定义剧本,远程所有被管理主机,调用user模块,创建用户
#需要创建的用户名ansible_hostname是一个ansible_facts变量
3)Playbook变量(使用vars关键词可以在playbook内定义变量)
--- - hosts: test vars: #vars是关键词,用来定义变量用的 iname: heal #具体变量名是iname,值是heal ipass: '123456' #再定义一个变量名是ipass,值是123456 #注意密码必须是字符串,需要引号 tasks: #tasks定义需要执行的任务 - name: Use variables create user. #给任务写个描述信息 user: #调用user模块创建用户 name: "{{ iname }}" #用户名的是前面定义的变量 password: "{{ ipass | password_hash('sha512') }}"
4)单独定义个变量文件
vim ~/ansible/variables.yml --- iname: cloud ipass: '123456'
在playbook中用vars_files调用该文件
--- - hosts: test vars_files: variables.yml #当变量比较多时,专门定义一个文件用来存变量 tasks: - name: create user. user: name: "{{ iname }}" password: "{{ ipass | password_hash('sha512') }}"
三.Ansible高级语法应用
1.error错误处理
默认ansible在遇到error会立刻停止playbook,使用ignore_errors可以忽略错误,继续后续的任务。
--- - hosts: test tasks: - name: start a service that does not exist. service: name: hehe state: started ignore_errors: true #针对某一个任务忽略错误(ignore_errors是关键词) - name: touch a file. # ignored=1(忽略1个) file: path: /tmp/service.txt state: touch
--- - hosts: test ignore_errors: true #针对playbook全局忽略错误 tasks: - name: start a service that does not exist. service: name: hehe state: started - name: touch a file. file: path: /tmp/service.txt state: touch
2.handlers
在剧本中tasks用来定义任务(一定会执行),handlers也可以定义任务(不一定执行),handlers任务要想执行必须要被别人触发才能执行
--- - hosts: test tasks:(一定安顺序执行) - 任务1 notify:任务5(仅当第一个执行且为黄色再执行【绿色不行】) - 任务2 handlers:(不一定执行)(仅当前面执行且为黄色再执行【绿色不行】) - 任务5(当任务相同只执行一次而且是在tasks执行完后再执行) - 任务6
3.when条件判断
when可以定义判断条件,条件为真时才执行某个任务。 常见条件操作符有:==、!=、>、>=、<、<=。多个条件可以使用and(并且)或or(或者)分割,when表达式中调用变量不要使用{{ }}。
--- - hosts: test tasks: - name: check memory size. service: name: NetworkManager state: stopped when: ansible_memfree_mb < 700
#被管理端主机剩余内存不足700M则关闭NetworkManager服务(也可以关闭别的不需要的服务)skipped=1(跳过一个)
4.block任务块
如果我们需要当条件满足时执行N个任务,我们可以给N个任务后面都加when判断(但是很麻烦),此时可以使用block定义一个任务块,当条件满足时执行整个任务块.
任务块就是把一组任务合并为一个任务组,使用block语句可以将多个任务合并为一个任务组。
--- - hosts: test tasks: - name: define a group of tasks. block: #block是关键词,定义任务组 - name: install httpd #任务组中的第一个任务 yum: #调用yum模块安装httpd软件包 name: httpd state: present - name: start httpd #任务组中的第二个任务 service: #调用service模块启动httpd服务 name: httpd state: started when: ansible_distribution == "RedHat" #仅当条件满足再执行任务组
注意:when和block是对齐的,他们在一个级别,当条件满足时要执行的是任务组(不是某一个任务)
5.always语句定义无论block任务是否成功,都要执行的任务
---
- hosts: test
tasks:
- block:
- name: touch a file test1.txt
file:
name: /tmp/test1.txt #如果修改为/tmp/xyz/test1.txt就无法创建成功
state: touch
rescue:(block成功则rescue失败)(反之即可)
- name: touch a file test2.txt
file:
name: /tmp/test2.txt
state: touch
always:(总是执行)
- name: touch a file test3.txt
file:
name: /tmp/test3.txt
state: touch
主:Ansible从上到下执行
6.loop循环
相同模块需要反复被执行怎么处理?使用loop循环可以避免重复
--- - hosts: test tasks: - name: mkdir multi directory. file: path=/tmp/{{item}} #注意,item是关键字,调用loop循环的值 state=directory (目前版本还是可以这么写的) loop: #loop是关键词,定义循环的值,下面是具体的值 - School - Legend - Life
四.Ansible Roles角色
1.roles的简介
为了实现不同的功能,我们会编写大量的playbook文件。而且,每个playbook还可能会调用其他文件(如变量文件),对于海量的、无规律的文件,管理起来非常痛苦!
Ansible从1.2版本开始支持Role,Role是管理ansible文件的一种规范(目录结构),Role(角色)会按照标准的规范,自动到特定的目录和文件中读取数据。
如果我们创建了一个名称为user.example的Role(角色),则其标准的目录结构如下
2.roles目录介绍
defualts/main.yml :定义变量的缺省值,优先级较低
vars/main.yml :定义变量,优先级高
files目录 :存储静态文件的目录,如tar包、音乐、视频等
templates目录 :存放动态数据文件的地方(文件中包含了变量的模板文件)
meta/main.yml :写作者、版本等描述信息
README.md :整个角色(role)的描述信息
handlers/main.yml :定义handlers
tasks/main.yml :定义任务的地方
3.创建一个简单的roles
公共Roles仓库(https://galaxy.ansible.com)管理
1)创建目录
mkdir ~/ansible/roles
2)创建角色
使用ansible-galaxy install可以直接下载Role,也可以编写requirements.yml文件下载Role。
如:直接 ansible-galaxy init ~/ansible/roles/issue
剧本
#格式一:可以直接从Ansible Galaxy官网下载 - src: acandid.httpd #格式二:可以从某个git服务器下载 - src: http://gitlab.com/xxx/xxx.git scm: git version: 56e00a54 name: nginx-acme #格式三:可以指定位置下载tar包,支持http、https、file - src: http://example.com/myrole.tar name: myrole [root@control ansible]# ansible-galaxy install \ -r ~/ansible/roles/requirements.yml \ -p roles # -r后面跟文件名,该文件中包含了需要下载哪些role以及他们的链接位置 # -p 指定将下载的role保存到哪个目录
4.写一个稍微难一点的rodes(自动部署Web集群)
1)创建role角色
ansible-galaxy init ~/ansible/roles/http
2)修改roles配置文件,准备2台http网站的素材
vim roles/http/tasks/main.yml --- - name: install httpd yum: name: httpd state: present - name: create index.html copy: content: "{{ansible_hostname}}"(不拷贝文件拷贝内容)(等同于剧本先读取变量成直) dest: /var/www/html/index.html - name: set firewalld firewalld: service: http state: enabled permanent: yes immediate: yes - name: start httpd service: name: httpd state: started enabled: yes
#文件中包含多个任务,每个任务可以设置一个name名字(也可以没有name)
#第一个任务调用yum模块安装httpd软件包
#第二个任务调用copy模块创建一个新的网页文件(index.html)
#调用copy模块时可以在没有源文件的情况下,直接使用content指定文件的内容
#将该内容直接拷贝到被管理主机的某个文件中(/var/www/html/index.html)
#第三个任务调用firewalld模块,设置防火墙规则,允许访问http服务
#第四个任务调用service模块将httpd服务启动,并设置开机自启。
3)编写Playbook调用role,并执行Playbook。
vim web.yml --- - hosts: webserver roles: - http [root@control ansible]# ansible-playbook web.yml
4)部署nginx代理服务器
(1) 创建roles角色
ansible-galaxy init ~/ansible/roles/proxy
(2) 准备代理服务器需要的素材并安装
vim ~/ansible/roles/proxy/files/nginx_install.sh #!/bin/bash dnf -y install net-tools psmisc gcc make pcre-devel openssl-devel wget https://sourceforge.net/projects/pcre/files/pcre/8.35/pcre-8.35.tar.gz/download?use_mirror=udomain
(3)新建一个Nginx代理服务器的配置文件模板
vim ~/ansible/roles/proxy/files/nginx.conf worker_processes 2; #error_log logs/error.log; events { worker_connections 65535; } http { include mime.types; default_type application/octet-stream; sendfile on; tcp_nopush on; keepalive_timeout 65; #gzip on; upstream webs { server 192.168.4.13; server 192.168.4.14; } server { listen 80; server_name localhost; location / { proxy_pass http://webs; root html; index index.html index.htm; } error_page 404 /404.html; error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } }
(4)修改role配置文件
vim roles/proxy/tasks/main.yml --- - name: install nginx through shell script. script: nginx_install.sh args: creates: /usr/local/nginx/sbin/nginx - name: copy nginx.conf to destination host. copy: src: nginx.conf dest: /usr/local/nginx/conf/nginx.conf - name: run nginx service. shell: /usr/local/nginx/sbin/nginx args: creates: /usr/local/nginx/logs/nginx.pid #nginx.pid存在,说明nginx已经启动。如果该文件存在,则不再启动nginx。 - name: set firewalld firewalld: service: http state: enabled permanent: yes immediate: yes
#执行源码编译安装脚本,如果已经安装nginx,则不再执行安装脚本.
#args是关键词,设置script模块的参数,通过creates参数做判断,creates也是关键词 #creates后面跟文件名,如果creates判断文件存在的话就不再执行script模块对应的命令。
(5)编写Playbook调用role,并执行Playbook
[root@control ansible]# vim proxy.yml --- - hosts: proxy roles: - proxy [root@control ansible]# ansible-playbook proxy.yml