根据 DockerHub 上的数据,整个 Kolla 项目管理的 镜像有 2000 多个,这么多的镜像,是怎么定义,又是如何构建的呢?

简介

我们一直在说的 Kolla,通常情况下泛指,包括了 KollaKolla-Ansible 两个项目。

“ 实际上,根据 OpenStack Wiki,还有个 Kayobe 项目也是相关的。但是这个用的比较少,而且我试用后觉得不是特别符合我的需求,就不过多介绍了。
“ 此外还有一个项目 Kolla-kubernetes 致力于和 Kubernetes 结合,但是和另一个项目 openstack-helm 重合较多,提前退休了。

Kolla 项目开始之初只有一个项目,从构建 docker 容器,到使用 ansible 部署,全流程搞定。后来把 ansible 这块分离了出来,独立为 kolla-ansible 项目,原来的 kolla 专门负责 docker 镜像的构建。

镜像划分的维度

虽然最终的镜像个数超过 2000 个,实际并不是完全独立的 2000 多个服务。而是针对不同的场景分别构建,多维度全面覆盖的结果。

镜像分层

熟悉 Docker 的小伙伴都知道,Dockerfile 是可以指定“继承”关系的。也就是利用镜像分层的特性,逐层构建。

OpenStack 中有很多子服务隶属于同一个项目,例如,nova-apinova-compute 等都属于 nova,所以,很自然地可以先构建一个通用的 nova-base 镜像,然后在此基础上分别构建不同的服务。

这是一个纵向的划分维度。

功能划分

因为 Kolla 项目不仅是把 OpenStack 的服务集成了,周边用到的组件和辅助服务也都囊括在内。包括 RabbitMQMariaDB 等。

这是一个横向的划分维度。

以上两个是最基础的划分维度,也是我们能够很容易想到的。

操作系统

每个 Docker 镜像最底层只能是操作系统的基础镜像。现在主流的 Linux 发行版有好几家,OpenStack 作为一个世界级的开源项目,要是只绑定一家,其他人可不答应。

所以,必须要同时支持多个操作系统。这个靠 Dockerfile 显然解决不了。

如果为每个操作系统单独的定义一份 Dockerfile 显然不够聪明。 Kolla 使用了 Jinja 模板文件多做了一层抽象,根据指定的参数先由 Dockerfile.j2 生成 Dockerfile

这个维度在 kolla 中对应的参数是 base,目前支持的操作系统有:

['centos', 'rhel', 'ubuntu', 'debian']

“ Jinja 是 Python 中使用比较广泛的模板引擎(template engine)。之所以叫 Jinja,是因为日本的神社(Jinja)英文单词是 temple,而模板的英文是 template,两者发音很相似(什么脑回路)。Jinja 项目的 Logo 也是一个神社的图标,可能是因为这层关系,这个在国内似乎讨论的并不多。

安装方式

Kolla 不仅是要作单纯的部署工具,还希望能够替代 devstack 为开发助力,所以除了从软件源(如 yumapt 等)直接安装打包好的程序,还要能够直接从源码安装。

从软件包称为 binary,从源码安装称为 source

这个维度也是在处理 Jinja 模板的阶段完成。

“ 实际上,还有 2 个安装方式,rdorhos,都是针对 RedHat 系统的,一般不怎么会用到。

操作系统和安装方式这两个维度,决定了镜像名称的前缀:

文件的组织结构

了解了划分维度,我们来看一下具体的文件组织结构是怎样的。

所有的构建 Docker 镜像相关的文件都存放在 kolla/docker 目录下。这下面的文件夹众多,下面把有代表性的列了出来:

docker/
├── base
│   └── Dockerfile.j2
├── horizon
│   └── Dockerfile.j2
├── mariadb
│   └── Dockerfile.j2
├── nova
│   ├── nova-api
│   │   └── Dockerfile.j2
│   ├── nova-base
│   │   └── Dockerfile.j2
│   └── nova-compute
│       └── Dockerfile.j2
└── openstack-base└── Dockerfile.j2

每个文件夹代表了一个服务,除了名字带 base 的,其中顶层的有 2 个:

  • base 这是所有镜像的初始层
  • openstack-base 这是所有 OpenStack 相关服务的初始层

