当前位置: 首页 > news >正文

Linux:用 runc 构建 ARM 平台容器

文章目录

  • 1. 前言
  • 2. 构建 runc
    • 2.1 准备 C 交叉编译器
    • 2.2 编译 libseccomp 库
    • 2.3 编译 runc
      • 2.3.1 安装 go 编译器
      • 2.3.2 编译 runc
  • 3. 构建 runc 镜像包 + 测试运行
    • 3.1 OCI 规范
    • 3.2 手工构建 OCI 镜像
    • 3.3 运行

1. 前言

限于作者能力水平,本文可能存在谬误,因此而给读者带来的损失,作者不做任何承诺。

2. 构建 runc

runc 是容器的运行时容器运行时的基础组件,常见容器直接使用 Docker 构建,但在资源受限的一些嵌入式设备,Docker 整体就会显得庞大且冗余,这时候我们通常会使用 runc + OCI 镜像的简单组合,来构建容器。

2.1 准备 C 交叉编译器

本文描述在 Ubuntu 22.04.5 LTS 桌面系统下,为 aarch64 平台构建容器的过程,不管是构建 runc 用到的 libseccomp 库,还是编译 runc 源代码中的 C 代码,都需要用到 aarch64 的交叉编译器,所以首先安装交叉编译器:

$ sudo apt-get install gcc-aarch64-linux-gnu

当然,读者也可以使用已有的交叉编译器。

2.2 编译 libseccomp 库

runc 使用了 libseccomp 库,我们先构建 libseccomp 。下载 libseccomp 源码并解压,切换到 libseccomp 源码目录:

$ sudo apt-get install autoconf libtool
$ ./autogen.sh
$ ./configure --host=aarch64-linux-gnu --prefix=`pwd`/_install
$ make && make install

成功编译完成后,在 libseccomp 源码目录下的 _install 目录下,生成了如下文件:

$ cd _install
$ tree
.
├── bin
│   └── scmp_sys_resolver
├── include
│   ├── seccomp.h
│   └── seccomp-syscalls.h
├── lib
│   ├── libseccomp.a
│   ├── libseccomp.la
│   ├── libseccomp.so -> libseccomp.so.0.0.0
│   ├── libseccomp.so.0 -> libseccomp.so.0.0.0
│   ├── libseccomp.so.0.0.0
│   └── pkgconfig
│       └── libseccomp.pc
└── share
    └── man
        ├── man1
        │   └── scmp_sys_resolver.1
        └── man3
            ......

8 directories, 44 files

然后将 seccomp.h,seccomp-syscalls.h,libseccomp.so.0.0.0 安装到交叉编译器 gcc-aarch64-linux-gnu 的对应目录:

$ sudo cp include/*.h /usr/aarch64-linux-gnu/include
$ sudo cp lib/libseccomp.a /usr/aarch64-linux-gnu/lib
$ sudo cp lib/libseccomp.la /usr/aarch64-linux-gnu/lib
$ sudo cp lib/libseccomp.so.0.0.0 /usr/aarch64-linux-gnu/lib
$ sudo ln -s /usr/aarch64-linux-gnu/lib/lib/libseccomp.so.0.0.0 /usr/aarch64-linux-gnu/lib/lib/libseccomp.so.0
$ sudo ln -s /usr/aarch64-linux-gnu/lib/lib/libseccomp.so.0.0.0 /usr/aarch64-linux-gnu/lib/lib/libseccomp.so

2.3 编译 runc

2.3.1 安装 go 编译器

runc 源码使用了 goC 语言,C 语言需要的交叉编译器前面已经准备好了,现在参考 Download and install 安装 go 编译器

$ wget https://golang.google.cn/dl/go1.22.4.linux-amd64.tar.gz
$ rm -rf /usr/local/go && tar -C /usr/local -xzf go1.22.4.linux-amd64.tar.gz
$ export PATH=$PATH:/usr/local/go/bin
$ go version
go version go1.22.4 linux/amd64

2.3.2 编译 runc

下载 runc 源码解压到 runc 目录,然后编译:

$ cd runc
$ GOARCH=arm64 CGO_ENABLED=1 make
$ PREFIX=`pwd`/_install make install
$ file _install/sbin/runc
_install/sbin/runc: ELF 64-bit LSB pie executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, BuildID[sha1]=db10b08ff0a8c578e7c80a9009ca5234b258c9e2, for GNU/Linux 3.7.0, with debug_info, not stripped

libseccomp.so.0.0.0 拷贝到 aarch64 目标机器的目录 /usr/lib,并创建符号链接文件 libseccomp.so.0

# ln -s /usr/lib/libseccomp.so.0.0.0 /usr/lib/libseccomp.so.0

拷贝 runc 文件到 aarch64 目标机器的目录 /usr/sbin,然后添加可执行权限:

# chmod +x /usr/sbin/runc

测试运行:

# ./runc --version
runc version 1.2.0-rc.2+dev
commit: v1.2.0-rc.2-29-gad5b481d
spec: 1.2.0
go: go1.22.4

3. 构建 runc 镜像包 + 测试运行

runc 将配置文件 config.json 运行于一个通过 Linux 命名空间cgroup 隔离的独立环境。Linux 命名空间 用来控制可见的视野,cgroup 用于资源(CPU、内存、磁盘、网络等)的隔离。runc 运行需要一个镜像包,这个镜像包需要符合 (OCI: Open Container Initiative) 的相关规范。

3.1 OCI 规范

开放容器计划 (OCI: Open Container Initiative) 是一个轻量级的开放式治理结构(项目),在 Linux 基金会的支持下成立,其明确目的是围绕容器格式和运行时创建开放的行业标准。OCI 于 2015 年 6 月 22 日由 DockerCoreOS 和容器行业的其他领导者推出。

OCI 目前包含 3 个规范:运行时规范 (runtime-spec)镜像规范 (image-spec)分发规范 (distribution-spec)运行时规范概述了如何运行在磁盘上解压的 OCI 镜像包

为了支持 OCI 镜像格式包含足够的信息以在目标平台上启动应用程序(例如命令、参数、环境变量等)。此规范定义了如何创建 OCI 镜像(通常由构建系统完成),并输出镜像清单、文件系统(层)序列化、镜像配置。概括地说,镜像清单包含有关镜像内容和依赖关系的元数据,包括一个或多个文件系统序列化存档的内容可寻址标识,这些存档将被解压缩以构成最终的可运行文件系统。镜像配置包括应用程序参数、环境等信息。镜像清单镜像配置和一个或多个文件系统序列化的组合称为 OCI 镜像

3.2 手工构建 OCI 镜像

托管在 Docker Hub 上的 Docker 官方镜像,是现成可用的 OCI 镜像,但很可惜,国外的这些镜像无法正常访问,国内的一些镜像也不是长期可用。同时由于这些镜像对于嵌入式设备来说,往往显得庞大冗余,这时候我们就可以选择手工构建简易的、满足自身需求的、符合 OCI 相关规范的镜像文件。

构建一个运行于容器环境的测试程序 oci_test.c

#include <stdio.h>
#include <unistd.h>

int main(void)
{
	int count = 0;

	while (1) {
		printf("oci test: count = %d\n", ++count);
		sleep(3);
	}
	return 0;
}
$ aarch64-linux-gnu-gcc -o oci_test oci_test.c
$ mkdir -p mycontainer/rootfs
$ mkdir -p mycontainer/rootfs/{bin,dev,etc,lib,proc,sbin,sys,tmp,usr/bin,usr/lib,usr/sbin,var}
$ cp oci_test mycontainer/rootfs/usr/bin
$ cp /usr/aarch64-linux-gnu/lib/ld-linux-aarch64.so.1 mycontainer/rootfs/lib/
$ cp /usr/aarch64-linux-gnu/lib/libc.so.6 mycontainer/rootfs/lib/
$ cp /usr/aarch64-linux-gnu/lib/libm.so.6 mycontainer/rootfs/lib/
$ cp /usr/aarch64-linux-gnu/lib/libresolv.so.2 mycontainer/rootfs/lib/

$ tar -cf mycontainer.tar mycontainer

将镜像打包成 mycontainer.tarOCI 镜像就制作完成了。

3.3 运行

如章节 2.3 中准备好 runc,假定 runc 放置在 aarch64 目标机器/test 目录下,将章节 3.2 中制作好的 mycontainer.tar 也拷贝到 /test 目录下:

# cd /test
# ./runc spec # 生成配置文件 config.json

编辑 /test/config.json,将配置项 terminal 修改为 false,容器入口程序修改为 oci_test

在这里插入图片描述

接着创建并启动容器实例:

# mv config.json ./mycontainer
# ./runc run -d -b ./mycontainer ocitest > ocitest.log 2>&1
# ./runc list
ID          PID         STATUS      BUNDLE                      CREATED                          OWNER
ocitest     16427       running     /test/mycontainer       1970-01-01T08:10:45.791058625Z   root
# ./runc ps ocitest
# ps -ef | grep -v grep | grep "oci_test"
16427 root     oci_test
# ls /sys/fs/cgroup/cpu/ocitest/ -l
total 0
-rw-r--r--    1 root     root             0 Jan  1 08:12 cgroup.clone_children
-rw-r--r--    1 root     root             0 Jan  1 08:10 cgroup.procs
-rw-r--r--    1 root     root             0 Jan  1 08:12 cpu.shares
-rw-r--r--    1 root     root             0 Jan  1 08:12 notify_on_release
-rw-r--r--    1 root     root             0 Jan  1 08:12 tasks
# cat ocitest.log 
oci test: count = 1
oci test: count = 2
oci test: count = 3
oci test: count = 4
oci test: count = 5
oci test: count = 6
oci test: count = 7
oci test: count = 8
oci test: count = 9
oci test: count = 10
oci test: count = 11
oci test: count = 12
oci test: count = 13
oci test: count = 14
oci test: count = 15
oci test: count = 16
oci test: count = 17
oci test: count = 18
oci test: count = 19
oci test: count = 20
oci test: count = 21
oci test: count = 22
oci test: count = 23
oci test: count = 24
oci test: count = 25
oci test: count = 26
oci test: count = 27
oci test: count = 28

停止容器实例:

# ./runc kill ocitest
# kill -9 16427
# ./runc list
ID          PID         STATUS      BUNDLE                      CREATED                          OWNER
ocitest     0           stopped     /test/mycontainer       1970-01-01T08:10:45.791058625Z   root

在删除容器实例之前,其 cgroup 信息仍然存在:

# ls /sys/fs/cgroup/cpu/ocitest/
cgroup.clone_children  cpu.shares             tasks
cgroup.procs           notify_on_release

最后,删除容器实例:

# ./runc delete ocitest
# ls /sys/fs/cgroup/cpu/ocitest/
ls: /sys/fs/cgroup/cpu/ocitest/: No such file or directory
http://www.dtcms.com/a/75466.html

相关文章:

  • 电动车出入库管理软件,电动车维修保养售后服务管理系统,佳易王电动车店管理系统操作教程
  • SQLMesh 系列教程:Airbnb数据分析项目实战
  • 一、初始 Linux
  • 【网络】手动部署并测试内网穿透
  • 网络华为HCIA+HCIP 以太网链路聚合与交换机堆叠、集群
  • 【Python】Python与算法有应用关系吗?
  • 施耐德PLC仿真软件Modbus tcp通讯测试
  • 离散概率分布:正态分布,二项分布,连续分布,正态分布的性质
  • Python实现自动提取目标文档的大纲(13)
  • 《驾驭MXNet:深度剖析分布式深度学习训练的高效之道》
  • Python学习- 数据结构类型
  • Folder Icons for Mac v2.0.3 文件/文件夹图标美化 支持M、Intel芯片
  • DeepSeek + Kimi 自动生成 PPT
  • 数据结构之双向链表
  • 【实战指南】基于DevExpress轻量化主题实现WPF应用性能升级
  • React类的生命周期
  • Ajax入门
  • C#进阶-ASP.NET网站会话固定漏洞的解决
  • 在云平台上用Claude 3.7 AI代理自动化电脑图形界面点击操作做表格
  • 05 MP4解码AAC + 格式知识
  • Python刷题:流程控制(上)
  • 【Kubernetes】Kube Proxy 如何帮助 Pod 之间通信?Kube-Proxy 实践案例
  • 我爱学算法之——滑动窗口攻克子数组和子串难题(上)
  • 网页复印机:只需一个网址,一键克隆任何网站!(可根据需求生成/优化相关代码)
  • [操作系统] 进程间通信:匿名管道原理与操作
  • js逆向-下载某音乐
  • Spring Cloud Alibaba Nacos 2023.X 配置问题
  • 人工智能_大模型097_TRAE_AI开发工具_企业级项目开发---人工智能工作笔记0242
  • 基于SpringBoot+Vue的大学校园志愿者管理系统+LW示例参考
  • 自动化测试工具-Playwright介绍和快速实例