博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
无需Docker, 5分钟徒手DIY 一个Linux容器
阅读量:6202 次
发布时间:2019-06-21

本文共 4339 字,大约阅读时间需要 14 分钟。

容器技术,其优势以及应用场景想必大家都不陌生。本文旨在用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的, 原文中有几个地方我没有直接走通,这里加了一些个人的剪裁和修改。我的环境是Ali Linux 4.4.114-1.al7.x86_64, 接下来的步骤无需安装Docker也不需要安装其他工具

Namespace隔离

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

container filesystem本质上就是一个tarball, 有兴趣的话可以看一下Redbeard的 视频,核心是一句话: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 rootfsbin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

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

2. 创建一个简陋的容器

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

# 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/lsbin  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

3. 隔离PID

为了限制/bin/bash进程能看到的pids,我们需要为bash进程创建pid namespace。用 Linux 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 auxUSER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMANDroot         1  0.0  0.0  20272  3284 ?        S    19:08   0:00 /bin/bashroot         2  0.0  0.0  17500  2084 ?        R+   19:08   0:00 bin/ps aux

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

Resource 隔离

(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/bashroot     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/bashroot     10028  0.0  0.0  20264  3068 pts/0    S+   01:49   0:00 /bin/bashroot     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 <
./test.pya = ''i=0while True:i += 1print "%dmb" % (i*10,)some_str = ' ' * 10000000a = a + some_strEOF# 执行脚本,可以看到内存接近100M的时候脚本会被kill, 现在我们再也不用担心这个容器内的进程会用光host的内存啦, nice!root@iZ2zea1bcc0lrqq26qw1esZ:/# /usr/bin/python test.py 10mb20mb30mb40mb50mb60mb70mb80mbKilled

总结

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

转载地址:http://ujxca.baihongyu.com/

你可能感兴趣的文章
KMP算法的Next数组详解(转)
查看>>
用Vim搭建C/C++开发环境
查看>>
关于box-shadow和drop-shadow的显著区别
查看>>
POJ 刷题进程.2
查看>>
安装php xdebug扩展
查看>>
[PHP] 算法-二叉树的子结构判断的PHP实现
查看>>
python re.sub
查看>>
Spring Cache 配置及一些问题的解决
查看>>
ASP.NET MVC 3 网站优化总结(六)压缩 HTML
查看>>
透彻理解块级元素的宽度
查看>>
把图片存入数据库
查看>>
冒泡排序
查看>>
HttpClient和HttpURLConnection的区别
查看>>
BZOJ-1024: [SCOI2009]生日快乐 (搜索经典好题)
查看>>
第六章函数与宏定义
查看>>
在 .NET Core 中结合 HttpClientFactory 使用 Polly(上篇)
查看>>
【369】列表/字典的分拆, unpacking
查看>>
Effect_Players
查看>>
制作百度地图
查看>>
CSS文档流
查看>>