前面的几篇文章我们介绍了crun的编译方法、基本使用教程,以及制作了基础镜像nginx-ubuntu。本文研究在不依赖Docker的情况下,我们使用底层命令crun来运行Docker镜像的方法。
总体来说,使用crun运行Docker镜像,并且外网可以访问内部nginx服务,实施步骤如下:
- 第一,在宿主机上添加网桥,给宿主机以及容器添加虚拟网卡对;
- 第二,获取Docker镜像,并将其转换成bundle文件;
- 第三,修改config.json文件,加入网络namespace的文件路径;
- 第四,使用curn以前台或者后台方式启动容器;
- 第五,在宿主机上添加网络转发规则,让外部请求转给容器然后传递到nginx;
- 第六,从宿主机以外的机器,访问容器中的nginx,测试服务是否正常;
下面我们逐步开始实施。
第0x01步:添加网桥和虚拟网卡对
1 |
|
对IP地址的说明:
- 我的地网络网段是 192.168.0.0/24,为了和本地网络区分开以免互相影响,我将网桥和网卡设置在网段 192.168.3.0/24 。
- 网桥的IP地址为 192.168.3.1/24
- 容器中网卡的地址为 192.168.3.2/24
- 容器中网卡的默认路由规则是发送到 192.168.3.1
将上述内容保存为文件,如 setnet.sh ,然后在服务器上使用命令 sudo sh setnet.sh
,即可完成所有添加操作。结果如下图所示:
第0x02步:下载镜像文件
获取Docker镜像,并将其转换成根文件系统,需要用到skopeo和umoci工具,首先我们使用如下命令安装依赖工具:
1 | $ sudo apt install -y skopeo umoci |
然后使用如下命令开始拉取镜像文件:
1 | $ skopeo copy docker://mancodenet/nginx-ubuntu:1.0.0 oci:nginx-ubuntu:1.0.0 |
命令执行如下图所示:
nginx-ubuntu目录就是我们拉取的镜像文件,我们看下它的目录结构:
第0x03步:解包镜像文件,转换为根文件系统
1 | $ sudo umoci unpack --image nginx-ubuntu:1.0.0 nginx-bundle |
命令执行如下图所示:
第0x04步:修改nginx-bundle/config.json,添加网络namespace路径
打开nginx-bundle/config.json,找到 namespaces 配置域,然后找到 “type”: “network” 配置域,在其配置域内添加 “path” 配置项,其值指向上述我们添加的网络namespace的文件路径。
文件修改之前,如下图所示:
文件修改之后,如下图所示:
第0x05步:使用crun前台方式启动nginx-ubuntu容器
1 | $ sudo crun run --bundle=nginx-bundle demo-nginx-ubuntu |
启动容器执行过程如下图所示:
保持该当前终端窗口不关闭以及当前容器不退出的情况下,我们打开另外一个终端窗口,查看容器的运行情况:
1 | $ sudo crun list |
结果如下图所示:
第0x06步:打开数据转发,将对应的访问请求,转发给容器,然后传递给容器中的nginx
1 | # 设置转发规则:将访问宿主机 TCP:80 端口的数据,转给容器 demo-nginx-ubuntu 的80端口 |
第0x07步:验证访问容器的nginx,看是否可以正常提供服务
从前文我们知道宿主机的IP是:192.168.0.51,我们在其他机器上打开浏览器,然后访问:http://192.168.0.51 ,如下图所示:
直观上看,我们已经成功的访问nginx服务。
为了进一步验证,我们访问一个特殊的URL:http://192.168.0.51/test-404-not-found.html ,然后深入容器,看下nginx的访问日志以佐证:
如何使用crun后台方式启动nginx-ubuntu容器?
我们知道加上 -d 选项,表明让容器在后台运行,那么我们先使用如下命令测试下后台运行:
1 | $ sudo crun run -d --bundle=nginx-bundle demo-nginx-ubuntu |
使用上述命令启动,无法启动容器,且报错如下:
1 | mancode@manos:~/crun$ sudo crun run -d --bundle=nginx-bundle demo-nginx-ubuntu |
提示我们后台运行错误:当使用terminal启动容器时,须配合 --console-socket
参数一起使用。按要求,它是一个Unix套接域文件,用于传递信息。
明确了后台启动的要求之后,我们总结下后台启动容器的步骤:
第一,该套接域文件必须是真实存在的;
第二,该套接域文件由一个监听程序创建,比如 /tmp/demo-nginx-ubuntu.sock ;
第三,然后使用crun后台启动容器时,使用 --console-socket=/tmp/demo-nginx-ubuntu.sock
的方式进行连接。
这个监听程序哪里来呢?
A)在crun的源代码中,crun-1.14.4/contrib/terminal-receiver 提供了一个demo程序,我们编译该文件可生成监控程序。
B)该文件可以访问 本地 或者 Github 下载。
C)使用命令cc terminal-receiver.c -o terminal-receiver
编译,即可生成一个名为 terminal-receiver 的可用的监听程序。
下面我们开始正式后台启动容器:
第一步,启动监听程序,如下所示:
1 | $ ./terminal-receiver /tmp/demo-nginx-ubuntu.sock |
第二步,另起一个终端窗口,我们使用crun后台启动容器,如下所示:
1 | $ sudo crun run -d --bundle=nginx-bundle --console-socke=/tmp/demo-nginx-ubuntu.sock demo-nginx-ubuntu |
网络转发设置以及测试运行方法,与前文所述一致,读者自行验证。到此我们成功使用后台启动的方法运行了容器。
另外一种使用crun后台运行容器的方法
前文后台运行容器时,提示我们后台运行错误:当使用terminal启动容器时,须配合 --console-socket
参数一起使用。那我们可以禁止使用terminal,选项开关在配置文件config.json中。
打开nginx-bundle/config.json,修改 “process”>”terminal” 为false。
修改文件前:
修改文件后:
使用如下命令,以后台方式启动容器:
1 | $ sudo crun run -d --bundle=nginx-bundle demo-nginx-ubuntu |
命令执行结果如下图所示:
从上图结果我们可以看出,修改配置文件之后,我们不再需要terminal-receiver,即能以后台方式启动容器。