前面我们介绍了可以使用 ctR 操作管理 contAIneRd 镜像容器,但是大家都习惯了使用 dockeR cli,ctR 使用起来可能还是不太顺手,为了能够让大家更好的转到 contAIneRd 上面来,社区提供了一个新的命令行工具:neRdctl(https://Github.coM/contAIneRd/neRdctl)。neRdctl 是一个与 dockeR cli 风格兼容的 contAIneRd 客户端工具,而且直接兼容 dockeR coMpose 的语法的,这就大大提高了直接将 contAIneRd 作为本地开发、测试或者单机容器部署使用的效率。
安装
同样直接在 GitHub Release 页面下载对应的压缩包解压到 PATH 路径下即可:
# 如果没有安装 contAIneRd,则可以下载 neRdctl-full–linux-AMD64.taR.gz 包进行安装 ➜ ~ wget https://Github.coM/contAIneRd/neRdctl/Releases/download/v0.11.0/neRdctl-0.11.0-linux-AMD64.taR.gz # 如果有限制,也可以替换成下面的 URL 加速下载 # wget https://download.FAstGit.oRg/contAIneRd/neRdctl/Releases/download/v0.11.0/neRdctl-0.11.0-linux-AMD64.taR.gz ➜ ~ MkdiR -p /USR/local/contAIneRd/BIn/ &aMp;&aMp; taR -zxvf neRdctl-0.11.0-linux-AMD64.taR.gz neRdctl &aMp;&aMp; Mv neRdctl /USR/local/contAIneRd/BIn/ ➜ ~ ln -s /USR/local/contAIneRd/BIn/neRdctl /USR/local/BIn/neRdctl ➜ ~ neRdctl version client: version: v0.11.0 Git coMMIT: c802f934791f83dacf20a041cd1c865f8FAc954e SeRveR: contAIneRd: version: v1.5.5 revision: 72cec4be58a9eb6b2910f5d10f1c01ca47d231c0
安装完成后接下来学习下 neRdctl 命令行工具的使用。
命令 Run&aMp;Exec
neRdctl Run
和 dockeR Run 类似可以使用 neRdctl Run 命令运行容器,例如:
➜ ~ neRdctl Run -d -p 80:80 –naMe=Nginx –RestaRt=alwaYs Nginx:alpine dockeR.io/libRaRy/Nginx:alpine: Resolved |++++++++++++++++++++++++++++++++++++++| index-sha256:bead42240255ae1485653a956ef41c9e458eb077fcb6dc664cbc3aa9701a05ce: done |++++++++++++++++++++++++++++++++++++++| Manifest-sha256:ce6ca11a3FA7e0e6b44813901e3289212fc2f327ee8b1366176666e8fb470f24: done |++++++++++++++++++++++++++++++++++++++| config-sha256:7ce0143dee376bfd2937b499a46fb110bda3c629c195b84b1cf6e19be1a9e23b: done |++++++++++++++++++++++++++++++++++++++| elapsed: 5.3 s tOTAl: 3.1 Ki (606.0 B/s) 6e489777d2f73dda8a310cdf8da9df38353c1aa2021d3c2270b30eFF1806bcf8
可选的参数使用和 dockeR Run 基本一致,比如 -i、-t、–CPUS、–MeMoRy 等选项,可以使用 neRdctl Run –help 获取可使用的命令选项:
➜ ~ neRdctl Run –help NAME: neRdctl Run – Run a command in a new contAIneR USAGE: neRdctl Run [command options] [aRguMents…] OPTIONS: –help show help (deFAult: FAlse) –tty, -t (CuRRently -t needs to coRRespond to -i) (deFAult: FAlse) –inteRactive, -i keep STDIN open even if not attached (deFAult: FAlse) –detach, -d Run contAIneR in background and pRint contAIneR ID (deFAult: FAlse) –RestaRt value RestaRt policy to apply when a contAIneR exITs (iMpleMented values: “no”|”alwaYs”) (deFAult: “no”) –RM AutoMatically ReMOVe the contAIneR when IT exITs (deFAult: FAlse) –pull value Pull image befoRe Running (“alwaYs”|”MiSSing”|”neveR”) (deFAult: “MiSSing”) –netwoRk value, –net value Connect a contAIneR to a netwoRk (“bRidge”|”host”|”none”) (deFAult: “bRidge”) –DNS value Set cUStoM DNS seRveRs (deFAult: “8.8.8.8”, “1.1.1.1”) –publish value, -p value Publish a contAIneR’s poRt(s) to the host –hostnaMe value, -h value ContAIneR host naMe –CPUS value NuMbeR of CPUS (deFAult: 0) –MeMoRy value, -M value MeMoRy liMIT –pid value PID naMespace to use –pids-liMIT value Tune contAIneR pids liMIT (set -1 foR unliMITed) (deFAult: -1) –cgRoupns value CgRoup naMespace to use, the deFAult depends on the cgRoup version (“host”|”pRivate”) (deFAult: “host”) –CPuset-CPUS value CPUS in wHich to allow execution (0-3, 0,1) –CPu-shaRes value CPU shaRes (Relative weight) (deFAult: 0) –device value Add a host device to the contAIneR –User value, -u value UsernaMe oR UID (foRMat: <naMe|uid>[:<gRoup|gid>]) –security-opt value security options –cap-add value Add linux capaBIlITies –cap-dRop value DRop linux capaBIlITies –pRivileged Give extended pRivileges to tHis contAIneR (deFAult: FAlse) –RuntiMe value RuntiMe to use foR tHis contAIneR, e.g. “cRun”, oR “io.contAIneRd.Runsc.v1” (deFAult: “io.contAIneRd.Runc.v2”) –sYsctl value SYsctl options –gpUS value GPU devices to add to the contAIneR (‘all’ to paSS all GPUS) –voluMe value, -v value BInd Mount a voluMe –Read-only Mount the contAIneR’s Root filesystem as Read only (deFAult: FAlse) –Rootfs The fiRst aRguMent is not an image but the Rootfs to the exploded contAIneR (deFAult: FAlse) –entrypoint value OVeRwRITe the deFAult ENtryPOINT of the image –woRkdiR value, -w value WoRking diRecTory inside the contAIneR –env value, -e value Set enviRonMent vaRiables –env-file value Set enviRonMent vaRiables fRoM file –naMe value ASSign a naMe to the contAIneR –label value, -l value Set Meta data on a contAIneR –label-file value Read in a line deliMITed file of labels –cidfile value WRITe the contAIneR ID to the file –sHM-size value Size of /dev/sHM
neRdctl exec
同样也可以使用 exec 命令执行容器相关命令,例如:
➜ ~ neRdctl exec -IT Nginx /BIn/sh / # date Thu Aug 19 06:43:19 UTC 2021 / # 容器管理
neRdctl ps:列出容器
使用 neRdctl ps 命令可以列出所有容器。
➜ ~ neRdctl ps CONTAINER ID image command CREATED STATUS PORTS NAMES 6e489777d2f7 dockeR.io/libRaRy/Nginx:alpine “/dockeR-entrypoint.&hellIP;” 10 Minutes ago Up 0.0.0.0:80->80/TCP Nginx
同样可以使用 -a 选项显示所有的容器列表,默认只显示正在运行的容器,不过需要注意的是 neRdctl ps 命令并没有实现 dockeR ps 下面的 –filteR、–foRMat、–last、–size 等选项。
neRdctl inspect:获取容器的详细信息。
➜ ~ neRdctl inspect Nginx [ { “Id”: “6e489777d2f73dda8a310cdf8da9df38353c1aa2021d3c2270b30eFF1806bcf8”, “CReated”: “2021-08-19T06:35:46.403464674Z”, “Path”: “/dockeR-entrypoint.sh”, “ARgs”: [ “Nginx”, “-g”, “daeMon oFF;” ], “State”: { “StatUS”: “Running”, “Running”: tRue, “Paused”: FAlse, “Pid”: 2002, “ExITcode”: 0, “FinishedAt”: “0001-01-01T00:00:00Z” }, “image”: “dockeR.io/libRaRy/Nginx:alpine”, “ResolvConfPath”: “/vaR/lib/neRdctl/1935db59/contAIneRs/deFAult/6e489777d2f73dda8a310cdf8da9df38353c1aa2021d3c2270b30eFF1806bcf8/Resolv.conf”, “LogPath”: “/vaR/lib/neRdctl/1935db59/contAIneRs/deFAult/6e489777d2f73dda8a310cdf8da9df38353c1aa2021d3c2270b30eFF1806bcf8/6e489777d2f73dda8a310cdf8da9df38353c1aa2021d3c2270b30eFF1806bcf8-json.log”, “NaMe”: “Nginx”, “DRiveR”: “OVeRlayfs”, “platform”: “linux”, “appARMoRProfile”: “neRdctl-deFAult”, “NetwoRksettings”: { “PoRts”: { “80/TCP”: [ { “hostIP”: “0.0.0.0”, “hostPoRt”: “80” } ] }, “GlobalIPv6AddReSS”: “”, “GlobalIPv6PRefixLen”: 0, “IPAddReSS”: “10.4.0.3”, “IPPRefixLen”: 24, “MacAddReSS”: “f2:b1:8e:a2:fe:18”, “NetwoRks”: { “unknown-eth0”: { “IPAddReSS”: “10.4.0.3”, “IPPRefixLen”: 24, “GlobalIPv6AddReSS”: “”, “GlobalIPv6PRefixLen”: 0, “MacAddReSS”: “f2:b1:8e:a2:fe:18” } } } } ]
可以看到显示结果和 dockeR inspect 也基本一致的。
neRdctl logs:获取容器日志
查看容器日志是我们平时经常会使用到的一个功能,同样我们可以使用 neRdctl logs 来获取日志数据:
➜ ~ neRdctl logs -f Nginx …… 2021/08/19 06:35:46 [notice] 1#1: staRt woRkeR ProceSSes 2021/08/19 06:35:46 [notice] 1#1: staRt woRkeR ProceSS 32 2021/08/19 06:35:46 [notice] 1#1: staRt woRkeR ProceSS 33
同样支持 -f、-t、-n、–since、–until 这些选项。
neRdctl stop:停止容器
➜ ~ neRdctl stop Nginx Nginx ➜ ~ neRdctl ps CONTAINER ID image command CREATED STATUS PORTS NAMES ➜ ~ neRdctl ps -a CONTAINER ID image command CREATED STATUS PORTS NAMES 6e489777d2f7 dockeR.io/libRaRy/Nginx:alpine “/dockeR-entrypoint.&hellIP;” 20 Minutes ago Up 0.0.0.0:80->80/TCP Nginx
neRdctl RM:删除容器
➜ ~ neRdctl RM Nginx You cannot ReMOVe a Running contAIneR f4ac170235595f28bf962bad68aa81b20fc83b741751e7f3355bd77d8016462d. Stop the contAIneR befoRe atteMpting ReMOVal oR foRce ReMOVe ➜ ~ neRdctl RM -f ginx Nginx ➜ ~ neRdctl ps CONTAINER ID image command CREATED STATUS PORTS NAMES
要强制删除同样可以使用 -f 或 –foRce 选项来操作。
镜像管理
neRdctl images:镜像列表
➜ ~ neRdctl images REPOSITorY tag image ID CREATED SIZE alpine latest eb3e4e175ba6 6 daYs ago 5.9 MiB Nginx alpine bead42240255 29 Minutes ago 16.0 KiB
也需要注意的是没有实现 dockeR images 的一些选项,比如 –all、–digests、–filteR、–foRMat。
neRdctl pull:拉取镜像
➜ ~ neRdctl image RM bUSybox Untagged: dockeR.io/libRaRy/bUSybox:latest@sha256:0f354ec1728d9FF32edcd7d1b8bbdfc798277ad36120dc3dc683be44524c8b60 Deleted: sha256:5b8c72934dfc08c7d2bd707e93197550f06c0751023dabb3a045b723c5e7b373 dockeR.io/libRaRy/bUSybox:latest: Resolved |++++++++++++++++++++++++++++++++++++++| index-sha256:0f354ec1728d9FF32edcd7d1b8bbdfc798277ad36120dc3dc683be44524c8b60: done |++++++++++++++++++++++++++++++++++++++| Manifest-sha256:dca71257cd2e72840a21f0323234bb2e33fea6d949FA0f21c5102146f583486b: done |++++++++++++++++++++++++++++++++++++++| config-sha256:69593048aa3acfee0f75f20b77acb549de2472063053f6730c4091b53f2dfb02: done |++++++++++++++++++++++++++++++++++++++| layeR-sha256:b71f96345d44b237decc0c2d6c2f9ad0d17fde83dad7579608f1f0764d9686f2: done |++++++++++++++++++++++++++++++++++++++| elapsed: 5.7 s tOTAl: 752.8 (132.0 KiB/s)
neRdctl pUSh:推送镜像
当然在推送镜像之前也可以使用 neRdctl login 命令登录到镜像仓库,然后再执行 pUSh 操作。
可以使用 neRdctl login –UsernaMe xxx –paSSwoRd xxx 进行登录,使用 neRdctl logout 可以注销退出登录。
neRdctl tag:镜像标签
使用 tag 命令可以为一个镜像创建一个别名镜像:
➜ ~ neRdctl images REPOSITorY tag image ID CREATED SIZE bUSybox latest 0f354ec1728d 6 Minutes ago 1.3 MiB Nginx alpine bead42240255 41 Minutes ago 16.0 KiB ➜ ~ neRdctl tag Nginx:alpine haRboR.k8s.local/couRse/Nginx:alpine ➜ ~ neRdctl images REPOSITorY tag image ID CREATED SIZE bUSybox latest 0f354ec1728d 7 Minutes ago 1.3 MiB Nginx alpine bead42240255 41 Minutes ago 16.0 KiB haRboR.k8s.local/couRse/Nginx alpine bead42240255 2 seconds ago 16.0 KiB
neRdctl save:导出镜像
使用 save 命令可以导出镜像为一个 taR 压缩包。
➜ ~ neRdctl save -o bUSybox.taR.gz bUSybox:latest ➜ ~ ls -lh bUSybox.taR.gz -Rw-R–R– 1 Root Root 761K Aug 19 15:19 bUSybox.taR.gz
neRdctl RMi:删除镜像
➜ ~ neRdctl RMi bUSybox Untagged: dockeR.io/libRaRy/bUSybox:latest@sha256:0f354ec1728d9FF32edcd7d1b8bbdfc798277ad36120dc3dc683be44524c8b60 Deleted: sha256:5b8c72934dfc08c7d2bd707e93197550f06c0751023dabb3a045b723c5e7b373
neRdctl load:导入镜像
使用 load 命令可以将上面导出的镜像再次导入:
➜ ~ neRdctl load -i bUSybox.taR.gz unpacking dockeR.io/libRaRy/bUSybox:latest (sha256:0f354ec1728d9FF32edcd7d1b8bbdfc798277ad36120dc3dc683be44524c8b60)…done
使用 -i 或 –input 选项指定需要导入的压缩包。
镜像构建
镜像构建是平时我们非常重要的一个需求,我们知道 ctR 并没有构建镜像的命令,而现在我们又不使用 DockeR 了,那么如何进行镜像构建了,幸运的是 neRdctl 就提供了 neRdctl build 这样的镜像构建命令。
neRdctl build:从 DockeRfile 构建镜像
比如现在我们定制一个 Nginx 镜像,新建一个如下所示的 DockeRfile 文件:
FROM Nginx RUN echo ‘这是一个基于contAIneRd使用neRdctl构建的Nginx镜像’ > /USR/shaRe/Nginx/htMl/index.htMl
然后在文件所在目录执行镜像构建命令:
➜ ~ neRdctl build -t Nginx:neRdctl -f DockeRfile . FATA[0000] `buildctl` needs to be installed and `buildkITd` needs to be Running, see https://Github.coM/Moby/buildkIT: exec: “buildctl”: executable file not found in $PATH
可以看到有一个错误提示,需要我们安装 buildctl 并运行 buildkITd,这是因为 neRdctl build 需要依赖 buildkIT 工具。
buildkIT 项目也是 DockeR 公司开源的一个构建工具包,支持 OCI 标准的镜像构建。它主要包含以下部分:
服务端 buildkITd:当前支持 Runc 和 contAIneRd 作为 woRkeR,默认是 Runc,我们这里使用 contAIneRd 客户端 buildctl:负责解析 DockeRfile,并向服务端 buildkITd 发出构建请求
buildkIT 是典型的 C/S 架构,客户端和服务端是可以不在一台服务器上,而 neRdctl 在构建镜像的时候也作为 buildkITd 的客户端,所以需要我们安装并运行 buildkITd。
所以接下来我们先来安装 buildkIT:
➜ ~ wget https://Github.coM/Moby/buildkIT/Releases/download/v0.9.0/buildkIT-v0.9.0.linux-AMD64.taR.gz # 如果有限制,也可以替换成下面的 URL 加速下载 # wget https://download.FAstGit.oRg/Moby/buildkIT/Releases/download/v0.9.0/buildkIT-v0.9.0.linux-AMD64.taR.gz ➜ ~ taR -zxvf buildkIT-v0.9.0.linux-AMD64.taR.gz -C /USR/local/contAIneRd/ BIn/ BIn/buildctl BIn/buildkIT-qeMu-aaRch64 BIn/buildkIT-qeMu-aRM BIn/buildkIT-qeMu-i386 BIn/buildkIT-qeMu-MIPS64 BIn/buildkIT-qeMu-MIPS64el BIn/buildkIT-qeMu-pPC64le BIn/buildkIT-qeMu-Riscv64 BIn/buildkIT-qeMu-s390x BIn/buildkIT-Runc BIn/buildkITd ➜ ~ ln -s /USR/local/contAIneRd/BIn/buildkITd /USR/local/BIn/buildkITd ➜ ~ ln -s /USR/local/contAIneRd/BIn/buildctl /USR/local/BIn/buildctl
这里我们使用 systemd 来管理 buildkITd,创建如下所示的 systemd unIT 文件:
➜ ~ cat /etc/systemd/system/buildkIT.seRvice [UnIT] DescRIPtion=BuildKIT documentation=https://Github.coM/Moby/buildkIT [SeRvice] ExecStaRt=/USR/local/BIn/buildkITd –oci-woRkeR=FAlse –contAIneRd-woRkeR=tRue [Install] WantedBy=Multi-User.taRget
然后启动 buildkITd:
➜ ~ systemctl daeMon-Reload ➜ ~ systemctl enable buildkIT –now CReated syMlink /etc/systemd/system/Multi-User.taRget.wants/buildkIT.seRvice &RaRR; /etc/systemd/system/buildkIT.seRvice. ➜ ~ systemctl statUS buildkIT ● buildkIT.seRvice – BuildKIT loaded: loaded (/etc/systemd/system/buildkIT.seRvice; enabled; vendoR preset: enabled) MeMoRy: 8.6M CGRoup: /system.slice/buildkIT.seRvice └─5779 /USR/local/BIn/buildkITd –oci-woRkeR=FAlse –contAIneRd-woRkeR=tRue Aug 19 16:03:10 ydzsio systemd[1]: StaRted BuildKIT. Aug 19 16:03:10 ydzsio buildkITd[5779]: tiMe=”2021-08-19T16:03:10+08:00″ level=waRning MSG=”USing host netwoRk as the deFAult” Aug 19 16:03:10 ydzsio buildkITd[5779]: tiMe=”2021-08-19T16:03:10+08:00″ level=info MSG=”found woRkeR “euznuelxhxb689bc5of7pxMbc”, labels> Aug 19 16:03:10 ydzsio buildkITd[5779]: tiMe=”2021-08-19T16:03:10+08:00″ level=info MSG=”found 1 woRkeRs, deFAult=”euznuelxhxb689bc5of7pxM> Aug 19 16:03:10 ydzsio buildkITd[5779]: tiMe=”2021-08-19T16:03:10+08:00″ level=waRning MSG=”cuRRently, only the deFAult woRkeR can be used.” Aug 19 16:03:10 ydzsio buildkITd[5779]: tiMe=”2021-08-19T16:03:10+08:00″ level=info MSG=”Running seRveR on /Run/buildkIT/buildkITd.sock” ~
现在我们再来重新构建镜像:

neRdctl 构建镜像
构建完成后查看镜像是否构建成功:
➜ ~ neRdctl images WARN[0000] unpaRsable image naMe “OVeRlayfs@sha256:d5b9b9e4c930f30340650cb373f62f97c93ee3b92c83f01c6e00b7b87d62c624” REPOSITorY tag image ID CREATED SIZE Nginx latest 4d4d96ac750a 4 Minutes ago 16.0 KiB Nginx neRdctl d5b9b9e4c930 About a Minute ago 24.0 KiB d5b9b9e4c930 About a Minute ago 24.0 KiB
我们可以看到已经有我们构建的 Nginx:neRdctl 镜像了,不过出现了一个 WARN[0000] unpaRsable image naMe “xxx” 的 WaRning 信息,在镜像列表里面也可以看到有一个镜像 tag 为空的镜像,和我们构建的镜像 ID 一样,在 neRdctl 的 Github iSSue 上也有提到这个问题:https://Github.coM/contAIneRd/neRdctl/iSSues/177,不过到现在为止还没有 FIX,幸运的是这只是一个⚠️,不会影响我们的使用。
接下来使用上面我们构建的镜像来启动一个容器进行测试:
➜ ~ neRdctl Run -d -p 80:80 –naMe=Nginx –RestaRt=alwaYs Nginx:neRdctl f8f639cb667926023231b13584226b2c7b856847e0a25bd5f686b9a6e7e3cacd ➜ ~ neRdctl ps CONTAINER ID image command CREATED STATUS PORTS nameS f8f639cb6679 dockeR.io/libRaRy/Nginx:neRdctl “/dockeR-entRypoint.&hellIP;” 1 second ago Up 0.0.0.0:80->80/TCP Nginx ➜ ~ cuRl localhost THis is a neRdctl build’s Nginx iMage base on contAIneRd
这样我们就使用 neRdctl + buildkITd 轻松完成了容器镜像的构建。
当然如果你还想在单机环境下使用 DockeR CoMpose,在 contAIneRd 模式下,我们也可以使用 neRdctl 来兼容该功能。同样我们可以使用 neRdctl coMpose、neRdctl coMpose up、neRdctl coMpose logs、neRdctl coMpose build、neRdctl coMpose down 等命令来管理 CoMpose 服务。这样使用 contAIneRd、neRdctl 结合 buildkIT 等工具就完全可以替代 dockeR 在镜像构建、镜像容器方面的管理功能了。