3.1 Ansible Playbooks 高级一
Handlers 触发器
这个东西类似一个触发器,比如这么一个场景,我们把nginx conf配置文件拷贝到目标机器,那么当这个配置文件更新后,需要重启nginx,类似这种需求我们就拿 Ansible handlers 来做
- name: Copy configuration files copy: src: xtest1.conf dest: /etc/nginx/conf.d/xtest1.conf notify: - restart_nginx handlers: - name: restart_nginx service: name: nginx state: restarted
完整示例
https://gitee.com/as4k/ysansible/blob/master/handlers/main.yml
环境变量增加与修改
有多种场景,我们需要改动目标机器的一些变量(或配置),比如关闭selinux,这种操作若是写成shell脚本,可以像下面这样
sed 's#^SELINUX=.*#SELINUX=disabled#g' /etc/selinux/config
Ansible也提供了类似的用法,如下面这样
- name: Ensure SELinux is set to disabled mode lineinfile: path: /etc/selinux/config regexp: '^SELINUX=' line: SELINUX=disabled
如果需要改动一个文本文件里的某一行,或者增加一行,基本用lineinfile
模块就妥
比如我们在~/.bash_profile
增加环境变量,类似如下
- name: Add an environment variable to the remote user's shell. lineinfile: path: "~/.bash_profile" regexp: "^ENV_VAR=" line: "ENV_VAR=value_helloworld"
上面这个模块的含义是保证~/.bash_profile
,有这一行ENV_VAR=value_helloworld
,有保持不动,没有给增加上去
另外需要一提的是,不同的环境变量最好放到一个单独文件中去,这样最方便维护,比如在CenOS7中环境变量可以放在/etc/profile.d
,这样我们简单的copy文件即可,易于阅读和维护
- name: Copy java_env copy: src: java_env.sh dest: /etc/profile.d/java_env.sh
虽然Ansible有很多高级牛逼的用法,但在生产环境中使用Ansible不是为了炫技,能用简单的模块解决问题,则用简单的模块
完整示例
https://gitee.com/as4k/ysansible/blob/master/env_variables/main.yml
在剧本中使用变量
不管在编程语言中亦或是Ansible中,总有那么一些东西是需要反复被使用,此时我们应该将这些东西提出成变量,以方便维护和修改,比如我们写一个用来安装wordpress(一款PHP写的博客软件)的剧本,那么软件版本号就比较适合做成变量,这样以后我们需要升级或者是把剧本给别人用,拿过来只要更改一下版本号即可,不需要去剧本中对应的地方都手动修改一下
一般拿到一个剧本,首先就是看有哪些变量,这些变量相当于对外访问的接口,如果一些东西比如软件的版本号,软件的数据存放目录,这些明显需要根据不同的场景传递不同的变量来使用的,通常都建议提成变量使用
变量命名规则
开头是 [A-Za-z]其它地方可以包含 下划线_ 数字[0-9]合法的变量示例:foo, foo_bar, foo_bar_5不合法的变量示例:_foo, foo-bar, 5_foo_bar, foo.bar
内嵌在剧本中的变量
vars: http_port: 80https://gitee.com/as4k/ysansible/blob/master/variables/playbook_var_in_file.yml
单独写在YAML文件里的变量
vars_files: - vars.ymlhttps://gitee.com/as4k/ysansible/blob/master/variables/playbook_var_file.yml
直接在命令行中添加的变量
# ansible-playbook playbook_var_cmd.yml --extra-vars "foo=bar" --limit 192.168.31.100 # ansible-playbook playbook_var_cmd.yml --extra-vars "@vars.yml" --limit 192.168.31.100https://gitee.com/as4k/ysansible/blob/master/variables/playbook_var_cmd.yml
这几种方式使用变量有优先级的区别,在命令行中使用的变量优先级最高,详情可以参考下面的文档
https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable
如果仅仅是用剧本来组织Ansible(比较初级,后面我们还会介绍roles),那么变量少内嵌到playbook里,变量多独立成一个或多个文件即可,建议少用--extra-vars
形式,除非拿来测试,因为这种形式不好追踪,而写到文件里,通过git等代码管理工具即可追踪
注册变量 register 捕获命令输出
有些场景下,比如我们要在目标机器安装一个软件,但是安装之前我们需要执行一个命令,动态判断目标机器的状态,假设有A、B、C这三种状态,而每种状态要执行的东西不一样,因此有必要先把状态(也就是变量)保存下来,备用,如下面这样
- name: Register the output of the 'uptime' command. command: uptime register: system_uptime - name: Print a simple message if a command resulted in a change. debug: msg="Command resulted in a change!" when: system_uptime.changed
https://gitee.com/as4k/ysansible/blob/master/registered_var/main1.yml
某些时候,我们需要从目标配置文件中把某个变量读取出来,记录下来,以便后续使用,比如把目标机器的机房信息读出来,可以利用register
实现,如下面这样
# ignore_errors 用来防止playbook被打断 - name: Run a shell command and register its output as a variable shell: cat /etc/redhat-release register: foo_result ignore_errors: true - name: Run a shell command using output of the previous task shell: echo "ok" > /tmp/tmp.txt when: foo_result.rc == 0
参考示例:https://gitee.com/as4k/ysansible/blob/master/env_variables/main.yml
变量的类型以及访问变量
我们知道Ansible的主要开发语言是python,很多python的数据类型在Ansible里一样有,比如数组、字典等,Ansible在模板变量替换方面使用的是jinjia语法
最基础
- name: test1 debug: msg: "{{ foo }}"不加双引号会报错
数组
foo3_list: - one - two - three========== - name: test3 debug: msg: "{{ foo3_list[1] }}" - name: test4 debug: msg: "{{ foo3_list|first }}"数组从0开始{{ foo3_list|first }} 与 {{ foo3_list[1] }} 等价, |first 是jinjia过滤器的语法
字典
foo4_dict: xiaoming: 186 xiaowang: 187 xiaoli: 188============ - name: test4 debug: msg: "{{ foo4_dict.xiaoming }}" - name: test5 debug: msg: "{{ foo4_dict['xiaoli'] }}" - name: test6 debug: msg: "{{ ansible_eth0['ipv4']['address'] }}"{{ foo4_dict.xiaoming }} 与 {{ foo4_dict['xiaoli'] }} 等价如果字典的key有些什么特殊符号之类,用第2种
变量的类型还可以进行复杂的嵌套,但是如无必要尽量使用简单的数据类型
完整示例
https://gitee.com/as4k/ysansible/blob/master/acccessing_var/main1.yml
主机清单里的变量 Inventory variables
形式如下面这样
cat /etc/ansible/hosts[allservers]192.168.31.106192.168.31.100192.168.31.101192.168.31.102192.168.31.103192.168.31.104192.168.31.105192.168.31.107192.168.31.108[webservers]192.168.31.100 os=centos73 admin_user=jane192.168.31.101 os=centos77 admin_user=jack192.168.31.102 os=centos78[webservers:vars]dns1=223.5.5.5dns2=8.8.8.8admin_user=admin
在这里定义的变量跟在剧本里定义的变量,逻辑上无太多区别,都可以在剧本中使用,一般只有和指定机器或者指定机器组强相关的变量,如一批机器大家用的NTP时间服务器都在国内,但其中一台机器特殊,使用的是国外时间服务器,那么即可在主机清单使用变量进行标识
不过变量太多都写在主机清单里则比较乱,更适合的方案是独立出来,即 "主机变量和组变量"
主机变量和组变量 Host and Group variables
观察下面的目录结构
[root@192_168_31_106 /data/ysansible]# tree host_and_group_variables/host_and_group_variables/├── group_vars│ └── webservers├── hosts├── host_vars│ ├── 192.168.31.100│ ├── 192.168.31.101│ └── 192.168.31.102├── main1.yml└── README.md# 对应线上代码在 https://gitee.com/as4k/ysansible/tree/master/host_and_group_variables
hosts即主机清单文件,实际执行的时候我们移动到当前目录,使用-i
参数指定这个主机清单,如
ansible-playbook main1.yml -i hosts
group_vars
和host_vars
文件夹为固定目录,并且必须和主机清单处在同一级目录里,其中group_vars下面的文件名和主机清单里的组名对应,host_vars目录下的文件名和主机清单里的hosts对应(可能是IP也可能是域名),分别代表该组机器共用的变量,以及单个机器拥有的变量,hosts_vars优先级高于group_vars
另外还有一个特殊的组名(文件名)all
,代表全部机器(组)都可以使用的变量
Facts 系统变量收集
Linux操作系统有很多基础的信息,诸如内存、CPU、操作系统版本、内网IP地址等,这些信息在我们部署服务等时候经常也能用到,Ansible称呼这些东西为facts,这个功能默认是开启的,我们可以直接使用
---- hosts: all gather_facts: yes # gather_facts: no #默认是yes #关掉信息收集可以提升性能,但不能再使用相关变量 tasks: - name: get ip address debug: msg: "{{ ansible_eth0['ipv4']['address'] }}"
如果我们想看到全部可以使用的facts,可以使用下面的命令
ansible 192.168.31.100 -m setup > ansible_setup.json
CentOS7收集的全部系统变量,参考如下:
https://gitee.com/as4k/ysansible/blob/master/facts/ansible_setup.json
参考示例:https://gitee.com/as4k/ysansible/blob/master/facts/main.yml
我们也可以自己手动增加系统变量,如下是一个使用shell命令获取IP地址的示例
- name: Get host IP address. shell: > prefix=`/sbin/ip route | awk '/default/ { print $3 }' | sed -r 's#\.[0-9]+$##g'`; hostname -I | egrep -o "$prefix\.[0-9]+" register: host_ip changed_when: false - name: Set host_ip_address variable. set_fact: host_ip_address: "{{ host_ip.stdout }}"
参考示例:https://gitee.com/as4k/ysansible/blob/master/facts/set_fact.yml
内置的主机清单变量
这方面我们介绍一个ansible_host
- name: ansible_host debug: msg: "echo {{ ansible_host }}"
这个内置的变量专门用来获取主机清单里的IP地址(当然也可能是域名),因为在生产环境中通常机器的网卡不止一个,内网IP地址也不止一个,但一般会有一个主要使用的内网IP地址,此时如果我们使用上一小节的facts来收集IP地址则会得到多个,如何区分哪个IP是我们主要使用的IP地址,就有点麻烦。因此我们直接使用ansible_host
这个内置的主机清变量,这样只需我们自己把主要使用的IP地址放到主机清单里即可
参考示例:https://gitee.com/as4k/ysansible/blob/master/centos7_init/centos7_init.yml
Vault 安全加密
有些时候我们的playbook里有些敏感信息,类似数据库root密码这种,不想给别人看到,也不想直接同步到git仓库上去,此时比较简单的办法是把相关密码等敏感信息都独立出来,比如直接放到当前项目之外,用的时候copy到目标机器。不过这种方法不太方便管理,也比较乱,破坏原有playbook的完整性,这种情况下我们可以考虑使用Ansible Vault加密功能
看一个简单的示例
cat vars.ymlmy_password: hello123456=============#执行加密指令ansible-vault encrypt vars.yml #系统会要求输入密码,需要记住这个密码New Vault password: 123456Confirm New Vault password: 123456Encryption successful=============cat vars.yml$ANSIBLE_VAULT;1.1;AES256376138643139653936316533393566333766663865373533386138653738633165623964613033663161643662343963316534396365643265383562303862360a363662636437313033646333363339303332326563613632336264363834343862346463613031303536626335663732313339346565356561373861346434650a30363533363261626337363139356666636337333430316236316138633839646333353137396133363831663166633366323731646339396261623432336361303039643164343933653839323932366537333663623037666638333764336338643436383463386464303266643539663066316231323839626261653937636166353462313234663461386538613564333563613834346431636430383366323235346662653337633739366564643637313164326662633933346236326365386465376639333738363862343663373636613233343136353466333132666433656531656437643437666365363830353162666163643365313366353937
可以看到,原先的文本被直接修改加密了,下面我们看下如何使用
交互式输入密码执行
[root@192-168-31-106 /data/ysansible/vault]# ansible-playbook main1.yml --limit 192.168.31.100 --ask-vault-passVault password: 123456 (这个是我们执行ansible-vault encrypt vars.yml命令要求输入的密码,不是vars.yml里面记录的内容)....
非交互式的直接运行
touch ~/.ansible/vault_pass.txtecho "123456" > ~/.ansible/vault_pass.txtchmod 0600 ~/.ansible/vault_pass.txtansible-playbook main1.yml --limit 192.168.31.100 --vault-password-file ~/.ansible/vault_pass.txt
其它vault常用命令
解密成原始文本,需要输入密码ansible-vault decrypt vars.yml 编辑原始文件,需要输入密码ansible-vault edit vars.yml查看原始的文本ansible-vault view vars.yml
总结来说,使用Ansible加密信息,我们需要:
- 将文本进行加密(文本内容无需改动)
- 把加密用的密码妥善保存起来
- 执行命令的时候增加
--vault-password-file
参数
引入加密还是需要一些额外的维护成本的,加密后的文本单独看基本无意义,大家根据情况取舍
参考示例:https://gitee.com/as4k/ysansible/blob/master/vault/main1.yml
YAML 换行语法
- name: test3 copy: content: > 这里的内容完全是在一行的 this is really a single line of text despite appearances 末尾有换行 dest: /root/test3.txt - name: test4 copy: content: | 这里的内容保持原样,是在多行的 this is really a single line of text despite appearances dest: /root/test4.txt - name: test5 copy: content: >- 这里的内容完全是在一行的 this is really a single line of text despite appearances 末尾没有有换行 dest: /root/test5.txt - name: test6 copy: content: |- 这里的内容保持原样,是在多行的 this is really a single line of text despite appearances 末尾没有换行 dest: /root/test6.txt
参考示例: https://gitee.com/as4k/ysansible/blob/master/yaml_syntax/main1.yml
参考资料
https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#registering-variableshttps://docs.ansible.com/ansible/latest/user_guide/playbooks_conditionals.html#playbooks-conditionals
©著作权归作者所有:来自51CTO博客作者阿胜4K的原创作品,如需转载,请注明出处,否则将追究法律责任
更多相关文章
- 3.2 Ansible Playbooks 高级二
- JavaScript变量中你不知道的几个小埋伏!
- Java怎么配置环境变量?
- 记录shell脚本中的特殊变量
- JS变量中你不知道的小埋伏
- 下划线_在Python中的用途
- 大数据成神之路-Java高级特性增强(Volatile)
- 对查询的结果集添加自增序号
- 【面试】两个变量进行交替的N种方法