0%
crun#001#手工编译crun的release包的方法

crun是一个快速轻量级、低内存、全功能、符合OCI规范、用于运行容器的Runtime,与runc一样可以用于创建、部署容器,它使用C语言开发。

本文记录手工编译crun以及使用crun创建容器的方法,供后续学习源代码做准备。

关于 git clone 项目代码编译的说明

一般而言,编译crun最好的方法是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 第一步,git clone 源代码
$ git clone git@github.com:containers/crun.git

# 第二步,在crun项目的源代码目录内执行如下命令
# 拉取crun依赖的libocispec项目:
# https://github.com/containers/libocispec.git
#
# 拉取libocispec依赖的项目:
# https://github.com/opencontainers/runtime-spec
# https://github.com/opencontainers/image-spec
# https://github.com/containers/yajl.git
$ ./autogen.sh

# 第三步,使用autogen.sh生成的configure进行项目配置生成Makefile文件
$ ./configure

# 第四步,make以及make install
$ make & sudo make install

使用上述方法简单快捷、成功率高。那我们使用官方提供的release包来编译,是否也是如此顺利?

使用release包编译肯定可以成功,但执行make命令时,会提示一个 找不到git-version.h文件 的错误:

1
src/crun.c:20:10: fatal error: git-version.h: No such file or directory

所以,只要我们解决了 git-version.h 的生成问题,编译也同样顺利!

git-version.h文件是做什么用的?

我们执行 crun --version 命令时会有 commit 的一行输出,它代表当前代码在git仓库中的版本号,而这个版本号就是出自于git-version.h文件。

git-version.h文件是如何产生的?
我们打开Makefile的模板文件Makefile.am,文件中有这么几行:

可见 git-version.h 文件有两种产生途径:

第一种,如果当前目录中存在 .tarball-git-version.h 文件,直接拷贝重命名生成 git-version.h。
第二种,如果当前目录中没有 .tarball-git-version.h 文件,版本号由git命令从当前仓库中取出,然后写入生成 git-version.h。

而我们下载的release包,比如crun-1.14.4.tar.gz,解压后,它既没有 .tarball-git-version.h 文件,又不是一个有效的git仓库,所以上述两种方法都无法正常生成 git-version.h。

明白上述原因之后,我们来总结下:
clone项目代码的方法很容易生成 git-version.h,而使用release包来编译crun,需要我们按照 git-version.h 的文件内容格式,手工添加 .tarball-git-version.h 文件,然后让make命令顺利执行,生成 git-version.h 文件后,编译成功。

正常 git-version.h 文件的内容格式如下所示:

编译release包>第一步 安装依赖

1
2
$ sudo apt-get install -y make cmake git gcc build-essential pkgconf libtool go-md2man autoconf python3 automake \
libsystemd-dev libprotobuf-c-dev libcap-dev libseccomp-dev libyajl-dev

编译release包>第二步 下载源代码

下载crun代码包:

网站地址:https://github.com/containers/crun/releases

从上图可知,我们下载1.14.4版本的发行包,然后得知该版本的commit版本号是:a220ca661ce078f2c37b38c92e66cf66c012d9c1。记下该commit版本号,后续在生成git-version.h文件时,需要使用到。

下载crun依赖的libocispec代码包:

由于libocispec没有打tag或者release包,我们直接下载当前仓库的zip包:

网站地址:https://github.com/containers/libocispec

下载libocispec依赖的image-spec代码包:

网站地址:
https://github.com/opencontainers/image-spec/releases

选择版本后下载,本文使用如下版本:
https://github.com/opencontainers/image-spec/archive/refs/tags/v1.1.0.tar.gz

下载libocispec依赖的runtime-spec代码包:

网站地址:
https://github.com/opencontainers/runtime-spec/releases

选择版本后下载,本文使用如下版本:
https://github.com/opencontainers/runtime-spec/archive/refs/tags/v1.2.0.tar.gz

下载libocispec依赖的yajl代码包:

网站地址:
https://github.com/containers/yajl/tags

选择版本后下载,本文使用如下版本:
https://github.com/containers/yajl/archive/refs/tags/2.1.0.tar.gz

我们下载完代码之后,所有代码包如下所示:

编译release包>第三步 解压源代码

解压crun-1.14.4.tar.gz

1
$ tar -zxf crun-1.14.4.tar.gz

解压libocispec-main.zip

1
2
3
$ cd crun-1.14.4/libocispec
$ unzip ../../libocispec-main.zip
$ mv libocispec-main/* .

解压image-spec-1.1.0.tar.gz

1
2
3
$ cd crun-1.14.4/libocispec/image-spec
$ tar -zxf ../../../image-spec-1.1.0.tar.gz
$ mv image-spec-1.1.0/* .

解压runtime-spec-1.2.0.tar.gz

1
2
3
$ cd crun-1.14.4/libocispec/runtime-spec
$ tar -zxf ../../../runtime-spec-1.2.0.tar.gz
$ mv runtime-spec-1.2.0/* .

解压yajl-2.1.0.tar.gz

1
2
3
$ cd crun-1.14.4/libocispec/yajl
$ tar -zxf ../../../yajl-2.1.0.tar.gz
$ mv yajl-2.1.0/* .

编译release包>第四步 生成.version、.tarball-version和.tarball-git-version.h文件

1
2
3
4
5
6
7
8
9
$ cd crun-1.14.4
$
$ echo '1.14.4-build-diy-release' > .version
$ echo '1.14.4-build-diy-release' > .tarball-version
$ cat > .tarball-git-version.h << "EOF"
#ifndef GIT_VERSION
#define GIT_VERSION "a220ca661ce078f2c37b38c92e66cf66c012d9c1"
#endif
EOF

上述命令中我们指定GIT_VERSION为 a220ca661ce078f2c37b38c92e66cf66c012d9c1,该字段的值在上节下载crun源代码时,我们提及过获取的方法。它代表当前包在git中的commit版本号。
当然该字段,我们也可以随意填写,字段值只是用于提示,并没有特别重要的意义,随意填写不影响可执行程序的使用。

生成过程如下图所示:

编译release包>第五步 生成crun的configure文件

1
2
$ cd crun-1.14.4
$ autoreconf -fi

编译release包>第六步 配置生成Makefile以及编译、安装

1
2
3
4
$ cd crun-1.14.4
$ ./configure --prefix=/home/mancode/apps/crun/crun-1.14.4
$ make
$ sudo make install

编译和安装成功之后,我们看下安装目录的结构:

使用crun运行容器

第一步,生成config.json

使用如下命令:

1
$ crun spec

执行过程如下图所示:

第二步,生成镜像根文件系统,我们使用busybox的docker镜像。

使用如下命令:

1
2
$ mkdir rootfs
$ sudo docker export $(sudo docker create busybox) | tar -C rootfs -xvf - >/dev/null

执行过程如下图所示:

第三步,启动镜像

使用如下命令:

1
$ sudo crun run demo-container_with_crun

执行过程如下图所示:

保持终端不关闭以及当前容器不退出,我们在另外一个终端上查看下当前机器上的容器运行情况。

使用如下命令:

1
$ sudo crun list

执行过程如下图所示: