kolla-ansible是一个结构相对简单的项目,它经过一个shell脚本,根据用户的参数,选择不一样的playbook和不一样的参数调用ansible-playbook执行,没有数据库,没有消息队列,因此本文的重点是ansible自己的语法。html
kolla-ansible命令的主要代码以下:java
#!/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语法便可。node
一个简单的ansible命令示例以下:
ansible -i /root/myhosts ha01 -m setup
这个命令的做用是,对/root/hosts文件中的全部属于ha01分类的主机,执行setup模块收集该主机的信息,它包括两种元素,主机清单和模块,下面分别介绍这两种元素。python
host inventory 是一个文件,存放了全部被ansible管理的主机,能够在调用anabile命令时,经过-i参数指定。mysql
193.192.168.1.50 ha01 ha02·
能够执行如下命令检查ha01是否可以连通git
ansible -i $filename ha01 -m ping ha01 | SUCCESS => { "changed": false, "ping": "pong" }
2.咱们能够把主机分类,示例以下web
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
[openstack-common:children] openstack-controller openstack-compute [common:children] openstack-common databases ha
ansible -i $file common -m ping
ansible封装了不少python脚本做为module提供给使用者,如:yum、copy、template,command,etc. 当咱们会特定主机执行某个module时,ansible会把这个module对应的python脚本,拷贝到目标主机上执行。可使用ansible-doc -l来查看ansible支持的全部module。使用ansible -v 模块名 来查看该模块的详细信息。sql
上文的例子,使用了-m ping参数,意思是对这些主机,执行ping 模块,ping 模块是一个python脚本,做用是用来判断:目标机器是否可以经过ssh连通而且已经安装了python。docker
# 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()
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
shell
如上文所述,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.
不建议深刻去学,太多了,用到的时候一个个去查就行了
待补充
前文提到的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
--- - 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服务,在任务的最后,确保服务在启动状态。
play中的hosts表明这个play要在哪些主机上执行,这里可使一个或者多个主机,也能够是一个或者多个主机组。remote_user表明要以指定的用户身份来执行此play。remote_user能够细化到task层。
--- - hosts: webservers remote_user: root tasks: - name: test connection ping: remote_user: yourname
task是要在目标机器上执行的一个最小任务,一个play能够包含多个task,全部的task顺序执行。
在play中能够定义一些参数,如上文webservers中定义的http_port和max_clients,这两个参数会做用到这个play中的task上,最终template模块会使用这两个参数的值来生成目标配置文件。
当某个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"
上文给出的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 }
能够考虑这样两个问题:
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中的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的功能是:
下面分别介绍几种kolla-ansible中经常使用的ansible语法。
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。
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']
一种错误处理机制,通常用来检测执行的结果,若是执行失败,终止任务,和条件语句搭配使用
当咱们控制一些远程主机执行某些任务时,当任务在远程主机上成功执行,状态发生更改时,会返回changed状态响应,状态未发生更改时,会返回OK状态响应,当任务被跳过期,会返回skipped状态响应。咱们能够经过changed_when来手动更改changed响应状态。
当对一个主机组赋予进行操做时,有部分操做并不须要在每一个主机上都执行,好比说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控制节点或者存储机器上执行任务。例如:
通常状况下, ansible会同时在全部服务器上执行用户定义的操做, 可是用户能够经过serial参数来定义同时能够在多少太机器上执行操做.
- name: test play
hosts: webservers
serial: 3
webservers组中的3台机器彻底完成play后, 其余3台机器才会开始执行
这种循环由三个指令完成:
示例以下:
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/