如果一个组件包含多个服务,比如 nova,它内部就会又多出一层基础层: nova-base。所有其它的 nova-<xxx> 都是从这层开始。如果一个组件只有一个服务,则不需要再有子文件夹,直接是 Dockerfile.j2 文件。

镜像层之间的关系是在 Dockerfile 文件中的 FROM 语句定义的。它们在 jinja 模板中是固定的。

例如 horizon/Dockerfile.j2 中:

FROM {{ namespace }}/{{ image_prefix }}openstack-base:{{ tag }}

openstack-base/Dockerfile.j2 中:

FROM {{ namespace }}/{{ image_prefix }}base:{{ tag }}

它们之间的依赖关系是这样的:

base
├── openstack-base
│   ├── nova-base
│   │   └── nova-api
│   │   └── nova-compute
│   └── horizon
└── mariadb

可以看到,最多就 4 层。

包含 .j2 文件的文件夹名字最终会成为镜像名的一部分,如 <os>-<type>-nova-api

这里的 <os>-<type>- 也就是对应上面的 {{ image_prefix }} 字符串,分别对应:

  • 操作系统,如 centos
  • 安装类型,如 binary

所以最终上面的文件对应的镜像是:

centos-binary-base
centos-binary-openstack-base
centos-binary-nova-base
centos-binary-nova-api
centos-binary-nova-compute
centos-binary-horizon

“ 注意,并不是每个镜像都支持任意的类型组合,具体需要查看 kolla 源码。

base 镜像的作用

所有镜像的源头都是 base,所以它肯定是很重要的。其中内容主要有两个地方比较关键:

设置软件仓库源

所有软件包的安装源配置都在 base 中完成。不管是 OpenStack 安装源还是其它依赖的公共组件安装源,统统在基础镜像里固定下来了。

所以在国内网络不好的情况下,就必须要替换其中的仓库源。

设置容器启动命令

定义了默认的 ENTRYPOINTCMD,也就是把容器的启动方式固定了下来。

相信这里大家会有疑惑,那么多不同的服务,怎么可能在这里把启动命令固定下来呢?其实这里有一点技巧。

这里 kolla 固定了一个启动脚本 start.sh,在这个脚本里从固定位置 /run_command 读到真正的执行命令。/run_command 则是由 kolla-ansible 在启动容器的时候注入的。

还记得在 介绍 Kolla 的配置文件 时看到的 config.json 么,其中有一个 command 字段。例如 Horizon 服务的配置:

{"command": "/usr/sbin/httpd -DFOREGROUND","config_files": [{"source": "/var/lib/kolla/config_files/horizon.conf","dest": "/etc/httpd/conf.d/horizon.conf","owner": "horizon","perm": "0600"},]
}

这样做,既保证了构建镜像时候的一致性,又保证了容器启动的灵活性。

处理流程

kolla 构建镜像的流程非常简单,大体就是 5 个步骤:

1. 生成 Dockerfile

docker 整个目录复制到一个临时的工作目录,然后在其中扫描包含有 Dockerfile.j2 文件的文件夹。正如在上面分析的那样,这样的一个文件夹就对应一个镜像。

使用从配置文件中获取的操作系统基础镜像和安装方式等参数,渲染生成 Dockerfile 文件。

“ 参考源码:create_dockerfiles

2. 构建镜像列表

将上一步生成的 Dockerfile 都读取到内存,处理里面的 FROM 语句,可以获得每个镜像的 parent 名字。还有其它一些关于安装方式的细节也要处理,不用过多关心。

这一步完成我们就得到了一个镜像列表。这里的镜像指的是 kolla 定义的 Image 类的实例。

3. 查找镜像关系

遍历整个镜像列表,把它们的依赖关系整理清楚。

4. 过滤镜像列表

因为总共镜像数量比较多,所以需要根据用户提供的参数做一下过滤。

过滤参数有两种方式:

  • 预先定义了几组常用的镜像分组,称为 profile,指定分组名,就可以构建对应的镜像
  • 通过正则表达式匹配镜像的名字来选择

5. 执行构建

使用多线程任务队列,批量执行构建。

构建完镜像后,还有一个可选操作,将镜像 push 到指定的 registry 中。

以上过程,有兴趣的可以自行去看 kolla 源码,主要内容就集中在 1 个 build.py 文件,还是很简单的。

使用方法

为避免本文内容失效,请关注 Kolla 项目官方文档 获取更新。

安装 Python 3

CentOS 7 自带的 Python 版本还是 2.7,在 2020 年后不再维护,Kolla 项目有的依赖包不再支持。

yum install python3

“ CentOS 7 的安装源提供的 Python 3 版本是 3.6.8

创建虚拟环境(可选)

推荐在 Python 虚拟环境中安装 Kolla:

python3 -m venv .virtualenvs/kolla-build
source .virtualenvs/kolla-build/bin/activate
(kolla-build) [root@davycloud ~]#

以下操作默认都在虚拟环境下执行。

安装 Kolla

有两种方式,

  • 使用 pip 安装
  • 从源码安装

推荐采用后者,有助于学习,也方便改代码。

使用 git 下载源码:

# OpenStack 官方 git 源
git clone https://opendev.org/openstack/kolla# 上面网速慢的可以使用下面的镜像站地址
git clone http://git.trystack.cn/openstack/kolla

然后使用 pip 安装即可:

(kolla-build) $ pip install kolla/

注意最后的斜杠,表示我们安装的是本地目录。安装完毕后可以执行:

(kolla-build) [root@davycloud ~]# kolla-build --version
9.1.0

生成配置文件

Kolla 构建镜像有不少配置项,但是基本保持默认即可。并且缺少配置文件 kolla-build 命令也能执行,所以这一步这里就 略过 了。

如果你想生成 kolla-build.conf 配置文件,可以参考 官方文档

构建 base 镜像

构建最最基础的 base 镜像:

(kolla-build) [root@davycloud ~]# kolla-build ^base
INFO:kolla.common.utils:Found the docker image folder at /root/.virtualenvs/kolla-build/share/kolla/docker
INFO:kolla.common.utils:Added image base to queue
INFO:kolla.common.utils:Attempt number: 1 to run task: BuildTask(base)
INFO:kolla.common.utils.base:Building started at 2020-01-28 19:54:50.158139
INFO:kolla.common.utils.base:Step 1/37 : FROM centos:7
INFO:kolla.common.utils.base: ---> 5e35e350aded
INFO:kolla.common.utils.base:Step 2/37 : LABEL maintainer="Kolla Project
...
INFO:kolla.common.utils.base:Successfully tagged kolla/centos-binary-base:9.1.0

注意^base 前面的 ^ 符号不可省略,这是正则表达式中表示句首的符号,如果缺少该符号,kolla-build 会把 openstack-basenova-base 等一众名字包含 base 的镜像都匹配上了。

构建的镜像标签默认是 kolla 的版本号,9.1.0,我们后面会指定自己的版本号。

修改 base 镜像

我们在前面分析过了,所有的安装源都在 base 镜像中指定了。

如果我们直接使用这个 base 镜像,后面的镜像构建过程中软件的安装速度没法保证。

当然,我们可以在下载完 kolla 源码之后就直接修改 base 对应的 Dockerfile.j2 和相关的构建文件,但是这样修改是比较麻烦的。因为其中夹杂着其它情况的处理代码,例如:

{% if base_package_type == 'rpm' %}
# For RPM Variants, enable the correct repositories - this should all be done
# in the base image so repos are consistent throughout the system.  This also
# enables to provide repo overrides at a later date in a simple fashion if we
# desire such functionality.  I think we will :)RUN CURRENT_DISTRO_RELEASE=$(awk '{match($0, /[0-9]+/,version)}END{print version[0]}' /etc/system-release); if [  $CURRENT_DISTRO_RELEASE != "{{ supported_distro_release }}" ]; then echo "Only release '{{ supported_distro_release }}' is supported on {{ base_distro }}"; false; fi && cat /tmp/kolla_bashrc >> /etc/bashrc && sed -i 's|^(override_install_langs=.*)|# 1|' {% if distro_package_manager == 'dnf' %}/etc/dnf/dnf.conf{% else %}/etc/yum.conf{% endif %}{% block base_yum_conf %}{% if distro_package_manager == 'dnf' %}
COPY dnf.conf /etc/dnf/dnf.conf
{% else %}
COPY yum.conf /etc/yum.conf
{% endif %}

