Kata container 简介
Kata Container 是两个现有的开源项目合并:Intel Clear Containers和Hyper runV。
Intel Clear Container项目的目标是通过英特尔®虚拟化技术(VT)解决容器内部的安全问题,并且能够将容器作为轻量级虚拟机(VM)启动,提供了一个可选的运行时间,专注于性能(<100ms启动时间),可与Kubernetes 和Docker 等常用容器环境互操作。英特尔®Clear Container表明,安全性和性能不必是一个折衷,将硬件隔离的安全性与容器的性能可以兼得。
hyper runV优先于技术无关支持许多不同的CPU架构和管理程序。
容器安全
使用Docker轻量级的容器时,最大的问题就是会碰到安全性的问题,其中几个不同的容器可以互相的进行攻击,如果把这个内核给攻掉了,其他所有容器都会崩溃。如果使用KVM等虚拟化技术,会完美解决安全性的问题,但响应的性能会受到一定的影响。
单单就Docker来说,安全性可以概括为两点:
- 不会对主机造成影响
- 不会对其他容器造成影响
所以安全性问题90%以上可以归结为隔离性问题。而Docker的安全问题本质上就是容器技术的安全性问题,这包括共用内核问题以及Namespace还不够完善的限制:
- /proc、/sys等未完全隔离
- Top, free, iostat等命令展示的信息未隔离
- Root用户未隔离
- /dev设备未隔离
- 内核模块未隔离
- SELinux、time、syslog等所有现有Namespace之外的信息都未隔离
当然,镜像本身不安全也会导致安全性问题。
kata 隔离技术
我们都知道 Docker 等一类的容器使用 Cgroup 进行资源限制,使用 linux 的 namespace 机制对容器进行隔离,但在实际运行中,仍是由宿主机向容器直接提供网络、存储、计算等资源,虽然性能损失很小,但存在一定的安全问题。
Kata Containers是一个开放源代码社区,致力于通过轻量级虚拟机来构建安全的容器运行时,这些虚拟机的感觉和性能类似于容器,但是使用硬件虚拟化技术作为第二防御层,可以提供更强的工作负载隔离。
kata 底层实现了Intel Clear Containers的最佳部分与Hyper.sh RunV合并,并进行了扩展,以包括对主要架构的支持,包括x86_64之外的AMD64,ARM,IBM p系列和IBM z系列。
Kata Containers还支持多个虚拟机管理程序,包括QEMU,NEMU和Firecracker,并与其他容器化项目集成。
QEMU 一种虚拟机,与KVM相似,但KVM 是硬件辅助的虚拟化技术,主要负责 比较繁琐的 CPU 和内存虚拟化,而 Qemu 则负责 I/O 虚拟化
架构原理
kata 实际上是通过创建轻量级虚拟机实现容器之间的资源隔离,再在虚拟机中运行容器运行时,这样就使容器在专用内核中运行,提供网络,I / O和内存的隔离,并可以通过虚拟化VT扩展利用硬件强制隔离。提供安全性的同时,其仍然由很高的性能。
kata 包含的主要组件有两部分:
- container runtime: 负责为每个 container 或 pod 创建QEMU*/KVM虚拟机,支持 OCI 运行时规范,可以以插件形式嵌入到 Docker 中作为底层的容器运行时;也支持 K8s 的 CRI 接口,可以与 CRI-O 和 containerd 集成
- agent :在宿主机中用于管理容器和在这些容器中运行的进程。
kata 与 kata-shim
在 Docker 引擎中,Docker 调用 containerd,containerd 通过 shim 调用 runc创建底层的容器,(之前在 深入理解container 篇中详细描述过此过程),若将kata 集成到 Docker 中时,containerd 则调用 kata 提供的 kata-shim
去创建 kata 容器运行时。
值得提的一点是,kata 现在正在努力推行 shimv2 接口,shimv2 主要影响了 K8s 调用 CRI 创建 pod 和容器。
借助shimv2,Kubernetes可以使用每个Pod一个shimv2 而不是2N + 1 个shim(每个容器和Pod沙箱本身的容器shim和kata shim)
agent
容器进程由 agent 生成,agent 在虚拟机内部作为守护进程运行。
kata-agent使用 VIRTIO 串行或 VSOCK 接口在宿主机中运行gRPC服务器,QEMU在宿主机中通过暴露 socket 文件向外部提供链接。kata-runtime 使用 gRPC 协议与 agent 进行通信。该协议允许运行时将容器管理命令发送到 agent。该协议还用于在容器和管理引擎(例如Docker Engine)之间传输I/O流(stdout,stderr,stdin)。也就是说在容器中,包括 init 进程在内,所有与容器交互的命令以及 IO 均会通过 VIRTIO 或 VSOCK。
K8s 集成 kata-container
准备过程
- 硬件支持
首先节点需要支持以下四种任意一种cpu虚拟化技术- Intel VT-x technology
- ARM Hyp mode
- IBM Power Systems
- IBM Z manframes
如果部署在VMware虚拟机中,需要在宿主机开启嵌套虚拟化的功能,开启步骤见链接https://blog.51cto.com/114348…
- 软件依赖
- 正常运行的 K8s 环境
- containerd
安装 kata-container
执行以下脚本安装
1 2 3 4 5 6 7 8 9 10 11 12 |
# kata repo的地址是: http://download.opensuse.org/repositories/home:/katacontainers:/releases:/x86_64:/master/CentOS_7/home:katacontainers:releases:x86_64:master.repo cat > /etc/yum.repos.d/kata.repo <<EOF [home_katacontainers_releases_x86_64_master] name=Branch project for Kata Containers branch master (CentOS_7) type=rpm-md baseurl=http://download.opensuse.org/repositories/home:/katacontainers:/releases:/x86_64:/master/CentOS_7/ gpgcheck=1 gpgkey=http://download.opensuse.org/repositories/home:/katacontainers:/releases:/x86_64:/master/CentOS_7/repodata/repomd.xml.key enabled=1 EOF yum -y install kata-runtime kata-proxy kata-shim |
安装完成之后,执行命令 kata-runtime kata-check
检查系统是否支持运行 kata runtime
[root@master kata]# kata-runtime kata-check
System is capable of running Kata Containers
System can currently create Kata Containers
K8s 对接运行时更改为 containerd
修改 containerd 的配置文件,/etc/containerd/config.toml
,如果没有此配置文件, 可以手动生成:
1 |
containerd config default > /etc/containerd/config.toml |
官网默认配置见链接:https://github. com/containerd/cri/blob/master/docs/config.md
需要注意的是:
-
- [plugins.cri] 条目下,可以配置 K8s sandbox 使用的镜像, 默认为
k8s.io/pause-amd64:3.2
- 我的配置为: sandbox_image = “reg.yyuap.io/kubernetes/pause-amd64:3.1”
- 注意修改CNI的目录:
-
123[plugins."io.containerd.grpc.v1.cri".cni]bin_dir = "/usr/local/bin"conf_dir = "/etc/cni/net.d"
-
- containerd 1.3.2 版本以前,不支持非安全的 registry,也就是说拉镜像时使用的必须是 https 协议,自 己搭私有仓库的同学,可以升级到 1.3.3,并且增加条目
-
12[plugins."io.containerd.grpc.v1.cri".registry.mirrors."your registry".tls]insecure_skip_verify = true
containerd 升级方法为:
-
-
1234wget https://github.com/containerd/containerd/releases/download/v1.3.3/containerd-1.3.3.linux-amd64.tar.gztar -zxvf containerd-1.3.3.linux-amd64.tar.gzcp bin/* /usr/local/bin/containerd --version
我测试的结果是, 即使加了这个参数insecure_skip_verify, 也有问题, kubelet拉镜像还是会报https的错误, 只好去将harbor配置为https了, 具体配置方法为: - 配置Harbor https证书:
-
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152#!/bin/bash# 配置Harbor https证书registry_url="reg.yyuap.io"# 生成使用的相关证书openssl genrsa -out ca.key 4096openssl req -x509 -new -nodes -sha512 -days 3650 \-subj "/C=CN/ST=Beijing/L=Beijing/O=example/OU=Personal/CN=$registry_url" \-key ca.key \-out ca.crtopenssl genrsa -out $registry_url.key 4096openssl req -sha512 -new \-subj "/C=CN/ST=Beijing/L=Beijing/O=example/OU=Personal/CN=$registry_url" \-key $registry_url.key \-out $registry_url.csrcat > v3.ext <<-EOFauthorityKeyIdentifier=keyid,issuerbasicConstraints=CA:FALSEkeyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEnciphermentextendedKeyUsage = serverAuthsubjectAltName = @alt_names[alt_names]DNS.1=$registry_urlDNS.2=reg.yyuapDNS.3=`hostname`EOFopenssl x509 -req -sha512 -days 3650 \-extfile v3.ext \-CA ca.crt -CAkey ca.key -CAcreateserial \-in $registry_url.csr \-out $registry_url.crtopenssl x509 -inform PEM -in $registry_url.crt -out $registry_url.certmkdir -p /etc/docker/certs.d/$registry_url/cp $registry_url.cert /etc/docker/certs.d/$registry_url/cp $registry_url.key /etc/docker/certs.d/$registry_url/cp ca.crt /etc/docker/certs.d/$registry_url/#将证书加入系统级别信任cp /etc/docker/certs.d/ca.crt /etc/pki/ca-trust/source/anchors/update-ca-trust extract# systemctl daemon-reload && systemctl restart docker
- 注: reg.yyuap.io为自定义harbor仓库的域名, 即使不是默认的80端口, 也不用加端口
- [plugins.cri] 条目下,可以配置 K8s sandbox 使用的镜像, 默认为
-
- 修改harbor.cfg如下选项:
-
12345hostname =reg.yyuap.ioui_url_protocol = httpsssl_cert = /data/harbor/harbor/cert/reg.yyuap.io.crtssl_cert_key = /data/harbor/harbor/cert/reg.yyuap.io.key
-
- 重启harbor:
-
12docker-compose -f docker-compose.yml downdocker-compose -f docker-compose.yml start
-
- 修改harbor.cfg如下选项:
-
- 修改docker配置文件:
-
-
-
12345678910111213141516171819cat /etc/docker/daemon.json{"registry-mirrors": ["https://reg.yyuap.io", "https://registry.docker-cn.com", "https://docker.mirrors.ustc.edu.cn"],"max-concurrent-downloads": 10,"log-driver": "json-file","log-level": "warn","storage-driver": "overlay2","log-opts": {"max-size": "10m","max-file": "3"},"data-root": "/data/docker","default-runtime": "kata-runtime","runtimes": {"kata-runtime": {"path": "/usr/bin/kata-runtime"}}}
注意:- http://reg.yyuap.io改为https://reg.yyuap.io, 去掉”insecure-registries”: [“0.0.0.0/0”]
- 增加如下选项:
-
123456"default-runtime": "kata-runtime","runtimes": {"kata-runtime": {"path": "/usr/bin/kata-runtime"}}
-
- 如不修改/etc/docker/daemon.json, 也可以选择在/usr/lib/systemd/system/docker.service里增加参数:
-
12ExecStart=/usr/local/bin/dockerd -D -H fd:// --containerd=/run/containerd/containerd.sock \--add-runtime kata-runtime=/usr/bin/kata-runtime --default-runtime kata-runtime
-
-
- 可以通过ansible来将配置拷贝到其它机器上:
-
1234ansible -i inventory/cluster/hosts.ini all -m copy -a "src=/etc/docker/daemon.json dest=/etc/docker/daemon.json"ansible -i inventory/cluster/hosts.ini all -m copy -a "src=/etc/docker/certs.d/ dest=/etc/docker/certs.d/"ansible -i inventory/cluster/hosts.ini all -m copy -a "src=/etc/docker/certs.d/ca.crt dest=/etc/pki/ca-trust/source/anchors/ca.crt"ansible -i inventory/cluster/hosts.ini all -m shell -a "update-ca-trust extract"
- 最后需要重启docker: systemctl daemon-reload && systemctl restart docker
-
-
- 测试docker运行kata-runtime:
-
-
12345[root@master kata]# docker run --rm -it radial/busyboxplus:curl uname -aLinux 2820715966f8 5.4.15-60.1.container #1 SMP Thu Jan 1 00:00:00 UTC 1970 x86_64 GNU/Linux[root@master kata]# uname -aLinux master 4.18.8-1.el7.elrepo.x86_64 #1 SMP Sat Sep 15 10:10:09 EDT 2018 x86_64 x86_64 x86_64 GNU/Linux[root@master kata]#
- 可以看到, 容器里的内核比宿主机内核版本高
-
-
- 修改docker配置文件:
- 修改 kubelet 启动参数
1 2 3 4 |
mkdir -p /etc/systemd/system/kubelet.service.d/ cat << EOF | sudo tee /etc/systemd/system/kubelet.service.d/0-containerd.conf [Service] Environment="KUBELET_EXTRA_ARGS=--container-runtime=remote --runtime-request-timeout=15m --container-runtime-endpoint=unix:///run/containerd/containerd.sock" EOF |
-
- 注: /etc/systemd/system/kubelet.service 文件里的启动参数需要增加 $KUBELET_EXTRA_ARGS
- 重启 containerd 和 kubele
123systemctl daemon-reloadsystemctl restart containerdsystemctl restart kubelet
K8s 配置使用Kata
K8s 使用 Kata 有两种方式:
- 使用 K8s untrusted_workload_runtime
- 使用 K8s 的 RuntimeClass,这个在 1.12 版本作为alpha特性使用
使用 untrusted_workload_runtime
首先在 containerd 的配置文件中,增加条目
1 2 |
[plugins."io.containerd.grpc.v1.cri".containerd.untrusted_workload_runtime] runtime_type = "io.containerd.kata.v2" |
若使用的 kata 版本较低,不支持 shimV2,则使用条目
1 2 3 4 5 6 |
[plugins.cri.containerd.untrusted_workload_runtime] # runtime_type is the runtime type to use in containerd e.g. io.containerd.runtime.v1.linux runtime_type = "io.containerd.runtime.v1.linux" # runtime_engine is the name of the runtime engine used by containerd. runtime_engine = "/usr/bin/kata-runtime" |
然后重启 containerd
systemctl daemon-reload & systemctl restart containerd
K8s 资源需要增加 annotation
1 2 |
annotations: io.kubernetes.cri.untrusted-workload: "true" |
例如:
1 2 3 4 5 6 7 8 9 10 11 12 |
apiVersion: v1 kind: Pod metadata: name: nginx-untrusted namespace: isv-demo annotations: io.kubernetes.cri.untrusted-workload: "true" spec: nodeName: 172.20.58.132 containers: - name: nginx image: nginx |
使用 RuntimeClass
这种模式下,相关软件版本需求如下:
- Kata Container >= 1.5.0
- containerd >= 1.2.0
- K8s >= 1.12.0
在 Containerd 配置文件中配置相关条目
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 |
[plugins.cri.containerd] no_pivot = false [plugins.cri.containerd.runtimes] [plugins.cri.containerd.runtimes.runc] runtime_type = "io.containerd.runc.v1" [plugins.cri.containerd.runtimes.runc.options] NoPivotRoot = false NoNewKeyring = false ShimCgroup = "" IoUid = 0 IoGid = 0 BinaryName = "runc" Root = "" CriuPath = "" SystemdCgroup = false [plugins.cri.containerd.runtimes.kata] runtime_type = "io.containerd.kata.v2" [plugins.cri.containerd.runtimes.katacli] runtime_type = "io.containerd.runc.v1" [plugins.cri.containerd.runtimes.katacli.options] NoPivotRoot = false NoNewKeyring = false ShimCgroup = "" IoUid = 0 IoGid = 0 BinaryName = "/usr/bin/kata-runtime" Root = "" CriuPath = "" SystemdCgroup = false |
在 K8s 中创建 RuntimeClass
1 2 3 4 5 |
apiVersion: node.k8s.io/v1beta1 # RuntimeClass is defined in the node.k8s.io API group kind: RuntimeClass metadata: name: kata handler: kata # 这里与containerd配置文件中的 [plugins.cri.containerd.runtimes.{handler}] 匹配 |
创建pod
1 2 3 4 5 6 7 8 9 10 11 |
apiVersion: v1 kind: Pod metadata: name: kata-nginx spec: runtimeClassName: kata containers: - name: nginx image: nginx ports: - containerPort: 80 |
通过kata-runtime list
可以查看创建出来的 container
1 2 3 4 5 |
[root@master test]# kata-runtime list ID PID STATUS BUNDLE CREATED OWNER c1d3da016c84203bb55c48260bf36d57cd92090c080cfb94a56ca9906f0c5d47 -1 running /run/containerd/io.containerd.runtime.v2.task/k8s.io/c1d3da016c84203bb55c48260bf36d57cd92090c080cfb94a56ca9906f0c5d47 2020-04-02T03:22:21.110582849Z #0 c024c162d1d1d87e6e6e24be5348e5b3d48df4adda49e2c077d41b78887e9cc9 -1 running /run/containerd/io.containerd.runtime.v2.task/k8s.io/c024c162d1d1d87e6e6e24be5348e5b3d48df4adda49e2c077d41b78887e9cc9 2020-04-02T03:21:49.261039956Z #0 6820ace3d68a9b4bd443254d35a7dbc2cc29958358ccb61427d6cb2d5c2c7aca -1 running /run/containerd/io.containerd.runtime.v2.task/k8s.io/6820ace3d68a9b4bd443254d35a7dbc2cc29958358ccb61427d6cb2d5c2c7aca 2020-04-02T03:21:52.940466855Z #0 |
参考: https://segmentfault.com/a/1190000021845002
0 Comments