Playbook介绍
Playbook与ad-hc相比,是一种完全不同的运用ansible的方式,类似与saltstack的state状态文件。ad-hoc无法持久使用,playbook可以持久使用。playbook是由一个或多个play组成的列表,play的主要功能在于将事先归并为组的主机装扮成事先通过ansible中的task定义好的角色。从根本上来讲,所谓的task无非是调用ansible的一个module。将多个play组织在一个playbook中,即可以让它们联合起来按事先编排的机制完成某一任务
Ansible playbook使用场景
执行一些简单的任务,使用ad-hoc命令可以方便的解决问题,但是有时一个设施过于复杂,需要大量的操作的时候,执行的ad-hoc命令是不合适的,这时候最好使用playbook。
就像执行shell命令与写shell脚本一样,也可以理解为批处理任务,不过playbook有自己的语法格式
使用playbook可以方便的重复使用这些代码,可以移植到不同的机器上面,像函数一样,最大化的利用代码。在你使用Ansible的过程中,你也会发现,你所处理的大部分操作都是编写playbook。可以把常见的应用都编写playbook,之后管理服务器会变得很简单。
核心元素
- Hosts:主机组
- Tasks:任务列表
- Variables:变量,设置方式有四种
- Templates:包含了模块语法的文本文件
- Handlers:由特定条件触发的任务。
Playbook语法
playbook使用yaml语法格式,后缀可以是yaml,也可以是yml。
在单一一个playbook文件中,可以连续三个连子号(---)
区分多个play。还有选择性的连续三个点好(...)用来表示
play的结尾,也可省略。
次行开始正常写playbook的内容,一般都会写上描述该
playbook的功能。
使用#号注释代码。
缩进必须统一,不能空格和tab混用。
缩进的级别也必须是一致的,同样的缩进代表同样的级别程序判别配置的级别是通过缩进结合换行实现的
YAML文件内容和Liux系统大小写判断方式保持一致,是区分大小写的,k/v的值均需大小写敏感
k/v的值可同行写也可以换行写。同行使用:分隔。
ⅴ可以是个字符串,也可以是一个列表
一个完整的代码块功能需要最少元素包括name:task
Playbook的运行方式
通过ansible-playbook命令运行
格式:ansible--playbook<filename.yml>,.[options]
[root@ansible PlayBook]#ansible-playbook -h
#ansible-playbook常用选项:
--check or -C #只检测可能会发生的改变,但不真正执行操作
--list-hosts #列出运行任务的主机
--list-tags #列出playbook文件中定义所有的tags
--list-tasks #列出playbook文件中定义的所以任务集
--limit #主机列表只针对主机列表中的某个主机或者某个组执行
-f #指定并发数,默认为5个
-t #指定tags运行,运行某一个或者多个tags。(前提playbook中有定义tags)
-V #显示过程 -VV -vvv更详细
tasks任务列表
每一个task必须有一个名称name,这样在运行playbook时,从其输出的任务执行信息中可以很清楚的辨别是属于哪一个task的,如果没有定义name,action的值将会用作输出信息中标记特定的task。
每一个playbook中可以包含一个或者多个tasks任务列表,每一个tasks完成具体的一件事,(任务模块)比如创建一个用户或者安装一个软件等,在hosts中定义的主机或者主机组都将会执行这个被定义的tasks。
Handlers(动作)与 Notify(触发)
很多时候当我们某一个配置发生改变,我们需要重启服务,(比如httpd配置文件文件发生改变了)这时候就可以用到handlers和notify了:
(当发生改动时)notify actions会在playbook的每一个task结束时被触发,而且即使有多个不同task通知改动的发生,notify actions知会被触发一次:比如多个resources指出因为一个配置文件被改动,所以apache需要重启,但是重新启动的操作知会被执行一次。
Playbook示例
使用Playbook安装各种服务
使用本地yum源安装服务
[root@localhost ~]# vim httpd.yml
---
- hosts: web
remote_user: root
tasks:
- name: 编写本地yum源
yum_repository: name=local description="yum" baseurl=file:///mnt enabled=1 gpgcheck=0 file=yum
- name: 立即挂载
mount: src=/dev/cdrom path=/mnt fstype=iso9660 state="mounted"
- name: 开机自动挂载
mount: src=/dev/cdrom path=/mnt fstype=iso9660 state="present"
- name: 安装httpd服务
yum: name=httpd state=installed
- name: 配置httpd
template: src=/root/httpd.conf dest=/etc/httpd/conf/httpd.conf
notify:
- restart httpd
- name: 准备网站图片
copy: src=1.jpg dest=/var/www/html/
- name: 准备http页面
copy: content='<img src="1.jpg" />' dest=/var/www/html/index.html
- name: 启动httpd服务
systemd: name=httpd state=started enabled=yes
- name: 添加防火墙规则放行httpd服务
shell: firewall-cmd --add-port=80/tcp --permanent && firewall-cmd --add-port=443/tcp --permanent && firewall-cmd --reload
handlers:
- name: restart httpd
systemd: name=httpd state=restarted
编译安装nginx服务
---
- hosts: web
remote_user: root
tasks:
- name: 创建nginx用户
user: name=nginx
- name: 安装nginx依赖包
yum:
name:
- GeoIP-devel.x86_64
- gd-devel.x86_64
- libxslt-devel
- gcc
- gcc-c++
- autoconf
- automake
- zlib
- zlib-devel
- openssl
- openssl-devel
- pcre*
- name: 下载nginx源码包
get_url:
url: https://nginx.org/download/nginx-1.23.3.tar.gz
dest: /opt
- name: 创建目录
file:
path: /usr/local/nginx
state: directory
- name: 解压下载nginx源码包
shell: tar zxvf nginx-1.23.3.tar.gz -C /usr/src ; cd /usr/src/nginx-1.23.3 ; ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_stub_status_module && make && make install
- name: 编写系统启动脚本
template: src=nginx.service dest=/usr/lib/systemd/system/
- name: 启动nginx
systemd: name=nginx state=started enabled=yes
- name: 防火墙
shell: firewall-cmd --zone=public --add-port=80/tcp --permanent && firewall-cmd --reload
tags: firewalld
yum安装lnmp服务
[root@localhost ~]# cat yml/lnmp.yml
---
- hosts: lnmp
remote_user: root
tasks:
- name: 创建nginx用户
user: name=nginx system=yes shell=/sbin/nologin
- name: 搭建阿里云yum 源
shell: wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo && sed -i -e '/mirrors.cloud.aliyuncs.com/d' -e '/mirrors.aliyuncs.com/d' /etc/yum.repos.d/CentOS-Base.repo && wget -O /etc/yum.repos.d/epel.repo https://mirrors.aliyun.com/repo/epel-7.repo && yum makecache fast && yum clean all
- name: 搭建nginx yum源
yum_repository: name=nginx-stable description="nginx" baseurl=http://nginx.org/packages/centos/$releasever/$basearch/ gpgcheck=0 enabled=1 file=nginx
- name: 安装nginx服务
yum: name=nginx state=installed
- name: 启动nginx服务
systemd: name=nginx state=started enabled=yes
- name: 添加防火墙规则
shell: firewall-cmd --add-port=80/tcp --permanent && firewall-cmd --add-port=443/tcp --permanent && firewall-cmd --reload
- name: 创建mysql用户
user: name=mysql system=yes shell=/sbin/nologin
- name: 搭建mysql yum 源
yum_repository: name=mysql description="mysql" baseurl=https://mirrors.tuna.tsinghua.edu.cn/mysql/yum/mysql-5.7-community-el7-x86_64/ enabled=1 gpgcheck=0
- name: 安装mysql服务
yum: name=mysql-community-server.x86_64 state=installed
- name: 启动mysql服务
systemd: name=mysqld state=started enabled=yes
- name: 添加防火墙规则
shell: firewall-cmd --add-port=3306/tcp --permanent && firewall-cmd --reload
- name: 搭建php-fpm yum源
shell: yum install https://rpms.remirepo.net/enterprise/remi-release-7.rpm
- name: 安装 yum-utils 软件包的命令(用于 yum-config-manager 命令)
yum: name=yum-utils state=installed
- name: 启用存储库的命令
shell: yum-config-manager --disable 'remi-php*' && yum-config-manager --enable remi-php82 && yum-config-manager --enable remi-php82
tags: yum php
- name: 安装php-fpm服务
yum: name=php-fpm state=installed
- name: 安装php-mysql服务
yum: name=php-mysql state=installed
- name: 安装php-gd服务
yum: name=php-gd state=installed
- name: 启动php-fpm服务
systemd: name=php-fpm state=started enabled=yes
yum安装mysql
---
- hosts: mysql
remote_user: root
tasks:
- name: 创建mysql用户
user: name=mysql system=yes shell=/sbin/nologin
- name: 搭建mysql yum 源
shell: wget https://repo.mysql.com//mysql80-community-release-el7-7.noarch.rpm
- name: 下载mysql yum源
shell: yum -y install mysql80-community-release-el7-7.noarch.rpm
- name: 安装mysql服务
yum: name=mysql-community-server.x86_64 state=installed
- name: 启动mysql服务
systemd: name=mysqld state=started enabled=yes
- name: 添加防火墙规则
shell: firewall-cmd --add-port=3306/tcp --permanent && firewall-cmd --reload
安装zabbix_agentd端
---
- hosts: zabbix_agentd
remote_user: root
tasks:
- name: 搭建阿里云yum 源
shell: wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo && sed -i -e '/mirrors.cloud.aliyuncs.com/d' -e '/mirrors.aliyuncs.com/d' /etc/yum.repos.d/CentOS-Base.repo && wget -O /etc/yum.repos.d/epel.repo https://mirrors.aliyun.com/repo/epel-7.repo && yum makecache fast && yum clean all
tags: aliyun
- name: 创建zabbix组
group: name=zabbix state=present
- name: 创建zabbix用户
user: name=zabbix shell=/sbin/nologin system=yes group=zabbix
- name: 下载zabbix依赖包
yum: name=mysql-devel,net-snmp-devel,libevent-devel,curl-devel,libxml2,libxml2-devel state=installed
- name: 下载centos-release-scl
yum: name=centos-release-scl state=installed
tags: centos-release-scl
- name: 下载gcc
yum: name=devtoolset-9-gcc,devtoolset-9-gcc-c++,devtoolset-9-binutils state=installed
tags: gcc_install
- name: 临时升级gcc
shell: scl enable devtoolset-9 bash
- name: 永久升级gcc
shell: echo "source /opt/rh/devtoolset-9/enable" >>/etc/profile
- name: 下载zabbix安装包
shell: wget https://cdn.zabbix.com/zabbix/sources/stable/6.0/zabbix-6.0.13.tar.gz
- name: 创建zabbix目录
file: path=/usr/local/zabbix state=directory
- name: 配置zabbix
shell: tar zxvf zabbix-6.0.13.tar.gz -C /usr/src/
- name: config
shell: cd /usr/src/zabbix-6.0.13/ && ./configure --prefix=/usr/local/zabbix --enable-agent --enable-ipv6 --with-net-snmp --with-libcurl --with-libxml2 && make install
- name: pid存储位置
file: path=/usr/local/zabbix/pid state=directory owner=zabbix group=zabbix recurse=yes
tags: pid
- name: 创建zabbix日志存储位置
file: path=/usr/local/zabbix/logs state=directory owner=zabbix group=zabbix recurse=yes
tags: chown
- name: 复制系统启动脚本到agent
copy: src=/root/zabbix-agent.service dest=/usr/lib/systemd/system/zabbix-agent.service
- name: 配置zabbix-agent
template: src=/root/zabbix_agentd.conf dest=/usr/local/zabbix/etc/zabbix_agentd.conf
notify: restart zabbix-agent
tags: notify
- name: 启动zabbix-agent
systemd: name=zabbix-agent enabled=yes state=started
handlers:
- name: restart zabbix-agent
systemd: name=zabbix-agent state=restarted
tags: handlers
在本地编写系统启动脚本
[root@localhost ~]# vim zabbix-agent.service
[Unit]
Description=Zabbix Agent
After=syslog.target network.target network-online.target
Wants=network.target network-online.target
[Service]
Type=simple
User=root
ExecStart=/usr/local/zabbix/sbin/zabbix_agentd -c /usr/local/zabbix/etc/zabbix_agentd.conf
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
安装node_exporter
在本地编写启动脚本
[root@localhost ~]# vim node_exporter.service
[Unit]
Description=node_exporter
After=network.target
[Service]
User=prometheus
Group=prometheus
ExecStart=/usr/local/node_exporter/node_exporter --web.listen-address=:20001 --collector.systemd --collector.systemd.unit-whitelist=(sshd|nginx).service --collector.processes --collector.tcpstat
[Install]
WantedBy=multi-user.target
[root@localhost yml]# cat node_exporter.yml
---
- hosts: node_exporter
gather_facts: no
become: yes
become_method: sudo
tasks:
- name: 创建组
group: name=prometheus state=present
- name: 创建用户
user: name=prometheus shell=/sbin/nologin system=yes group=prometheus
- name: 解压安装包
unarchive:
src: /root/node_exporter-1.5.0.linux-amd64.tar.gz
dest: /opt
- name: mv
shell: mv /opt/node_exporter-1.5.0.linux-amd64 /usr/local/node_exporter
- name: 给授权目录
shell: chown -R prometheus:prometheus /usr/local/node_exporter/
- name: 将启动脚本发送到目标主机
copy: src=/root/node_exporter.service dest=/usr/lib/systemd/system/node_exporter.service
- name: 重新加载启动脚本
systemd:
daemon_reload: yes
- name: 启动node_exporter
systemd: name=node_exporter enabled=yes state=started
- name: 添加防火墙规则
shell: firewall-cmd --add-port=20001/tcp --permanent && firewall-cmd --reload
filebeat安装脚本
[root@localhost yml]# cat filebeat.yml
---
- hosts: node_exporter
become: yes
become_method: sudo
tasks:
- name: 下载并安装公共签名秘钥
shell: sudo rpm --import https://packages.elastic.co/GPG-KEY-elasticsearch
- name: 搭建filebeat YUM仓库
yum_repository: name=elastic-8.x description="Elastic repository for 8.x packages" baseurl=https://artifacts.elastic.co/packages/8.x/yum enabled=1 gpgcheck=0
- name: 安装filebeat服务
yum: name=filebeat state=installed
- name: 配置filebeat配置文件
template: src=/root/filebeat.yml dest=/etc/filebeat/
notify:
- restart filebeat
tags: notify
- name: 启动filebeat
systemd: name=filebeat state=started enabled=yes
handlers:
- name: restart filebeat
systemd: name=filebeat state=restart
tags: handlers
palybook文件中定义变量
---
- hosts: web
vars:
pkg: httpd
remote_user: root
tasks:
- name: Install Apache
yum: name={{ pkg }} state=installed
调用setup模块获取变量
setup模块默认是获取主机信息的,有的时候在playbook中需要用到,所以可以直接调用,常用的参数之前的setup模块
---
- hosts: web
remote_user: root
tasks:
- name: create file
file: name=/root/{{ ansible_all_ipv4_addresses }} state=touch
执行后,可以在被控端设备上,创建以该设备IP地址命名的文件。
独立的变量文件
为了方便管理将所有的变量统一放在一个独立的变量YAML文件中,playbook文件直接引用文件调用变量即可
定义存放变量的文件
var1: vsftpd
var: httpd
---
- hosts: web
remote_user: root
vars_files:
- ./var.yml
tasks:
- name: install vsftpd
yum: name={{ var1 }}
- name: install httpd
yum: name={{ var2 }}
Playbook中标签的使用
一个playbook 文件中,执行时如果想执行某一个任务,那么可以给每个任务集进行打标签,这样在执行的时候可以通过-t 选择指定标签执行,还可以通过--skip-tags 选择除了某个标签外全部执行等。
---
- hosts: web
remote_user: root
vars_files:
- ./var.yml
tasks:
- name: install vsftpd
yum: name={{ var1 }}
tags: install vsftpd
- name: install httpd
yum: name={{ var2 }}
通过-t指定tags名称,多个tags用逗号隔开
[root@localhost ~]# ansible-playbook httpd.yml -t install_vsftpd
通过--skip-tags选项排除不执行的tags
[root@localhost ~]# ansible-playbook --skip-tags install_vsftpd httpd.yml
Playbook中模板的使用
Ansible的Playbook支持Template模板的使用,Template模板在运用时与copy模块类似,区别在于可以在Ansible的Playbook执行的时候,根据一定的条件灵活的设置要复制文件中的部分关键内容。同时,Ansible的Playbook中关于Template的使用支持条件判断、循环、逻辑运算、比较等内容,增强了配置的灵活性。在Ansible中,Templat模板使用jinjia2语言进行配置,模板文件的后缀名为.j2。
说明:
1、多数情况下都将 template 文件放在和playbook 文件同级的 templates 目录下(手动创建),这样 playbook 文件中可以直接引用,会自动去找这个文件。如果放在别的地方,也可以通过绝对路径去指定。
2、模板文件后缀名为.j2。
---
- hosts: web
remote_user: root
vars:
- listen_port: 8000
tasks:
- name: install httpd
yum: name=httpd state=installed
- name: config httpd
template: src=httpd.conf dest=/etc/httpd/conf/httpd.conf
notify: restart httpd
- name: start httpd
systemd: name=httpd state=started
handlers:
- name: restart httpd
systemd: name=httpd state=restarted
模板文件准备,httpd配置文件准备,这里配置文件端口使用了变量
[root@localhost ~]# cat httpd.conf | grep ^Listen
Listen {{ listen_port }}
看客户端httpd的端口号
[root@localhost ~]# netstat -anptu | grep httpd
tcp6 0 0 :::8000 :::* LISTEN 37810/httpd
template之when
Ansible Template的when语句可以用于条件测试,when的引入可以使得Ansible的Playbook根据不同的条件执行不同的命令
---
- hosts: web
remote_user: root
tasks:
- name: Install Apache
yum: name=httpd state=installed
- name: Config CentOS6 Apache
copy: src=/etc/ansible/centos6_httpd.conf dest=/etc/httpd/conf/httpd.conf
when: ansible_distribution_major_version == "6"
- name: Config CentOS7 Apache
copy: src=/etc/ansible/centos7_httpd.conf dest=/etc/httpd/conf/httpd.conf
when: ansible_distribution_major_version == "7"
- name: Start Apache
systemd: name=httpd state=started
template之with_items
Ansible还支持使用迭代的变量,迭代的数据类型可以是列表或者是字典
---
- hosts: web
remote_user: root
tasks:
- name: Greate new group
group: name={{ item }} state=present
with_items:
- group1
- group2
- group3
- name: Greate new user
user: name={{ item.user }} group ={{ item.group }} state=present
with_items:
- { user: "user1", group: "group1"}
- { user: "user2", group: "group2"}
- { user: "user3", group: "group3"}
template之for
---
- hosts: web
remote_user: root
vars:
nginx_vhosts:
- vhost1:
port: 81
server_name: "web1.lzz.com"
root: "/var/www/nginx/web1"
- vhost2:
port: 82
server_name: "web2.lzz.com"
root: "/var/www/nginx/web2"
- vhost3:
port: 83
server_name: "web3.lzz.com"
root: "/var/www/nginx/web3"
tasks:
- name: install Nginx
yum: name=nginx state=installed
- name: config nginx
template: src=nginx.conf dest=/etc/nginx/nginx.conf
- name: Start Nginx
systemd: name=nginx state=started
nginx.conf模板文件部分如下:
{% for vhost in nginx_vhosts %}
server{
{% if vhost.port is defined%}
listen {{ vhost.port }};
{% else %}
listen 88;
{% endif %}
server_name {{ vhost.server_name }};
root {{ vhost.root }};
}
{% endfor %}