实施playbook
1.1 编写和运行playbook
yaml 格式通常以yml 为扩展名,yaml 对于缩进量没有严格要求,但是有两个基本原则:
1.处于同一层次结构中同一级别的数据元素必须具有相同的缩进量
2.如果项目属于其他项目的子项,其缩进量必须大于父项
示例1:
查看指定用户的临时命令
ansible -m user -a "name=student uid=1000 state=present" servera.lab.example.com
改写为playbook:
--- #开头三个破折号,文档的开始标记
- name: Configure User #可选,但是建议使用
hosts: servera.lab.example.com
tasks:
- name: Student User
user:
name: student
uid: 1000
state: present
... #结尾三个省略号,结束标记(通常省略)
play 本身是一个键值对集合,同一play 中的键应当使用相同的缩进量
示例2:安装apache
---
- name: Setup Webserver
hosts: servera.lab.example.com
tasks:
- name: Http Installed
yum:
name: httpd
state: latest
...
示例3:确保服务开机启动
---
- name: Setup Webserver
hosts: servera.lab.example.com
tasks:
- name: Apache is enabled
service:
name: httpd
enabled: true
- name: Postfix is enabled
service:
name: postfix
enabled: true
...
1.2 提高输出详细程度:
ansible-playbook 默认输出不提供详细任务执行信息。-v 参数提供,共四个级别:
-v
#显示任务结果
-vv
#显示任务结果和任务配置
-vvv
#包含关于与受管主机的连接信息
-vvvv
#增加连接插件相关的额外详细程度选项(包括受管主机上用于执行脚本的用户及所执行的脚本)
1.3 语法检测:
ansible-playbook --syntax-check webserver.yml
无语法错误:
playbook: webserver.yml
有语法错误,会提示错误位置
1.4 执行空运行
ansible-playbook -C webserver.yml
空运行会报告执行这个playbook 将会发生什么,但不会改变目标主机
示例4:安装、配置默认发布页并启动apache
---
- name: Install and Start Apache
host: web
tasks:
- name: Apache is present
yum:
name: httpd
state: present
- name: Change index.html
copy:
src: files/index.html
dest: /var/www/html/index.html
- name: Start Apache
service:
name: httpd
state: started
enabled: true
检测语法:
ansible-playbook --syntax-check site.yml
playbook: site.yml
创建配置文件和清单:
vim ansible.cfg
[defaults]
inventory = ./inventory
vim inventory
[web]
serverb.lab.example.com
serverc.lab.example.com
默认发布页面:
vim files/index.html
www.westos.org
执行playbook:
ansible-playbook site.yml
ansible-doc 的用法:
ansible-doc -l #列出所有模块
ansible-doc yum #列出yum 的用法和示例
ansible-doc -s yum #终端中输出yum 模块中各参数的用法
1.5 管理变量和事实
ansible 变量简介:
变量可能包含下面这些值:
要创建的用户、要安装的软件包、要重启的服务、要删除的文件、要从互联网检索的文档
命名变量:
变量名称必须以字母开头,并且只能含有字母、数字和下划线
错误 | 正确 |
---|---|
web server | web_server |
westos.file | remote_file |
1st file | file1 |
定义变量:
全局范围:从命令行或ansible 配置设置的变量
play 范围:在play 和相关结构中设置的变量
主机范围:由清单、事实收集或注册的任务,在主机组和个别主机上设置的变量
如果多个级别上定义了相同名称的变量,优先采用级别最高的变量,窄范围优先于广范围
playbook 中的变量:
1.常见方式:在playbook 开头的vars 块中:
- host: all
vars:
user: student
home: /home/student
2.在外部文件定义playbook 变量:
- hosts: all
vars_files:
- vars/users.yml
在users.yml 文件中写入:
user: student
home: /home/student
在playbook 中使用变量:
将变量名称放在花括号内即可
vars:
user: westos
tasks:
- name: Create user {{ user }}
user:
name: "{{ user }}"
注意:当变量用作开始一个值的第一元素时,必须使用引号
主机变量和组变量:
直接应用于主机的清单变量分为两大类:
1.主机变量:应用于特定主机
2.组变量:应用于一个主机组或一组主机组中的所有主机
主机变量优先于组变量,但是playbook 中定义的变量比这两者更高
定义主机变量和组变量:
方法一(比较旧,不建议采用):
定义server1.example.com 的ansible_user 主机变量:
[webservers]
server1.example.com ansible_user=student
定义dbservers 主机组的user 组变量:
[dbserver]
dbserver1.example.com
dbserver2.example.com
[dbservers:vars]
user=student
定义嵌套组user 变量:
[servers1]
node1.example.com
node2.example.com
[servers2]
node3.example.com
node4.example.com
[servers:children]
servers1
servers2
[servers:vars]
user=student
这种做法使的清单文件难以处理,在同一文件中混合提供主机和变量信息,语法也过时
方法二:使用目录填充主机和组变量
定义主机和主机组变量的首选做法是与清单文件或目录相同的工作目录中,创建group_vars和host_vars 两个目录,这两个目录分别包含用于定义组变量和主机变量的文件
创建group_vars/servers 的YAML 文件,设置变量为值:
user: student
同样需要在host_vars 目录中创建名称与主机匹配的文件来存放主机变量
所以一个项目目录中包含:
ansible.cfg、group_vars、host_vars、inventory、playbook.yml
从命令行覆盖变量
清单变量可以被playbook 中设置的变量覆盖,两者又可通过命令行参数覆盖
使用数组作为变量:
users:
lilei:
first_name: lei
last_name: li
home_dir: /home/lilei
hanmeimei:
first_name: meimei
last_name: han
home_dir: /home/hanmeimei
访问:
users.lilei.first_name
users.hanmeimei.home_dir
变量被定义为python 字典,可以使用替代语法:
users['lilei']['first_name']
使用已注册变量捕获命令输出
管理员可以使用register 语句捕获命令输出
---
- name: Install a packages
hosts: all
tasks:
- name: Install
yum:
name: httpd
state: installed
register: install_result
- debug: var=install_result
管理变量的练习:
创建playbook,来安装apache 并开启,使可被访问,playbook 查询web 服务器并确认它已经设置好并在运行
web_pkg #要安装的web 服务器软件包
firewall_pkg #要安装的防火墙软件包
web_service #要管理的web 服务
firewall_service #要管理的防火墙服务
python_pkg #uri 模块所需软件包
rule #要打开的服务
vim playbook.yml
---
- name: Deploy and start Apache service
hosts: webservers
vars:
web_pkg: httpd
firewall_pkg: firewalld
web_service: httpd
firewall_service: firewalld
python_pkg: python3-PyMySQL
rule: http
#确保安装软件包且是最新的
tasks:
- name: Required packages are installed and latest
yum:
name:
- "{{ web_pkg }}"
- "{{ firewall_pkg }}"
- "{{ python_pkg }}"
state: latest
#确保firewalld 和apache 开机启动
- name: The {{ firewall_service }} service is started and enabled
service:
name: "{{ firewall_service }}"
enabled: true
state: started
- name: The {{ web_service }} service is started and enabled
service:
name: "{{ web_service }}"
enabled: true
state: started
#配置默认发布页面
- name: Web content is in place
copy:
content: "Hello Westos!"
dest: /var/www/html/index.html
#使防火墙允许http
- name: The firewall port for {{ rule }} is open
firewalld:
service: "{{ rule }}"
permanent: true
immediate: true
state: enabled
#验证apache 服务
- name: Verify the Apache service
hosts: localhost
become: false #在本机测试,不必更改身份
tasks:
- name: Ensure the webserver is reachable
uri:
url: http://servera.lab.example.com
status_code: 200
1.6 管理机密
目标:使用ansible vault 加密敏感变量,并运行vault 加密变量文件的playbook
介绍ansible vault:
ansible 可能需要访问密码或者api 密钥等敏感数据,以便配置主机
加密解密工具:ansible-vault 命令
ansible vault 不实施自有的加密函数,而使用外部python 工具集
创建加密文件:
ansible-vault create filename
ansible-vault create secret.yml
需要输入密码
创建加密文件同时将密码保存,westos 文件中必须先写入密码:
ansible-vault create --vault-password-file=westossecret.yml
查看加密文件:
ansible-vault view westos.yml
编辑现有的加密文件:
原理:将文件解密为一个临时文件,并编辑;保存时,复制内容并删除临时文件
edit 命令始终重写文件,因此只有在更改文件时使用,查看尽量使用view
加密现有的文件:
方法:ansible-vault encrypt filename #filename 参数可以是多个
可以使用–output=filename 将加密文件保存为新的名称,使用此参数时输入文件只能是一个
解密现有的文件:
方法:ansible-vault decrypt filename
ansible-vault decrypt westos.yml --output=redhat.yml#解密的同时改名
更改加密文件密码:
方法:ansible-vault rekey filename
可以一次更新多个文件密码
1.7 管理事实
事实包括:主机名称、内核版本、网络借口、IP 地址等
描述ansible 事实
查看主机信息:
vim fact.yml
- name: Fact dump
hosts: all
tasks:
- name: Print all facts
debug:
var: ansible_facts #系统变量名
再将事实替换为动态的值:
---
- name: Fact dump
hosts: all
tasks:
- name: Print all facts
debug:
var: ansible_facts
- hosts: all
tasks:
- name: Print ansible facts
debug:
msg:
The IPv4 address of {{ ansible_facts.fqdn }} #使用字典的方式查询值
is {{ ansible_facts.all_ipv4_addresses }}
ansible 事实作为变量注入
使用setup 模块显示所有事实信息:
ansible servera.lab.example.com -m setup
关闭事实收集,开提升执行速度:
---
- name: Configure User
hosts: servera.lab.example.com
gather_facts: no
tasks:
- name: Student User
user:
name: student
uid: 1000
state: present
...
创建自定义事实:
可以使用INI 格式或者JSON 格式
INI 格式:
[packages]
web_package = httpd
db_package = mariadb-server
[users]
user1 = westos
user2 = redhat
JSON 格式:
{
"packages": {
"web_package": "httpd",
"db_package": "mariadb-server"
},
"users": {
"user1": "westos",
"user2": "redhat"
}
}
自定义格式不能使用ymal 格式,使用最为接近的json 最好
自定义事实的使用方式和默认事实相同
使用魔法变量:
hostvars #包含受管主机的变量,可以用于获取另一台受管主机的变量的值
group_names #列出当前受管主机所属的所有组
groups #列出清单中的所有组和主机
inventory_hostname #包含清单中配置的当前受管主机的主机名称
使用debug 模块报告特定主机的hostvars 的值:
ansible localhost -m debug -a 'var=hostvars["servera.lab.example.com"]'
练习:使用基本身份认证的httpd
---
- name: Webserver vars
hosts: webservers
vars:
firewall_pkg: firewalld
firewall_srv: firewalld
web_pkg: httpd
web_srv: httpd
ssl_pkg: mod_ssl
httpdconf_src: files/httpd.conf
httpdconf_dest: /etc/httpd/conf/httpd.conf
secrets_dir: /etc/httpd/secrets
secrets_src: files/htpasswd
secrets_dest: "{{ secrets_dir }}/htpasswd"
web_root: /var/www/html
tasks:
- name: Install packages
yum:
name:
- "{{ firewall_pkg }}"
- "{{ web_pkg }}"
- "{{ ssl_pkg }}"
state: latest
- name: Configure service
copy:
src: "{{ httpdconf_src }}"
dest: "{{ httpdconf_dest }}"
owner: root
group: root
mode: 0644
- name: Create secrets directory
file:
path: "{{ secrets_dir }}"
state: directory
owner: apache
group: apache
mode: 0500
- name: Create htpasswd
copy:
src: "{{ secrets_src }}"
dest: "{{ secrets_dest }}"
owner: apache
group: apache
mode: 0400
- name: Create index.html
copy:
content: "{{ ansible_facts['fqdn'] }}
({{ ansible_facts['all_ipv4_addresses'] }})\n"
dest: "{{ web_root }}/index.html"
- name: Configure firewalld service
service:
name: "{{ firewall_srv }}"
state: started
enabled: true
- name: Firewalld permits https
firewalld:
service: https
state: enabled
immediate: true
permanent: true
- name: Configure apache service
service:
name: "{{ web_srv }}"
state: started
enabled: true
- name: Test apache
hosts: localhost
become: no
vars:
- web_user: admin
vars_files:
- vars/secret.yml
tasks:
- name: Connect to apache with auth
uri:
url: https://serverb.lab.example.com
validate_certs: no
force_basic_auth: yes
user: "{{ web_user }}"
password: "{{ web_pass }}" #定义了访问apache 的用户密码
return_content: yes
status_code: 200
register: auth_test
- debug:
var: auth_test.content