Ussuri版kolla-ansible脚本分析

基于OpenStack Ussuri版,源码下载地址:

# git clone https://github.com/openstack/kolla-ansible -b stable/ussuri

相关命令:

# kolla-ansible -i ./multinode bootstrap-servers
# kolla-ansible -i ./multinode prechecks
# kolla-ansible -i ./multinode deploy

简介:

kolla-ansible是自动化部署OpenStack的项目,通过一个shell脚本,根据用户的传参,选择不同的playbook和参数调用ansible-playbook执行,没有数据库和消息队列,主要是ansible语法的处理。

一、kolla-ansible脚本入口

1、kolla-ansible命令入口文件

[root@ksfusion1 wuyongpeng]# whereis kolla-ansible
kolla-ansible: /usr/local/bin/kolla-ansible

#查看文件格式为Bourne-Again shell,即bash脚本
[root@ksfusion1 wuyongpeng]# file /usr/local/bin/kolla-ansible
/usr/local/bin/kolla-ansible: Bourne-Again shell script, ASCII text executable

2、kolla-ansible脚本结构

脚本处理流程是,先定义几个函数,再用case … esac处理不同参数情况的处理。最后一行的process_cmd是脚本入口。

1)脚本整体结构

###******************** kolla-ansible start *****************************###

function check_environment_coherence {
    执行which ansible获取ansible路径;
    获取并校验ansible shebang line,从shebang line中截取python cmdline;
    根据ansible_python_cmdline获取python版本;
    检查python环境检查是否存在kolla_ansible模块;
    获取ansible具体版本,定义最小版本2.8,最大版本2.9;检查若不在规定版本范围内,则报错退出。
}
function find_base_dir {
    根据dirname "$0",获取dir_name,用于找到kolla-ansible脚本所在的路径。
    根据返回不同的dir_name,拼接不同的BASEDIR,作为全局变量
    【此处dirname执行时,不是以root用户,而是以kolla用户的身份执行,返回的不是"/bin",而是"/usr/local/bin"}
function process_cmd {
    直接执行拼接的CMD命令(CMD命令即:ansible-playbook -i 加指定参数)。
}
function usage {
    使用手册打印值(即在xshell中直接执行kolla-ansible后返回值,用于命令行添加参数--help返回的帮助文档)
}
function bash_completion {
    用于配合bash-completion工具,实现命令行自动补全增强功能(详见bash-completion工具用法)
}

INVENTORY="${BASEDIR}/ansible/inventory/all-in-one"  # INVENTORY默认值
PLAYBOOK="${BASEDIR}/ansible/site.yml"  # 若不指定PLAYBOOK变量,则默认值/usr/local/share/kolla-ansible/ansible/site.yml
EXTRA_OPTS=${EXTRA_OPTS}
CONFIG_DIR="/etc/kolla"
....
#While判断,当参数个数不为0,开始匹配参数,以”kolla-ansible -i ./multinode deploy”为例分析
while [ "$#" -gt 0 ]; do
    case "$1" in
    (--inventory|-i)
            INVENTORY="$2"  # 获取第二个参数,如上例,即把’/multinode’赋值给INVENTORY
            shift 2           # shift命令用于位置参数左移,如上例,shift 2执行前,$1是’-i’,执行后$1是’deploy’,(多个条件处理时,用shift可适配不同个数的参数)
            ;;               # case固定用法,匹配发现取值符合某一模式后,其间所有命令开始执行直至 ;;
    (......)
# 其它参数类似处理
esac
done
case "$1" in
(prechecks)
        ACTION="Pre-deployment checking"
        EXTRA_OPTS="$EXTRA_OPTS -e kolla_action=precheck"
;;
(mariadb_recovery)
        ACTION="Attempting to restart mariadb cluster"
        EXTRA_OPTS="$EXTRA_OPTS -e kolla_action=deploy"
        PLAYBOOK="${BASEDIR}/ansible/mariadb_recovery.yml"
        ;;
(bootstrap-servers)
        ACTION="Bootstrapping servers"
        PLAYBOOK="${BASEDIR}/ansible/kolla-host.yml"
        EXTRA_OPTS="$EXTRA_OPTS -e kolla_action=bootstrap-servers"
        ;;
(deploy)
        ACTION="Deploying Playbooks"
        EXTRA_OPTS="$EXTRA_OPTS -e kolla_action=deploy"
(......)
esac    # esac是case的结束标记。case ... esac,与switch ... case 语句类似,是一种多分枝选择结构。case匹配一个值或一个模式成功,执行匹配的命令。
#  CONFIG_DIR变量默认值为:"/etc/kolla";
#  EXTRA_OPTS的值根据shift之后的$1来确定,例如deploy对应值为"$EXTRA_OPTS -e kolla_action=deploy"(EXTRA_OPTS初始值为空)

