你只管做自己的事,
把你的全部身心都投入到正在发生的事情中去,
而不是把你的全部身心都投入到个人的敏感多虑中去。
——迈克尔·辛格《清醒地活》
容器化是一种轻量级、可移植、自给自足的软件打包技术,能够让软件运行在几乎任何地方。这听起来有点像虚拟机,但容器是更轻量级的,它不需要像虚拟机那样模拟整个操作系统。在去年的文章已经普及过docker的基础概念和命令行操作,不知道还记得否,今天就来复习下:
容器化的优势:
自从k8s-1.24版本之后,k8s采删除了内置支持Docker Engine(Docker引擎)容器运行时环境的功能,v1.24 之前的 Kubernetes 版本直接集成了 Docker Engine 的一个组件,名为 dockershim。所以现在containerd成为广泛使用的容器运行时,更为详细的操作建议直接官方查阅学习。https://github.com/containerd/containerd/blob/main/docs/getting-started.md
Docker 是一个完整的容器化平台,它不仅提供容器运行时,还包含了图形界面、命令行界面、镜像管理以及一个集成的容器编排工具(Docker Compose)。
containerd 是一个容器运行时守护进程,它专注于管理容器的生命周期,例如容器的创建、执行、暂停和销毁。它是一个更为“纯粹”的容器运行时,去除了很多Docker附加的功能,比如图形界面和编排。
最直接的区别在于:
创建一个简单一点的容器模拟器,我们可以按照以下几个步骤操作。会用到Linux的一些高级特性,如命名空间(namespaces)、控制组(Control Groups, cgroups)、文件系统隔离(chroot)等,以实现容器的基本功能。
但这只是一个简单示例,实际上Docker的实现要复杂得多,包括网络设置、存储卷管理、镜像分层、安全机制等等。
下面是在 CentOS 7.9 上创建一个简单容器并在其中运行进程的步骤:
sudo yum install -y yum-utils
# 创建一个目录作为容器的根文件系统
sudo mkdir -p /path/to/container-rootfs
# 安装一个最小的CentOS系统
sudo yum --releasever=7 --installroot=/path/to/container-rootfs --setopt=tsflags=nodocs install -y bash coreutils yum
CentOS 7 使用的是旧版本的unshare,可能不支持 --mount-proc 选项, 但你可以手动挂载 proc 系统。
# 创建新的网络、进程、IPC、挂载点命名空间
sudo unshare --fork --pid --net --ipc --uts --mount
然后,另外开一个终端,继续以下步骤:
# 为新的PID命名空间挂载proc文件系统
sudo mount -t proc proc /path/to/container-rootfs/proc
# 为容器挂载sys文件系统(可选)
sudo mount -t sysfs sys /path/to/container-rootfs/sys
# 为容器挂载dev文件系统(可选)
sudo mount --rbind /dev /path/to/container-rootfs/dev
# 切换到容器的根目录
sudo chroot /path/to/container-rootfs /bin/bash
# 创建cgroups(如果系统没有安装cgroups工具,需要先安装它)
sudo yum install -y libcgroup
sudo systemctl start cgconfig
# 创建cgroup并限制CPU和内存
sudo cgcreate -g cpu,memory:/mycontainer
echo 512 > /sys/fs/cgroup/cpu/mycontainer/cpu.shares
echo 100000000 > /sys/fs/cgroup/memory/mycontainer/memory.limit_in_bytes
在chroot容器环境中执行以下命令:
# 获取当前shell的进程ID
echo $$
# 使用获取到的进程ID,替换下面命令中的<PID>
sudo cgclassify -g cpu,memory:/mycontainer <PID>
现在你可以在这个隔离环境中运行一个简单的进程,例如一个bash shell。
/bin/bash
至此,你已经在CentOS 7.9上使用Linux命名空间和控制组功能手动创建了一个简单的容器环境,并运行了一个简单的bash进程。对于学习容器原理而言,这是一个不错的开始。
所以简化以下流程:
更新系统:
sudo yum update -y
安装必要的依赖:
sudo yum install -y epel-release
sudo yum install -y libcgroup libcgroup-tools
启动 cgroup 服务:
sudo systemctl start cgconfig
创建 cgroup:
sudo cgcreate -g cpu,memory:/mycontainer
设置资源限制(可选,但推荐):
mycontainer容器设置CPU资源限制:echo 512 | sudo tee /sys/fs/cgroup/cpu/mycontainer/cpu.shares
mycontainer容器设置内存资源限制:echo $((100*1024*1024)) | sudo tee /sys/fs/cgroup/memory/mycontainer/memory.limit_in_bytes
创建一个隔离的文件系统:
mkdir -p ~/mycontainer/{bin,lib64}
安装必要的程序和库:
ldd来检查需要哪些库,例如安装bash:
ldd /bin/bash
bash和它所需要的库复制到容器的文件系统中:
cp /bin/bash ~/mycontainer/bin/
cp -v $(ldd /bin/bash | grep -o '/lib.*[ ].so[^ ]*' | sort | uniq) ~/mycontainer/lib64/
注意:这里如果复制不成功,就手动复制 linux-vdso.so.1 => (0x00007fffd7f2b000)
libtinfo.so.5 => /lib64/libtinfo.so.5 (0x00007f9b76f4e000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f9b76d4a000)
libc.so.6 => /lib64/libc.so.6 (0x00007f9b7697c000)
/lib64/ld-linux-x86-64.so.2 (0x00005620622cc000)
cp /lib64/libtinfo.so.5 ~/mycontainer/lib64/
cp /lib64/libdl.so.2 ~/mycontainer/lib64/
cp /lib64/libc.so.6 ~/mycontainer/lib64/
cp /lib64/ld-linux-x86-64.so.2 ~/mycontainer/lib64/
运行一个隔离的进程:命令解释:
cgexec用于在指定的cgroup中启动程序。unshare用于创建隔离的命名空间。-u, -m, -p 分别用于隔离UTS, 挂载点, 和进程。-f表示创建新的会话。chroot更改根目录到~/mycontainer。/bin/bash是隔离环境中运行的shell。cgexec命令在mycontainer cgroup中启动一个隔离的进程:sudo cgexec -g cpu,memory:/mycontainer unshare -u -m -p -f chroot ~/mycontainer /bin/bash
通过这些步骤,您就能够在CentOS 7.9上模拟出一个基本的容器环境了。
检查:



在这个新的PID命名空间中,bash进程将有一个PID为1。您可以通过运行echo $$来检查当前bash会话的PID,如果返回1,则表示您在新的PID命名空间中。
通过以上步骤,虽然不能完全模拟,但也能大致明白其中流程了,希望对各位读者有用,觉得有用的话,关注下希里安!