修改难度是比较大的,要把其中的逻辑捋清楚才能下手。而且以后每次这个文件的版本有变化,更新都要对照着修改。

这里我采取了比较投机取巧的办法,等这个 base 镜像构建完成后,直接在它之上修改。这个时候我们已经确定了操作系统(CentOS)和安装方式(Binary),这样只需要替换 /etc/yum.repos.d/ 下面的 .repo 文件即可。

先把 kolla/centos-binary-base:9.1.0 镜像内的 /etc/yum.repos.d/ 整个文件夹都拷贝出来,逐个 .repo 修改,把其中的 URL 替换成阿里云镜像站的 URL。

然后写了一个超级简单粗暴的 Dockerfile:

FROM kolla/centos-binary-base:9.1.0RUN mkdir -p /etc/yum.repos.d/bak && mv /etc/yum.repos.d/*.repo /etc/yum.repos.d/bakCOPY CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo
COPY CentOS-Ceph-Nautilus.repo /etc/yum.repos.d/CentOS-Ceph-Nautilus.repo
COPY CentOS-CR.repo /etc/yum.repos.d/CentOS-CR.repo
COPY CentOS-Debuginfo.repo /etc/yum.repos.d/CentOS-Debuginfo.repo
COPY CentOS-fasttrack.repo /etc/yum.repos.d/CentOS-fasttrack.repo
COPY CentOS-Media.repo /etc/yum.repos.d/CentOS-Media.repo
COPY CentOS-NFS-Ganesha-28.repo /etc/yum.repos.d/CentOS-NFS-Ganesha-28.repo
COPY CentOS-OpenStack.repo /etc/yum.repos.d/CentOS-OpenStack.repo
COPY CentOS-OpsTools.repo /etc/yum.repos.d/CentOS-OpsTools.repo
COPY CentOS-QEMU-EV.repo /etc/yum.repos.d/CentOS-QEMU-EV.repo
COPY CentOS-Sources.repo /etc/yum.repos.d/CentOS-Sources.repo
COPY CentOS-Storage-common.repo /etc/yum.repos.d/CentOS-Storage-common.repo
COPY CentOS-Vault.repo /etc/yum.repos.d/CentOS-Vault.repo
COPY crmsh.repo /etc/yum.repos.d/crmsh.repo
COPY elasticsearch.repo /etc/yum.repos.d/elasticsearch.repo
COPY epel.repo /etc/yum.repos.d/epel.repo
COPY epel-testing.repo /etc/yum.repos.d/epel-testing.repo
COPY grafana.repo /etc/yum.repos.d/grafana.repo
COPY influxdb.repo /etc/yum.repos.d/influxdb.repo
COPY opendaylight.repo /etc/yum.repos.d/opendaylight.repo
COPY rabbitmq_rabbitmq-server.repo /etc/yum.repos.d/rabbitmq_rabbitmq-server.repo
COPY td.repo /etc/yum.repos.d/td.repo

然后用它来构建一个新的镜像:

(kolla-build) [root@davycloud ~]# docker build . -t kolla/centos-binary-base:davycloud

注意,其中的镜像 tag 可以自己随便定义。

构建 openstack-base 镜像

有了基础镜像,就可以开始构建其它的镜像了。可以先挑一个试一试,比如 openstack-base

注意,上面已经把 tag 修改了,所以接下来的命令必须要带两个选项:

  • --tag davycloud,用来指定自定义的 tag,
  • --skip-existing,略过已经创建好的镜像
(kolla-build) [root@davycloud aliyun]# kolla-build --tag davycloud --skip-existing  openstack-baseINFO:kolla.common.utils:Found the docker image folder at /root/.virtualenvs/kolla-build/share/kolla/docker
INFO:kolla.common.utils:===========================
INFO:kolla.common.utils:Images that failed to build
INFO:kolla.common.utils:===========================
ERROR:kolla.common.utils:openstack-base Failed with status: matched

会出现这么一个莫名其妙的错误。这其实是 kolla 这里处理的逻辑有点问题。找到下面所示代码,在 image.status = STATUS_UNMATCHED 上面加一个判断:

@@ -1117,9 +1117,9 @@ class KollaWorker(object):ancestor_image.status = STATUS_MATCHEDLOG.debug('Image %s matched regex', image.name)else:
+                    # See: https://bugs.launchpad.net/kolla/+bug/1810979
+                    if image.status != STATUS_SKIPPED:
+                        image.status = STATUS_UNMATCHED
-                    # we do not care if it is skipped or not as we did not
-                    # request it
-                    image.status = STATUS_UNMATCHEDelse:for image in self.images:if image.status != STATUS_UNBUILDABLE:

“ 我已经给社区提了修改补丁,但是没有下文。

修改完毕之后,就可以重试上面的命令来构建镜像了。

构建其它镜像

Kolla 总共支持的镜像比较多,不太可能全部需要,所以最好事先挑选一番。

最简单的是通过 profile 来批量指定,然后通过 --list-images 选项,在构建之前查看镜像列表,做到心中有数:

(kolla-build) [root@davycloud aliyun]# kolla-build -p default --list-images1 : openstack-base
2 : chrony
3 : barbican-keystone-listener
4 : barbican-base
5 : nova-spicehtml5proxy
6 : nova-conductor
7 : nova-ssh
8 : nova-libvirt
9 : nova-scheduler
10 : nova-compute-ironic
11 : nova-novncproxy
12 : nova-serialproxy
13 : nova-api
14 : nova-compute
15 : nova-base
16 : glance-api
17 : glance-registry
18 : glance-base
19 : kolla-toolbox
20 : neutron-server-opendaylight
21 : neutron-l3-agent
22 : neutron-mlnx-agent
23 : neutron-server
24 : neutron-server-ovn
25 : neutron-metadata-agent
26 : neutron-dhcp-agent
27 : neutron-openvswitch-agent
28 : neutron-bgp-dragent
29 : neutron-linuxbridge-agent
30 : neutron-infoblox-ipam-agent
31 : neutron-base
32 : neutron-metering-agent
33 : neutron-sriov-agent
34 : neutron-metadata-agent-ovn
35 : fluentd
36 : heat-api-cfn
37 : heat-engine
38 : heat-base
39 : heat-api
40 : heat-all
41 : ironic-neutron-agent
42 : mariadb
43 : keystone-ssh
44 : keystone
45 : keystone-fernet
46 : keystone-base
47 : openvswitch-db-server
48 : openvswitch-base
49 : openvswitch-vswitchd
50 : prometheus-haproxy-exporter
51 : prometheus-base
52 : prometheus-memcached-exporter
53 : base
54 : rabbitmq
55 : cron
56 : haproxy
57 : keepalived
58 : memcached
59 : horizon
60 : placement-base
61 : placement-api

“ 也可以查看源码文件:kolla/common/config.py 中的 _PROFILE_OPTS 查看支持哪些 profile 以及包含的镜像列表。

(kolla-build) [root@davycloud ~]# kolla-build --tag davycloud --skip-existing -p default

把镜像推送到 registry

可以是本地自建的服务,也可以是其它平台提供的,比如 阿里云的容器镜像服务

一切完工之后就可以参考我之前的文章,在使用 Kolla-Ansible 部署环境的时候在 globals.yml 中修改 registry 相关配置,使用自己的镜像源了。


如果本文对你有帮助,请 点赞关注分享,谢谢!

anconda设置镜像源_管理2000+Docker镜像,Kolla是如何做到的相关推荐

  1. dashboard 镜像源_使用国内docker镜像源

    在国内,通过Docker的pull和push命令访问hub.docker时,网络十分慢,而且会出现各种各样的网络连接问题.因此这里介绍下如何使用国内的镜像源,这里以DaoCloud为例. 注册完成后, ...

  2. 清华镜像源_Hyperledger Fabric2.x Docker镜像编译加速

    一.问题描述 最近工作需要对fabric2的源码进行改造,每次改完想要部署测试的时候,make docker这个命令执行起来超级慢.找到这篇文章的读者应该都遇到与我相同的问题,本文将分析问题产生的原因 ...

  3. 群晖docker镜像源更换为阿里云镜像源

    群晖硬件:DS218+ 系统版本:DSM 7.0-41890 docker版本:20.10.3-1233 前言:除了群晖自带的应用之外,docker里也拥有及其丰富的软件,这都是得益于开源精神.而国内 ...

  4. Homebrew切换镜像源(中科大清华镜像)

    零.Homebrew 镜像地址(推荐中科大镜像) 1.brew.git 镜像 中科大镜像:https://mirrors.ustc.edu.cn/brew.git 清华镜像:https://mirro ...

  5. anconda设置镜像源_三、DockerFile 定制属于自己的专属镜像

    前言 上篇文章我们知道了怎么操作镜像和容器,到基础都是从已经存在的镜像开始的,那我们自己怎样搭建一个镜像并使用它呢?接下来就让我们学习使用dockerfile 创建属于自己的镜像吧. dockerfi ...

  6. docker 修改阿里镜像源_使用阿里云容器镜像服务托管私有Docker镜像

    一个只用markdown语法编写文章的90后野路子Web架构师,每天都分享一些有用的知识点,欢迎关注- 前言 概述 本文主要讲解如何托管自己的Docker镜像到阿里云容器镜像服务ACR上,以及如何使用 ...

  7. docker镜像指定安装源_如何修改docker pull镜像源

    狐的传说 修改docker pull镜像源的方法安装或升级DockerDocker 1.3.2版本以上才支持Docker Hub Mirror机制,如果您还没有安装Docker或者版本过低,请安装或升 ...

  8. docker 导入镜像_官方下一代Docker镜像构建神器 -- BuildKit

    BuildKit是Docker官方社区推出的下一代镜像构建神器--可以更加快速,有效,安全地构建docker 镜像.Docker v18.06已经集成了该组件.BuildKit可用于多种导出格式(例如 ...

  9. dockhub 好用的镜像_玩转docker镜像和镜像构建

    摘要 本文从个人的角度,讲述对于docker镜像和镜像构建的一些实践经验.主要内容包括利用docker hub进行在线编译,下载镜像,dind的实践,对于镜像的一些思考等.本文是对当时微信分享内容的一 ...

最新文章

  1. Linux进阶:DNS详解
  2. JSF, MyFaces, RichFaces 和 Facelets的区别
  3. C/C++程序员必须熟悉的开源库
  4. php 正则提取url,php 正则表达式提取网页超级链接url的函数
  5. 终于有人把AI、BI、大数据、数据科学讲明白了
  6. 批量文件替换_CAD图形文件中如何快速批量替换文字?【AutoCAD教程】
  7. c++成员声明中的非法限定名_new 一个对象有哪两个过程?很多人在面试中都问住了...
  8. 即时通讯安全问题大曝光
  9. 收缩 虚拟硬盘 shrink vhd
  10. 2016阿里技术论坛,阿里技术大神的互联网趋势分享
  11. 9,求整数的二进制中1的个数《剑指offer》
  12. 论文笔记:OverFeat
  13. 大数据基础课02 从萌芽到爆发,大数据经历了哪些发展?
  14. 城镇居民医保指南[南京]
  15. 小米 samba linux,解决Win10.4无法访问samba协议小米路由盘修复方法
  16. C语言【程序19】题目:两个乒乓球队进行比赛,各出三人。
  17. Expected binary or unicode string, got 3
  18. 液晶12864显示字符
  19. solar2 android,solarwalk2
  20. Python + PIL + Tkinter: 图片原比例缩放

热门文章

  1. 运行时修改Standard shader的Mode
  2. mac 版ideal 查找类_4款mac窗口切换工具 提高你的工作效率
  3. OpenShift 4 之AMQ Streams(1) - 多个Consumer从Partition接收数据
  4. 为Raspberry Pi开发.NET应用程序:第2部分
  5. android seekbar 源码,Android SeekBar调节音量
  6. 机器人施教器的信息丢失_一种精准定位学习难度的施教方法及教育机器人与流程...
  7. python和excel能结合应用吗_通过Python在Excel中使用机器学习
  8. python程序实例讲解_python入门编程实例 python入门编程实例解析
  9. 配置生产环境加路径 /开发环境
  10. java中fitlter,068.Python框架Django之DRF视图集使用