PASSWORDS_FILE="${PASSWORDS_FILE:-${CONFIG_DIR}/passwords.yml}"
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"  # ansible-playbook指定参数变量的调用,参数都是以上shell脚本内容处理之后的值
process_cmd         # 整个脚本的调用入口,其实只是调用了CMD命令
###*********************** kolla-ansible end **************************###

2)CMD命令具体解析

CMD结构:

CMD="ansible-playbook -i $INVENTORY $CONFIG_OPTS $EXTRA_OPTS $PLAYBOOK $VERBOSITY"

参数解释:
INVENTORY参数,即INVENTORY文件,用于ansible配置主机组信息;(Ansible可同时操作属于一个组的多台主机,组和主机之间的关系通过 inventory 文件配置. 默认的文件路径为/etc/ansible/hosts)

CONFIG_OPTS,用于指定globals.yml,passwords.yml,配置文件目录,主要是指定一些配置相关;

EXTRA_OPTS主要是指定执行的动作,例如”-e kolla_action=deploy”;

PLAYBOOK为roles的入口文件site.yml.(Playbooks是Ansible的配置、部署、编排语言.可以被描述为一个需要远程主机执行命令的方案,或者一组IT程序运行的命令集合。)

Deploy动作的调用过程为:kolla-ansible -i multinode deploy ---->调用/usr/local/share/kolla-ansible/ansible/site.yml ---->根据site.yml文件的task调用执行各role

例如,执行以下三个命令,实际调用的ansible-playbook及参数如下:

[root@ksfusion1 ]# kolla-ansible -i ./multinode bootstrap-servers
Bootstrapping servers : ansible-playbook -i ./multinode -e @/etc/kolla/globals.yml -e @/etc/kolla/passwords.yml -e CONFIG_DIR=/etc/kolla  -e kolla_action=bootstrap-servers /usr/local/share/kolla-ansible/ansible/kolla-host.yml
[root@ksfusion1 ]# kolla-ansible -i ./multinode prechecks
Pre-deployment checking : ansible-playbook -i ./multinode -e @/etc/kolla/globals.yml -e @/etc/kolla/passwords.yml -e CONFIG_DIR=/etc/kolla  -e kolla_action=precheck /usr/local/share/kolla-ansible/ansible/site.yml
[root@ksfusion1 ]# kolla-ansible -i ./multinode deploy
Deploying Playbooks : ansible-playbook -i ./multinode -e @/etc/kolla/globals.yml -e @/etc/kolla/passwords.yml -e CONFIG_DIR=/etc/kolla  -e kolla_action=deploy /usr/local/share/kolla-ansible/ansible/site.yml

执行的ansible-playbook命令,是一个软链接,本质上还是调用ansible命令,区别是ansible一般执行pattern参数,ansible-playbook指定playbook参数,多用于分布式系统的批量配置、部署、运维。

[root@ksfusion1 ]# whereis ansible-playbook
ansible-playbook: /usr/local/bin/ansible-playbook
[root@ksfusion1 ]# file /usr/local/bin/ansible-playbook
/usr/local/bin/ansible-playbook: symbolic link to ansible
[root@ksfusion1 ]# ll /usr/local/bin/ansible-playbook
lrwxrwxrwx. 1 root root 7 Aug 20 15:53 /usr/local/bin/ansible-playbook -> ansible
[root@ksfusion1 wuyongpeng]# ansible --help
usage: ansible [-h] [--version] [-v] [-b][-i INVENTORY] [-e EXTRA_VARS] [......] pattern
[root@ksfusion1 ~]# ansible-playbook -h
usage: ansible-playbook [-h] [--version] [-v] [-k] [-i INVENTORY] [-e EXTRA_VARS] playbook [playbook ...]

说明:

-e: playbook通过参数-e传入变量,作为全局变量在整个playbook中被调用。【-e @指定文件,用于批量导入全局变量】
-i: 用于指定INVENTORY文件
patterm: 用于指定yaml文件
playbook: 直译“剧本”,可理解为yaml格式的任务列表文件。playbook是ansible用于配置,部署和管理被控节点的剧本。通过playbook的详细描述,执行其中的一系列tasks,可以让远端主机达到预期的状态。

3)扩展: 什么是shebang
Shebang,也念做 hashbang,Linux中国翻译组的GOLinux将其翻译为“释伴”,即“解释伴随行”的简称。Unix 术语中,井号通常称为 sharp,hash 或 mesh;而叹号则常常称为 bang。
Shebang通常出现在类Unix系统的脚本中第一行,作为前两个字符。在Shebang之后,可以有一个或数个空白字符,后接解释器的绝对路径,用于指明执行这个脚本文件的解释器。在直接调用脚本时,系统的程序载入器会分析 Shebang 后的内容,将这些内容作为解释器指令,并调用该指令,将载有 Shebang 的文件路径作为该解释器的参数,执行脚本,从而使得脚本文件的调用方式与普通的可执行文件类似。
例如,以指令#!/bin/sh开头的文件,在执行时会实际调用 /bin/sh 程序(通常是 Bourne shell 或兼容的 shell,例如 bash、dash 等)来执行。

Shebang的用法:
如果#!之后的解释程序是一个可执行文件,那么执行这个脚本时,它就会把文件名及其参数一起作为参数传给那个解释程序去执行。

Shebang注意事项:
#! 必须连接在一起
#! 一句必须在文件的最开始的第一行
#开头的语句一般情况下会被当成注释而忽略,所以Shebang 对文件的内容是没有影响的
#! 开头的一行会设置解释器运行环境
参考:https://blog.csdn.net/u012294618/article/details/78427864

3、kolla-ansible项目文件目录分析

a、一级目录

1)ansible[d]: ansible的整个playbook代码,包括部署docker容器和openstack组件。源码主要集中在这个目录下。
2)Doc[d]:文档
3)Etc[d]: 配置文件,当前只有globals.yml和passwords.yml两个文件,安装完了引用到了/etc目录下。
4)Tools[d]: 一些和kolla交换的脚本工具,大部分是可手动调用,主要完成一些安装前后的一些操作。有些会被ansible目录下的task调用到。
包括kolla-ansible指定命令脚本、init-runonce初始化配置脚本、openrc-example生成openrc模板等文件
5)文件及说明
setup.cfg[-]:安装配置入口文件 
setup.py[-]:安装执行脚本,通过pbr打包,执行过程会读取setup.cfg配置,还会安装同父目录下requirements.txt中的依赖。setup.py所需的实际元数据存储在setup.cfg中
python pbr打包说明 : [OpenStack项目都使用了setuptools和pbr来执行打包工作,项目的元数据都放在 setup.cfg 文件中]

b、二级目录(只分析ansible目录的二级目录)

1)ansible/action_plugins[d]: 自定义ansible插件,两个脚本,用于合并yml和conifg的配置文件。
merge_configs.py文件,在playbook内通过使用merge_config来合并配置文件模板,生成openstack各服务的配置文件
2)ansible/group_vars[d]: 目录下只有一个all.yml文件,用于ansible脚本的全局变量定义。
all.yml文件作为ansible的变量文件,定义了各类配置信息。比如:配置文件路径,网卡,IP,端口号,各服务的开启等。与global.yml文件的差别就是,部分的配置已经在global.yml文件内做了定义,global.yml具有更高优先级。
3)ansible/inventory[d]: 包括all-in-one和mulitnode两个inventory清单模板文件。
4)ansible/library[d]: 包括一些自定义的ansible模块,bslurp.py和kolla_docker.py用到比较多。
5)ansible/role[d]: 所有的openstack的组件,几乎包含了说有开源项目,当前Ussuri版本有81个组件。
6)ansible/site.yml[-] : roles引用的入口文件,kolla-ansible部署的入口,kolla调用ansible执行playbook的入口文件

c、三级目录library

1)ansible/library/bslurp.py : 从远程节点获取文件,并分发到更多节点
2)ansible/library/kolla_docker.py : 用于控制Docker容器的启动、删除等相关操作。openstack的组件都通过容器部署,每个组件role的部署都会用到。
3)ansible/library/kolla_container_facts.py : 用于检查是否有容器正在运行

d、三级目录role
在kolla-ansible内,为了便于维护不同组件业务的多个playbook文件,对各个openstack服务进行部署,ansible采用role的方式对playbook进行目录结构规范。
在roles目录内,有部署openstack各服务所需的各种playbook、定义的变量以及模板文件等。
以roles目录下的nova目录为例说明,路径/usr/local/src/kolla-ansible/ansible/roles/nova

nova/  //nova角色的目录
├── defaults  //为当前角色设定默认变量时使用此目录,应当包含一个main.yml文件
│   └── main.yml //作为当前role的变量文件,定义了关于nova服务的相关参数
├── handlers  //此目录总应当包含一个main.yml文件,用于定义各角色用到的各handler
│   └── main.yml //创建,启动nova各服务容器的playbook,但handlers只能在被触发的情况下才会去执行相关被触发的task
├── tasks
│   ├── bootstrap_service.yml //将会启动bootstrap引导容器,用于解决nova服务所需的依赖配置,在完成后,这些引导容器将被自动删除
│   ├── bootstrap.yml //为nova创建数据库及数据库用户等
│   ├── config.yml //通过模板为nova的各服务生成配置文件
│   ├── deploy.yml
│   ├── main.yml //入口执行文件
│   ├── precheck.yml
│   ├── pull.yml
│   ├── reconfigure.yml
│   ├── register.yml
│   └── upgrade.yml
└── templates //templates目录下存放着很多j2格式的文件,他们都是nova各服务的配置文件模板,这些模板将被config.yml根据需要生成为各服务的配置文件. template模块会自动在此目录中寻找Jinja2模板文件
    ├── nova-api-bootstrap.json.j2
    ├── nova-api.json.j2
    ├── nova.conf.j2
    ├── nova-scheduler.json.j2
    └── nova-super-conductor.json.j2

二、bootstrap-servers动作

1、命令描述

shell调用命令:

# kolla-ansible -i ./multinode bootstrap-servers

在kolla-ansible脚本中的相关处理:

(bootstrap-servers)
        ACTION="Bootstrapping servers"
        PLAYBOOK="${BASEDIR}/ansible/kolla-host.yml"  # 此处即/usr/local/share/kolla-ansible/ansible/kolla-host.yml
        EXTRA_OPTS="$EXTRA_OPTS -e kolla_action=bootstrap-servers"
        ;;
具体调用:
# ansible-playbook -i ./multinode -e @/etc/kolla/globals.yml -e @/etc/kolla/passwords.yml -e CONFIG_DIR=/etc/kolla  -e kolla_action=bootstrap-servers /usr/local/share/kolla-ansible/ansible/kolla-host.yml

2、yaml文件分析

源码如下:

[root@ksfusion1 ]# cat /usr/local/share/kolla-ansible/ansible/kolla-host.yml
---
- import_playbook: gather-facts.yml
- name: Apply role baremetal
  hosts: baremetal
  serial: '{{ kolla_serial|default("0") }}'
  gather_facts: false
  roles:
    - { role: baremetal,
        tags: baremetal }

说明:

1)import_playbook:主playbook可以导入子playbook,./kolla-ansible/ansible/gather-facts.yml用于获取远程主机信息。
2)hosts值为baremetal,在all-in-one节点,baremetal指向control组;在multinode节点,baremetal指向control、network、compute等所有物理节点的组;
all-in-one node:
[baremetal:children]
control
multinode node:
[baremetal:children]
control
network
compute
storage
monitoring
3)role和tags都为baremetal,接下来进入roles的baremetal目录中执行
4)roles/baremetal/defaults/main.yml文件中,定义了default变量。
5)roles/baremetal/tasks/main.yml文件,为入口文件

使用include_tasks分散调用tasks:

---
- include_tasks: "{{ kolla_action }}.yml" 

即调用执行bootstrap-servers.yml,内容如下:

---
- include_tasks: pre-install.yml
- include_tasks: install.yml
- include_tasks: post-install.yml
- include_tasks: configure-containerd-for-zun.yml
  when: containerd_configure_for_zun|bool and
        inventory_hostname in groups['zun-cni-daemon']

pre-install.yml、install.yml、post-install.yml等文件中,直接展示的是task的内容。
因此,执行 kolla-ansible -i ./multinode bootstrap-servers,实际执行的是pre-install.yml、install.yml、post-install.yml等文件的tasks任务清单。

6)pre-install.yml文件task内容分析
共有6个task和一个block

  task1:Ensure localhost in /etc/hosts
  task2:Ensure hostname does not point to 127.0.1.1 in /etc/hosts
  task3:把所有节点信息写入/etc/hosts
  task4:检查cloud-init是否已安装,确保manage_etc_hosts配置disabled。
  task5:确保sudo组状态为present
  task6:确保kolla组状态为present

block(当前只分析RedHat,包含四个task):
(1)确保/etc/yum.repos.d/目录存在
(2)启动docker的yum仓库yum_repository
(3)确保/etc/yum.repos.d/docker.repo中module_hotfixes = True
(4)安装docker rpm gpg key

7)install.yml文件task内容分析
共有12个task和一个bolck,主要功能如下:

  更新Debian apt缓存;
  关闭Debian防火墙;
  检查RedHat下firewalld是否安装;
  关闭RedHat下firewalld;
  检查是否有docker运行;
  安装apt/RPM包(从roles/baremetal/defaults/main.yml的对应变量中读取安装包列表,例如redhat_pkg_install);
  启动docker,并等待Docker启动成功;
  当环境是virtualenv,在对应virtualenv中安装最新的pip;
  为python安装docker SDK;
  删除配置文件列表中指定的待删除包(roles/baremetal/defaults/main.yml中的ubuntu_pkg_removals和redhat_pkg_removals);

8)post-install.yml文件task内容分析
共有35个task,主要功能如下:

  创建kolla用户、添加kolla用户的公钥、授权kolla用户无密码sudo权限;
  确保virtualenv权限正确;确保node_config_directory对应目录存在,且给kolla用户使用
