前言

容器虽然带来了高效快捷的虚拟化,但是由于共用内核,容器的安全性也是最受关注的。gVisor是google引入的一套全新的容器安全解决方案,重新实现容器进程的每一个系统调用,其性能相比runc等下降了不少。本文主要介绍gVisor的基本概念及使用。


提示:以下是本篇文章正文内容,下面案例可供参考

一、gVisor引入背景

容器主要使用Linux kernel提供的name space和cgroup机制进行了访问控制及资源隔离,相比裸金属方式的虚拟化,由于容器共用hostos kernel,其性能获得较大提升,但是共享kernel带来的最大问题就是安全性无法获得保障。google引入了gVisor,其在name space和cgroup隔离的基础上添加了一层防护,旨在提供进程级的轻量虚拟化。

二、gVisor简介

1.架构图

gVisor提供了两种方式对容器进程的系统调用进行了拦截实现,它包含以下几个进程:
gVisor架构图

2.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文件系统也没有实现。

三、使用

1.安装

官方安装脚本:

(
  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

2.配置

runsc使用kvm或者ptrace的方式对系统调用进行拦截,默认ptrace,如果想使用kvm,则需要进行如下配置:

  1. 架构选择
    如果运行的是基于Debian的系统,如Debian或Ubuntu,可以查看/dev/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"
            ]
       }
    }
}   		
  1. 配置文件系统
    要将主机文件系统与sandbox隔离,可以在整个文件系统的顶部设置一个可写的tmpfs覆盖,所有修改都是对覆盖进行的,保持主机文件系统不变。修改/etc/docker/daemon.json然后重启docker daemon.
{
    "runtimes": {
        "runsc": {
            "path": "/usr/local/bin/runsc",
            "runtimeArgs": [
                "--overlay"
            ]
       }
    }
}
  1. 网络配置
    对于高性能网络应用程序,可以选择禁用用户空间网络堆栈,而使用主机网络堆栈,包括环回,此模式会降低与主机的隔离度。修改/etc/docker/daemon.json
{
   "runtimes": {
       "runsc": {
           "path": "/usr/local/bin/runsc",
           "runtimeArgs": [
               "--network=host"
           ]
      }
   }
}

要将主机和网络与sandbox完全隔离,可以禁用外部网络。sandbox仍将包含netstack提供的环回。
此时配置–network=none即可。

3.go get方式安装

笔者在使用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

4.作为docker runtime使用

#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/

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