Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EulerPublisher: 一键发布openEuler镜像背后的技术 #2

Open
Yikun opened this issue Jul 20, 2023 · 0 comments
Open

EulerPublisher: 一键发布openEuler镜像背后的技术 #2

Yikun opened this issue Jul 20, 2023 · 0 comments
Labels
openEuler Improvements or additions to documentation publish New feature or request

Comments

@Yikun
Copy link
Contributor

Yikun commented Jul 20, 2023

作者:@wjunLu

1. EulerPublisher架构

eulerpublisher作为一款openEuler“一键式”发布工具,提供openEuler容器镜像、云镜像、WSL等镜像定制、发布和测试的能力。本项目主要使用python语言实现,并且以CLI的方式提供给用户使用。

eulerpublisher按照使用场景,分为容器镜像(container)、云镜像(cloudimg)、WSL(wsl)这几个模块,而每个模块又按照子场景划分不同的子功能模块,每个子场景功能模块具备prepare、build、publish、check等能力,因而形成一种按照主场景子场景、以及对应动作构成的分层软件架构,如图所示:
无标题-2023-08-14-0928-3

以下围绕eulerpublisher cli的使用方式,来理解eulerpublisher的软件架构,cli通用形式如下:

eulerpublisher <Command1> <Command2> <Command3> <Options>

详细说明如下:

  • Command1
    Command1为主场景命令,使用时必填,取值有containercloudimgwsl

  • Command2
    Command2确定子场景,使用时可选,具体情况如下:

    1. Command1 == container场景,使用Docker完成镜像构建等一系列动作,暂无其他子场景,无 Command2;
    2. Command1 ==cloudimg场景,会针对不同云厂商有着不同的镜像定制及发布要求,因此Command 2必选,取值有awsazurehwcloud等。
  • Command3
    Command3Command 1~2 组合场景下的“动作”,可选preparebuildpushpublishcheck等,具体Command 1~3的可选组合请使用eulerpublisher --help逐级查看

  • Options
    Options是被执行命令的一组参数,每个不同的Command 1~3组合会有不同的参数选择,使用eulerpublisher --help查看。

示例如下:

container场景

# 容器镜像发布
eulerpublisher container publish --repo openeuler/openeuler --version 22.03-LTS-SP1 --registry registry-1.docker.io --dockerfile /Path/To/Dockerfile

上述效果是向dockerhub(https://hub.docker.com)的openeuler/openeuler仓库发布由Dockerfile定制的tag为22.03-LTS-SP1的支持arm64、amd64多平台的openeuler容器镜像。

cloudimg场景

# AMI镜像构建
eulerpublisher cloudimg aws build --version 22.03-LTS-SP1 --arch aarch64 --bucket openeuler --region ap-southeast-2

此命令将在AWS的ap-southeast-2区的AMI列表生成一个22.03-LTS-SP1版本的aarch64架构的openEuler镜像,其制作的原始镜像来源于openeuler桶中。

2. EulerPublisher容器镜像构建原理

背景

eulerpublisher基于Docker CLI和Dockerfile实现定制Docker容器镜像的功能。在介绍eulerpublisher实现容器镜像构建的原理之前,有必要先梳理一下有关的背景知识:

1). 容器镜像

容器镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的配置参数。关于容器和容器镜像的关系,可以类比为程序设计中的类和实例,容器镜像是静态的类定义,容器是镜像运行时的实例。

2). Docker镜像分层

Docker镜像是由多个文件系统叠加而成。最底层是一个引导文件系统,即bootfs,第二层是root文件系统 rootfs,它位于bootfs之上,其他的文件系统在rootfs之上。

在Docker镜像中,所有的文件系统是只读的,这也体现了Docker镜像的静态属性。当Docker启动一个容器时,会加载这些只读层并在这些只读层的上面增加一个读写层,该读写层一般也被称为容器层。这时如果修改正在运行的容器中已有的文件,那么这个文件将会从只读层复制到读写层。该文件的只读版本还在,只是被上面读写层的该文件的副本隐藏。当删除docker,或者重新启动时,之前的更改将会消失。
layer

3). Dockerfile

Dockerfile是构建Docker镜像的“生产手册”,决定着Docker镜像的内容,以下是Dockerfile指令

