目的:实现自动化的部署
编写语法格式:playbook以yaml语言编写。
文件第一行以 “—”开始,表示文件的开始。
在同一行中井号表示注释。
列表形式以 “-”开头,跟着一个空格。同一个列表中的元素应该保持相同的缩进。
例:
--- #开头
- hosts: test #对哪个组进行任务
tasks: #任务
- name: install apache #下面开始新的列表##任务名
yum: #调用模块
name: httpd #服务名
state: installed #动作
- name: start apache
service:
name: httpd
state: started
如果愿意,可以一直往下写。
基本命令
[ansible@server10 ~]$ ansible-playbook playbook.yml --syntax-check ##检测语法使用参数--syntax-check
playbook: playbook.yml
[ansible@server10 ~]$ ansible-playbook playbook.yml --list-hosts ##检测主机
playbook: playbook.yml
play #1 (test): test TAGS: []
pattern: [u'test']
hosts (1): ##现在作用主机就只有一个
server11
[ansible@server10 ~]$ ansible-playbook playbook.yml --list-tasks ##查看有几个任务
playbook: playbook.yml
play #1 (test): test TAGS: []
tasks:
install apache TAGS: []
start apache TAGS: []
[ansible@server10 ~]$ ansible-playbook playbook.yml ##运行文件中的配置
PLAY [test] ***************************************************************************
TASK [Gathering Facts] ****************************************************************
ok: [server11]
TASK [install apache] *****************************************************************
ok: [server11]
TASK [start apache] *******************************************************************
changed: [server11]
PLAY RECAP ****************************************************************************
server11 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
运行完成之后在test组的节点进行查看。
[root@server11 ~]# netstat -antpl ##80端口已经开启
tcp6 0 0 :::80 :::* LISTEN 2953/httpd
创建完成之后下一步可以编辑默认发布页面。
- name: create index.html
copy: ##拷贝模块
content: “www.server10.com” ##添加的内容
dest: /var/www/html/index.html ##复制到的位置
设置完成之后进行运行。
[ansible@server10 ~]$ ansible-playbook playbook.yml
[ansible@server10 ~]$ curl server11 ##远程访问。
www.server10.com
可以访问之后我们可以在部署之前进行配置。在安装完apache服务之后加入如下。
- name: config apache
copy:
src: httpd.conf ##将本地的httpd配置文件复制到下面的地址
dest: /etc/httpd/conf/httpd.conf
在本地的配置文件中将端口号进行修改
Listen 8080
[ansible@server10 ~]$ ansible-playbook playbook.yml
TASK [config apache] ******************************************************************
changed: [server11] ##这里提示已经改变
没有报错后进入远端进行查看。
[root@server11 conf]# netstat -antpl
tcp6 0 0 :::80 :::* LISTEN 2953/httpd
我们发现这这端口并没有进行改变,因为现在是服务部署完成再进行改变的,如果想让文件生效有两个办法,一个是手动进入远端重启服务,另一个就是继续编写playbook,在文件中将服务重启,或者设置触发机制。
触发器的设置
在playbook文件中最下面设置触发器
handlers:
- name: restart apache
service:
name: httpd
state: restarted
设置完成之后,在编辑配置文件的地方放置触发器,只要文件发生变动,就会触发,将服务重启。
- name: config apache
copy:
src: httpd.conf
dest: /etc/httpd/conf/httpd.conf
notify: restart apache
设置多个play
任务可以有很多,play也可以有很多,下来就设置一个测试用play
- hosts: localhost ##在本地
become: no ##不切换用户
tasks: ##任务
- name : test apache
uri: ##uri模块
url: http://server11/index.html
编写完成后接着运行
[ansible@server10 ~]$ ansible-playbook playbook.yml
PLAY [localhost] **************************************************************************
TASK [Gathering Facts] ********************************************************************
ok: [localhost]
TASK [test apache] ************************************************************************
ok: [localhost]
PLAY RECAP ********************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
server11 : ok=7 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
在本地运行的play没有问题。
设置完多个play之后如果我们想跑指定的play呢?目前只能指定从哪个任务开始。–start-at-task参数进行指定
[ansible@server10 ~]$ ansible-playbook playbook.yml --start-at-task "test apache"
PLAY [test] *******************************************************************************
PLAY [localhost] **************************************************************************
TASK [Gathering Facts] ********************************************************************
ok: [localhost]
TASK [test apache] ************************************************************************
ok: [localhost]
PLAY RECAP ********************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
这样就直接从我们的测试任务开始,而不做前面的任务。
或者不加这个参数而是在playbook文件中添加一个标签,这样设置,查看的时候标签也能进行显示。
uri:
url: http://server11/index.html
tags: test
[ansible@server10 ~]$ ansible-playbook playbook.yml --list-tasks
play #2 (localhost): localhost TAGS: []
tasks:
test apache TAGS: [test]
使用的时候直接指定标签即可。
[ansible@server10 ~]$ ansible-playbook playbook.yml -t test
上面两个方法的效果是相同的
变量
首先定义模版文件。
可以在hosts文件中直接定义。
[test]
server11 web_package=httpd
定义完成后使用时需要进行调用。调用方法使用"{{ 变量名}}"
比如说我们在安装软件的时候使用变量。
- name: install apache
yum:
name: "{{web_package}}"
state: installed
然后运行,运行是正常的那就说明变量使用没有问题。
定义变量的位置有很多,也可以直接在playbook文件中进行添加。
---
- hosts: test
vars:
web_package: httpd
在开头的地方设置变量,调用的方式都是一样的。但是直接在playbook中进行定义的变量比在别的地方定义的变量优先级要高。因为playbook加载是最后的,playbook中的变量将其他变量覆盖掉了。说白了就是哪个文件最后加载的,最后加载的文件中如果有变量就会覆盖前一个变量。
当然,ansible也有自己的内置变量,使用下面的命令进行查看。
[ansible@server10 ~]$ ansible server11 -m setup
默认是直接启用的,因为在运行playbook文件的时候第一个加载的就是内置变量TASK [Gathering Facts],当然这个选项在你不用他的时候是可以禁掉的。当我们进行调用的时候可以查看完变量再进行设置。例如这样:
- name: create index.html
copy:
content: "{{ansible_hostname}}"
dest: /var/www/html/index.html
运行之后我们进行查看。
[ansible@server10 ~]$ curl server11
server11
已经添加进去了,这种方法虽然可以设置变量,但是官方建议的方式为:
- name: create index.html
copy:
content: “{{ansible_facts[‘hostname’]}}”
dest: /var/www/html/index.html
还有更复杂的方式,例如下面,我再起一个play,我们在每一台机器上面都创建一个文件,文件中的内容为本机ip。
- hosts: all
tasks:
- name: create hostinfo
copy:
content: "{{ ansible_facts['ens3']['ipv4']['address'] }}" ##这个方法将ip定位ens3网卡上面的ipv4的地址
dest: /tmp/hostinfo
tags: info ##给play设置标签
[ansible@server10 ~]$ ansible-playbook playbook.yml -t info ##运行从标签info开始
[root@server11 conf]# cat /tmp/hostinfo
192.168.122.11
[root@server12 ~]# cat /tmp/hostinfo
192.168.122.12
这样每一台主机上的ip地址就都创建完成了。
或者再使用另一种模版jinja2模版。
- hosts: all
tasks:
- name: create hostinfo
template:
src: hostinfo.j2 ##源文件
dest: /tmp/hostinfo
在playbook中定义完成后就要去编写jinja2文件来进行运用。
[ansible@server10 ~]$ vim hostinfo.j2
ip:{{ ansible_facts['ens3']['ipv4']['address']}}
hostname:{{ ansible_facts['hostname']}}
hostiface:{{ ansible_facts['interfaces']}}
dns:{{ ansible_facts['dns']['nameservers']}}
{{ ansible_facts['kernel']}}
memoryfree: {{ ansible_facts['memfree_mb']}}
里面全部使用变量形式,playbook运行完之后再推送到远端。
[root@server11 conf]# cat /tmp/hostinfo
ip:192.168.122.11
hostname:server11
hostiface:[u'lo', u'ens3']
dns:[u'114.114.114.114']
3.10.0-1062.el7.x86_64
memoryfree: 686
注册变量
以下面这一段为例
- hosts: localhost
become: no
tasks:
- name : test apache
uri:
url: http://server11/index.html
现在这个输出只有ok没有其他的东西,那么我们就要定义一个变量,将变量的值进行输出。
url: http://server11/index.html
register: result ##定义变量
- debug:
var: result ##输出
运行之后就有了别的输出值
TASK [debug] ******************************************************************************
ok: [localhost] => {
"result": {
"accept_ranges": "bytes",
"changed": false,
"connection": "close",
"content_length": "8",
"content_type": "text/html; charset=UTF-8",
"cookies": {},
"cookies_string": "",
"date": "Sun, 08 Mar 2020 12:42:40 GMT",
"elapsed": 0,
"etag": "\"8-5a055938dc004\"",
"failed": false,
"last_modified": "Sun, 08 Mar 2020 10:44:51 GMT",
"msg": "OK (8 bytes)",
"redirected": false,
"server": "Apache/2.4.6 (CentOS)",
"status": 200,
"url": "http://server11/index.html"
}
}
但是,如果在进一步,这些东西显示的太多了,我们只想要特定的内容,那么该如何做到。
那么就需要首先知道你需要哪些信息,从上面的信息中进行筛选。
比如说我需要知道时间的信息。
- debug:
var: result.date
设置成这样再运行信息就出来了。
TASK [debug] ******************************************************************************
ok: [localhost] => {
"result.date": "Sun, 08 Mar 2020 13:04:29 GMT"
}
loop循环
重新创建一个play进行用户的创建
- hosts: test
vars: ##定义变量
user: user1
passwd: aekhg777
tasks:
- name: create users
user:
name: "{{user}}"
password: "{{passwd|password_hash('sha512')}}" ##密码加密 不能使用明文密码
tags: user
创建完成之后可以在server11中进行查看。
如何创建多个用户,使用loop循环,将变量删除,加入循环
tasks:
- name: create users
user:
name: "{{item.user}}"
password: "{{item.passwd|password_hash('sha512')}}"
loop: ##可以有多组循环
- {user:user1, passwd:asd }
- {user:user2, passwd:qwe }
完成之后运行
TASK [create users] ***********************************************************************
changed: [server11] => (item={u'passwd': u'asd', u'user': u'user1'})
changed: [server11] => (item={u'passwd': u'qwe', u'user': u'user2'})
切换到server11上面进行查看
user1:x:1001:1001::/home/user1:/bin/bash
user2:x:1002:1002::/home/user2:/bin/bash
已经创建完成。
但是这种方式不安全,密码在文件中全部明文进行展示。
首先创建一个文件
[ansible@server10 ~]$ cat vars/userlist.yml
---
userlist: ##创建的变量
- user: user1 ##里面的组
passwd: asd
- user: user2
passwd: qwe
再将这个文件指定进playbook文件
- hosts: test
vars_files:
- vars/userlist.yml
tasks:
- name: create users
user:
name: "{{item.user}}"
password: "{{item.passwd|password_hash('sha512')}}"
loop: "{{userlist}}" ##循环变量中的组
创建完成,可以进行查看
魔术变量
自动的循环多台主机,例:自动创建hosts文件
创建一个jinja2的文件
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
{% for host in groups['web']%} ##for循环开始 提取组为web中的机器
{{ hostvars[host]['ansible_ens3']['ipv4']['address']}} {{ hostvars[host]['ansible_facts']['hostname' ]}} ##提取ip地址 提取用户名
{% endfor%} ##循化结束
创建完成编写playbook
- hosts: all ##集群中的所有
tasks:
- name: create hosts
template: ##使用模版
src: test.j2
dest: /tmp/hosts
tags: hosts
运行ansible创建。然后进入别的节点进行查看。
[root@server11 conf]# cat /tmp/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.122.11 server11
192.168.122.12 server12
或者在看一个例子,部署haproxy负载均衡
首先配置playbook文件安装haproxy软件。
- hosts: all
tasks:
- name: install haproxy
yum:
name: haproxy
state: installed
when: ansible_hostname == 'server10'##当用户是server10才会安装
tags: haproxy
安装完成将haproxy的配置文件复制出来改为jinja2形式。并修改配置文件
在配置的时候使用魔术变量
#---------------------------------------------------------------------
# main frontend which proxys to the backends
#---------------------------------------------------------------------
frontend main *:80
default_backend app
#---------------------------------------------------------------------
# static backend for serving up images, stylesheets and such
#---------------------------------------------------------------------
#---------------------------------------------------------------------
# round robin balancing between the various backends
#---------------------------------------------------------------------
backend app
balance roundrobin
{% for host in groups['web']%} ##开始
server {{hostvars[host]['ansible_facts']['hostname']}} {{ hostvars[host]['ansible_ens3']['ipv4']['address']}}:80 check ##提取用户名 和ip
{% endfor%} ##结束
这个设置完成再完善playbook,继续添加如下
- name: config haproxy
template:
src: haproxy.cfg.j2
dest: /etc/haproxy/haproxy.cfg
notify: restart haproxy
when: ansible_hostname == 'server10'
- name: start haproxy
service:
name: haproxy
state: started
when: ansible_hostname == 'server10'
handlers: ##触发器
- name: restart haproxy
service:
name: haproxy
state: reloaded
tags: haproxy
在运行访问本机
[ansible@server10 ~]$ curl server10
server11
[ansible@server10 ~]$ curl server10
server12
[ansible@server10 ~]$ curl server10
server11
实现负载均衡
加密文件
ansible自带加密功能使用命令进行加密,我们使用最早实验用的用户名和密码做实验。
[ansible@server10 vars]$ ansible-vault encrypt userlist.yml
New Vault password:
Confirm New Vault password:
Encryption successful
[ansible@server10 vars]$ cat userlist.yml
$ANSIBLE_VAULT;1.1;AES256
62633139313432323765313233353738326561636166623335313561393034613938333336386661
3262653737643638643934353264363438656161643235340a356136663234396630383732303134
31323833626364316232343565636634623561363262393465316564363435326135626633383137
6431323935653533640a373663663635326332616137626233313762383965626361643737626363
63353966376431653236326365666566373931633038303833333566343034343830666230326139
37393361636236663363303337306335333537386333386139656638643635383631663361643539
66316231386637613535363936313335306232336265663062306539393862343734306138633731
61303365346364343539
这样就被加密了,如何查看,需要输入加密时输入的密码。
[ansible@server10 vars]$ ansible-vault view userlist.yml
Vault password:
---
userlist:
- user: user1
passwd: asd
- user: user2
passwd: qwe
解密
[ansible@server10 vars]$ ansible-vault decrypt userlist.yml
Vault password:
Decryption successful
[ansible@server10 vars]$ cat userlist.yml
---
userlist:
- user: user1
passwd: asd
- user: user2
passwd: qwe
但是现在用的还时加密文件,这个加密文件应该如何使用?因为如果直接使用加密文件的话会运行playbook会报错,所以使用的时候要给命令行中加一个参数来输入密码--ask-vault-pass
。
最后附上所有playbook的内容。
---
- hosts: web
gather_facts: yes
vars:
web_package: httpd
web_service: httpd
tasks:
- name: install apache
yum:
name: "{{web_package}}"
state: installed
ignore_errors: True
- name: config apache
template:
src: httpd.conf.j2
dest: /etc/httpd/conf/httpd.conf
notify: restart apache
- name: start apache
service:
name: "{{web_service}}"
state: started
enabled: yes
- name: create index.html
copy:
content: "{{ansible_facts['hostname']}}"
dest: /var/www/html/index.html
- name: start firewall
service:
name: firewalld
state: started
enabled: yes
- name: custom firewalld
firewalld:
service: http
permanent: yes
state: enabled
immediate: yes
handlers:
- name: restart apache
service:
name: "{{web_service}}"
state: restarted
tags: apache
- hosts: all
tasks:
- name: install haproxy
yum:
name: haproxy
state: installed
when: ansible_hostname == 'server10'
- name: config haproxy
template:
src: haproxy.cfg.j2
dest: /etc/haproxy/haproxy.cfg
notify: restart haproxy
when: ansible_hostname == 'server10'
- name: start haproxy
service:
name: haproxy
state: started
when: ansible_hostname == 'server10'
handlers:
- name: restart haproxy
service:
name: haproxy
state: reloaded
tags: haproxy
- hosts: localhost
become: no
tasks:
- name : test apache
uri:
url: http://server11/index.html
register: result
- debug:
#var: result.date
tags: test
- hosts: all
tasks:
- name: create hostinfo
template:
src: hostinfo.j2
dest: /tmp/hostinfo
tags: info
- hosts: all
tasks:
- name: create hosts
template:
src: test.j2
dest: /tmp/hosts
tags: hosts
- hosts: test
vars_files:
- vars/userlist.yml
tasks:
- name: create users
user:
name: "{{item.user}}"
password: "{{item.passwd|password_hash('sha512')}}"
loop: "{{userlist}}"
tags: user