Containerd 命令行工具 nerdctl

Containerd 命令行工具 nerdctl

前面我们介绍了可以使用 ctr 操作管理 containerd 镜像容器,但是大家都习惯了使用 docker cli,ctr 使用起来可能还是不太顺手,为了能够让大家更好的转到 containerd 上面来,社区提供了一个新的命令行工具:nerdctl。nerdctl 是一个与 docker cli 风格兼容的 containerd 客户端工具,而且直接兼容 docker compose 的语法的,这就大大提高了直接将 containerd 作为本地开发、测试或者单机容器部署使用的效率。

安装

安装nerdctl

同样直接在 GitHub Release 页面下载对应的压缩包解压到 PATH 路径下即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
cd /server/tools
# 如果没有安装 containerd,则可以下载 nerdctl-full-<VERSION>-linux-amd64.tar.gz 包进行安装
wget https://github.com/containerd/nerdctl/releases/download/v1.5.0/nerdctl-1.5.0-linux-amd64.tar.gz
tar xf nerdctl-1.5.0-linux-amd64.tar.gz
mv nerdctl /bin/
# 检查结果
$ nerdctl version
WARN[0000] unable to determine buildctl version: exec: "buildctl": executable file not found in $PATH
Client:
Version: v1.5.0
OS/Arch: linux/amd64
Git commit: b33a58f288bc42351404a016e694190b897cd252
buildctl:
Version:

Server:
containerd:
Version: v1.7.3
GitCommit: 7880925980b188f4c97b462f709d0db8e8962aff
runc:
Version: 1.1.8
GitCommit: v1.1.8-0-g82f18fe0

安装buildkit

在镜像构建时需要我们安装 buildctl 并运行 buildkitd,这是因为 nerdctl build 需要依赖 buildkit 工具。

buildkit 项目也是 Docker 公司开源的一个构建工具包,支持 OCI 标准的镜像构建。它主要包含以下部分:

  • 服务端 buildkitd:当前支持 runc 和 containerd 作为 worker,默认是 runc,我们这里使用 containerd
  • 客户端 buildctl:负责解析 Dockerfile,并向服务端 buildkitd 发出构建请求

buildkit 是典型的 C/S 架构,客户端和服务端是可以不在一台服务器上,而 nerdctl 在构建镜像的时候也作为 buildkitd 的客户端,所以需要我们安装并运行 buildkitd

所以接下来我们先来安装 buildkit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# 下载地址
wget https://github.com/moby/buildkit/releases/download/v0.12.1/buildkit-v0.12.1.linux-amd64.tar.gz

# 解压文件
cd /server/tools
mkdir /opt/buildkit && tar -zxvf buildkit-v0.12.1.linux-amd64.tar.gz -C /opt/buildkit/
ln -s /opt/buildkit/bin/buildctl /usr/local/bin/
ln -s /opt/buildkit/bin/buildkitd /usr/local/bin/

