Kata Containers学习笔记
Kata Containers是基于Intel Clear Container + Hyper runV实现的轻量级的虚拟机,能够无缝的集成到容器生态系统中。Kata和Container一样轻量、快速,同时具有传统虚拟化的安全优势,Kata和Docker的OCI规范、K8S的CRI接口兼容。
迁移到容器云需要面临的一个重要挑战就是安全问题。多租户环境下,不安全负载和受信任负载在一起运行。Kata利用基于硬件的隔离,实现容器/Pod的安全边界,解决了传统容器架构共享内核的安全缺陷(提权漏洞)。使用Kata,你可以在单个K8S集群中服务多个租户。
支持工业标准,包括OCI容器格式、K8S的CRI接口。
这是虚拟化的优势,即允许使用任意的客户机操作系统,允许设备穿透访问。
Kata包含Agent、Runtime、Proxy、Shim、Kernel、Hypervisor等组件。
运行在虚拟机内部,负责创建容器环境和进程。
运行在宿主机上,负责协调和Agent的交互。
可选的工具,用于监控容器,去除重复内存,以最大化容器部署密度。
容器管理器调用此组件,该组件提供操控容器的高层接口,提供了CLI。该组件和OCI、CRI-O、Containerd兼容。
运行在宿主机上的进程,为了兼容OCI规范而存在。垫片在宿主机上代表工作负载(运行在虚拟机)处理标准的IO、信号。
使用QEMU 2.11。
QEMU使用Linux内核来启动客户机镜像。
宿主机必须支持KVM:
1 2 3 4 5 |
apt-get install ubuntu-virt-server kvm-ok # INFO: /dev/kvm exists # KVM acceleration can be used |
如果宿主机本身就是虚拟机,则宿主机的宿主机应当开启嵌套虚拟化:
1 2 |
cat /sys/module/kvm_intel/parameters/nested # Y |
1 2 3 |
echo "deb http://download.opensuse.org/repositories/home:/katacontainers:/release/xUbuntu_$(lsb_release -rs)/ /" > /etc/apt/sources.list.d/kata-containers.list curl -sL http://download.opensuse.org/repositories/home:/katacontainers:/release/xUbuntu_$(lsb_release -rs)/Release.key | sudo apt-key add - apt update && apt -y install kata-runtime kata-proxy kata-shim |
执行下面的命令,检查当前环境是否具备运行Kata的条件:
1 |
kata-runtime kata-check |
如果一切正常,应当没有错误日志。
创建配置文件:
1 2 3 4 |
[Service] Type=simple ExecStart= ExecStart=/usr/bin/dockerd -D --default-runtime runc --add-runtime kata-runtime=/usr/bin/kata-runtime |
重启Docker:
1 2 3 4 |
systemctl daemon-reload systemctl restart docker.service docker info | grep runtime # Runtimes: kata-runtime runc |
执行下面的命令,以Kata作为Runtime创建容器:
1 |
docker run -d --name ubuntu --runtime kata-runtime docker.gmem.cc/ubuntu:16.04 sleep 3600 |
容器运行起来之后,你可以看到QEMU进程qemu-lite-system-x86_64。
Kata是OCI兼容的容器运行时,不能直接和K8S的CRI API交互。因此,想集成K8S,先要安装一个支持CRI - OCI适配的CRI实现,可供选择的有 CRI-O、 CRI-containerd。
CRI-O是基于OCI的CRI实现。
skopeo是一个命令行工具,支持对容器镜像、仓库进行各种操作。skopeo支持OCI镜像以及Docker v2镜像格式。skopeo可以和支持API v2的镜像仓库进行交互。
和Docker不同,skopeo不需要运行守护程序即可完成以下操作:
- 在多种存储机制之间拷贝镜像,例如从一个仓库拷贝到另外一个
- 查看远程镜像的属性,包括它的层,而不需要预先拉取到本地
- 从仓库中删除镜像
- 支持向仓库提供身份凭证信息
执行下面的命令安装:
1 2 3 |
add-apt-repository ppa:projectatomic/ppa apt-get update apt-get install skopeo-containers -y |
这是一个轻巧的CLI工具,可以基于OCI规范产生和运行容器进程。
1 2 3 4 |
pushd /usr/bin wget https://github.com/opencontainers/runc/releases/download/v1.0.0-rc6/runc.amd64 mv runc.amd64 runc chmod +x runc |
CRI-O可以支持多种运行时,可以将runc作为默认运行时,让kata作为不受信任负载的运行时。
crio没有提供预编译的二进制文件,你需要自己编译。首先安装Go的SDK并初始化工作区:
1 2 3 4 5 6 7 |
wget https://dl.google.com/go/go1.11.4.linux-amd64.tar.gz tar zxf g1.11.4.linux-amd64.tar.gz mv go $HOME/Go/sdk/1.11.4 mkdir -p $HOME/Go/workspaces/default export GOROOT=$HOME/Go/sdk/1.11.4 export GOPATH=$HOME/Go/workspaces/default export PATH=$PATH:$GOROOT/bin |
然后构建crictl:
1 2 3 4 5 |
go get github.com/kubernetes-incubator/cri-tools/cmd/crictl cd $GOPATH/src/github.com/kubernetes-incubator/cri-tools git checkout release-1.12 make make install |
然后从源码构建crio:
1 2 3 4 5 6 7 8 9 10 11 |
apt install -y libglib2.0-dev libseccomp-dev libgpgme11-dev libdevmapper-dev make git gcc go-md2man go get -d github.com/kubernetes-sigs/cri-o cd $GOPATH/src/github.com/kubernetes-sigs/cri-o git checkout release-1.12 make install.tools make make install # 生成并安装配置文件 make install.config |
修改配置文件中的以下字段:
1 2 3 4 5 6 7 8 9 10 |
[crio.image] registries = ['docker.io'] [crio.runtime] manage_network_ns_lifecycle = true # 不受信任的负载用Kata运行 runtime_untrusted_workload = "/usr/bin/kata-runtime" # 默认认为负载是受信任的 default_workload_trust = "trusted" log_level = "info" |
注意,CRI-O默认使用的运行时是runc。
创建Systemd服务定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
Description=OCI-based implementation of Kubernetes Container Runtime Interface Documentation=https://github.com/kubernetes-sigs/cri-o [Service] Environment="HTTP_PROXY=http://10.0.0.1:8087" Environment="HTTPS_PROXY=http://10.0.0.1:8087" ExecStart=/usr/local/bin/crio Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target |
1 2 3 |
systemctl daemon-reload systemctl enable crio systemctl start crio |
使用下面的命令检测crio是否正常运行:
1 2 3 4 5 6 |
crictl --runtime-endpoint unix:///var/run/crio/crio.sock version # Version: 0.1.0 # RuntimeName: cri-o # RuntimeVersion: 1.14.0-dev # RuntimeApiVersion: v1alpha1 |
1 |
--container-runtime=remote --runtime-request-timeout=15m --container-runtime-endpoint=unix:///var/run/crio/crio.sock |
重新加载配置,重启kubelet后,在K8S主节点上可以看到容器运行时变为cri-o:
1 2 3 4 |
NAME AGE VERSION OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME jade 6m18s v1.12.1 Ubuntu 16.04.1 LTS 4.4.0-66-generic cri-o://1.14.0-dev # xenial-101 77d v1.12.1 Ubuntu 16.04.3 LTS 4.13.0-41-generic docker://1.13.1 # xenon 9d v1.12.1 Ubuntu 16.04.4 LTS 4.15.0-34-generic docker://18.6.1 |
使用如下命令尝试拉取必备的镜像:
1 2 3 4 5 6 7 8 9 10 11 |
crictl pull docker.gmem.cc/k8s/kube-apiserver:v1.12.1 crictl pull docker.gmem.cc/k8s/kube-controller-manager:v1.12.1 crictl pull docker.gmem.cc/k8s/kube-scheduler:v1.12.1 crictl pull docker.gmem.cc/k8s/kube-proxy:v1.12.1 crictl pull docker.gmem.cc/k8s/pause:3.1 crictl pull docker.gmem.cc/k8s/etcd:3.2.24 crictl pull docker.gmem.cc/k8s/coredns:1.2.2 crictl pull k8s.gcr.io/pause:3.1 crictl pull docker.gmem.cc/calico/node:v3.2.3 crictl pull docker.gmem.cc/calico/cni:v3.2.3 crictl pull docker.gmem.cc/calico/kube-controllers:v3.2.3 |
kube-proxy等Daemonset管理的Pod会自动在所有节点上运行,你可以使用如下命令查看本机运行的Pod:
1 2 3 4 5 6 7 8 |
# 查看Pod crictl pods # POD ID CREATED STATE NAME NAMESPACE ATTEMPT # 6914a958097c2 25 minutes ago Ready speaker-qkng4 metallb-system 0 # 查看容器 crictl ps # CONTAINER ID IMAGE CREATED STATE NAME |
如果默认运行时是runc,则此时看不到Kata容器:
1 2 |
kata-runtime list # NONE |
我们可以创建一个标注为“不受信任”的Pod,这样CRI-O将会以Kata作为运行时来运行它:
1 |
kubectl label node jade k8s.gmem.cc/allow-untrusted-workload=true |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
cat <<EOF | kubectl apply -f - apiVersion: v1 kind: Pod metadata: name: ubuntu-untrusted annotations: io.kubernetes.cri-o.TrustedSandbox: "false" spec: nodeSelector: k8s.gmem.cc/allow-untrusted-workload: "true" containers: - args: - -c - sleep 365d command: - /bin/sh image: docker.gmem.cc/ubuntu:16.04 imagePullPolicy: Always name: ubuntu EOF |
上述Pod运行起来后,你可以在节点上看到Kata容器、QEMU进程。
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
[crio] # 注意,存储配置默认从 /etc/containers/storage.conf 读取 # 根目录,包括容器、镜像都存放在此 root = "/var/lib/containers/storage" # 状态信息的根目录 runroot = "/var/run/containers/storage" # 存储驱动 storage_driver = "overlay" # 使用文件锁还是内存锁 file_locking = true # 文件锁的位置 file_locking_path = "/run/crio.lock" # kubelet/gRPC接口相关配置 [crio.api] # 守护程序监听的AF_LOCAL接口 listen = "/var/run/crio/crio.sock" # 流服务器监听的IP地址 stream_address = "127.0.0.1" # 流服务器监听的端口 stream_port = "0" # 流服务器是否启用TLS stream_enable_tls = false # 流服务器TLS证书配置 stream_tls_cert = "" stream_tls_key = "" stream_tls_ca = "" # 使用哪些OCI运行时,如何管理这些OCI运行时 [crio.runtime] # 管理网络命名空间的生命周期 manage_network_ns_lifecycle = true # 为每个容器设置的默认ulimit,如果不指定从CRI-O守护进程继承 # 示例:nofile=1024:2048 default_ulimits = [ ] # 运行受信任工作负载的OCI运行时的路径,未来该属性将废弃 runtime = "" # 默认运行时的名称,此名称定义在运行时映射配置项(Runtime mapping)中 default_runtime = "runc" # 未来该属性将废弃,使用crio.runtime.runtimes代替此属性 # 此属性相当于在crio.runtime.runtimes中创建一个名为untrusted的运行时处理器 runtime_untrusted_workload = "/usr/bin/kata-runtime" # 未来该属性将废弃 # 工作负载的默认受信任级别,默认值trusted,可选untrusted。CRI-O根据信任级别选择适当的运行时 # kubelet可以将工作负载标记为不受信任或受信任 default_workload_trust = "trusted" # 用于监控OCI运行时的公共二进制文件位置 conmon = "/usr/local/libexec/crio/conmon" # 公共环境变量 conmon_env = [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", ] # 使用使用SELinux来隔离工作负载 selinux = false # 默认的安全配置文件位置 seccomp_profile = "/etc/crio/seccomp.json" # CRI-O默认的AppArmor配置的名称 apparmor_profile = "crio-default" # 使用的CGroups管理机制 cgroup_manager = "cgroupfs" # 容器默认特性列表 default_capabilities = [ "CHOWN", "DAC_OVERRIDE", "FSETID", "FOWNER", "NET_RAW", "SETGID", "SETUID", "SETPCAP", "NET_BIND_SERVICE", "SYS_CHROOT", "KILL", ] # 容器默认sysctls列表 default_sysctls = [ ] # 额外的设备列表 # 格式:device-on-host:device-on-container:permissions,例如/dev/sdc:/dev/xvdc:rwm additional_devices = [ ] # OCI钩子目录,其中的钩子会自动执行 hooks_dir = [ ] # 每个容器默认挂载的文件 default_mounts_file = "" # 容器中最大允许的线程数量 pids_limit = 1024 # 容器日志的最大尺寸 log_size_max = -1 # 容器退出文件存放位置 container_exits_dir = "/var/run/crio/exits" # 容器Attach套接字的存放位置 container_attach_socket_dir = "/var/run/crio" # 如果设置为true则所有容器运行在只读模式 read_only = false # 日志输出级别 log_level = "info" # 到宿主机的UID映射,格式containerUID:HostUID:Size,逗号分隔 uid_mappings = "" # 到宿主机的UID映射,格式containerGID:HostGID:Size,逗号分隔 gid_mappings = "" # 认为终止容器操作超时的最小时间 ctr_stop_timeout = 0 # 容器运行时映射表 [crio.runtime.runtimes.runc] runtime_path = "/usr/bin/runc" [crio.runtime.runtimes.untrusted] runtime_path = "/usr/bin/kata-runtime" # 管理OCI镜像的配置 # 默认从/etc/containers/registries.conf读取镜像仓库信息 [crio.image] # 拉取镜像使用的默认传输协议 default_transport = "docker://" # K8S pause镜像 pause_image = "k8s.gcr.io/pause:3.1" pause_command = "/pause" # 执行一个策略文件,此文件用于决定是否信任拉取的镜像 # 默认策略,例如/etc/containers/policy.json通常足够 signature_policy = "" # 拉取非全限定名称的镜像时,从什么仓库拉取 registries = ['docker.io'] # CNI配置 [crio.network] # CNI配置文件所在目录 network_dir = "/etc/cni/net.d/" # CNI二进制文件所在目录 plugin_dir = "/opt/cni/bin/" |
子命令 | 说明 | ||
images | 列出镜像 | ||
pull | 拉取镜像,默认配置的默认传输是docker://,因此可以直接使用docker pull语法拉取Docker镜像:
|
||
inspecti | 查看一个或多个镜像的状态:
|
||
imagefsinfo | 查看镜像的文件系统信息 | ||
stats | 显示容器用量信息,包括CPU、内存、磁盘、INODES | ||
ps | 列出容器 | ||
info | 显示容器运行时的信息:
|
||
create | 创建新容器 | ||
update | 更新运行中的容器 | ||
start | 启动已经存在的容器 | ||
stop | 停止容器 | ||
exec | 在容器中执行命令: crictl exec -it 4ae949f913362 sh | ||
inspect | 查看一个或多个容器的状态 | ||
logs | 查看容器日志 | ||
pods | 列出Pod | ||
runp | 运行一个新的Pod: crictl runp pod-config.yaml | ||
stopp | 停止一个Pod,注意必须传入Pod的ID而不是名称 | ||
rmp | 删除一个Pod,注意必须传入Pod的ID而不是名称 |
Leave a Reply