王先森2023-08-092023-08-09
前面我们介绍了可以使用 ctr
操作管理 containerd 镜像容器,但是大家都习惯了使用 docker cli,ctr
使用起来可能还是不太顺手,为了能够让大家更好的转到 containerd 上面来,社区提供了一个新的命令行工具:nerdctl。nerdctl 是一个与 docker cli 风格兼容的 containerd 客户端工具,而且直接兼容 docker compose 的语法的,这就大大提高了直接将 containerd 作为本地开发、测试或者单机容器部署使用的效率。
同样直接在 GitHub Release 页面下载对应的压缩包解压到 PATH 路径下即可:
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
在镜像构建时需要我们安装 buildctl
并运行 buildkitd
,这是因为 nerdctl build
需要依赖 buildkit
工具。
buildkit 项目也是 Docker 公司开源的一个构建工具包,支持 OCI 标准的镜像构建。它主要包含以下部分:
buildkitd
:当前支持 runc 和 containerd 作为 worker,默认是 runc,我们这里使用 containerdbuildctl
:负责解析 Dockerfile,并向服务端 buildkitd 发出构建请求buildkit 是典型的 C/S 架构,客户端和服务端是可以不在一台服务器上,而 nerdctl
在构建镜像的时候也作为 buildkitd
的客户端,所以需要我们安装并运行 buildkitd
。
所以接下来我们先来安装 buildkit
:
# 下载地址
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
k8s
默认使用k8s.io
,而 nerdctl
默认使用 default namspace
。如果需要查看 k8s 相关镜像需要加上”--namespace=k8s.io
“来指定。
nerdctl images --namespace=k8s.io
nerdctl -n=k8s.io images
或者在 nerdctl
配置文件中指定 nerdctl
默认使用 k8s.io namespace
mkdir /etc/nerdctl/
cat >> /etc/nerdctl/nerdctl.toml << EOF
namespace = "k8s.io"
EOF
nerdctl run和 docker run
类似可以使用 nerdctl run
命令运行容器,例如:
$ 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
命令执行容器相关命令,例如:
$ nerdctl exec -it nginx /bin/sh
/ # date
Wed Aug 9 08:12:10 UTC 2023
/ # ls
nerdctl ps:列出容器
使用 nerdctl ps
命令可以列出所有容器。
$ 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:获取容器的详细信息。
$ 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
来获取日志数据:
$ 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:停止容器
# 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:删除容器
$ nerdctl rm nginx
container 883a46df6f5875a6afae26414b498f396ea5e8ca1c24f91f97a2695c7b187ec0 is in running status. unpause/stop container first or force
$ nerdctl rm -f nginx
如果要强制删除同样可以使用 -f
或 --force
选项来操作。
erdctl images:镜像列表
$ 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
命令可以为一个镜像创建一个别名镜像:
$ 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:拉取镜像
$ nerdctl pull docker.io/library/busybox:latest
nerdctl push:推送镜像
当然在推送镜像之前也可以使用 nerdctl login
命令登录到镜像仓库,然后再执行 push 操作。
可以使用 nerdctl login --username xxx --password xxx
进行登录,使用 nerdctl logout
可以注销退出登录。
nerdctl save:导出镜像
使用 save
命令可以导出镜像为一个 tar
压缩包。
$ 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:删除镜像
$ nerdctl rmi busybox
Untagged: docker.io/library/busybox:latest@sha256:3fbc632167424a6d997e74f52b878d7cc478225cffac6bc977eedfe51c7f4e79
Deleted: sha256:3d24ee258efc3bfe4066a1a9fb83febf6dc0b1548dfe896161533668281c9f4f
nerdctl load:导入镜像
使用 load
命令可以将上面导出的镜像再次导入:
$ 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 文件:
cat > Dockerfile <<EOF
FROM nginx:alpine
RUN echo -e "#version wangxiansen\nHello Nerdctl From Containerd" > /usr/share/nginx/html/index.html
EOF
然后在文件所在目录执行镜像构建命令:
$ nerdctl build -t nginx:nerdctl -f Dockerfile .
构建完成后查看镜像是否构建成功:
$ 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
镜像了。接下来使用上面我们构建的镜像来启动一个容器进行测试:
$ 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 compose
、nerdctl compose up
、nerdctl compose logs
、nerdctl compose build
、nerdctl compose down
等命令来管理 Compose 服务。这样使用 containerd、nerdctl 结合 buildkit 等工具就完全可以替代 docker 在镜像构建、镜像容器方面的管理功能了。