kolla-ansible快速入门
kolla-ansible是一个结构相对简单的项目,它通过一个shell脚本,根据用户的参数,选择不同的playbook和不同的参数调用ansible-playbook执行,没有数据库,没有消息队列,所以本文的重点是ansible本身的语法。
kolla-ansible命令
kolla-ansible命令的主要代码如下:
#!/bin/bash
#
# This script can be used to interact with kolla via ansible.
# 默认变量
INVENTORY="${BASEDIR}/ansible/inventory/all-in-one"
PLAYBOOK="${BASEDIR}/ansible/site.yml"
CONFIG_DIR="/etc/kolla"
PASSWORDS_FILE="${CONFIG_DIR}/passwords.yml"
while [ "$#" -gt 0 ]; do
case "$1" in
(--inventory|-i)
INVENTORY="$2"
shift 2
;;
kolla-ansible支持的各种参数,略
esac
done
case "$1" in
(prechecks)
ACTION="Pre-deployment checking"
EXTRA_OPTS="$EXTRA_OPTS -e action=precheck"
;;
(mariadb_recovery)
略,以下类似皆略
esac
CONFIG_OPTS="-e @${CONFIG_DIR}/globals.yml -e @${PASSWORDS_FILE} -e CONFIG_DIR=${CONFIG_DIR}"
CMD="ansible-playbook -i $INVENTORY $CONFIG_OPTS $EXTRA_OPTS $PLAYBOOK $VERBOSITY"
process_cmd
可以看出,当我们执行kolla-ansible deploy时,kolla-ansible命令帮我们调用了对应的ansible-playbook执行,除此之外,没有其他工作。所以对于kolla-ansible项目,主要学习ansible语法即可。
ansible
一个简单的ansible命令示例如下:ansible -i /root/myhosts ha01 -m setup
这个命令的作用是,对/root/hosts文件中的所有属于ha01分类的主机,执行setup模块收集该主机的信息,它包括两种元素,主机清单和模块,下面分别介绍这两种元素。
Host Inventory(主机清单)
host inventory 是一个文件,存放了所有被ansible管理的主机,可以在调用anabile命令时,通过-i参数指定。
- 下面是一个最简单的hosts file的例子,包含1个主机ip和两个主机名:
193.192.168.1.50
ha01
ha02·
可以执行以下命令检查ha01是否能够连通
ansible -i $filename ha01 -m ping
ha01 | SUCCESS => {
"changed": false,
"ping": "pong"
}
2.我们可以把主机分类,示例如下
deploy-node
[ha]
ha01
ha02
[compute]
compute01
compute02
compute03
- 如果主机数量比较多,也可以用正则表达,示例如下:
deploy-node
[ha]
ha[01:02]
[openstack-compute]
compute[01:50]
[openstack-controller]
controller[01:03]
[databases]
db-[a:f].example.com
- 所有的controller和compute,都是openstack的节点,所以我们可以再定义一个类别openstack-common,把他们里面的主机都包括进去
[openstack-common:children]
openstack-controller
openstack-compute
[common:children]
openstack-common
databases
ha
- 当我们有了如上的inventory 文件后,可以执行如下命令,检验是不是所有机器都能够被ansible管理
ansible -i $file common -m ping
Module(模块)
ansible封装了很多python脚本作为module提供给使用者,如:yum、copy、template,command,etc. 当我们会特定主机执行某个module时,ansible会把这个module对应的python脚本,拷贝到目标主机上执行。可以使用ansible-doc -l来查看ansible支持的所有module。使用ansible -v 模块名 来查看该模块的详细信息。
1. 一个例子,ping
上文的例子,使用了-m ping参数,意思是对这些主机,执行ping 模块,ping 模块是一个python脚本,作用是用来判断:目标机器是否能够通过ssh连通并且已经安装了python。
# ping module主要源码
description:
- A trivial test module, this module always returns C(pong) on successful
contact. It does not make sense in playbooks, but it is useful from
C(/usr/bin/ansible) to verify the ability to login and that a usable python is configured.
- This is NOT ICMP ping, this is just a trivial test module.
options: {}
from ansible.module_utils.basic import AnsibleModule
def main():
module = AnsibleModule(
argument_spec=dict(
data=dict(required=False, default=None),
),
supports_check_mode=True
)
#什么都不做,构建一个json直接返回
result = dict(ping='pong')
if module.params['data']:
if module.params['data'] == 'crash':
raise Exception("boom")
result['ping'] = module.params['data']
module.exit_json(**result)
if __name__ == '__main__':
main()
2. 自定义模块
example:Ansible模块开发-自定义模块
如果默认模块不能满足需求,可以自定义模块放到ansible指定的目录,默认的ansible配置文件是/etc/ansible/ansible.cfg,library配置项是自定义模块的目录。
openstack的kolla-ansbile项目的ansible/library目录下面存放着kolla自定义的module,这个目录下每一个文件都是一个自定义moudle。可以使用如下的命令来查看自定义module的使用方法:ansible-doc -M /usr/share/kolla-ansible/ansible/library -v merge_configs
3. action moudle
如上文所述,ansible moudle最终执行的位置是目标机器,所以module脚本的执行依赖于目标机器上安装了对应的库,如果目标机器上没有安装对应的库,脚本变不能执行成功。这种情况下,如果我们不打算去改动目标机器,可以使用action moudle,action moudle是一种用来在管理机器上执行,但是可以最终作用到目标机器上的module。
例如,OpenStack/kolla-ansible项目部署容器时,几乎对每一台机器都要生成自己对应的配置文件,如果这个步骤在目标机器上执行,那么需要在每个目标机器上都按照配置文件对应的依赖python库。为了减少依赖,kolla-ansible定义了action module,在部署节点生成配置文件,然后通过cp module将生成的文件拷贝到目标节点,这样就不必在每个被部署节点都安装yml,oslo_config等python库,目标机器只需要支持scp即可。kolla-ansible的action module存放的位置是ansible/action_plugins.
4. 模块学习
不建议深入去学,太多了,用到的时候一个个去查就好了
- 这篇文章介绍了ansible常用模块的用法:http://blog.csdn.net/iloveyin/article/details/46982023
- ansible官网提供了所有module的用法:http://docs.ansible.com/ansible/latest/modules_by_category.html
- ansible 所有module源码存放路径:/usr/lib/python2.7/site-packages/ansible/modules/
ansible-playbook
待补充
Playbook(剧本)
前文提到的ansible命令,都是一些类似shell命令的功能,如果要做一些比较复杂的操作,比如说:部署一个java应用到10台服务器上,一个模块显然是无法完成的,需要安装模块,配置模块,文件传输模块,服务状态管理模块等模块联合工作才能完成。把这些模块的组合使用,按特定格式记录到一个文件上,并且使该文件具备可复用性,这就是ansible的playbook。如果说ansible模块类似于shell命令,那playbook类似于shell脚本的功能。
这里举一个使用playbook集群的例子,kolla-ansible deploy 实际上就是调用了:
ansible-playbook -i /usr/share/kolla-ansible/ansible/inventory/all-in-one -e @/etc/kolla/globals.yml -e @/etc/kolla/passwords.yml -e CONFIG_DIR=/etc/kolla -e action=deploy /usr/share/kolla-ansible/ansible/site.yml
1. 一个简单的playbook
---
- hosts: webservers
vars:
http_port: 80
max_clients: 200
remote_user: root
tasks:
- name: ensure apache is at the latest version
yum: name=httpd state=latest
- name: write the apache config file
template: src=/srv/httpd.j2 dest=/etc/httpd.conf
notify:
- restart apache
- name: ensure apache is running (and enable it at boot)
service: name=httpd state=started enabled=yes
handlers:
- name: restart apache
service: name=httpd state=restarted
这个playbook来自ansible官网,包含了一个play,功能是在所有webservers节点上安装配置apache服务,如果配置文件被重写,重启apache服务,在任务的最后,确保服务在启动状态。
playbook中的元素
1. hosts and remote_user
play中的hosts代表这个play要在哪些主机上执行,这里可以使一个或者多个主机,也可以是一个或者多个主机组。remote_user代表要以指定的用户身份来执行此play。remote_user可以细化到task层。
---
- hosts: webservers
remote_user: root
tasks:
- name: test connection
ping:
remote_user: yourname
2. tasks
task是要在目标机器上执行的一个最小任务,一个play可以包含多个task,所有的task顺序执行。
3. vars
在play中可以定义一些参数,如上文webservers中定义的http_port和max_clients,这两个参数会作用到这个play中的task上,最终template模块会使用这两个参数的值来生成目标配置文件。
4. handlers
当某个task对主机造成了改变时,可以触发notify操作,notify会唤起对应的handler处理该变化。比如说上面的例子中,如果template module重写/etc/httpd.conf文件后,该文件内容发生了变化,就会触发task中notify部分定义的handler重启apache服务,如果文件内容未发生变化,则不触发handler。
也可以通过listen来触发想要的handler,示例如下:
handlers:
- name: restart memcached
service: name=memcached state=restarted
listen: "restart web services"
- name: restart apache
service: name=apache state=restarted
listen: "restart web services"
tasks:
- name: restart everything
command: echo "this task will restart the web services"
notify: "restart web services"
使用role和include更好的组织playbook
1. role
上文给出的webserver playbook中,task和hanler的部分是最通用的,vars部分其次,hosts参数最次。其他人拿到这个playbook想到使用,一般不需要修改task,但是host和vars部分,就需要修改成自己需要的值。所以ansible这里引入了role的概念,把host从playbook中移出,把剩下的内容按照下面示例的样式,拆成几部分,handler存放到handler中,task存放到task目录中去,默认变量存放到default中,使用到的文件'httpd.j2'存放到templates目录下,按照这样的目录格式组织完成后,我们就得到了一个webserber role。
tasks中可以有很多task,被执行的入口是main.yml
# 官网的一个role目录结构的例子
site.yml
webservers.yml
fooservers.yml
roles/
common/
tasks/
main.yml
handlers/
files/
templates/
defaults/
meta/
webservers/
tasks/
main.yml
defaults/
meta/
templates/
role的使用方法,可以参考下面的例子,下面的playbook作用是:对所有的webservers机器,执行common,weservers,foo_app_instance对应的task,执行最后一个role时,传递了dir和app_port两个参数。
---
- hosts: webservers
roles:
- common
- webservers
- { role: foo_app_instance, dir: '/opt/a', app_port: 5000 }
2. include
可以考虑这样两个问题:
- 上文我们定义webserver role作用是在指定服务器上安装并确保apache服务运行,那么如果我们想要升级,关闭或者卸载apache服务呢,该怎么办,再定义新的role,webserver-upgrade看起来似乎太蠢笨了。能不能像面向对象那样,一个对象支持不同的操作?
- 上文中的webserver服务安装比较简单,所以我们的playbook也比较简单,但是有时候会遇到比较麻烦的需求,比如说安装openstack的neutron服务,它需要先检车设置,再生存配置文件,同步数据库,等步骤,这项功能如果都写成一个playbook,这个playbook是不是太大了,很难维护。可不可以把检查,配置,同步等功能做成不同的playbook,然后从一个主playbook中看情况调用?
include功能可以解决这样的问题,一个include的例子如下
tasks/
bootstrap.yml
ceph.yml
config.yml
check.yml
deploy.yml
upgrade.yml
precheck.yml
register.yml
main.yml
main.yml
---
- include: "{{ action }}.yml"
deploy.yml
---
- include: ceph.yml
when:
- enable_ceph | bool and nova_backend == "rbd"
- inventory_hostname in groups['ceph-mon'] or
略
- include: register.yml
when: inventory_hostname in groups['nova-api']
- include: config.yml
- include: bootstrap.yml
when: inventory_hostname in groups['nova-api'] or
inventory_hostname in groups['compute']
略
当nova role被赋给一台服务器后,如果用户指定的action是deploy,ansible会引入deploy.yml,如果是upgrade,则引入upgrade.yml。这样根据用户参数的不同,include不同的playbook,从而实现一个role支持多种功能。
deploy playbook又由多个不同的playbook组成,根据用户的配置的参数,有不同的组合方式,很灵活。
我的理解是,在role的task中,一个play就好像一个内部函数,一个playbook是由一个由多个play组成的公有函数,被其他playbook根据include参数组合调用。
kolla-ansible中常见ansible语法
kolla-ansible中的play都比上面的例子复杂很多,它很多时候都不直接调用module,而是加了很多判断,循环,错误处理之类的逻辑,一个例子:
ansible.roles.prechecks.tasks.package_checks.yml
---
- name: Checking docker SDK version
command: "/usr/bin/python -c \"import docker; print docker.__version__\""
register: result
changed_when: false
when: inventory_hostname in groups['baremetal']
failed_when: result | failed or
result.stdout | version_compare(docker_py_version_min, '<')
这个playbook的功能是:
- 开始执行book中的第一个play:Checking docker SDK version
- 判断目标主机inventory_hostname是否属于主机清单中的baremetal组
- 如果属于,到这台主机上执行command module,参数是"/usr/bin/python -c "import docker; print docker.version""
- 将执行的结果赋值给result变量
- 因为这个模块不会更改目标主机上的任何设置,所以change_when是false,无论执行结果如何,都不会去改变这个当然任务的changed属性
- 将result变量传递给failed函数,判断命令是否执行成功
- 如果命令执行成功,将result中的输出结果,传递给version_compare函数,判断版本是否符合要求
- 因为这个模块不会更改目标主机上的任何设置,所以change_when永远是false
- 如果failed_when判断结果为失败,则设置任务状态为失败,停止执行此playbook
下面分别介绍几种kolla-ansible中常用的ansible语法。
1.条件语句
when,faild_when, change_when 后面可以接入一个条件语句,条件语句的值是true或者false,条件语句示例如下:
ansible_os_family == "Debian"
test == 1 or run == always
hostname in [1,2,3,4]
ansible除了上文的==, or, in来进行判断外,ansible还支持通过管道调用ansible自定义的test plugin进行判断,上文中的 result | failed or result.stdout | version_compare(docker_py_version_min, '<')
用到了version_compare和failed两个test plugin,这两个test plugin本质是ansible指定目录下两个python函数,用来解析字符串判断版本版本是否匹配,执行命令是否成功。它们的源码位于ansible.plugins.test.core, ansible。所有test plugin位于ansible.plugins.test,ansible支持自定义test plugin。
2. 迭代
with_itmes 是ansible的迭代语句,作用类似python的 for item in {}, 用法示例:
- name: test list
command: echo {{ item }}
with_items: [ 0, 2, 4, 6, 8, 10 ]
when: item > 56
- name: Setting sysctl values
sysctl: name={{ item.name }} value={{ item.value }} sysctl_set=yes
with_items:
- { name: "net.bridge.bridge-nf-call-iptables", value: 1}
- { name: "net.bridge.bridge-nf-call-ip6tables", value: 1}
- { name: "net.ipv4.conf.all.rp_filter", value: 0}
- { name: "net.ipv4.conf.default.rp_filter", value: 0}
when:
- set_sysctl | bool
- inventory_hostname in groups['compute']
3. failed_when
一种错误处理机制,一般用来检测执行的结果,如果执行失败,终止任务,和条件语句搭配使用
4. changed_when
当我们控制一些远程主机执行某些任务时,当任务在远程主机上成功执行,状态发生更改时,会返回changed状态响应,状态未发生更改时,会返回OK状态响应,当任务被跳过时,会返回skipped状态响应。我们可以通过changed_when来手动更改changed响应状态。
5. run_once
当对一个主机组赋予进行操作时,有部分操作并不需要在每个主机上都执行,比如说nova服务安装时,需要初始化nova数据库,这个操作只需要在一个节点上执行一次就可以了,这种情况可以使用run_once标记,被标记的任务不会在多个节点上重复执行。
delegate_to可以配合run_once使用,可以在playbook中指定数据库任务要执行的主机,下面的例子中,指定要执行数据库创建的主机是groups['nova-api'][0]
- name: Creating Nova databases
kolla_toolbox:
module_name: mysql_db
module_args:
login_host: "{{ database_address }}"
login_port: "{{ database_port }}"
login_user: "{{ database_user }}"
login_password: "{{ database_password }}"
name: "{{ item }}"
register: database
run_once: True
delegate_to: "{{ groups['nova-api'][0] }}"
with_items:
- "{{ nova_database_name }}"
- "{{ nova_database_name }}_cell0"
- "{{ nova_api_database_name }}"
delegate_to指定的机器可以当前任务的机器没有任何关系,比如,在部署nova服务时,可以delegate_to的目标不限于nova机器,可以到delegate_to ansible控制节点或者存储机器上执行任务。例如:
- hosts: app_servers
tasks:- name: gather facts from db servers
setup:
delegate_to: "{{item}}"
delegate_facts: True
with_items: "{{groups[‘dbservers‘}}"
该例子会收集dbservers的facts并分配给这些机器, 而不会去收集app_servers的facts
- name: gather facts from db servers
6. serial
一般情况下, ansible会同时在所有服务器上执行用户定义的操作, 但是用户可以通过serial参数来定义同时可以在多少太机器上执行操作.
- name: test play
hosts: webservers
serial: 3
webservers组中的3台机器完全完成play后, 其他3台机器才会开始执行
7. until
这种循环由三个指令完成:
- until是一个条件表达式,如果满足条件循环结束
- retry是重试的次数
- delay是延迟时间
示例如下:
- action: shell /usr/bin/foo
register: result
until: result.stdout.find("all systems go") != -1
retries: 5
delay:
8. wait_for
wait_for 可以让ansible等待一段时间,直到条件满足,再继续向下执行,这个模块主要用来等待之前的操作完成,比如服务启动成功,锁释放。
下面是一个kolla-ansible判断murano-api服务是否启动成功的例子:
在murano-api[0]节点上, 尝试和api_interface_address:murano_api_port建立链接,如果成功建立连接,结束等待。如果1秒(connect_timeout)内未建立成功,放弃,休眠1秒(参数sleep,未配置,默认值)后重试,如果60秒(timeout)内没有成功创建链接,任务失败。
- name: Waiting for Murano API service to be ready on first node
wait_for:
host: "{{ api_interface_address }}"
port: "{{ murano_api_port }}"
connect_timeout: 1
timeout: 60
run_once: True
delegate_to: "{{ groups['murano-api'][0] }}"
参考文档
ansible入门书:https://ansible-book.gitbooks.io/ansible-first-book/content/begin/basic_module/module_list_details.html
ansible循环用法:http://www.cnblogs.com/PythonOrg/p/6593910.html
自定义过滤器:http://rfyiamcool.blog.51cto.com/1030776/1440686/
异步和轮询:http://www.mamicode.com/info-detail-1202005.html
ansible 语法:http://blog.csdn.net/ggz631047367/article/details/50359127
ansible官网:http://docs.ansible.com/ansible/latest/