【当前node_config_directory变量配置路径:kolla-ansible/ansible/group_vars/all.yml:node_config_directory: "/etc/kolla"】;
【以下操作,由于当前defaults/main.yml配置中docker_custom_option相关值为空,因此不执行。】
  Merge Zun docker config;
  警告docker_custom_option是不赞成的使用方法;设置docker不安全的注册表;设置docker存储驱动;设置docker运行目录;
  docker默认iptables的警告;禁用docker默认ipbtales规则;merge自动以的docker配置;把自定义docker配置写入/etc/docker/daemon.json;移除旧的docker配置文件;
  确保docker服务目录/etc/systemd/system/docker.service.d存在;使用此目录下的kolla.conf,配置docker服务;
  Reload docker service文件;
  创建docker group;添加kolla用户到docker组;启动docker;当docker有变化,重启docker;
  按OS类型,停止时间服务器;若enable_host_ntp为True(当前为False),则同步时间;启动ntpd服务;
  更改selinux状态;

补充:

(1)node_config_directory默认为/etc/kolla/,如下:

# ll /etc/| grep kolla
drwxr-xr-x. 42 kolla kolla   4096 Nov 11 17:54 kolla

在何处配置读取node_config_directory变量的默认值,待分析。

三、prechecks动作 和 deploy动作

1、prechecks命令描述

# kolla-ansible -i ./multinode prechecks
具体调用:
ansible-playbook -i ./multinode -e @/etc/kolla/globals.yml -e @/etc/kolla/passwords.yml -e CONFIG_DIR=/etc/kolla  -e kolla_action=precheck /usr/local/share/kolla-ansible/ansible/site.yml

2、deploy命令描述

# kolla-ansible -i ./multinode deploy
具体调用:
ansible-playbook -i ./multinode -e @/etc/kolla/globals.yml -e @/etc/kolla/passwords.yml -e CONFIG_DIR=/etc/kolla  -e kolla_action=deploy /usr/local/share/kolla-ansible/ansible/site.yml

3、site.yml文件结构task内容分析

共有69个task和2个import_playbook。

import_playbook包括最开始的gather-facts.yml和nova.yml。
其中nova.yml中又包含10个task子任务,分别完成nova API和cell的数据库初始化、调用nova role的main.yml、调用nova-cell role的main.yml、重载scheduler|conductor|api|cell服务等操作。

site.yml文件中,除了第一个task,其它task都是基于roles的应用,会执行kolla-ansible/ansible/roles/目录下对应roles目录中的内容。
第一个task,用于根据kolla的配置对主机进行分组,共有两个group_by进行分组:
1)第一个分组,是根据传入的kolla_action变量进行hosts分组,之后的tasks列表中,只有kolla_action_precheck使用此分组,此处指定kolla_action=precheck,即执行此role内容;
2)第二个分组,会遍历with_items中所有roles列表。

4、prechecks调用

对应site.yml中的task如下:

- name: Apply role prechecks
  gather_facts: false
  # Apply only when kolla action is 'precheck'.
  hosts: kolla_action_precheck
  roles:
    - role: prechecks

即调用roles下prechecks目录对应的main.yml文件,依次执行以下导入yml对应的task。

---
- include_tasks: host_os_checks.yml
  when: prechecks_enable_host_os_checks | bool
- include_tasks: timesync_checks.yml
  when:
    - not enable_chrony | bool
- include_tasks: datetime_checks.yml
- include_tasks: port_checks.yml
  when:
    - inventory_hostname not in groups['deployment']|default([])
- include_tasks: service_checks.yml
- include_tasks: package_checks.yml
- include_tasks: user_checks.yml
- include_tasks: database_checks.yml

疑问:kolla_action_precheck变量从哪里定义的? 若没有定义,是否默认值是localhost?

5、deploy 调用

1)deploy操作整体分析
具体调用:

# ansible-playbook -i ./multinode -e @/etc/kolla/globals.yml -e @/etc/kolla/passwords.yml -e CONFIG_DIR=/etc/kolla  -e kolla_action=deploy /usr/local/share/kolla-ansible/ansible/site.yml

deploy操作对应的kolla_action参数deploy,但是调用site.yml会遍历执行yml中的所有符合条件的任务,而不仅仅是kolla_action=deploy的task。

2)site.yml文件中kolla_action=deploy时执行的操作
kolla_action=deploy时,执行是name为’Apply role haproxy’的task,使用include_role动态导入tasks列表中所有组件的role。

- name: Apply role haproxy
  gather_facts: false
  hosts:
    - haproxy
    - '&enable_haproxy_True'
  serial: '{{ kolla_serial|default("0") }}'
  tags:
    - haproxy
  roles:
    - { role: haproxy,
        when: enable_haproxy | bool }
  tasks:
    - block:
        - include_role:
            name: aodh
            tasks_from: loadbalancer
          tags: aodh
          when: enable_aodh | bool
        - include_role:
            name: barbican
         ...... #此处省略openstack其它组件的role导入,共47个组件
