前言
1.什么是ansible playbook?
Playbooks是一种完全不同的运用Ansible的方式,而且是非常之强大的;也是系统ansible命令的集合,其利用yaml语言编写,运行过程,ansbile-playbook命令根据自上而下的顺序依次执行。
简单来说,Playbooks 是一种简单的配置管理系统与多机器部署系统的基础。与现有的其他系统有不同之处,且非常适合于复杂应用的部署。
同时,Playbooks开创了很多特性,它可以允许你传输某个命令的状态到后面的指令,如你可以从一台机器的文件中抓取内容并附为变量,然后在另一台机器中使用,这使得你可以实现一些复杂的部署机制,这是ansible命令无法实现的。
Playbooks可用于声明配置,更强大的地方在于,在Playbooks中可以编排有序的执行过程,甚至于做到在多组机器间,来回有序的执行特别指定的步骤。并且可以同步或异步的发起任务。
我们使用Ad-Hoc时,主要是使用 /usr/bin/ansible 程序执行任务.而使用Playbooks时,更多是将之放入源码控制之中,用之推送你的配置或是用于确认你的远程系统的配置是否符合配置规范。
2.playbook的语言格式
playbooks 的格式是yaml,语法做到最小化,意在避免 playbooks 成为一种编程语言或是脚本,但它也并不是一个配置模型或过程的模型。
playbook是由一个或多个“play”组成的列表。play的主要功能在于将事先归并为一组的主机装扮成事先通过Ansible中的tasks定义好的角色(play的内容被称为tasks,即任务)。从根本上来讲所谓tasks无非是调用Ansible的一个module。将多个“play”组织在一个playbook中即可以让它们联同起来按事先编排的机制一同工作。
“plays”算是一个类比,可以通过多个plays告诉系统做不同的事情,不仅是定义一种特定的状态或模型。也可以在不同时间运行不同的plays。
playbook文件开头为 —;这是YAML将文件解释为正确的文档的要求。YAML允许多个“文档”存在于一个文件中,每个“文档”由 — 符号分割,但Ansible只需要一个文件存在一个文档即可,因此这里需要存在于文件的开始行第一行。
YAML对空格非常敏感,并使用空格来将不同的信息分组在一起,在整个文件中应该只使用空格而不使用制表符,并且必须使用一致的间距,才能正确读取文件。相同缩进级别的项目被视为同级元素。
以 - 开头的项目被视为列表项目。作为散列或字典操作,它具有key:value格式的项。YAML文档基本上定义了一个分层的树结构,其中位于左侧是包含的元素。YAML文件扩展名通常为.yaml或者.yml。
3.playbook的构成
Playbook主要有以下四部分构成:
- target section:定义将要执行playbook的远程主机组
- variable section:定义playbook运行时需要使用的变量
- task section:定义将要在远程主机上执行的任务列表
- handler section:定义task执行完成以后需要调用的任务
而Playbook对应的目录层有五个,分别如下:
一般所需的目录层有:(视情况可变化)
- vars 变量层
- tasks 任务层
- handlers 触发条件
- files 文件
- template 模板
下面我们开始playbook文件的编写
1.实验环境
首先你需要部署好ansible,这里用的是前面部署好的环境,具体可参考博客:https://blog.csdn.net/meltsnow/article/details/95998573
2.修改vim编辑
我们在前面说过yaml文件的格式对空格时很敏感的,一般需要顶格书写,段落划分为两个空格,所以为了我们的书写习惯,我们修改.vimrc的形式,让我们的tab键一次时两个空格,方便我们的书写习惯。
[devops@server1 ansible]$ cd ..
[devops@server1 ~]$ ls
ansible
[devops@server1 ~]$ vim .vimrc
[devops@server1 ~]$ cat .vimrc
autocmd filetype yaml setlocal ai ts=2 sw=2
[devops@server1 ~]$
这样更改后我们的devops的家目录地下的全部文件的vim编写tab键就都是两个空格了
3.编写playbook文件,自动安装httpd
[devops@server1 ~]$ cd ansible/
[devops@server1 ansible]$ mkdir file
[devops@server1 ansible]$ cd file/
[devops@server1 file]$ scp server2:/etc/httpd/conf/httpd.conf .
httpd.conf 100% 11KB 11.5KB/s 00:00
[devops@server1 file]$ ll
total 12
-rw-r--r-- 1 devops devops 11753 Jul 16 01:38 httpd.conf
[devops@server1 file]$ cd ..
[devops@server1 ansible]$ pwd
/home/devops/ansible
[devops@server1 ansible]$
[devops@server1 ansible]$ vim playbook.yml
[devops@server1 ansible]$ cat playbook.yml
---
# deploy apache
- hosts: webservers
tasks:
- name: install httpd 安装httpd
yum:
name: httpd
state: latest
- name: create index.html 书写默认发布界面
copy:
content: "www.ljz.org\n"
dest: /var/www/html/index.html
- name: configure httpd 指定httpd的默认配置文件
copy:
src: file/httpd.conf
dest: /etc/httpd/conf/httpd.conf
owner: root
group: root
mode: 644
notify: restart httpd 设置触发器,当更改httpd.conf就触发
- name: start httpd 启动httpd
service:
name: httpd
state: started
enabled: true
handlers: 触发器,那么一定要和前面的notify后面的一致
- name: restart httpd
service:
name: httpd
state: restarted
测试:
[devops@server1 ansible]$ ansible-playbook playbook.yml --syntax-check ##语法检测
playbook: playbook.yml
[devops@server1 ansible]$ ansible-playbook playbook.yml ##执行playbook里的内容
更改配置文件,设置端口为8080(测试触发器)
[devops@server1 ansible]$ md5sum file/httpd.conf
04e9239e7bd5d5b9b85864226d60eee5 file/httpd.conf
[devops@server1 ansible]$ vim file/httpd.conf
Listen 8080
[devops@server1 ansible]$ md5sum file/httpd.conf
04e9239e7bd5d5b9b85864226d60eee5 file/httpd.conf
[devops@server1 ansible]$ ansible-playbook playbook.yml
如果在更改端口的后,执行playbok出现了 TASK [configure httpd] 的报错,如下图,那你需要检查以下是否是触发器写错了
4.添加自动部署防火墙的功能(在前面写过的playbook中添加)
[devops@server1 ansible]$ vim playbook.yml
---
# deploy apache
- hosts: webservers
tasks:
- name: install httpd
yum:
name: httpd
state: latest
- name: create index.html
copy:
content: "www.peng.org\n"
dest: /var/www/html/index.html
- name: configure httpd
copy:
src: file/httpd.conf
dest: /etc/httpd/conf/httpd.conf
owner: root
group: root
mode: 644
notify: restart httpd
- name: start httpd
service:
name: httpd
state: started
enabled: true
- name: start firewalld
service:
name: firewalld
state: started
enabled: true
- name: configure firewalld
firewalld:
service: http
state: enabled
permanent: yes
immediate: yes
handlers:
- name: restart httpd
service:
name: httpd
state: restarted
[devops@server1 ansible]$ vim playbook.yml
[devops@server1 ansible]$ ansible-playbook playbook.yml --syntax-check
playbook: playbook.yml
[devops@server1 ansible]$ vim file/httpd.conf ##将端口改回80,或者在火墙策略中添加允许8080端口
[devops@server1 ansible]$ ansible-playbook playbook.yml
在火墙开启的情况下仍能访问apache服务
二、通过变量名修改服务参数
我们在日常的生产中有些时候或许因为一些原因,我们的一些参数会发生变化,那么我们就需要变量的方式更改节点的信息,这些信息我们可以通过ansible node -m setup查看到,这些我们就可以通过变量的方式来匹配
例如我们将其web默认发布界面内容更改为主机名
[devops@server1 ansible]$ vim playbook.yml
- name: create index.html
copy:
content: "{{ ansible_facts['hostname'] }}\n" 或者为ansible_facts.hostname
dest: /var/www/html/index.html
[devops@server1 ansible]$ ansible-playbook playbook.yml
[devops@server1 ansible]$ curl server2
server2
[devops@server1 ansible]$ curl server3
server3
添加更多的变量到默认发布文件中
[devops@server1 ansible]$ vim playbook.yml
- name: create index.html
copy:
content: "{{ ansible_facts['hostname'] }} {{ ansible_facts['eth0']['ipv4']['address'] }}\n"
dest: /var/www/html/index.html
[devops@server1 ansible]$ ansible-playbook playbook.yml
[devops@server1 ansible]$ curl server2
server2 172.25.66.2
[devops@server1 ansible]$ curl server3
server3 172.25.66.3
三、添加标记,执行指定标记的任务
[devops@server1 ansible]$ vim playbook.yml
- name: create index.html
copy:
content: "{{ ansible_facts['hostname'] }} {{ ansible_facts['eth0']['ipv4']['address'] }}\n"
dest: /var/www/html/index.html
tags: one
[devops@server1 ansible]$ ansible-playbook playbook.yml -t one
四、jinjia2模板
[devops@server1 ansible]$ cd file/
[devops@server1 file]$ mv httpd.conf httpd.conf.j2
[devops@server1 file]$ cd ..
[devops@server1 ansible]$ vim playbook.yml
4 vars:
5 http_port: 80
26 src: file/httpd.conf.j2
[devops@server1 ansible]$ vim file/httpd.conf.j2
Listen {{ http_port }} 读取指定端口
[devops@server1 ansible]$ ansible-playbook playbook.yml
五、书写一个获取主机信息的yml文件
[devops@server1 ansible]$ vim hostinfo.yml ##编写新的yml文件
---
- hosts: all
tasks:
- name: create infofile
template:
src: templates/info.j2
dest: /mnt/hostinfo
[devops@server1 ansible]$ cd templates/
[devops@server1 templates]$ vim info.j2
主机名:{{ ansible_facts['hostname'] }}
主机ip:{{ ansible_facts['eth0']['ipv4']['address'] }}
根分区大小:{{ ansible_facts['devices']['dm-0']['size'] }}
系统版本:{{ ansible_facts['distribution_version'] }}
系统内核:{{ ansible_facts['kernel'] }}
[devops@server1 templates]$ cd ..
[devops@server1 ansible]$ ansible-playbook hostinfo.yml
注意:上图中所用到的参数都可以使用ansible命令查看到
[devops@server1 ansible]$ ansible all -a 'cat /mnt/hostinfo' ##查看文件采集结果
在server2,server3主机/mnt下,也能看到该文件
六、指定主机安装软件(判断)
假如ansible里有很多主机,但是你需要给特定的主机安装服务的时候,就可以使用下面的方法
[devops@server1 ansible]$ vim install.yml
---
- hosts: all
tasks:
- name: install pkgs
yum:
name: "{{ item }}"
state: present
when: ansible_facts['hostname'] == 'server2'
loop:
- httpd
- mariadb
- php
- php-mysql
- name: install mariadb
yum:
name: mariadb
state: present
when: ansible_facts['hostname'] == 'server3'
[devops@server1 ansible]$ ansible-playbook install.yml --syntax-check ##语法判断
playbook: install.yml
[devops@server1 ansible]$ ansible-playbook install.yml
可以看到软件只在server2上安装,server3直接跳过
七、自动生成主机解析
[devops@server1 ansible]$ vim hostinfo.yml
---
- hosts: all
tasks:
- name: create infofile
template:
src: templates/info.j2
dest: /mnt/hostinfo
- name: create hosts
template:
src: templates/hosts.j2
dest: /etc/hosts
owner: root
group: root
mode: 0644
[devops@server1 ansible]$ cp /etc/hosts templates/hosts.j2
[devops@server1 ansible]$ vim templates/hosts.j2
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
{% for host in groups['webservers'] %}
{{ hostvars[host]['ansible_facts']['eth0']['ipv4']['address'] }} {{ hostvars[host]['ansible_facts']['hostname'] }}
{% endfor %}
[devops@server1 ansible]$ vim inventory
[devops@server1 ansible]$ cat inventory
[test]
server2
server1
[db]
server3
[webservers:children]
test
db
[devops@server1 ansible]$ vim /etc/sudoers
devops ALL=(ALL) NOPASSWD: ALL
[devops@server1 ansible]$ ansible-playbook hostinfo.yml
在server1\2\3上自动生成的解析
八、添加用户,并且用户密码为密文
[devops@server1 ansible]$ mkdir vars
[devops@server1 ansible]$ cd vars/
[devops@server1 vars]$ vim userlist.yml
---
userlist:
- user: user1
pass: redhat
- user: user2
pass: redhat
[devops@server1 vars]$ ansible-vault encrypt userlist.yml 给文件加密
New Vault password:
Confirm New Vault password:
Encryption successful
[devops@server1 vars]$ cat userlist.yml
$ANSIBLE_VAULT;1.1;AES256
64326232366232666166303864336363303065346530306138613139636238383065383335643063
3939363430343137396131353765636265613137383233610a393836383732656166623165366134
62346536643430613161626437663134336336383566386266373931383332323536306136353134
6239353738373162360a643863623465666365356338666230376436616661636630323666636563
32336434656131633233643335353330623133623137616364656531366638373130613230326538
30333834653061386231643531336430316231656638623535316633393236356439663735303866
38383133316565666136303465623837633365663663616132346535646631386230666461343366
35353935636665623365313531316438646663326361663237636331646231323234326334336138
6565
[devops@server1 vars]$ ansible-vault view userlist.yml ##输入密码后查看文件内容
Vault password:
---
userlist:
- user: user1
pass: redhat
- user: user2
pass: redhat
[devops@server1 vars]$ cd ..
[devops@server1 ansible]$ vim adduser.yml
---
- hosts: all
vars_files:
- vars/userlist.yml
tasks:
- name: create users
user:
name: "{{ item.user }}"
state: present
password: "{{ item.pass }}"
loop: "{{ userlist }}"
[devops@server1 ansible]$ ansible-playbook adduser.yml --ask-vault-pass
##加密运行,否则出不来,我们对文件是加密的
[devops@server1 vars]$ ansible-vault decrypt userlist.yml ##文件解密
通过上图我们发现用户是建立成功了,但是问题随之而来:我们建立出来的用户密码是明文的,如下图:
[devops@server1 ansible]$ ansible all -a 'cat /etc/shadow'
为了让密码加密存储,我们来修改adduser.yml
[devops@server1 ansible]$ vim adduser.yml
---
- hosts: all
vars_files:
- vars/userlist.yml
tasks:
- name: create users
user:
name: "{{ item.user }}"
state: present
password: "{{ item.pass | password_hash('sha512','mysecretsalt')}}" ##对用户密码进行加密
loop: "{{ userlist }}"
~
[devops@server1 ansible]$ ansible-playbook adduser.yml --ask-vault-pass
再次查看密码是否为明文
[devops@server1 ansible]$ ansible all -a 'cat /etc/shadow'