本节做一个实战的练习,使用buildkit完成容器镜像的远程构建,即实现本地的buildctl客户端远程请求服务器上的buildkitd完成一个容器镜像的构建并推送到镜像仓库中。
部署buildkitd服务端, 暴露为TCP服务
下面将在服务器上以二进制的形式部署服务端buildkitd,并将其gRPC API以TCP服务的形式暴露出来。 此处在部署buildkitd的时候是以具备生产环境可用为目的,为了安全性会以rootless的形式启动buildkitd,同时为gRPC Server和Client生成TLS证书,开启TLS认证以保障服务的安全。
服务端的环境信息如下:
- CentOS 7.9 (linux 3.10.0-1160)
- 本地局域网IP地址: 192.168.100.61
为了以rootless模式运行buildkitd,需要先下载并安装rootlesskit。
然后创建非特权用户如buildkit,之后使用cfssl或其他ssl工具生成服务端和客户端证书:
ca.crt
client.crt
client.key
server.crt
server.key证书生成成功后,就可以下载和安装buildkit相关的二进制文件,并创建buildkitd的配置文件buildkitd.toml。
这里把buildkit安装到/urs/local/buildkit下,前面的各个步骤执行完成后,目录结构如下:
/usr/local/buildkit/
├── bin
│ ├── buildctl
│ ├── buildkitd
│ ├── buildkit-qemu-aarch64
│ ├── buildkit-qemu-arm
│ ├── buildkit-qemu-i386
│ ├── buildkit-qemu-ppc64le
│ ├── buildkit-qemu-riscv64
│ ├── buildkit-qemu-s390x
│ ├── buildkit-runc
│ └── rootlesskit
├── config
│ └── buildkitd.toml
└── ssl
├── ca.crt
├── client.crt
├── client.key
├── server.crt
└── server.key配置文件buildkitd.toml的内容如下:
debug = false
root = "/var/lib/buildkit"
[grpc]
address = [ "unix:///run/user/997/buildkit/buildkitd.sock", "tcp://192.168.100.61:9090" ]
[grpc.tls]
cert = "/usr/local/buildkit/ssl/server.crt"
key = "/usr/local/buildkit/ssl/server.key"
ca = "/usr/local/buildkit/ssl/ca.crt"
[worker.oci]
enabled = true
snapshotter = "auto"
rootless = true # see docs/rootless.md for the details on rootless mode.
# Whether run subprocesses in main pid namespace or not, this is useful for
# running rootless buildkit inside a container.
noProcessSandbox = false
binary = "/usr/local/buildkit/bin/buildkit-runc"
gc = true
gckeepstorage = 9000
[worker.containerd]
address = "/run/containerd/containerd.sock"
enabled = false
namespace = "buildkit"
gc = true
gckeepstorage = 9000这个配置文件还有以下内容需要我们关注一下:
- 可以看出buildkitd的gRPC API在
unix:///run/user/997/buildkit/buildkitd.sock和tcp://192.168.100.61:9090上可用。 其中/run/user/997/buildkit/buildkitd.sock的997是前面创建的buildkit用户的uid。 root = "/var/lib/buildkit"指定是buildkitd的数据目录buildkitd的worker可以是containerd,也可以是oci,因为这里需要以rootless模式启动,rootless模式目前还不支持使用containerd作为worker,所以这里将worker containerd停用snapshotter = "auto"将snapshotter指定为auto,这是因为在rootless模式下,buildkit还不支持overlayfs,这里设置为auto,snapshotter会自动切换到native。
为了以非特权用户启动buldkitd服务,还需要一些配置,具体可参考Rootless mode
,这里以Cent OS 7.9为例。
需要添加user.max_user_namespaces=28633到 /etc/sysctl.conf(或/etc/sysctl.d下的buildkit.conf),然后运行sysctl -p。
接下来为buildkit用户映射下级用户和组:
usermod --add-subuids 100000-165535 --add-subgids 100000-165535上面的命令会往/etc/subuid和/etc/subgid中添加buildkit:100000:65536,为buildkit用户分配了从属uid的范围从100000到165535。
uid 100000将会以uid 0(root)映射到名称空间内(例如在容器中时),uid 100001将会以uid 1映射到名称空间,以此类推。也就是说如果某个进程尝试提权的话,如到uid 0(root),实际上只会作为主机上非特权的大编号uid,如此处为100000,大编号的uid甚至在主机上映射不到真实的用户,也就是说该进程不会在主机上取得特权,这样就起到了安全的作用。
接下来就编写如下的systemd unit文件buildkit.service:
[Unit]
Description=BuildKit
After=network.target
[Service]
User=buildkit
ExecStart=/usr/local/buildkit/bin/rootlesskit \
/usr/local/buildkit/bin/buildkitd \
--config=/usr/local/buildkit/config/buildkitd.toml
[Install]
WantedBy=multi-user.target部署完成后systemctl start buildkit启动buildkitd,systemctl status buildkit会提示running server on /run/user/997/buildkit/buildkitd.sock和running server on [::]:9090,前者本机buildctl客户端使用没有启用TLS,后者暴露给其他机器上buildctl客户端使用启用了TLS。
下面本机验证一下部署是否成功:
buildctl --addr=unix:///run/user/997/buildkit/buildkitd.sock debug workers
ID PLATFORMS
mcr24g17vg9of9zhv6ob0jw8m linux/amd64,linux/386如果正常打印出workers且没有报错,则buildkitd部署成功。 ps -ef | grep buildkitd查看一下,buildkitd确实由非特权用户buildkit启动。
buildctl远程调用buildkitd构建镜像
下面使用buildctl远程调用服务器上的buildkitd构建镜像。这里在我个人的macbook上下载mac os版本的buildctl,并把服务器端生成的证书ca.crt, client.crt, client.key拷贝到本地:
├── buildctl
├── ca.crt
├── client.crt
└── client.key编写一个最简单的Dockerfile:
mkdir /tmp/myproject
echo "FROM alpine" > /tmp/myproject/Dockerfile使用下面的命令构建镜像:
./buildctl --addr=tcp://192.168.100.61:9090 \
--tlscacert=./ca.crt \
--tlscert=./client.crt \
--tlskey=./client.key \
build \
--frontend dockerfile.v0 \
--local context=/tmp/myproject \
--local dockerfile=/tmp/myproject \
--output type=image,name=harbor.myorg.com/myproject/myimg:1.0,push=true上面的命令执行后,当镜像构建成功后将会自动推送镜像到镜像仓库中。
需要注意如果镜像仓库是私有仓库且开启了认证的话,需要在buildctl的执行用户的~/.docker目录下创建config.json:
{
"auths": {
"harbor.myorg.com": {
"auth": "base64(username:password)"
}
}
}因为目前buildctl默认读取这个config.json里的认证信息登录到私有镜像仓库。 这个在https://github.com/moby/buildkit/issues/565这个issue中有讨论。
总结
本节我们以二进制的形式rootless的模式部署了buildkitd,并使用buildctl远程调用buildkitd完成了一个容器镜像的构建,在下一节中我们将介绍在k8s集群中以容器的形式部署buildkitd。