when:
  - enable_haproxy | bool
  - kolla_action in ['deploy', 'reconfigure', 'upgrade', 'config']

3)haproxy role task中,包含47个task子任务,此处以nova为例分析
(1)在tasks中使用include_role动态导入nova的入口

在name为’Apply role haproxy’的tasks清单中,nova使用include_role动态导入流程如下(nova和nova-cell分开):

- include_role:
    name: nova
    tasks_from: loadbalancer
  tags:
    - nova
    - nova-api
  when: enable_nova | bool

此处的tasks_from,和include_role配合使用,用于指定要从tasks目录中加载的文件,即roles/nova/tasks/loadbalancer.yml(若tasks_from不指定,默认为main.yml),加载的文件如下:

[root@ksfusion1 nova]# cat roles/nova/tasks/loadbalancer.yml
---
- name: "Configure haproxy for {{ project_name }}"
  import_role:
    name: haproxy-config
  vars:
    project_services: "{{ nova_services }}"
  tags: always
[root@ksfusion1 nova]#

(2)使用import_role静态导入haproxy-config

首先,读取nova_services变量值,即project_services变量值的获取

变量会从roles/nova/defaults/main.yml中读取,nova_services为嵌套的字典结构,包括三个键值对,nova-api、nova-scheduler、nova-super-conductor,具体如下:

[root@ksfusion1 ansible]# more roles/nova/defaults/main.yml
---
project_name: "nova"
 
nova_services:
  nova-api:
    container_name: "nova_api"
    group: "nova-api"
    image: "{{ nova_api_image_full }}"
    enabled: True
    privileged: True
    volumes: "{{ nova_api_default_volumes + nova_api_extra_volumes }}"
    dimensions: "{{ nova_api_dimensions }}"
    haproxy:
      nova_api:
        enabled: "{{ enable_nova }}"
        mode: "http"
        external: false
        port: "{{ nova_api_port }}"
        listen_port: "{{ nova_api_listen_port }}"
        tls_backend: "{{ nova_enable_tls_backend }}"
      nova_api_external:
        enabled: "{{ enable_nova }}"
        mode: "http"
        external: true
        port: "{{ nova_api_port }}"
        listen_port: "{{ nova_api_listen_port }}"
        tls_backend: "{{ nova_enable_tls_backend }}"
      nova_metadata:
        enabled: "{{ enable_nova }}"
        mode: "http"
        external: false
        port: "{{ nova_metadata_port }}"
        listen_port: "{{ nova_metadata_listen_port }}"
        tls_backend: "{{ nova_enable_tls_backend }}"
      nova_metadata_external:
        enabled: "{{ enable_nova }}"
        mode: "http"
        external: true
        port: "{{ nova_metadata_port }}"
        listen_port: "{{ nova_metadata_listen_port }}"
        tls_backend: "{{ nova_enable_tls_backend }}"
  nova-scheduler:
    container_name: "nova_scheduler"
    group: "nova-scheduler"
    image: "{{ nova_scheduler_image_full }}"
    enabled: True
    volumes: "{{ nova_scheduler_default_volumes + nova_scheduler_extra_volumes }}"
    dimensions: "{{ nova_scheduler_dimensions }}"
  nova-super-conductor:
    container_name: "nova_super_conductor"
    group: "nova-super-conductor"
    enabled: "{{ enable_cells }}"
    image: "{{ nova_super_conductor_image_full }}"
    volumes: "{{ nova_super_conductor_default_volumes + nova_super_conductor_extra_volumes }}"
    dimensions: "{{ nova_super_conductor_dimensions }}"
......

对于always的tag,在执行playbook时,只要没有明确指定不执行always tag,那么它就会被执行。

因此,此处为导入nova组件的role真正执行的动作,即import_role静态导入haproxy-config的role,加载执行roles/haproxy-config/tasks/main.yml文件,如下:

[root@ksfusion1 ansible]# cat roles/haproxy-config/tasks/main.yml
---
- name: "Copying over {{ project_name }} haproxy config"
  vars:
    service: "{{ item.value }}"
    haproxy_templates:
      - "{{ node_custom_config }}/haproxy-config/{{ inventory_hostname }}/{{ haproxy_service_template }}"
      - "{{ node_custom_config }}/haproxy-config/{{ haproxy_service_template }}"
      - "templates/{{ haproxy_service_template }}"
    template_file: "{{ query('first_found', haproxy_templates) | first }}"
  template:
    src: "{{ template_file }}"
    dest: "{{ node_config_directory }}/haproxy/services.d/{{ item.key }}.cfg"
    mode: "0660"
  become: true
  when:
    - service.enabled | bool  # 从roles/nova/defaults/main.yml可知此变量为True
    - service.haproxy is defined # 从roles/nova/defaults/main.yml可知此变量已定义
    - enable_haproxy | bool # 从/etc/kolla/globals.yml可知此变量默认值为yes,因此,nova组件的三个条件都满足
  with_dict: "{{ project_services }}"
  notify:
    - Restart haproxy container
