根據 DockerHub 上的數據,整個 Kolla 項目管理的 鏡像有 2000 多個,這麼多的鏡像,是怎麼定義,又是如何構建的呢?html
咱們一直在說的 Kolla,一般狀況下泛指,包括了 Kolla
和 Kolla-Ansible
兩個項目。html5
實際上,根據 OpenStack Wiki,還有個
Kayobe
項目也是相關的。可是這個用的比較少,並且我試用後以爲不是特別符合個人需求,就不過多介紹了。python
此外還有一個項目
Kolla-kubernetes
致力於和 Kubernetes 結合,可是和另外一個項目openstack-helm
重合較多,提早退休了。linux
Kolla
項目開始之初只有一個項目,從構建 docker 容器,到使用 ansible 部署,全流程搞定。後來把 ansible 這塊分離了出來,獨立爲 kolla-ansible
項目,原來的 kolla
專門負責 docker 鏡像的構建。git
雖然最終的鏡像個數超過 2000 個,實際並非徹底獨立的 2000 多個服務。而是針對不一樣的場景分別構建,多維度全面覆蓋的結果。正則表達式
熟悉 Docker 的小夥伴都知道,Dockerfile 是能夠指定「繼承」關係的。也就是利用鏡像分層的特性,逐層構建。docker
OpenStack 中有不少子服務隸屬於同一個項目,例如,nova-api
, nova-compute
等都屬於 nova
,因此,很天然地能夠先構建一個通用的 nova-base
鏡像,而後在此基礎上分別構建不一樣的服務。json
這是一個縱向的劃分維度。ubuntu
由於 Kolla
項目不只是把 OpenStack 的服務集成了,周邊用到的組件和輔助服務也都囊括在內。包括 RabbitMQ
,MariaDB
等。centos
這是一個橫向的劃分維度。
以上兩個是最基礎的劃分維度,也是咱們可以很容易想到的。
每一個 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
爲開發助力,因此除了從軟件源(如 yum
,apt
等)直接安裝打包好的程序,還要可以直接從源碼安裝。
從軟件包稱爲 binary
,從源碼安裝稱爲 source
這個維度也是在處理 Jinja 模板的階段完成。
實際上,還有 2 個安裝方式,
rdo
和rhos
,都是針對 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 個:
若是一個組件包含多個服務,好比 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
中完成。不論是 OpenStack 安裝源仍是其它依賴的公共組件安裝源,通通在基礎鏡像裏固定下來了。
因此在國內網絡很差的狀況下,就必需要替換其中的倉庫源。
定義了默認的 ENTRYPOINT
和 CMD
,也就是把容器的啓動方式固定了下來。
相信這裏你們會有疑惑,那麼多不一樣的服務,怎麼可能在這裏把啓動命令固定下來呢?其實這裏有一點技巧。
這裏 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 個步驟:
把 docker
整個目錄複製到一個臨時的工做目錄,而後在其中掃描包含有 Dockerfile.j2
文件的文件夾。正如在上面分析的那樣,這樣的一個文件夾就對應一個鏡像。
使用從配置文件中獲取的操做系統基礎鏡像和安裝方式等參數,渲染生成 Dockerfile
文件。
參考源碼:
create_dockerfiles
將上一步生成的 Dockerfile 都讀取到內存,處理裏面的 FROM
語句,能夠得到每一個鏡像的 parent
名字。還有其它一些關於安裝方式的細節也要處理,不用過多關心。
這一步完成咱們就獲得了一個鏡像列表。這裏的鏡像指的是 kolla
定義的 Image
類的實例。
遍歷整個鏡像列表,把它們的依賴關係整理清楚。
由於總共鏡像數量比較多,因此須要根據用戶提供的參數作一下過濾。
過濾參數有兩種方式:
profile
,指定分組名,就能夠構建對應的鏡像使用多線程任務隊列,批量執行構建。
構建完鏡像後,還有一個可選操做,將鏡像 push
到指定的 registry 中。
以上過程,有興趣的能夠自行去看 kolla 源碼,主要內容就集中在 1 個 build.py
文件,仍是很簡單的。
爲避免本文內容失效,請關注 Kolla 項目官方文檔 獲取更新。
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-base
,nova-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.0 RUN mkdir -p /etc/yum.repos.d/bak && mv /etc/yum.repos.d/*.repo /etc/yum.repos.d/bak COPY 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-base INFO: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_MATCHED LOG.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_UNMATCHED else: for image in self.images: if image.status != STATUS_UNBUILDABLE:
我已經給社區提了修改補丁,可是沒有下文。
修改完畢以後,就能夠重試上面的命令來構建鏡像了。
Kolla 總共支持的鏡像比較多,不太可能所有須要,因此最好事先挑選一番。
最簡單的是經過 profile
來批量指定,而後經過 --list-images
選項,在構建以前查看鏡像列表,作到心中有數:
(kolla-build) [root@davycloud aliyun]# kolla-build -p default --list-images 1 : 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
能夠是本地自建的服務,也能夠是其它平臺提供的,好比 阿里雲的容器鏡像服務。
具體的過程就不贅述了
一切完工以後就能夠參考我以前的文章,在使用 Kolla-Ansible
部署環境的時候在 globals.yml
中修改 registry 相關配置,使用本身的鏡像源了。
若是本文對你有幫助,請 點贊、 關注、分享,謝謝!