容器虽然带来了高效快捷的虚拟化,但是由于共用内核,容器的安全性也是最受关注的。gVisor是google引入的一套全新的容器安全解决方案,重新实现容器进程的每一个系统调用,其性能相比runc等下降了不少。本文主要介绍gVisor的基本概念及使用。
提示:以下是本篇文章正文内容,下面案例可供参考
容器主要使用Linux kernel提供的name space和cgroup机制进行了访问控制及资源隔离,相比裸金属方式的虚拟化,由于容器共用hostos kernel,其性能获得较大提升,但是共享kernel带来的最大问题就是安全性无法获得保障。google引入了gVisor,其在name space和cgroup隔离的基础上添加了一层防护,旨在提供进程级的轻量虚拟化。
gVisor提供了两种方式对容器进程的系统调用进行了拦截实现,它包含以下几个进程:
1. runsc: 遵循OCI(Open Container Initiative)标准的容器runtime,它可以在docker或者kubernetes中使用。
2. Sentry:gVisor中最大的组件,可以将它视为“用户态内核”,Sentry实现了应用程序所需的所有内核功能,包括:系统调用、信号传递、内存管理和页面错误逻辑、线程模型等等。
3. Gofer:Gofer是一个标准主机进程,由每个容器启动,并通过套接字或共享内存通道通过9P协议与Sentry进行通讯。Sentry进程在受限制的seccomp容器中启动,无法访问文件系统资源。Gofer协调所有对这些资源的访问,提供额外的隔离级别。
4. Application: OCI运行时bundle中的普通Linux二进制文件,gVisior旨在提供一个与Linux v4.4相同的运行环境,因此应用程序应该能够无修改运行,gVisor目前没有实现每个系统调用,/proc、/sys文件系统也没有实现。
官方安装脚本:
(
set -e
ARCH=$(uname -m)
URL=https://storage.googleapis.com/gvisor/releases/release/latest/${ARCH}
wget ${URL}/runsc ${URL}/runsc.sha512 \
${URL}/containerd-shim-runsc-v1 ${URL}/containerd-shim-runsc-v1.sha512
sha512sum -c runsc.sha512 \
-c containerd-shim-runsc-v1.sha512
rm -f *.sha512
chmod a+rx runsc containerd-shim-runsc-v1
sudo mv runsc containerd-shim-runsc-v1 /usr/local/bin
)
安装gVisor作为docker的runtime,使用如下命令:
/usr/local/bin/runsc install
sudo systemctl reload docker
docker run --rm --runtime=runsc hello-world
runsc使用kvm或者ptrace的方式对系统调用进行拦截,默认ptrace,如果想使用kvm,则需要进行如下配置:
Inter CPU:sudo modprobe kvm-intel && sudo chmod a+rw /dev/kvm
AMD CPU: sudo modprobe kvm-amd && sudo chmod a+rw /dev/kvm
配置docker,通过runsc --platform来选择,修改/etc/docker/daemon.json来设置此参数
{
"runtimes": {
"runsc": {
"path": "/usr/local/bin/runsc",
"runtimeArgs": [
"--platform=kvm"
]
}
}
}
{
"runtimes": {
"runsc": {
"path": "/usr/local/bin/runsc",
"runtimeArgs": [
"--overlay"
]
}
}
}
{
"runtimes": {
"runsc": {
"path": "/usr/local/bin/runsc",
"runtimeArgs": [
"--network=host"
]
}
}
}
要将主机和网络与sandbox完全隔离,可以禁用外部网络。sandbox仍将包含netstack提供的环回。
此时配置–network=none即可。
笔者在使用pkgs.org中提供的rpm包直接安装后,使用runsc create容器时报错:
#runsc --platform=ptrace --debug --debug-log=/tmp/runsc-debug.log --strace --log-packets run hello
running container: creating container: waiting for sandbox to start: EOF
#runsc --platform=ptrace --debug --debug-log=/tmp/runsc-debug.log --strace --log-packets -TESTONLY-unsafe-nonroot run hello
#running container: starting container: starting root container: urpc method "containerManager.StartRoot" failed: EOF
随后卸载了rpm包的方式,使用go get重新安装,注意必须要"CGO_ENABLED=0 GO111MODULE=on",否则还是会报错。
#go env -w GO111MODULE=on;go env -w GOPROXY=https://goproxy.cn,direct
#echo "module runsc" > go.mod
GO111MODULE=on go get gvisor.dev/gvisor/runsc@go
CGO_ENABLED=0 GO111MODULE=on sudo -E go build -o /usr/local/bin/runsc gvisor.dev/gvisor/runsc
#sudo runsc install --runtime runsc-debug -- \
--debug \
--debug-log=/tmp/runsc-debug.log \
--strace \
--log-packets
#cat /etc/docker/daemon.json
"runtimes": {
"runsc": {
"path": "/usr/sbin/runsc"
},
"runsc-debug": {
"path": "/usr/sbin/runsc",
"runtimeArgs": [
"--debug",
"--debug-log=/tmp/runsc-debug.log",
"--strace",
"--log-packets"
]
}
}
#systemctl restart docker
#docker pull ubuntu
#docker run -it --runtime=runsc ubuntu bash
root@e2b2f32ea20a:/# ps
PID TTY TIME CMD
1 ? 00:00:00 bash
7 ? 00:00:00 ps
root@e2b2f32ea20a:/#
使用另外一个终端查看容器信息:
[root@oe2109 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e2b2f32ea20a ubuntu "bash" 14 minutes ago Up 14 minutes zen_lovelace
[root@oe2109 ~]# docker inspect e2b2
...
"ShmSize": 67108864,
"Runtime": "runsc"
[root@oe2109 ~]# ps -aux | grep docker
root 11013 0.0 0.8 750412 30340 ? Sl 14:11 0:00 runsc-gofer --root=/var/run/docker/runtime-runsc/moby --log=/run/docker/containerd/daemon/io.containerd.runtime.v1.linux/moby/e2b2f32ea20ac7a04dea3d89e47da51d6ce571edadeb50c432d71c5801f33100/log.json --log-format=json --log-fd=3 gofer --bundle /var/run/docker/containerd/daemon/io.containerd.runtime.v1.linux/moby/e2b2f32ea20ac7a04dea3d89e47da51d6ce571edadeb50c432d71c5801f33100 --spec-fd=4 --mounts-fd=5 --io-fds=6 --io-fds=7 --io-fds=8 --io-fds=9 --io-fds=10 --apply-caps=false --setup-root=false
nobody 11017 0.0 1.0 1812948 36204 pts/1 Ssl+ 14:11 0:00 runsc-sandbox --root=/var/run/docker/runtime-runsc/moby --log=/run/docker/containerd/daemon/io.containerd.runtime.v1.linux/moby/e2b2f32ea20ac7a04dea3d89e47da51d6ce571edadeb50c432d71c5801f33100/log.json --log-format=json --log-fd=3 boot --bundle=/var/run/docker/containerd/daemon/io.containerd.runtime.v1.linux/moby/e2b2f32ea20ac7a04dea3d89e47da51d6ce571edadeb50c432d71c5801f33100 --controller-fd=4 --mounts-fd=5 --spec-fd=6 --start-sync-fd=7 --io-fds=8 --io-fds=9 --io-fds=10 --io-fds=11 --io-fds=12 --stdio-fds=13 --stdio-fds=14 --stdio-fds=15 --cpu-num 4 --total-memory 3553030144 e2b2f32ea20ac7a04dea3d89e47da51d6ce571edadeb50c432d71c5801f33100
参考资料: https://gvisor.dev/docs/