Openstack容器部署工具—kolla-ansible源码解读

皇甫琛
2023-12-01

kolla介绍

Kolla-ansible是OpenStack下面的一个自动化部署的项目,基于docker和Ansible实现。
Docker负责镜像制作、容器管理。
Anisble负责环境部署管理。

目录结构

kolla-ansible
├── ansible # Ansible的playbook和roles在这个目录下面
├── doc # 一些文档说明书
├── etc_examples # Openstack部署需要的一些配置模板文件
├── init-runonce # 初始化配置脚本
├── init-vpn # 配置VPNaas的脚本
├── setup.cfg # 安装配置入口文件
└── tools # 和kolla交互的脚本工具

ansible目录结构

ansible
├── action_plugins # 自定义插件,用户yml和config的配置合并
├── filter_plugins # 自定义过滤器插件,用来处理变量数据
├── group_vars # 存放ansible的全局变量,比如:配置文件路径、网卡、IP、端口、服务的开启等。
├── inventory # 主机清单 分为单节点、多节点
├── library # 自定义的ansible模块
	bslurp.py:# 作用是从其他节点拷贝文件然后再复制给其他节点
	kolla_docker.py:# 作用是控制管理docker,通过连接docker API去对容器进行创建、删除等一些操作
	kolla_toolbox.py:# 负责容器的启动以及初始化的操作
	kolla_container_facts.py:# 用于检查容器是否正在运行
├── mariadb_backup.yml
├── mariadb_recovery.yml
├── nova.yml
├── post-deploy.yml
├── roles # 目录下有不同组件业务的playbook、定义的变量以及模板文件等
├── site.yml
└── vmha.yml

对neutron部署代码解读

neutron目录结构

neutron目录下有5个文件夹:
default: 定义了部署neutron各服务的各类参数
handlers: 定义了启动neutron各服务容器的操作
meta: 定义了部署neutron的依赖
tasks: 部署neutron的各playbook
templates: neutron各服务配置文件的模板

default

defaults下的main.yml,作为当前role的变量文件,定义了关于neutron及neutron各服务的相关参数

# 部分代码
---
project_name: "neutron"

# 定义了neutron_server相关的参数,容器名、镜像、卷等
neutron_services:
  neutron-server:
    # 定义neutron_server的容器名
    container_name: "neutron_server"
    # 定义容器使用的镜像
    image: "{{ neutron_server_image_full }}"
    enabled: true
    group: "neutron-server"
    host_in_groups: "{{ inventory_hostname in groups['neutron-server'] }}"
    # 容器和宿主机映射的卷
    volumes:
      - "{{ node_config_directory }}/neutron-server/:{{ container_config_directory }}/:ro"
      - "/etc/localtime:/etc/localtime:ro"
      - "kolla_logs:/var/log/kolla/"
      
# 定义neutron数据库地址等
neutron_database_name: "neutron"
neutron_database_user: "neutron"
neutron_database_address: "{{ kolla_internal_fqdn }}:{{ database_port }}"

# 定义neutron_server镜像名
neutron_server_image_full: "{{ neutron_server_image }}:{{ neutron_server_tag }}"

handlers

handlers下的main.yml文件,实际是创建、启动neutron各服务容器的playbook。但handlers只能在被触发的情况下才会去执行相关被触发的Task。

# 部分内容
# 启动neutron-server容器
---
- name: Restart neutron-server container
  # vars:task下定义的变量
  vars:
    service_name: "neutron-server"
    service: "{{ neutron_services[service_name] }}"
    config_json: "{{ neutron_config_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
    neutron_conf: "{{ neutron_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
    neutron_lbaas_conf: "{{ neutron_lbaas_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
    neutron_vpnaas_conf: "{{ neutron_vpnaas_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
    neutron_ml2_conf: "{{ neutron_ml2_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
    policy_json: "{{ policy_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
    neutron_server_container: "{{ check_neutron_containers.results|selectattr('item.key', 'equalto', service_name)|first }}"
  # 调用kolla-docker模块,启动容器
  kolla_docker:
    action: "recreate_or_restart_container"
    # docker的一些共用变量,在group/all.yml内有所定义
    common_options: "{{ docker_common_options }}"
    # 指定容器名
    name: "{{ service.container_name }}"
    # 指定启动容器所需镜像
    image: "{{ service.image }}"
    # 容器内配置文件等和宿主机的映射关系
    volumes: "{{ service.volumes }}"
    # 指定是否开启特权
    privileged: "{{ service.privileged | default(False) }}"
  # when:只有当列表下的所有条件满足时,才执行该task
  when:
    - action != "config"
    - service.enabled | bool
    - service.host_in_groups | bool
    - config_json | changed
      or neutron_conf | changed
      or neutron_lbaas_conf | changed
      or neutron_vpnaas_conf | changed
      or neutron_ml2_conf | changed
      or nsx_ini | changed
      or policy_json | changed
      or neutron_server_container | changed