Dockerfile 指令 说明
FROM 指定基础镜像,用于后续的指令构建。
MAINTAINER 指定Dockerfile的作者/维护者。(已弃用,推荐使用LABEL指令)
LABEL 添加镜像的元数据,使用键值对的形式。
RUN 在构建过程中在镜像中执行命令。
CMD 指定容器创建时的默认命令。(可以被覆盖)
ENTRYPOINT 设置容器创建时的主要命令。(不可被覆盖)
EXPOSE 声明容器运行时监听的特定网络端口。
ENV 在容器内部设置环境变量。
ADD 将文件、目录或远程URL复制到镜像中。
COPY 将文件或目录复制到镜像中。
VOLUME 为容器创建挂载点或声明卷。
WORKDIR 设置后续指令的工作目录。
USER 指定后续指令的用户上下文。
ARG 定义在构建过程中传递给构建器的变量,可使用 "docker build" 命令设置。
ONBUILD 当该镜像被用作另一个构建过程的基础时,添加触发器。
STOPSIGNAL 设置发送给容器以退出的系统调用信号。
HEALTHCHECK 定义周期性检查容器健康状态的命令。
SHELL 覆盖Docker中默认的shell,用于RUN、CMD和ENTRYPOINT指令。

示例

# eulerpublisher的默认Dockerfile

FROM scratch
ARG TARGETARCH
ADD openEuler-docker-rootfs.$TARGETARCH.tar.xz /
RUN ln -sf /usr/share/zoneinfo/UTC /etc/localtime && \
    sed -i "s/TMOUT=300/TMOUT=0/g" /etc/bashrc
CMD ["bash"]

解释

  • FROM scratch
    指定构建的Docker镜像的基础镜像是scratch,即一个空白镜像,没有预装任何软件包或依赖项。
  • ARG TARGETARCH
    声明一个构建变量TARGETARCH,在构建过程中会提供该变量的值。
  • ADD openEuler-docker-rootfs.$TARGETARCH.tar.xz /
    将根文件系统的压缩包(openEuler-docker-rootfs.$TARGETARCH.tar.xz)添加到Docker镜像的根目录(/)中。
  • RUN ln -sf /usr/share/zoneinfo/UTC /etc/localtime && \ ...
    设置系统时区为UTC、设置TMOUT=0、更新yum并清理缓存。
  • CMD ["bash"]
    指定了在Docker镜像运行容器时要执行的默认命令为bash,即启动一个交互式的Bash shell会话。

需要注意的是,通过Dockerfile构建Docker镜像时,Dockerfile中的每一个写指令执行后都将会在最终镜像增加一层。因此,为了减少镜像的分层(又称为镜像裁剪),编写Dockerfile时尽可能一行命令执行多个写操作。如上述Dockerfile中RUN ln -sf /usr/share/zoneinfo/UTC /etc/localtime && \ sed -i "s/TMOUT=300/TMOUT=0/g" /etc/bashrc使用一行命令执行2个操作也是出于此目的。

使用eulerpublisher默认Dockerfile构建的镜像分层(size不为0的)如下

IMAGE          CREATED        CREATED BY                                       SIZE      COMMENT
d9bff1b2db49   7 months ago   CMD ["bash"]                                     0B        buildkit.dockerfile.v0
<missing>      7 months ago   RUN |1 TARGETARCH=amd64 /bin/sh -c ln -sf /u…    168kB     buildkit.dockerfile.v0
<missing>      7 months ago   ADD openEuler-docker-rootfs.amd64.tar.xz / #…    191MB     buildkit.dockerfile.v0
<missing>      7 months ago   ARG TARGETARCH                                   0B        buildkit.dockerfile.v0

4). docker buildx build

eulerpublisher使用docker buildx build命令构建多架构(linux/arm64, linux/amd64)的openEuler镜像,核心命令示例如下:

docker buildx build  -t openeuler/openeuler:22.03-LTS-SP1 --platform linux/arm64,linux/amd64 --push .

该命令使用默认Dockerfile(见上文)构建openEuler镜像,由于多平台镜像构建结果无法在本地缓存,只能使用--push保存在openeuler/openeuler仓库中。