[root@ksfusion1 ansible]#

其中,ansible/group_vars/all.yml文件中有以下变量:node_config_directory: “/etc/kolla” ;node_custom_config: “/etc/kolla/config”

roles/haproxy-config/defaults/main.yml中有以下变量定义:haproxy_service_template: “haproxy_single_service_listen.cfg.j2”

当前环境中,由于无法读取到node_custom_config变量对应的路径(node_custom_config默认值为/etc/kolla/globals.yml中的#node_custom_config: “/etc/kolla/config”),因此

{{ query(‘first_found’, haproxy_templates) | first }}会遍历读取到第三个路径的文件,即roles/haproxy-config/templates/haproxy_single_service_listen.cfg.j2

template模块用于从本地拷贝文件到远程节点,并进行变量的替换。一般用于远程复制配置文件,用jinja2格式的{{}}注入变量。

此处,item.key为nova-api,template模块操作,把本地的haproxy_single_service_listen.cfg.j2模板,注入变量后,复制到远程的文件路径为/etc/kolla/haproxy/services.d/nova-api.cfg。

因此,47个task子任务中,nova子任务完成的实际操作是,把本地的haproxy_single_service_listen.cfg.j2模板注入变量后,复制到远程节点目录/etc/kolla/haproxy/services.d/nova-api.cfg。其它的nova相关操作,在nova.yml中执行。

4)haproxy role task中,包含47个task子任务,此处再以cinder为例分析
(1)在tasks中使用include_role动态导入cinder的入口

首先,根据全局配置文件,组成enable_cinder_True变量,使用group_by模块按此变量分组。

- enable_cinder_{{ enable_cinder | bool }}

在/etc/kolla/globals.yml配置文件中:enable_cinder: “yes”,因此,site.yml的第一个task中,组合的enable_cinder_True变量,

此变量用于group_by模块动态添加分组主机,使用流程为:先按模块分组;然后再分别对指定组进行playbook的设置。

(2)在name为’Apply role haproxy’的tasks清单中,cinder使用include_role动态导入流程如下:

- include_role:
    name: cinder
    tasks_from: loadbalancer
  tags: cinder
  when: enable_cinder | bool

此处的tasks_from,和include_role配合使用,用于指定要从tasks目录中加载的文件,即roles/cinder/tasks/loadbalancer.yml,加载的文件如下:

[root@ksfusion1 ansible]# cat roles/cinder/tasks/loadbalancer.yml
---
- name: "Configure haproxy for {{ project_name }}"
  import_role:
    name: haproxy-config
  vars:
    project_services: "{{ cinder_services }}"
  tags: always

(3)使用import_role静态导入haproxy-config

首先,读取cinder_services变量值,即project_services变量值的获取。

变量会从roles/cinder/defaults/main.yml中读取,cinder_services为嵌套的字典结构,包括四个键值对,cinder-api、cinder-scheduler、cinder-volume、cinder-backup,具体如下:

[root@ksfusion1 ansible]# more roles/cinder/defaults/main.yml
---
project_name: "cinder"
 
cinder_services:
  cinder-api:
    container_name: cinder_api
    group: cinder-api
    enabled: true
    image: "{{ cinder_api_image_full }}"
    volumes: "{{ cinder_api_default_volumes + cinder_api_extra_volumes }}"
    dimensions: "{{ cinder_api_dimensions }}"
    haproxy:
      cinder_api:
        enabled: "{{ enable_cinder }}"
        mode: "http"
        external: false
        port: "{{ cinder_api_port }}"
        listen_port: "{{ cinder_api_listen_port }}"
        tls_backend: "{{ cinder_enable_tls_backend }}"
      cinder_api_external:
        enabled: "{{ enable_cinder }}"
        mode: "http"
        external: true
        port: "{{ cinder_api_port }}"
        listen_port: "{{ cinder_api_listen_port }}"
        tls_backend: "{{ cinder_enable_tls_backend }}"
  cinder-scheduler:
    container_name: cinder_scheduler
    group: cinder-scheduler
    enabled: true
    image: "{{ cinder_scheduler_image_full }}"
    volumes: "{{ cinder_scheduler_default_volumes + cinder_scheduler_extra_volumes }}"
    dimensions: "{{ cinder_scheduler_dimensions }}"
  cinder-volume:
    container_name: cinder_volume
    group: cinder-volume
    enabled: true
    image: "{{ cinder_volume_image_full }}"
    privileged: True
    ipc_mode: "host"
    volumes: "{{ cinder_volume_default_volumes + cinder_volume_extra_volumes }}"
    dimensions: "{{ cinder_volume_dimensions }}"
  cinder-backup:
    container_name: cinder_backup
    group: cinder-backup
    enabled: "{{ enable_cinder_backup | bool }}"
    image: "{{ cinder_backup_image_full }}"
    privileged: True
    volumes: "{{ cinder_backup_default_volumes + cinder_backup_extra_volumes }}"
dimensions: "{{ cinder_backup_dimensions }}"
......

对于always的tag,在执行playbook时,只要没有明确指定不执行always tag,那么它就会被执行。

因此,此处为导入cinder组件的role真正执行的动作,即import_role静态导入haproxy-config的role,加载执行roles/haproxy-config/tasks/main.yml文件,如下:

[root@ksfusion1 ansible]# cat roles/haproxy-config/tasks/main.yml
---
- name: "Copying over {{ project_name }} haproxy config"
  vars:
    service: "{{ item.value }}"
    haproxy_templates:
      - "{{ node_custom_config }}/haproxy-config/{{ inventory_hostname }}/{{ haproxy_service_template }}"
      - "{{ node_custom_config }}/haproxy-config/{{ haproxy_service_template }}"
      - "templates/{{ haproxy_service_template }}"
    template_file: "{{ query('first_found', haproxy_templates) | first }}"
  template:
    src: "{{ template_file }}"
    dest: "{{ node_config_directory }}/haproxy/services.d/{{ item.key }}.cfg"
    mode: "0660"
  become: true
  when:
    - service.enabled | bool  # 从roles/nova/defaults/main.yml可知此变量为True
    - service.haproxy is defined # 从roles/nova/defaults/main.yml可知此变量已定义
    - enable_haproxy | bool # 从/etc/kolla/globals.yml可知此变量默认值为yes,因此,nova组件的三个条件都满足
  with_dict: "{{ project_services }}"
  notify:
    - Restart haproxy container
[root@ksfusion1 ansible]#

其中,ansible/group_vars/all.yml文件中有以下变量:node_config_directory: “/etc/kolla” ;node_custom_config: “/etc/kolla/config”

roles/haproxy-config/defaults/main.yml中有以下变量定义:haproxy_service_template: “haproxy_single_service_listen.cfg.j2”

当前环境中,由于无法读取到node_custom_config变量对应的路径(node_custom_config默认值为/etc/kolla/globals.yml中的#node_custom_config: “/etc/kolla/config”),因此

{{ query(‘first_found’, haproxy_templates) | first }}会遍历读取到第三个路径的文件,即roles/haproxy-config/templates/haproxy_single_service_listen.cfg.j2

template模块用于从本地拷贝文件到远程节点,并进行变量的替换。一般用于远程复制配置文件,用jinja2格式的{{}}注入变量。

此处,with_dict遍历读取project_services中的四组键值对,当item.key为cinder-api时,haproxy-config中template模块会把本地的haproxy_single_service_listen.cfg.j2模板,注入变量后,复制到远程节点路径为/etc/kolla/haproxy/services.d/cinder-api.cfg。

5)执行cinder服务相关操作
上一步,在haproxy中配置好cinder之后,往下会执行到名为Apply role cinder的task,如下:

- name: Apply role cinder
  gather_facts: false
  hosts:
    - cinder-api
    - cinder-backup
    - cinder-scheduler
    - cinder-volume
    - '&enable_cinder_True'
  serial: '{{ kolla_serial|default("0") }}'
  roles:
    - { role: cinder,
        tags: cinder,
        when: enable_cinder | bool }

此处,主要执行roles目录下cinder子目录中task中的main.yml,顺序调用deploy.yml中的任务即可。

主要实现:

  register.yml  调用roles/service-ks-register/tasks/main.yml,对cinder组件在keystone服务中创建相关的'endpoints''project''user''role'等。
  config.yml  调用roles/cinder/tasks/config.yml,实现cinder相关的检查配置policy文件、cinder-api服务配置、cinder.conf配置、cinder_volume使用的nfs配置、检查cinder container等。
  clone.yml  下载cinder源码;
  bootstrap.yml  创建cinder数据库、数据库用户及权限配置;
  check.yml  创建volume,清除volume操作
[root@ksfusion1 ansible]# cat roles/cinder/tasks/main.yml
---
- include_tasks: "{{ kolla_action }}.yml"
 
[root@ksfusion1 ansible]# cat roles/cinder/tasks/deploy.yml
---
- include_tasks: register.yml
  when: inventory_hostname in groups['cinder-api']
- include_tasks: config.yml
- include_tasks: clone.yml
  when: cinder_dev_mode | bool
- include_tasks: bootstrap.yml
  when: inventory_hostname in groups['cinder-api']
- name: Flush handlers
  meta: flush_handlers
- include_tasks: check.yml

此处的meta任务是一种特殊任务,meta任务可影响ansible的内部运行方式。meta:flush_handlers表示立即执行之前的task所对应handler.

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值