meta

meta下的main.yml指定了neutron这个role的依赖,从main.yml内容可以看出实际是依赖于common这个role,也就是在执行neutron的task前,会先去common这个role下执行相关task。

tasks

main.yml
在tasks目录下,有很多的yml文件,其中main.yml是入口执行文件。
当我们执行kolla-ansible deploy时,main.yml将调用deploy.yml

---
- include: "{{ action }}.yml"

ironic-check.yml
检查是否满足ironic开启时,neutron_plugin_agent配置为openvswitch,不满足则报错

- fail: msg="neutron_plugin_agent must use openvswitch with Ironic"
  when:
    - enable_ironic | bool
    - neutron_plugin_agent != "openvswitch"

register.yml
register.yml内进行了neutron的service和endpoint创建、project,user,和role创建。

在这里面调用了自定义的kolla_toolbox模块,该模块实际是去kolla_toolbox容器内调用自定义的kolla_keystone_service模块,并把module_args下的变量传递进去。

---
- name: Creating the Neutron service and endpoint
  调用kolla_toolbox模块
  kolla_toolbox:
    # kolla_keystone_service模块在kolla_toolbox容器内的/usr/share/ansible/目录下
    module_name: "kolla_keystone_service"
    # 定义创建service和endpoint所需的变量和值,供kolla_keystone_service模块执行
    module_args:
      service_name: "neutron"
      service_type: "network"
      description: "Openstack Networking"
      endpoint_region: "{{ openstack_region_name }}"
      url: "{{ item.url }}"
      interface: "{{ item.interface }}"
      region_name: "{{ openstack_region_name }}"
      auth: "{{ '{{ openstack_neutron_auth }}' }}"
      endpoint_type: "{{ openstack_interface }}"
    module_extra_vars:
      openstack_neutron_auth: "{{ openstack_neutron_auth }}"
  # run_once:任选单个节点执行一次,不会在所有节点执行
  run_once: True
  # with_items: 对列表进行循环操作
  with_items:
    - {'interface': 'admin', 'url': '{{ neutron_admin_endpoint }}'}
    - {'interface': 'internal', 'url': '{{ neutron_internal_endpoint }}'}
    - {'interface': 'public', 'url': '{{ neutron_public_endpoint }}'}

config.yml
config.yml是通过模板为neutron的各个服务生成配置文件

#确认配置文件的路径存在,不存在则创建
- name: Ensuring config directories exist
  file:
    path: "{{ node_config_directory }}/{{ item.key }}"
    state: "directory"
    recurse: yes
  when:
    - item.value.enabled | bool
    - item.value.host_in_groups | bool
  with_dict: "{{ neutron_services }}"

