typora-root-url: ./AnsiblePic
Ansible运维
第 1 章 Ansible 介绍及安装
1.1 介绍
Ansible 是一个 IT 自动化工具。它能配置系统、部署软件、编排更复杂的 IT 任务,如连续部署或零停机时间滚动更新。Ansible 用 Python 编写,尽管市面上已经有很多可供选择的配置管理解决方案(例如 Salt、Puppet、Chef等),但它们各有优劣,而Ansible的特点在于它的简洁。让 Ansible 在主流的配置管理系统中与众不同的一点便是,它并不需要你在想要配置的每个节点上安装自己的组件。同时提供的另一个优点,如果需要的话,你可以在不止一个地方控制你的整个基础架构。
1.2 工作原理
1、在ANSIBLE 管理体系中,存在"管理节点" 和 "被管理节点" 两种角色。
2、被管理节点通常被称为"资产"
3、在管理节点上,Ansible将 AdHoc 或 PlayBook 转换为Python脚本。并通过SSH将这些Python 脚本传递到
被管理服务器上。在被管理服务器上依次执行,并实时的将结果返回给管理节点。
管理节点
确保存在OpenSSH
确保Python 版本 >= 2.6
确保安装ansible
被管理节点
确保存在OpenSSH
确保Python 版本 >= 2.4 //若为2.4 版本,确保安装了python-samplesjson 扩展
不需要安装ansible
安装Ansible
# pip install ansible // 确保最新版本ansible 或者 pip3 install ansible
# yum -y install ansible // 不一定是最新版本ansible
确保管理节点与被管理节点之间SSH 信任关系
// 生成公私钥对
# ssh-keygen -t rsa
# cd ~/.ssh && ls
id_rsa id_rsa.pub
// 将公钥 id_rsa.pub copy 到 被管理服务器上 authorized_keys 文件中, 确保文件的权限为 0600
// managedhost 为被管理服务器,copy的过程中需要用户名及密码
# ssh-copy-id root@managedhost
1.4 快速入门
场景假设
管理节点:
192.168.122.130
被管理节点(资产):
192.168.122.129
192.168.122.131
且管理节点 和 被管理节点之间的节点已经打通 SSH 信任关系。
场景一
在管理节点上,确保同所有被管理节点的网络连通性。
# ansible all -i 192.168.122.129,192.168.122.131 -m ping
// 注意 -i 参数后面接的是一个列表(List)。因此当为一个被管理节点时,我们后面一定要加一个逗号(,)告知是List
# ansible all -i 192.168.122.129, -m ping
场景二
在管理节点上,确保文件/tmp/a.conf 发布到所有被管理节点
# ansible all -i 192.168.122.129,192.168.122.131 -m copy -a "src=/tmp/a.conf dest=/tmp/a.conf"
参数解释
-i // 指定Ansible 的资产,也就是被管理服务器。
-m // 指定要运行的模块,比如这里的 ping 模块和 copy 模块
-a // 指定模块的参数, 这里模块 ping 没有指定参数。 模块 copy 指定了 src 和 dest 参数
all // ansible 中, 将其叫做pattern , 即匹配。我通常称它为资产选择器。
// 就是匹配资产(-i 参数指定) 中的一部分。这里的 all 是匹配所有指定的所有资产。
// 在资产的章节中,我们将详细阐述。
第 2 章 Ansible 资产
在快速入门的场景中,我们一共管理了两台服务器。但是在实际场景中,我们要管理的服务器往往要多得多。难道依然要在Ansible 的 -i 参数后面一个个追加IP指定吗? 这显然不合乎常理。因此这一节我们主要去介绍一下Ansible的资产。Ansible 的资产分为静态资产和动态资产,下面我们将围绕这两部分分别介绍。
1.1 静态资产
顾名思义它本身是一个文本文件,一个格式类似INI的文件。默认情况下,Ansible的资产文件位于 /ect/ansible/hosts。我们这里给出一个自定义的静态资产实例,然后再具体解释其含义。
# cat inventory
1.1.1.1
2.2.2.2
3.3.3.[1:15]
test01.qfedu.com
test03.qfedu.com
test[05:09].qfedu.com
[web-servers]
192.168.1.2
192.168.1.3
192.168.1.5
[db-servers]
192.168.2.2
192.168.2.3
192.168.1.5
[all-servers]
[all-servers:children]
db-servers
web-servers
1、Ansible 的资产文件中,可以以IP地址的形式或者主机名的形式存在
2、Ansible 的资产若连续,可以使用[stat:end] 的形式去表达
3、可以将服务器按照业务场景定义成组,比如db-servers 和 web-servers
4、组和组之间可以存在继承关系,比如db-servers 和 web-servers 同时继承all-servers 组
如何使用自定义资产
// 通过 -i 参数指定自定义资产的位置即可(可以是全路径,也可以是相对路径)。
# ansible all -i inventory.ini ... // 伪指令,不可执行
如何验证自定义资产
// 假如我们刚刚定义的资产为 inventory.ini
// 列举出所有资产
# ansible all -i inventory.ini --list-hosts
// 列举出选定资产,比如这里列举出web-servers
// 注意这里使用的了资产选择器(pattern),我们将会在下面对他进行详细的阐述
# ansible web-servers -i inventory.ini --list-hosts
// 以上指令,若能列举出我们在资产中定义的服务器,那么你的自定义资产也就生效了。
1.2 动态资产
动态资产, -i 参数后面接的是一个可运行的脚本。脚本的结果为一个 Ansible 可理解的 JSON 格式字符串。
为什么要存在动态资产呢? 往往我们在使用 Ansible 管理服务器前,公司中有可能已经将服务器信息存储在了特定位置,比如 CMDB, 数据库等系统。
此时若我们再使用静态资产去管理服务器,势必会造成资产管理入口不统一的问题。
因此我们只能抛弃原先的静态资产,通过脚本从已存在的系统中获取要管理的节点,并按照特定的形>式传给 Ansible。这样既解决了公司资产统一入口, 也解决了Ansible 的服务器管理来源。
动态资产实例
{
"_meta": {
"hostvars": {
"192.168.100.10": {
"host_var": "hoge"
},
"192.168.100.20": {
"host_var": "fuga"
}
}
},
"sample-servers": {
"hosts": [
"192.168.100.10",
"192.168.100.20"
],
"vars": {
"group_var": "hogefuga"
}
}
}
1.3 资产选择器
有时操作者希望只对资产中的一部分服务器进行操作,而不是资产中列举的所有服务器。此时我们该如何选择呢?
这里我们将学习 Ansible 的资产选择器 PATTERN,通过资产选择器,我们可以灵活的选择想要操作的服务器。
格式
# ansible PATTERN -i inventory -m module -a argument // 伪代码,勿执行
选择一台或者几台服务器
# ansible 1.1.1.1 -i inventory.ini --list-hosts
# ansible test01.qfedu.com -i inventory.ini --list-hosts
# ansible 1.1.1.1,2.2.2.2 -i inventory.ini --list-hosts
选择所有服务器
# ansible '*' -i inventory.ini --list-hosts
# ansible all -i inventory.ini --list-hosts
选择一组服务器
# ansible web-servers -i inventory.ini --list-hosts
使用 * 匹配
# ansible 3.3.3.* -i inventory.ini --list-hosts
使用逻辑匹配
// web-servers 和 db-servers 的并集
# ansible 'web-servers:db-servers' -i inventory.ini --list-hosts
// web-servers 和 db-servers 的交集
# ansible 'web-servers:&db-servers' -i inventory.ini --list-hosts
// 在 web-servers 中, 但不在 db-servers 的服务器
# ansible 'web-servers:!db-servers' -i inventory.ini --list-hosts
第 3 章 Ansible Ad-Hoc
3.1 命令格式
我们在快速入门中执行的Ansible 命令,类似于我们的批处理命令。在Ansible 中统称为Ansible Ad-Hoc。
其命令语法格式如下:
ansible pattern [-i inventory] -m module -a argument
pattern, 资产选择器
-i , 指定资产的位置
-m , 指定本次Ansible ad-hoc 要执行的模块。可以类别成SHELL 中的命令。
-a , 模块的参数. 可以类比成SHELL 中的命令参数
Example
// 快速入门的实例
# ansible all -i 192.168.122.129,192.168.122.131 -m copy -a "src=/tmp/a.conf dest=/tmp/a.conf"
3.2 模块类型
Ansible 模块分三种类型: 核心模块(core module)、附加模块(extra module)及用户自定义模块(consume module)。
核心模块是由Ansible 的官方团队提供的。
附加模块是由各个社区提供的。例如: OPENSTACK 社区、DOCKER 社区等等。
当核心模块和附加模块都无法满足你的需求时,用户可以自定义模块。
默认情况下,在安装Ansible 的时候, 核心模块和附加模块都已经安装而无需用户干预。
3.3 联机帮助
Ansible 的核心模块和附加模块,数量有1000+ 。这样庞大的模块数量,对于任何一个接触Ansible 的人都不可能将其完全记住、掌握使用。 因此能够顺利使用Ansible 的帮助文档,对我们来说是很有必要的。Ansible 的帮助文档,由
它本身提供的命令 ansible-doc 实现。
常用帮助参数
// 列举出所有的核心模块和附加模块
# ansible-doc -l
// 查询某个模块的使用方法
# ansible-doc modulename
// 查询某个模块的使用方法,比较简洁的信息
# ansible-doc -s modulename
// Example
# ansible-doc yum
# ansible-doc -s yum
3.4 常用模块
command & shell 模块
两个模块都是在远程服务器上去执行命令。但command模块是ad-hoc的默认模块,在执行ad-hoc时,若不指定模块的名字则默认使用此模块.常用参数如下:
command & shell
- chdir 在运行命令之前,切换到此目录。
- executable 更改用于执行命令的shell(bash,sh),需要是可执行文件的绝对路径。
Example
// ad-hoc 默认在不指定 -m 参数的时候, 使用了默认的command 模块
# ansible all -i inventory -a "ls /root"
# ansible all -i inventory -m command -a "ls /root" //等同第一个命令
# ansible all -i inventory -m shell -a "ls /root"
两个模块功能类似的模块又存在的必要吗? 他们之间的差异在哪里?
shell 模块可以执行SHELL 的内置命令
command 模块无法执行SHELL 的内置命令
如何检测那些命令是shell 的 内置命令呢?
# type -a set // set 为SHELL内置命令
set is a shell builtin
# type -a env // env 非内置命令
env is /bin/env
env is /usr/bin/env
Example2
# ansible all -i localhost, -c local -a "set"
localhost | FAILED | rc=2 >>
[Errno 2] 没有那个文件或目录
// -c local 表示以本地的方式执行,不使用 SSH 连接的方式
# ansible all -i localhost, -c local -m shell -a "set"
localhost | SUCCESS | rc=0 >>
BASH=/bin/sh
BASHOPTS=cmdhist:extquote:force_fignore:hostcomplete:interactive_comments:progcomp:promptvars:sourcepath
BASH_ALIASES=()
BASH_ARGC=()
BASH_ARGV=()
BASH_CMDS=()
BASH_EXECUTION_STRING=set
BASH_LINENO=()
BASH_SOURCE=()
BASH_VERSINFO=([0]="4" [1]="1" [2]="2" [3]="1" [4]="release" [5]="x86_64-redhat-linux-gnu")
BASH_VERSION='4.1.2(1)-release'
DIRSTACK=()
......
......
script 模块
将管理节点上的脚本传递到远程服务器上进行执行,理论上此模块的执行完全不需要被管理服务器上有Python。
Example
// 管理节点上的一个脚本
# cat /root/a.sh
#/bin/bash
touch /tmp/testfile
# ansible all -i inventory -m script -a "/root/a.sh"
copy 模块
copy 模块的主要用于管理节点和被管理节点之间的文件拷贝。经常使用到的参数如下:
- src 指定拷贝文件的源地址
- dest 指定拷贝文件的目标地址
- backup 拷贝文件前,若原始文件发生变化,则对目标文件进行备份
- woner 指定新拷贝文件的所有者
- group 指定新拷贝文件的所有组
- mode 指定新拷贝文件的权限
Example
// copy 管理节点上的/tmp/a.conf 到被管理节点上
# ansible all -i inventory -m copy -a "src=/tmp/a.conf dest=/tmp/a.conf"
// copy 前, 在被管理节点上对原文件进行备份
# ansible all -i inventory -m copy -a "src=/tmp/a.conf dest=/tmp/a.conf backup=yes"
// copy 文件的同时对文件进行用户及用户组设置
# ansible all -i inventory -m copy -a "src=/tmp/a.conf dest=/tmp/a.conf owner=nobody group=nobody"
// copy 文件的同时对文件进行权限设置
# ansible all -i inventory -m copy -a "src=/tmp/a.conf dest=/tmp/a.conf mode=0755"
service 模块
管理远程节点上的服务。类似于Linux上的service命令。常用参数如下:
– enabled 是否开机启动 yes|no
– name 必选项,服务名称
– runlevel 运行级别
– sleep 如果执行了restarted,在则stop和start之间沉睡几秒钟
– state 对当前服务执行启动,停止、重启、重新加载等操作(started,stopped,restarted,reloaded)
注意:
使用 service 模块时, enabled 和 state 参数至少要指定一个。
使用 service 模块管理的服务,必须在系统中存在 /etc/init.d/XXX 对应的服务。
比如若管理Nginx 服务,则应该存在 /etc/init.d/nginx
Example
// 启动 Nginx 服务
# ansible all -i inventory -m service -a "name=nginx state=started"
// 关闭 Nginx 服务
# ansible all -i inventory -m service -a "name=nginx state=stopped"
// 重启 Nginx 服务
# ansible all -i inventory -m service -a "name=nginx state=restarted"
// 重新加载 Nginx 服务
# ansible all -i inventory -m service -a "name=nginx state=reloaded"
// 加 Nginx 服务设置开机自启动
# ansible all -i inventory -m service -a "name=nginx enabled=yes"
systemd 模块
管理远程节点上的 systemd 服务,就是由 systemd 所管理的服务。常用参数如下:
- daemon_reload 重新载入 systemd,扫描新的或有变动的单元
– enabled 是否开机启动 yes|no
– name 必选项,服务名称
– state 对当前服务执行启动,停止、重启、重新加载等操作(started,stopped,restarted,reloaded)
Example
// 重新加载 systemd
# ansible all -i inventory -m systemd -a "daemon_reload=yes"
// 启动 Mariadb 服务
# ansible all -i inventory -m systemd -a "name=mariadb state=started"
// 关闭 Mariadb 服务
# ansible all -i inventory -m systemd -a "name=mariadb state=stopped"
// 重启 Mariadb 服务
# ansible all -i inventory -m systemd -a "name=mariadb state=restarted"
// 重新加载 Mariadb 服务
# ansible all -i inventory -m systemd -a "name=mariadb state=reloaded"
// 将 Mariadb 服务设置开机自启动
# ansible all -i inventory -m systemd -a "name=mariadb enabled=yes"
yum 模块
等同于 Linux 上的YUM 命令, 对远程服务器上RPM包进行管理。常用参数如下:
- name 要安装的软件包名, 多个软件包以逗号(,) 隔开
- state 对当前指定的软件安装、拆卸操作(present installed latest absent removed)
安装参数 present installed latest
拆卸参数 absent removed
Example
// 安装一个软件包
# ansible all -i inventory -m yum -a "name=nginx state=present"
# ansible all -i inventory -m yum -a "name=nginx state=latest"
# ansible all -i inventory -m yum -a "name=nginx state=installed"
// 拆卸一个软件包
# ansible all -i inventory -m yum -a "name=nginx state=absent"
# ansible all -i inventory -m yum -a "name=nginx state=removed"
// 安装一个软件包组
# ansible all -i inventory -m yum -a "name='@Development tools' state=present"
group 模块
在被管理节点上,对组进行管理。 常用参数如下:
- name 组名称, 必须的
- system 是否为系统组, yes/no
Example
// 创建普通组 db_admin
# ansible all -i 172.16.153.160, -m group -a "name=db_admin"
user 模块
用于在被管理节点上对用户进行管理。常用参数如下:
- name 必须的参数, 指定用户名
- password 设置用户的密码,这里接受的是一个加密的值,因为会直接存到 shadow
- update_password 假如设置的密码不同于原密码,则会更新密码. 在 1.3 中被加入
- home 指定用户的家目录
- shell 设置用户的 shell
- uid 指定用户的 UID
- comment 用户的描述信息
- create_home 在创建用户时,是否创建其家目录。默认创建,假如不创建,设置为 no。2.5版本之前
使用 createhome
- group 设置用户的主组
- groups 将用户加入到多个组中,多个用逗号隔开,也可以是个列表
- system 设置为 yes 时,将会创建一个系统账号
- expires 设置用户的过期时间,值为时间戳,会转为为天数后,放在 shadow 的最后一个字段里
- generate_ssh_key 设置为 yes 将会为用户生成密钥,这不会覆盖原来的密钥
- ssh_key_type 指定用户的密钥类型, 默认 rsa, 具体的类型取决于被管理节点
- remove 当与 state=absent 一起使用,删除一个用户及其家目录,可选的值为: yes/no
Example
// 生成加密的密码
# echo test |openssl passwd -1 -stdin
// 创建一个用户 nginx, 指定其 shell 为 nologin
# ansible all -i inventory -m user -a "name=nginx shell=/sbin/nologin"
// 创建用户 yangge, 并且为其创建密钥对,并且密钥类型为: ecdsa
# ansible all -i inventory -m user -a "name=yangge generate_ssh_key=yes ssh_key_type=ecdsa"
// 创建用 tom, 并且设置其有效期到 2019年8月16日, 加入到组 db_admin 中
# timestamp=$(date +%s -d 20180725)
// 或者
# timestamp=$(python -c 'import time;print(time.mktime(time.strptime("2019-08-16", "%Y-%m-%d")))')
# ansible all -i 172.16.153.160, -m user -a "name=tom expires=$timestamp"
// 修改已有用户 tom 在 31 天后过期
# ansible all -i 172.16.153.160, -m user -a "name=tom expires=$(echo $((86400 * 31))) groups=db_admin,"
date 命令说明
// 计算 3 小时之后是几点几分
# date +%T -d '3 hours'
// 任意日期的前 N 天,后 N 天的具体日期
# date +%F -d "20190910 1 day"
# date +%F -d "20190910 -1 day"
// 计算两个日期相差天数, 比如计算生日距离现在还有多少天
# d1=$(date +%s -d 20180728)
# d2=$(date +%s -d 20180726)
# echo $(((d1-d2)/86400))
file 模块
file 模块主要用于远程主机上的文件操作,经常使用的模块参数如下:
- group 定义文件/目录的属组
- mode 定义文件/目录的权限
- owner 定义文件/目录的属主
- path 必选项,定义文件/目录的路径
- recurse 递归的设置文件的属性,只对目录有效
- src 要被链接(软/硬)的源文件的路径,只应用于state=link的情况
- dest 被链接到的路径,只应用于state=link的情况
- state
directory 如果目录不存在,创建目录
file 文件不存在,则不会被创建,存在则返回文件的信息,常用于检查文件是否存在。
link 创建软链接
hard 创建硬链接
touch 如果文件不存在,则会创建一个新的文件,如果文件或目录已存在,则更新其最后修改时间
absent 删除目录、文件或者取消链接文件
Example
// 创建一个文件
# ansible all -i inventory -m file -a "path=/tmp/foo.conf state=touch"
// 改变文件所有者及权限
# ansible all -i inventory -m file -a "path=/tmp/foo.conf owner=nobody group=nobody mode=0644"
// 创建一个软连接
# ansible all -i inventory -m file -a "src=/tmp/foo.conf dest=/tmp/link.conf state=link"
// 创建一个目录
# ansible all -i inventory -m file -a "path=/tmp/testdir state=directory"
// 取消一个连接
# ansible all -i inventory -m file -a "path=/tmp/link.conf state=absent"
// 删除一个文件
# ansible all -i inventory -m file -a "path=/tmp/foo.conf state=absent"
cron 模块
管理远程节点的CRON 服务。等同于Linux 中的CRON。 常用命令如下:
- name 指定一个cron job 的名字。一定要指定,便于日之后删除。
- minute 指定分钟,可以设置成(0-59, *, */2 等)格式。 默认是 * , 也就是每分钟。
- hour 指定小时,可以设置成(0-23, *, */2 等)格式。 默认是 * , 也就是每小时。
- day 指定天, 可以设置成(1-31, *, */2 等)格式。 默认是 * , 也就是每天。
- month 指定月份, 可以设置成(1-12, *, */2 等)格式。 默认是 * , 也就是每周。
- weekday 指定星期, 可以设置成(0-6 for Sunday-Saturday, * 等)格式。默认是 *,也就是每星期。
- job 指定要执行的内容,通常可以写个脚本,或者一段内容。
- state 指定这个job的状态,可以是新增(present)或者是删除(absent)。 默认为新增(present)
Example
// 新建一个 CRON JOB 任务
# ansible all -i inventory -m cron -a "name='create new job' minute='0' job='ls -alh > /dev/null'"
// 删除一个 CRON JOB 任务,删除时,一定要正确指定job 的name参数,以免误删除。
# ansible all -i inventory -m cron -a "name='create new job' state=absent"
登录任何一台管理机验证cron
# crontab -l
#Ansible: create new job
0 * * * * ls -alh > /dev/null
debug模块
debug 模块主要用于PlayBook调试时使用,通常的作用是将一个变量的结果打印出来。常用参数如下:
- var 直接打印一个指定的变量值
- msg 打印一段可以格式化的字符串
Example
// 这里引入了变量,我们只需了解 debug 模板的使用即可。在学习变量、剧本时,我们会对它有更深刻的理解。
# ansible all -i inventory -m debug -a "var=role" -e "role=web"
# ansible all -i inventory -m debug -a "msg='role is {{role}} '" -e "role=web"
template 模块
template 模块使用了Jinjia2格式作为文件模版,可以进行文档内变量的替换。
它的每次使用都会被ansible标记为”changed”状态。文件以 .j2 结尾
模块常用参数如下:
- backup 创建一个包含时间戳信息的备份文件,这样如果您以某种方式错误地破坏了原始文件,
就可以将其恢复原状。yes/no
- force 默认值是yes,当内容与源不同时,它将替换远程文件。如果no,仅在目标不存在时才传输文件。
- src 指定 Ansible 控制端的 文件路径
- dest 指定 Ansible 被控端的 文件路径
- owner 指定文件的属主
- group 指定文件的属组
- mode 指定文件的权限
- newline_sequence 指定新文件的换行符; \n,\r, 或 \r\n
内置变量
ansible_managed - 包含一个字符串,可用于描述模板名称,主机,模板文件的修改时间和所有者的uid
template_host - 包含模板机器的节点名称
template_uid - 所有者的uid
template_path - 模版路径
template_fullpath - 模版的绝对路径
template_run_date - 模版呈现的时间
Example
// 把本地的当前目录下的 jinja2 模板文件 foo.j2 传送到目标机器上,并指定属主为 shark, 属组 为 wheel, 权限为 0644
# ansible all -i 172.16.153.160, -m template -a "src=./foo.j2 dest=/tmp/foo.conf owner=shark group=wheel mode=0644"
// 上面的用法其实和 copy 模块一样,下面我们就来介绍 template 模块的强大之处
1. 建立一个 template 文件, 名为 hello_world.j2
# cat hello_world.j2
Hello {{var}} !
2. 执行命令,并且设置变量 var 的值为 world
# ansible all -i 172.16.153.160, -m template -a "src=hello_world.j2 dest=/tmp/hello_world.world" -e "var=world"
3. 在被控主机上验证
# cat /tmp/hello_world.world
Hello world !
所有模块列表 https://docs.ansible.com/ansible/latest/modules/list_of_all_modules.html
模块按照首字母排序
第 4 章 Ansible 剧本
通过对 AD-HOC 的学习,我们发现 AD-HOC 每次只能在被管理节点上执行简单的命令。而日常工作中,我们往往面临的是一系列的复杂操作,例如我们有可能需要安装软件、更新配置、启动服务等等一系列操作的结合。此时再通过 AD-HOC 去完成任务就有些力不从心了。在这种场景下,Ansible引进了 PLAYBOOK 来帮忙我们解决这样复杂问题。
4.1 PlayBook是什么
Playbook 也通常被大家翻译成剧本。可以认为它是Ansible 自定义的一门语言(可以将 Playbook 比作 Linux 中的 shell,而 Ansible 中的 Module 可以比作为 Linux 中的各种命令。通过这样的类比,我们对PlayBook就有了一个更形象的认识了)。既然 Playbook 是一门语言,那么它遵循什么样的语法格式? 有哪些语言呢性? 我们将通过下面的学习逐步了解。
4.2 YAML 学习
PlayBook遵循YAML 的语法格式。 因此在学习PlayBook之前,我们必须要先弄明白YAML 相关知识点。
YAML特点
YAML 文件以 # 为注释符
YAML 文件以 .yml 或者.yaml 结尾
YAML 文件以 --- 开始 , 以 ... 结束, 但开始和结束标志都是可选的
基本语法
大小写敏感
使用缩进表示层级关系
缩进时是使用Tab键还是使用空格一定要达到统一,建议使用空格。
相同层级的元素必须左侧对齐即可
YAML 支持的数据结构有三种: 字符串、列表、字典。
字符串
---
# YAML 中的字符串可以不使用引号,即使里面存在空格的时候,当然了使用单引号和双引号也没有错。
this is a string
'this is a string'
"this is a string"
# YAML 中若一行写不下你要表述的内容,可以进行折行。写法如下:
long_line: |
Example 1
Example 2
Example 3
# 或者
long_line: >
Example 1
Example 2
Example 3
...
列表
---
# 若熟悉 Python 的话, 可以认为它就是Python中的List ,若熟悉 C 语言的话, 可以认为它是 C 中的数组。
# 如何定义: 以短横线开头 + 空格 + 具体的值
- red
- green
- blue
# 以上的值假如转换成 python 的 List 会是这样:
# ['red', 'green', 'blue']
...
字典
---
# 若熟悉Python 的话, 可以认为它就是Python中的 Dict
# 如何定义: key + 冒号(:) + 空格 + 值(value), 即 key: value
name: Using Ansible
code: D1234
# 转换为 python 的 Dict
# {'name': 'Using Ansibel', 'code': 'D1234'}
...
混合结构
以上,针对YAML 的所有基础知识点就介绍完了。但在日常生活中,往往需要的数据结构会特别复杂,有可能会是字符串、列表、字典的组合形式。 这里举一个小例子:
所有人都上过学,都知道到学校里是以班级为单位。我们去使用列表和字典的形式去描述一个班级的组成。
---
class:
- name: stu1
num: 001
- name: stu2
num: 002
- name: stu3
num: 003
# {'class': [{'name': 'stu1', 'num': 1},{'name': 'stu2', 'num': 2},...]}
...
验证YAML 语法
// 将YAML文件,通过Python 的YAML 模块验证, 若不正确则报错。若正确则会输出YAML 里的内容。
// 注意使用时,一定确保安装了yaml 软件包。
python -c 'import yaml,sys; print yaml.load(sys.stdin)' < myyaml.yml
python3 -c 'import yaml,sys; print(yaml.load(sys.stdin))' < myyaml.yml
Example
// 正确的情况
# cat myyaml.yml
---
- red
- green
- blue
...
# python -c 'import yaml,sys; print yaml.load(sys.stdin)' < myyaml.yml
['red', 'green', 'blue']
// 错误的情况, 将YAML文件写错
# cat myyaml.yml
---
- red
- green
-blue
...
# python -c 'import yaml,sys; print yaml.load(sys.stdin)' < myyaml.yml
Traceback (most recent call last):
File "", line 1, in
File "/usr/local/lib/python2.7/site-packages/yaml/__init__.py", line 71, in load
return loader.get_single_data()
File "/usr/local/lib/python2.7/site-packages/yaml/constructor.py", line 37, in get_single_data
node = self.get_single_node()
...
...
4.3 Play 定义
由于Playbook 是由一个或者多个Play组成,那么如果我们熟悉Play 的写法,就自然掌握了我们这章的PlayBook。
那如何定义一个Play呢
1、每一个Play 都是以短横杠开始的
2、每一个Play 都是一个YAML 字典格式
根据上面两条Play 的规则,一个假想的 Play 应该是如下的样子
---
- key1: value1
key2: value2
key3: value3
...
...
由于一个Playbook 是由一个或者多个Play构成, 那么一个含有多个Play的Playbook 结构上应该是如下的样子
---
# 一个含有3个Play 的伪PlayBook构成
- key1: value1
key2: value2
key3: value3
- key4: value1
key5: value2
key6: value3
- key1: value1
key2: value2
key3: value3
...
4.4 Play 属性
以上一小节中的Play为基础, Play中的每一个key, key1、key2、key3等;这些key在PlayBook中被定义为Play的属性。这些属性都具有特殊的意义,我们不能随意的自定义Play 的属性。那么Ansible本身都支持哪些Play属性呢
常用属性
(1)、name 属性, 每个play的名字
(2)、hosts 属性, 每个play 涉及的被管理服务器,同ad hoc 中的patten
(3)、tasks 属性, 每个play 中具体要完成的任务,以列表的形式表达
(4)、become 属性,如果需要提权,则加上become 相关属性
(5)、become_user 属性, 若提权的话,提权到哪个用户上
(6)、remote_user属性,指定连接用户。若不指定,则默认使用当前执行 ansible Playbook 的用户
4.5 一个完整剧本
根据上一小节中介绍的真实的属性,一个含有一个Play 的 Playbook 应该是如下的样子
---
- name: the first play example
hosts: all
remote_user: root
tasks:
- name: install nginx package
yum: name=nginx state=present
- name: copy nginx.conf to remote server
copy: src=nginx.conf dest=/etc/nginx/nginx.conf
- name: start nginx server
service:
name: nginx
enabled: true
state: started
tasks 属性中任务的多种写法
# 以启动 nginx 服务,并增加开机启动为例
# 一行的形式:
service: name=nginx enabled=true state=started
# 多行的形式:
service: name=nginx
enabled=true
state=started
# 多行写成字典的形式:
service:
name: nginx
enabled: true
state: started
具有多个Play 的Playbook
---
- name: manage web servers
hosts: web-servers
remote_user: root
tasks:
- name: install nginx package
yum: name=nginx state=present
- name: copy nginx.conf to remote server
copy: src=nginx.conf dest=/etc/nginx/nginx.conf
- name: start nginx server
service:
name: nginx
enabled: true
state: started
- name: manager db servers
hosts: db-servers
tasks:
- name: update database confg
copy: src=my.cnf dest=/etc/my.cnf
如何对Playbook 进行语法校验
// 因为PlayBook 属于YAML 格式, 我们同样可以使用检查YAML的语法格式的方法进行检查PlayBook的语法正确性。
// 此形式的校验,只能校验PlayBook是否正确,而不能校验YAML文件是否语法正确。
# ansible-playbook myplaybook.yml --syntax-check
如何运行PlayBook
# ansible-playbook myplaybook.yml
如何单步跟从调试PlayBook
// 执行Task中的任务,需要手动确认是否往下执行。
# ansible-playbook myplaybook.yml --step
如何测试运行PlayBook
// 会执行完整个PlayBook ,但是所有Task中的行为都不会在远程服务器上执行,所有执行都是模拟行为。
# ansible-playbook myplaybook.yml -C
// -C 为大写的字母 C
第 5 章 Ansible 变量
我们在PlayBook一节中,将PlayBook类比成了Linux中的shell。那么它作为一门Ansible特殊的语言,肯定要涉及到变量定义、控制结构的使用等特性。在这一节中主要讨论变量的定义和使用。
变量命名规则
变量的名字由字母、下划线和数字组成,以字母开头。
如下变量命名为正确:
good_a OK
ok_b OK
如下变量命名为错误:
_aaa FAIL
2_bb FAIL
保留关键字不能作为变量名称
add, append, as_integer_ratio, bit_length, capitalize, center, clear, conjugate, copy, count, decode, denominator, difference, difference_update, discard, encode, endswith, expandtabs, extend, find, format, fromhex, fromkeys, get, has_key, hex, imag, index, insert, intersection, intersection_update, isalnum, isalpha, isdecimal, isdigit, isdisjoint, is_integer, islower, isnumeric, isspace, issubset, issuperset, istitle, isupper, items, iteritems, iterkeys, itervalues, join, keys, ljust, lower, lstrip, numerator, partition, pop, popitem, real, remove, replace, reverse, rfind, rindex, rjust, rpartition, rsplit, rstrip, setdefault, sort, split, splitlines, startswith, strip, swapcase, symmetric_difference, symmetric_difference_update, title, translate, union, update, upper, values, viewitems, viewkeys, viewvalues, zfill