#使用Systemd来管理buildkitd,创建如下所示的systemd unit文件
cat >> /etc/systemd/system/buildkit.service <<EOF
[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
EOF

# 启动buildkitd
systemctl daemon-reload
systemctl enable buildkit --now
systemctl status buildkit

# 验证 nerdctl与buildctl
$ nerdctl version
Client:
Version: v1.5.0
OS/Arch: linux/amd64
Git commit: b33a58f288bc42351404a016e694190b897cd252
buildctl:
Version: v0.12.1
GitCommit: bb857a0d49f45aa0ce9cd554b78d4075553e20f9

Server:
containerd:
Version: v1.7.3
GitCommit: 7880925980b188f4c97b462f709d0db8e8962aff
runc:
Version: 1.1.8
GitCommit: v1.1.8-0-g82f18fe0

常用nerdctl命令

k8s 默认使用k8s.io,而 nerdctl 默认使用 default namspace。如果需要查看 k8s 相关镜像需要加上”--namespace=k8s.io“来指定。

1
2
nerdctl images --namespace=k8s.io
nerdctl -n=k8s.io images

或者在 nerdctl 配置文件中指定 nerdctl 默认使用 k8s.io namespace

1
2
3
4
mkdir  /etc/nerdctl/
cat >> /etc/nerdctl/nerdctl.toml << EOF
namespace = "k8s.io"
EOF

Run&Exec

nerdctl rundocker run 类似可以使用 nerdctl run 命令运行容器,例如:

1
2
$ nerdctl run -d -p 80:80 --name=nginx --restart=always nginx:alpine
883a46df6f5875a6afae26414b498f396ea5e8ca1c24f91f97a2695c7b187ec0

可选的参数使用和 docker run 基本一直,比如 -i-t--cpus--memory 等选项,可以使用 nerdctl run --help 获取可使用的命令选项。

nerdctl exec

同样也可以使用 exec 命令执行容器相关命令,例如:

1
2
3
4
$ nerdctl exec -it nginx /bin/sh
/ # date
Wed Aug 9 08:12:10 UTC 2023
/ # ls

容器管理

nerdctl ps:列出容器

使用 nerdctl ps 命令可以列出所有容器。

1
2
3
$ nerdctl ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
883a46df6f58 docker.io/library/nginx:alpine "/docker-entrypoint.…" 5 minutes ago Up 0.0.0.0:80->80/tcp nginx

同样可选的参数使用和 docker ps 基本一直,比如 -q-n 等选项,可以使用 nerdctl ps --help 获取可使用的命令选项。

nerdctl inspect:获取容器的详细信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
$ nerdctl inspect nginx

[
{
"Id": "883a46df6f5875a6afae26414b498f396ea5e8ca1c24f91f97a2695c7b187ec0",
"Created": "2023-08-09T08:09:23.347598372Z",
"Path": "/docker-entrypoint.sh",
"Args": [
"nginx",
"-g",
"daemon off;"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": true,
"Pid": 2814,
"ExitCode": 0,
"Error": "",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Image": "docker.io/library/nginx:alpine",
"ResolvConfPath": "/var/lib/nerdctl/1935db59/containers/default/883a46df6f5875a6afae26414b498f396ea5e8ca1c24f91f97a2695c7b187ec0/resolv.conf",
"HostnamePath": "/var/lib/nerdctl/1935db59/containers/default/883a46df6f5875a6afae26414b498f396ea5e8ca1c24f91f97a2695c7b187ec0/hostname",
"LogPath": "/var/lib/nerdctl/1935db59/containers/default/883a46df6f5875a6afae26414b498f396ea5e8ca1c24f91f97a2695c7b187ec0/883a46df6f5875a6afae26414b498f396ea5e8ca1c24f91f97a2695c7b187ec0-json.log",
"Name": "nginx",
"RestartCount": 0,
"Driver": "overlayfs",
"Platform": "linux",
"AppArmorProfile": "",
"nerdctl/ports": "[{\"HostPort\":80,\"ContainerPort\":80,\"Protocol\":\"tcp\",\"HostIP\":\"0.0.0.0\"}]",
"nerdctl/state-dir": "/var/lib/nerdctl/1935db59/containers/default/883a46df6f5875a6afae26414b498f396ea5e8ca1c24f91f97a2695c7b187ec0"
}
},
"NetworkSettings": {
"Ports": {
"80/tcp": [
{
"HostIp": "0.0.0.0",
"HostPort": "80"
}
]
},
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "10.4.0.2",
"IPPrefixLen": 24,
"MacAddress": "4a:5b:f3:cf:cf:eb",
"Networks": {
"unknown-eth0": {
"IPAddress": "10.4.0.2",
"IPPrefixLen": 24,
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "4a:5b:f3:cf:cf:eb"
}
}
}
}
]

可以看到显示结果和 docker inspect 也基本一致的。

nerdctl logs:获取容器日志

查看容器日志是我们平时经常会使用到的一个功能,同样我们可以使用 nerdctl logs 来获取日志数据:

1
2
$ nerdctl logs -f nginx
10.4.0.1 - - [09/Aug/2023:08:09:46 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.29.0" "-"

同样支持 -f-t-n--since--until 这些选项。

nerdctl stop:停止容器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# stop属于重启重启
$ nerdctl stop nginx
nginx
$ nerdctl ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
$ nerdctl ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
883a46df6f58 docker.io/library/nginx:alpine "/docker-entrypoint.…" 15 minutes ago Up 0.0.0.0:80->80/tcp nginx
# kill 属于停止容器 容器状态属于为创建
$ nerdctl kill nginx
883a46df6f5875a6afae26414b498f396ea5e8ca1c24f91f97a2695c7b187ec0
$ nerdctl ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
$ nerdctl ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
883a46df6f58 docker.io/library/nginx:alpine "/docker-entrypoint.…" 17 minutes ago Created 0.0.0.0:80->80/tcp nginx

nerdctl rm:删除容器

1
2
3
$ nerdctl rm nginx
container 883a46df6f5875a6afae26414b498f396ea5e8ca1c24f91f97a2695c7b187ec0 is in running status. unpause/stop container first or force
$ nerdctl rm -f nginx

如果要强制删除同样可以使用 -f--force 选项来操作。

镜像管理

erdctl images:镜像列表

1
2
3
4
$ nerdctl images
REPOSITORY TAG IMAGE ID CREATED PLATFORM SIZE BLOB SIZE
nginx alpine 1713c88213a0 25 hours ago linux/amd64 43.0 MiB 16.2 MiB
$ nerdctl -n=k8s.io images

nerdctl tag:镜像标签

使用 tag 命令可以为一个镜像创建一个别名镜像:

1
2
3
4
5
6
7
8
$ nerdctl images
REPOSITORY TAG IMAGE ID CREATED PLATFORM SIZE BLOB SIZE
nginx alpine 1713c88213a0 25 hours ago linux/amd64 43.0 MiB 16.2 MiB
$ nerdctl tag nginx:alpine harbor.boysec.cn/course/nginx:alpine
$ nerdctl images
REPOSITORY TAG IMAGE ID CREATED PLATFORM SIZE BLOB SIZE
nginx alpine 1713c88213a0 25 hours ago linux/amd64 43.0 MiB 16.2 MiB
harbor.boysec.cn/course/nginx alpine 1713c88213a0 6 seconds ago linux/amd64 43.0 MiB 16.2 MiB

nerdctl pull:拉取镜像

1
$ nerdctl pull docker.io/library/busybox:latest

nerdctl push:推送镜像

当然在推送镜像之前也可以使用 nerdctl login 命令登录到镜像仓库,然后再执行 push 操作。

可以使用 nerdctl login --username xxx --password xxx 进行登录,使用 nerdctl logout 可以注销退出登录。

nerdctl save:导出镜像

使用 save 命令可以导出镜像为一个 tar 压缩包。

1
2
3
$ nerdctl save -o busybox.tar.gz busybox:latest
$ ls -lh busybox.tar.gz
-rw-r--r-- 1 root root 2.2M Aug 9 16:40 busybox.tar.gz

nerdctl rmi:删除镜像

1
2
3
$ nerdctl rmi busybox
Untagged: docker.io/library/busybox:latest@sha256:3fbc632167424a6d997e74f52b878d7cc478225cffac6bc977eedfe51c7f4e79
Deleted: sha256:3d24ee258efc3bfe4066a1a9fb83febf6dc0b1548dfe896161533668281c9f4f

nerdctl load:导入镜像

使用 load 命令可以将上面导出的镜像再次导入:

1
2
3
4
$ nerdctl load -i busybox.tar.gz
$ nerdctl images
REPOSITORY TAG IMAGE ID CREATED PLATFORM SIZE BLOB SIZE
busybox latest 3fbc63216742 7 seconds ago linux/amd64 4.1 MiB 2.1 MiB

使用 -i--input 选项指定需要导入的压缩包。

镜像构建

镜像构建是平时我们非常重要的一个需求,我们知道 ctr 并没有构建镜像的命令,而现在我们又不使用 Docker 了,那么如何进行镜像构建了,幸运的是 nerdctl 就提供了 nerdctl build 这样的镜像构建命令。

🐳nerdctl build:从 Dockerfile 构建镜像

比如现在我们定制一个 nginx 镜像,新建一个如下所示的 Dockerfile 文件:

1
2
3
4
cat > Dockerfile <<EOF
FROM nginx:alpine
RUN echo -e "#version wangxiansen\nHello Nerdctl From Containerd" > /usr/share/nginx/html/index.html
EOF

然后在文件所在目录执行镜像构建命令:

1
$ nerdctl build -t nginx:nerdctl -f Dockerfile .

构建完成后查看镜像是否构建成功:

1
2
3
4
5
6
$ nerdctl images
REPOSITORY TAG IMAGE ID CREATED PLATFORM SIZE BLOB SIZE
busybox latest 3fbc63216742 8 minutes ago linux/amd64 4.1 MiB 2.1 MiB
nginx alpine 1713c88213a0 25 hours ago linux/amd64 43.0 MiB 16.2 MiB
nginx nerdctl a0fd917f4722 47 seconds ago linux/amd64 43.1 MiB 16.2 MiB
harbor.boysec.cn/course/nginx alpine 1713c88213a0 12 minutes ago linux/amd64 43.0 MiB 16.2 MiB

我们可以看到已经有我们构建的 nginx:nerdctl 镜像了。接下来使用上面我们构建的镜像来启动一个容器进行测试:

1
2
3
4
5
6
7
8
$ nerdctl run -d -p 80:80 --name=nginx --restart=always nginx:nerdctl
4af4648264330c1ca46ae97299fb03ff7f3c98e9f627618e679eccf6b9df131d
$ nerdctl ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4af464826433 docker.io/library/nginx:nerdctl "/docker-entrypoint.…" 18 seconds ago Up 0.0.0.0:80->80/tcp nginx
$ curl localhost
#version wangxiansen
Hello Nerdctl From Containerd

这样我们就使用 nerdctl + buildkitd 轻松完成了容器镜像的构建。

当然如果你还想在单机环境下使用 Docker Compose,在 containerd 模式下,我们也可以使用 nerdctl 来兼容该功能。同样我们可以使用 nerdctl composenerdctl compose upnerdctl compose logsnerdctl compose buildnerdctl compose down 等命令来管理 Compose 服务。这样使用 containerd、nerdctl 结合 buildkit 等工具就完全可以替代 docker 在镜像构建、镜像容器方面的管理功能了。