# 为需要neutron.conf配置文件的服务生成neutron.conf配置文件  
- name: Copying over neutron.conf
  vars:
    service_name: "{{ item.key }}"
    # 定义需要neutron.conf配置文件的服务
    services_need_neutron_conf:
      - "neutron-dhcp-agent"
      - "neutron-l3-agent"
      - "neutron-linuxbridge-agent"
      - "neutron-metadata-agent"
      - "neutron-openvswitch-agent"
      - "neutron-server"
      - "neutron-lbaas-agent"
      - "neutron-vpnaas-agent"
      - "neutron-bgp-dragent"
  # 调用自定义的merge_configs模块
  # merge_configs模块将合并sources下列表的所有模板和文件,生成neutron.conf
  merge_configs:
    sources:
      # sources下列表的文件内,配置项重复时,下方的将覆盖上方的
      - "{{ role_path }}/templates/neutron.conf.j2"
      - "{{ node_custom_config }}/global.conf"
      - "{{ node_custom_config }}/database.conf"
      - "{{ node_custom_config }}/messaging.conf"
      - "{{ node_custom_config }}/neutron.conf"
      - "{{ node_custom_config }}/neutron/{{ item.key }}.conf"
      - "{{ node_custom_config }}/neutron/{{ inventory_hostname }}/neutron.conf"
    dest: "{{ node_config_directory }}/{{ item.key }}/neutron.conf"
  register: neutron_confs
  when:
    - item.value.enabled | bool
    - item.value.host_in_groups | bool
    - item.key in services_need_neutron_conf
  # 对neutron_services下的各服务进行循环
  with_dict: "{{ neutron_services }}"
  # 触发执行handlers下的Restart {{ item.key }} container的task
  # 被触发的task将在所有task执行完成后执行
  notify:
    - "Restart {{ item.key }} container"

bootstrap.yml
bootstrap.yml是为neutron创建数据库及数据库用户等

# 创建neutron的数据库
- name: Creating Neutron database
  # 调用kolla_toolbox模块
  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: "{{ neutron_database_name }}"
  # 将执行结果暂存到database
  register: database
  run_once: True
  # 指定在neutron-server主机组的第一个主机上执行该task
  delegate_to: "{{ groups['neutron-server'][0] }}"

# 当上方暂存的database有改变值时,将会去执行bootstrap_service.yml
- include: bootstrap_service.yml
  when: database.changed

bootstrap_service.yml
bootstrap_service.yml将会启动bootstrap引导容器,用于解决neutron服务所需的依赖配置,在完成后,这些引导容器将被自动删除

# 启动bootstrap_neutron容器
- name: Running Neutron bootstrap container
  vars:
    neutron_server: "{{ neutron_services['neutron-server'] }}"
  kolla_docker:
    action: "start_container"
    common_options: "{{ docker_common_options }}"
    detach: False
    environment:
      KOLLA_BOOTSTRAP:
      KOLLA_CONFIG_STRATEGY: "{{ config_strategy }}"
    image: "{{ neutron_server.image }}"
    labels:
      BOOTSTRAP:
    name: "bootstrap_neutron"
    restart_policy: "never"
    volumes: "{{ neutron_server.volumes }}"
  run_once: True
  delegate_to: "{{ groups[neutron_server.group][0] }}"

templates

templates目录下存放着很多j2格式的文件,他们都是neutron各服务的配置文件模板,这些模板将被config.yml根据需要生成为各服务的配置文件。
这里举neutron.conf.j2和neutron-server.json.j2为例进行分析

neutron.conf.j2

[DEFAULT]
# 直接生成配置项
log_dir = /var/log/kolla/neutron

# 将会读取变量文件中api_interface_address和neutron_server_port的值,生成配置项
bind_host = {{ api_interface_address }}
bind_port = {{ neutron_server_port }}

# 将根据if条件判断表达式,符合的表达式将生成对应的配置项
{% if neutron_plugin_agent == 'vmware_nsxv' %}
core_plugin = vmware_nsx.plugin.NsxVPlugin
{% elif neutron_plugin_agent == 'vmware_dvs' %}
core_plugin = vmware_nsx.plugin.NsxDvsPlugin
{% else %}
core_plugin = ml2
service_plugins = {{ neutron_service_plugins|map(attribute='name')|join(',') }}
{% endif %}

neutron-server.json.j2
config.yml将把neutron-server.json.j2生成为config.json,存放在/etc/kolla/neutron-server/目录下,同时该目录下还有neutron.conf等其他neutron-server的配置文件。

在启动容器时/etc/kolla/neutron-server/会被映射到neutron_server容器的/var/lib/kolla/config_files/目录下。

此时生成的config.json的作用就是提供/var/lib/kolla/config_files/目录下neutron-server服务各配置文件与真正配置文件目录:/etc/neutron/ 的链接关系

{
    "command": "neutron-server --config-file /etc/neutron/neutron.conf {% if neutron_plugin_agent in ['openvswitch', 'linuxbridge', 'opendaylight'] %} --config-file /etc/neutron/plugins/ml2/ml2_conf.ini --config-file /etc/neutron/neutron_lbaas.conf --config-file /etc/neutron/neutron_vpnaas.conf {% elif neutron_plugin_agent in ['vmware_nsxv', 'vmware_dvs'] %} --config-file /etc/neutron/plugins/vmware/nsx.ini {% endif %} --config-file /etc/neutron/fwaas_driver.ini",
    "config_files": [
        {
            # 提供/var/lib/kolla/config_files/neutron.conf和/etc/neutron/neutron.conf的链接
            "source": "{{ container_config_directory }}/neutron.conf",
            "dest": "/etc/neutron/neutron.conf",
            "owner": "neutron",
            "perm": "0600"
        }
    ]
}

命令参数解析

ansible-playbook -i $INVENTORY $CONFIG_OPTS $EXTRA_OPTS $PLAYBOOK $VERBOSITY
# -------------------------------------------------
INVENTORY:inventory文件,用于ansible配置主机信息,文件路径在/etc/ansible/hosts/
CONFIG_OPTS:指定globals.yml,password.yml文件
EXTRA_OPTS:指定执行的动作,如’-e kolla_action=deploy’
PLAYBOOK: 为role的入口文件site.yml

例如执行deploy动作的调用过程为kolla-ansible -i all-in-one deploy —> 调用/usr/local/share/kolla-ansible/ansible/site.yml —>根据site.yml文件的task调用执行roles

下面以reconfigure流程分析为例

命令执行参数 kolla-ansible -i /etc/ansible/hosts/ reconfigure -t keystone(组件名称)
具体调用ansible-playbook -i /etc/hosts -e @/etc/ict/globals.yml -e @/etc/kolla/globals.yml -e @/etc/kolla/passwords.yml -e CONFIG_DIR=/etc/kolla -e enable_horizon=false  --tags keystone -e kolla_action=reconfigure -e kolla_serial=0 /usr/share/kolla-ansible/ansible/site.yml

reconfigure操作对应的kolla_action参数为reconfigure,首先去调用site.yml中name为apply role haproxy的tasks

在haproxy role task中,有很多task子任务,此处以keystone为例
在tasks中使用include_role动态导入keystone
- include_role:
    role: keystone
    tasks_from: loadbalancer
  tags: keystone
  when: enable_keystone | bool
  
此处的tasks_from和include_role配合使用,用于指定要从tasks目录中加载的文件,即roles/keystone/tasks/loadbalancer(若tasks_from不指定,默认为main.yml)

- name: "Configure haproxy for {{ project_name }}"
  import_role:
    role: haproxy-config
  vars:
    project_services: "{{ keystone_services }}"
  tags: always
 
使用import_role静态导入haproxy-config

首先,读取keystone_services变量值,赋值给project_services,然后加载roles/haproxy-cofig/tasks/main.yml文件:主要完成的操作就是把本地的haproxy_single_service_listen.cfg.j2模块注入变量后,复制到远程节点目录/etc/kolla/haproxy/services.d/nova-api.cfg

在haproxy中配置好keystone之后,往下会执行到名为Apply role keystone的task
- name: Apply role keystone
  gather_facts: false
  hosts:
    - keystone
    - '&enable_keystone_True'
  serial: '{{ kolla_serial|default("0") }}'
  roles:
    - { role: keystone,
        tags: keystone,
        when: enable_keystone | bool }
       
然后会去执行roles/keystone/tasks/main.yml --> reconfigure.yml --> 主要任务实现都在deploy.yml文件

主要实现:
config.yml:实现keystone相关的检查配置文件
clone.yml:git下载keystone文件
bootstarp.yml: 创建keystone数据库用户权限等配置
meta: flush_handlers:meta任务可影响ansible内部运行方式,这里表示立即执行之前tasks所对应的handler

 类似资料: