• kolla-ansible快速入门


    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参数指定。

    1. 下面是一个最简单的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
    
    1. 如果主机数量比较多,也可以用正则表达,示例如下:
    deploy-node
    
    [ha]
    ha[01:02]
    
    [openstack-compute]
    compute[01:50]
    
    [openstack-controller]
    controller[01:03]
    
    [databases]
    db-[a:f].example.com
    
    1. 所有的controller和compute,都是openstack的节点,所以我们可以再定义一个类别openstack-common,把他们里面的主机都包括进去
    [openstack-common:children]
    openstack-controller
    openstack-compute
    
    [common:children]
    openstack-common
    databases
    ha
    
    1. 当我们有了如上的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-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

    可以考虑这样两个问题:

    1. 上文我们定义webserver role作用是在指定服务器上安装并确保apache服务运行,那么如果我们想要升级,关闭或者卸载apache服务呢,该怎么办,再定义新的role,webserver-upgrade看起来似乎太蠢笨了。能不能像面向对象那样,一个对象支持不同的操作?
    2. 上文中的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的功能是:

    1. 开始执行book中的第一个play:Checking docker SDK version
    2. 判断目标主机inventory_hostname是否属于主机清单中的baremetal组
    3. 如果属于,到这台主机上执行command module,参数是"/usr/bin/python -c "import docker; print docker.version""
    4. 将执行的结果赋值给result变量
    5. 因为这个模块不会更改目标主机上的任何设置,所以change_when是false,无论执行结果如何,都不会去改变这个当然任务的changed属性
    6. 将result变量传递给failed函数,判断命令是否执行成功
    7. 如果命令执行成功,将result中的输出结果,传递给version_compare函数,判断版本是否符合要求
    8. 因为这个模块不会更改目标主机上的任何设置,所以change_when永远是false
    9. 如果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

    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/

  • 相关阅读:
    你的背包,被我找到了(01背包问题)
    一点微小的改动,让你从B树理解到B+树
    有哪些令人拍案叫绝的算法?
    来来来,今天教你们用 CV 算法整点好玩的...
    内存都没了,还能运行程序?
    我的常用软件大公开!
    漫画:美团面试题(整数拆分)
    科普:我就想写个爬虫,到底要学多少东西啊?
    腾讯和阿里在 B 站评论区相遇了!
    程序员注意:这个群可以学英语,还全程免费!
  • 原文地址:https://www.cnblogs.com/zhangyufei/p/7645804.html
Copyright © 2020-2023  润新知