Eulerpublisher容器镜像构建

有了上述基础以后,eulerpublisher构建容器镜像的思路就很容易理解。

1)按照Dockerfile的内容,eulerpublisher制作镜像前需要先获取openEuler-docker-rootfs.$TARGETARCH.tar.xz。该步骤由prepare功能实现,执行命令示例如下

eulerpublisher container prepare --version 22.03-LTS-SP1

该命令从http://repo.openeuler.org/下载aarch64和x86_64的原始镜像,将主要文件重新压缩后得到openEuler-docker-rootfs.amd64.tar.xzopenEuler-docker-rootfs.arm64.tar.xz两个文件。

2)获取openEuler-docker-rootfs.$TARGETARCH.tar.xz之后,使用push功能构建并保存镜像,命令示例如下

eulerpublisher  container push --repo openeuler/openeuler --version 22.03-LTS-SP1 --registry registry-1.docker.io --dockerfile /Path/To/Dockerfile

该命令的核心步骤就是执行docker buildx build,构建的镜像将会保存在dockerhubopeneuler/openeuler仓库,tag为22.03-LTS-SP1

3. EulerPublisher云镜像构建原理

这部分描述eulerpublisher构建符合云商marketplace发布要求的云镜像的基本原理,按厂商不同分开说明

AWS

镜像发布要求

AWS Marketplace对发布的镜像规格存在一定约束:

  1. Virtual size最小为8GB
  2. ssh禁用password登录
  3. ssh禁用root用户登录
  4. 禁止set_hostname
  5. 禁止生成用户默认密码

为了满足上述约束,eulerpublisher提供如下两个脚本

  • aws_resize.sh 用于改变镜像大小和格式,并配置arm版本的ena.ko使能
  • aws_install.sh 用于修改镜像默认配置,并安装预置软件包

AMI构建原理

eulerpublisher构建AMI分为两个阶段:
1. prepare阶段

# prepare命令
eulerpublisher -v {VERSION} -a {ARCH} -b {BUCKET}

(a). 从repo.openeuler.org下载版本为VERSION、架构为ARCH的原始qcow2镜像
(b). (arm镜像)配置ena.ko使能
(c). 通过aws_resize.sh脚本resize该qcow2镜像并转换格式为RAW
(d). 通过AWS CLI将处理后的RAW镜像upload到AWS S3存储桶BUCKET
以上操作均在本地完成,得到制作AMI的基础镜像。

2. build阶段

# build命令
eulerpublisher -v {VERSION} -a {ARCH} -b {BUCKET} -r {REGION} -p {RPMLIST}

eulerpublisher通过packer在prepare的结果之上实现对AMI的定制,具体处理如下
(e). 使用packer启动REGION中存储桶BUCKET的 “基础云镜像” 虚拟机实例
(f). 在虚拟机中安装基础软件包,删除 root 密码、禁用password登录等。
(g). 最终制作的云镜像命名为openEuler-{VERSION}-{ARCH}-{DATETIME}-hvm
上述过程中需要准备好packer配置文件,packer配置文件的内容会由eulerpublisher进行填充。此外,若用户需要在最终镜像内预置软件包,需要提供rpmlist

# x86镜像构建的packer配置文件
{
    "builders": [
        {
            "type": "amazon-ebs",
            "name": "amazon-ebs-hvm-amd64",
            "region": "ap-southeast-2",
            "ami_regions": [
                "ap-southeast-2"
            ],
            "source_ami": "ami-0df315962e87a4cae",
            "instance_type": "t3a.micro",
            "ssh_username": "root",
            "ssh_password": "openEuler12#$",
            "ami_name": "openEuler-22.03-LTS-SP1-x86_64-20230719-hvm",
            "ena_support": "true"
        }
    ],
    "provisioners": [
        {
            "type": "shell",
            "environment_vars": [
            ],
            "script": "aws_install.sh"
        }
    ]
}
# rpmlist示例
cloud-init
wget
tar
telnet
unzip
curl
...
@Yikun Yikun added TODO openEuler Improvements or additions to documentation labels Jul 20, 2023
@Yikun Yikun added publish New feature or request and removed TODO labels Aug 31, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
openEuler Improvements or additions to documentation publish New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant