无需Docker, 5分钟徒手DIY 一个Linux容器

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介:

容器技术,其优势以及应用场景想必大家都不陌生。本文旨在用DIY一个简陋的Linux容器作为例子,让感兴趣的同学大致体会容器是如何建成的。

什么是容器?

提到容器最容易想到的大概就是Docker了, 然而Docker只是容器的一种实现以及提供丰富的周边工具,本质上也是利用了Linux primitives构建Linux container。如果要求我只能用一句话来定义容器,那么我会说:容器是 一个隔离的进程工作室 (an isolated process workspace)。这么定义当然太笼统,展开细节可以轻松讲几篇文章,我们这里聚焦最浅显的概念:隔离 (isolation),普遍的观点是将隔离分为两类:

  1. Namespace isolation: 容器内的进程看到的pid, 文件系统,hostname, IP, 网卡都是独立于host的,在namespace内无法修改其他namespaces的内容。
  2. Resource isolation: 容器内的进程系统资源的使用可以限制,例如容器内的进程们CPU/Memory使用不能超过quota等

DIY一个Linux容器

接下来我们将step by step讲解如何用Linux自带的工具将进程 (processes)放入容器 (an isolated workspace), 注: 整个流程参考了Eric Chiang的containers from scratch, 原文中有几个地方我没有直接走通,这里加了一些个人的剪裁和修改。我的环境是Ali Linux 4.4.114-1.al7.x86_64, 接下来的步骤无需安装Docker也不需要安装其他工具

Namespace隔离

1. 准备容器文件系统 (类似Docker image)

container filesystem本质上就是一个tarball, 有兴趣的话可以看一下Redbeard的minimal containers 视频,核心是一句话:A CONTAINER FILESYSTEM ISN'T MAGIC, IT'S JUST A TARBALL

# 下载+解压container filesystem tarball
[root@iZ2zea1bcc0lrqq26qw1esZ ~]# wget https://github.com/ericchiang/containers-from-scratch/releases/download/v0.1.0/rootfs.tar.gz
[root@iZ2zea1bcc0lrqq26qw1esZ ~]# tar -xzf rootfs.tar.gz

[root@iZ2zea1bcc0lrqq26qw1esZ ~]# ls rootfs
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
AI 代码解读

可以看到 rootfs下面看到的文件结构和Liunx / 下看到的很相似。

2. 创建一个简陋的容器

我们的目的是进入rootfs,并且以rootfs为新的root (/), 这样进程只能看到rootfs中的文件, Linux自带的chroot工具可以很容易达到这种效果

# Mount rootfs/proc,这样在rootfs子文件系统中的进程可以做`ps aux`这样的命令
[root@iZ2zea1bcc0lrqq26qw1esZ ~]# mount -t proc proc rootfs/proc

# 用chroot将 /bin/bash 进程看到的root限制在dir rootfs, 恭喜你进入了你自建的隔离非常简陋的容器!
[root@iZ2zea1bcc0lrqq26qw1esZ ~]# chroot rootfs /bin/bash

# 现在bash shell中的root (/) 已经变成了 host上面的“/root/rootfs”
root@iZ2zea1bcc0lrqq26qw1esZ:/# bin/ls
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  test.py  tmp  usr  var

# 这时文件系统隔离有了,但是进程隔离还没有, 下面的命令可以看到机器上所有的进程,我们容器里的shell甚至可以去kill其他进程,不理想!
root@iZ2zea1bcc0lrqq26qw1esZ:/# bin/ps aux

# 退出该容器
exit
AI 代码解读

3. 隔离PID

为了限制/bin/bash进程能看到的pids,我们需要为bash进程创建pid namespace。用 Linux unshare command 可以方便地为进程创造不同类型的namespace

# 下面的命令为 /bin/bash进程创建了一个新的process namespace
[root@iZ2zea1bcc0lrqq26qw1esZ ~]# unshare -p -f --mount-proc=$PWD/rootfs/proc chroot rootfs /bin/bash

# 现在shell里面只能看到本pid namespace的两个进程了,注意shell进程是pid 1, 这里和Docker的主进程为pid 1完全一样
root@iZ2zea1bcc0lrqq26qw1esZ:/# bin/ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0  20272  3284 ?        S    19:08   0:00 /bin/bash
root         2  0.0  0.0  17500  2084 ?        R+   19:08   0:00 bin/ps aux
AI 代码解读

上面几步之后,我们基本有了一个对filesystm和pid有隔离的容器,这个容器距离严谨的namespace隔离还有很长的路要走,例如创建Network namespace, 修改hostname, username space (不允许容器用户为root), 这里假设我们的隔离的需求很简单只是mount + pid。

Resource 隔离

CGroup (control group) 对于CPU, memory, 文件系统资源的隔离的技术已经很成熟,大多数容器也都选择用cgroup来做资源限制,对cgroup的细节不在这里介绍,下面的步骤会为上面创建好的container加上内存使用的限制

# 下面这些命令在host shell内执行,而不是刚才创建的container shell
# 创建一个叫做mygroup的memory cgroup
[root@iZ2zea1bcc0lrqq26qw1esZ ~]# mkdir /sys/fs/cgroup/memory/mygroup

# 限制在这个cgroup里面所有的进程内存使用和不能超过100MB
[root@iZ2zea1bcc0lrqq26qw1esZ ~]# echo "100000000" > /sys/fs/cgroup/memory/mygroup/memory.limit_in_bytes

# 找到我们的container在host上面的pid,这里是10028 (这里需要注意有两个bash进程,我们的容器进程是从unshare命令里面fork出来的,因此是10028而不是unshare 10027本身)
[root@iZ2zea1bcc0lrqq26qw1esZ ~]# ps aux|grep bin/bash
root     10027  0.0  0.0 107904   704 pts/0    S    01:49   0:00 unshare -p -f --mount-proc=/root/rootfs/proc chroot rootfs /bin/bash
root     10028  0.0  0.0  20264  3068 pts/0    S+   01:49   0:00 /bin/bash
root     10031  0.0  0.0 112668  2216 pts/1    S+   01:49   0:00 grep --color=auto bin/bash

# 根据你找到pid替换$MY_PID
[root@iZ2zea1bcc0lrqq26qw1esZ ~]# export MY_PID=10028

# 将shell pid加入mygroup, 加入之后,容器内所有的进程 (bash以及其子进程)都会受到内存使用100M的
[root@iZ2zea1bcc0lrqq26qw1esZ ~]# echo $MY_PID > /sys/fs/cgroup/memory/mygroup/tasks

# 下面这些命令在container shell内执行
# 测试一下效果,下面的python脚本会不断消耗内存
bin/cat <<EOF > ./test.py
a = ''
i=0
while True:
i += 1
print "%dmb" % (i*10,)
some_str = ' ' * 10000000
a = a + some_str
EOF

# 执行脚本,可以看到内存接近100M的时候脚本会被kill, 现在我们再也不用担心这个容器内的进程会用光host的内存啦, nice!
root@iZ2zea1bcc0lrqq26qw1esZ:/# /usr/bin/python test.py 
10mb
20mb
30mb
40mb
50mb
60mb
70mb
80mb
Killed
AI 代码解读

总结

到这里,我们DIY了一个文件系统,pid隔离,内存限制为100M的容器。通用的容器需要对网络,user namespace, 以及其他系统资源(CPU, disk等)做了更完整的隔离,这篇文章的目的不是鼓励大家去自建容器,而是通过一个简单的动手教程让大家熟悉Linux容器的构成和实现。Docker以及其他容器runtime都提供了强大的功能,但是归根溯源都还是将Linux已有的namespace工具,cgroup结合在一起搭建出了易用容器。欢迎对容器技术感兴趣的同学拍砖交流。

目录
打赏
0
0
0
0
15
分享
相关文章
Docker容器的实战讲解
这只是Docker的冰山一角,但是我希望这个简单的例子能帮助你理解Docker的基本概念和使用方法。Docker是一个强大的工具,它可以帮助你更有效地开发、部署和运行应用。
68 27
在Linux环境下备份Docker中的MySQL数据并传输到其他服务器以实现数据级别的容灾
以上就是在Linux环境下备份Docker中的MySQL数据并传输到其他服务器以实现数据级别的容灾的步骤。这个过程就像是一场接力赛,数据从MySQL数据库中接力棒一样传递到备份文件,再从备份文件传递到其他服务器,最后再传递回MySQL数据库。这样,即使在灾难发生时,我们也可以快速恢复数据,保证业务的正常运行。
93 28
容器技术实践:在Ubuntu上使用Docker安装MySQL的步骤。
通过以上的操作,你已经步入了Docker和MySQL的世界,享受了容器技术给你带来的便利。这个旅程中你可能会遇到各种挑战,但是只要你沿着我们划定的路线行进,你就一定可以达到目的地。这就是Ubuntu、Docker和MySQL的灵魂所在,它们为你开辟了一条通往新探索的道路,带你亲身感受到了技术的力量。欢迎在Ubuntu的广阔大海中探索,用Docker技术引领你的航行,随时准备感受新技术带来的震撼和乐趣。
101 16
zabbix7.0.9安装-以宝塔安装形式-非docker容器安装方法-系统采用AlmaLinux9系统-最佳匹配操作系统提供稳定运行环境-安装教程完整版本-优雅草卓伊凡
zabbix7.0.9安装-以宝塔安装形式-非docker容器安装方法-系统采用AlmaLinux9系统-最佳匹配操作系统提供稳定运行环境-安装教程完整版本-优雅草卓伊凡
142 30
揭秘 Microsoft.Docker.SDK:让容器开发更轻松的强大工具揭秘
随着云计算和容器技术的快速发展,`Docker` 已经成为容器化技术的事实标准。`Microsoft` 作为 `Docker` 的主要支持者和参与者,推出了 `Microsoft.Docker.SDK`,旨在帮助开发者更轻松地进行容器开发。本文将深入揭秘 Microsoft.Docker.SDK 的功能、使用方法以及它在容器开发中的应用。
81 12
自学软硬件第755 docker容器虚拟化技术youtube视频下载工具
docker容器虚拟化技术有什么用?怎么使用?TubeTube 项目使用youtube视频下载工具
linux怎么把文件传到docker里面
在现代应用开发中,Docker作为流行的虚拟化工具,广泛应用于微服务架构。文件传输到Docker容器是常见需求。常用方法包括:1) `docker cp`命令直接复制文件;2) 使用`-v`选项挂载宿主机目录,实现数据持久化和实时同步;3) 通过SCP/FTP协议传输文件;4) 在Dockerfile中构建镜像时添加文件。选择合适的方法并确保网络安全是关键。
209 1
Linux服务器部署docker windows
在当今软件开发中,Docker成为流行的虚拟化技术,支持在Linux服务器上运行Windows容器。流程包括:1) 安装Docker;2) 配置支持Windows容器;3) 获取Windows镜像;4) 运行Windows容器;5) 验证容器状态。通过这些步骤,你可以在Linux环境中顺利部署和管理Windows应用,提高开发和运维效率。
194 1
Docker+consul容器服务的更新与发现
通过本文的介绍,我们详细探讨了如何结合Docker和Consul来实现容器服务的更新与发现。通过Consul的服务注册和发现功能,可以高效地管理和监控容器化服务,确保系统的高可用性和可扩展性。希望本文能帮助您在实际项目中更好地应用Docker和Consul,提高系统的可靠性和管理效率。
92 23
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等