本地运行 Kata Containers CI
基于 Vagrant + VirtualBox 方案
本文主要参考 《Kata Containers CI》,大部分内容是直接从上面的文章中翻译的,但是我会根据我自己的实践,对原文做一定的改变,比如启动虚拟机使用 vagrant 等。Happy hacking on Kata Containers' CI!
Vagrant 安装
这部分内容参见斌哥的《使用 VirtualBox 安装虚拟机开发环境》。
安装 Virtual Box 参见 virtualbox。
$ wget https://download.virtualbox.org/virtualbox/7.1.4/virtualbox-7.1_7.1.4-165100~Ubuntu~jammy_amd64.deb \
-O virtualbox-7.1.4.deb
$ sudo dpkg -i virtualbox-7.1.4.deb
安装 Vagrant 参见 Install Vagrant,我的测试环境是 ubuntu 22.04,其他的系统参见前面的连接自行安装。
$ wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
$ echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
$ sudo apt update && sudo apt install vagrant
安装 vagrant-disksize 插件,否则虚拟机启动会报错。
$ vagrant plugin install vagrant-disksize
安装 vagrant-proxyconf 插件,负责配置代理。
$ vagrant plugin install vagrant-proxyconf
创建虚拟机
首先要确定虚拟机的规格,以 kata-containers-ci-on-push / run-docker-tests-on-garm / run-docker-tests (clh) 这个 CI 测试为例,去 workflows 中找到 run-docker-tests-on-garm.yaml,在 runs-on 可以看到运行的环境是 "garm-ubuntu-2304-smaller"。
OS 对应的 vagrant 镜像
- Ubuntu-2304: bento/ubuntu-23.04
规格
- Small: 2 CPUs, 8 GiB
- Normal: 4 CPUs, 16 GiB
(如果已经有配置,可以跳过本步骤)使用 Vagrant 创建一个 ubuntu-2304-small 规格的虚拟机配置。
$ VM_NAME=kata-ubuntu-2304-small
$ VM_IMAGE=bento/ubuntu-23.04
$ mkdir -p $HOME/vagrant/$VM_NAME
$ cd $HOME/vagrant/$VM_NAME
$ cat > Vagrantfile <<EOF
Vagrant.configure("2") do |config|
config.disksize.size = "30GB"
config.vm.box = "$VM_IMAGE"
config.vm.define "$VM_NAME" do |kata|
kata.vm.hostname = "$VM_NAME"
kata.vm.network "private_network", type: "dhcp"
kata.vm.provider "virtualbox" do |vb|
vb.cpus = 2
vb.memory = "8192"
vb.customize ["modifyvm", :id, "--nested-hw-virt", "on"]
end
end
if Vagrant.has_plugin?("vagrant-proxyconf")
config.proxy.http = "http://127.0.0.1:7890/"
config.proxy.https = "http://127.0.0.1:7890/"
config.proxy.no_proxy = "localhost,127.0.0.1,.example.com,10.0.0.0/8,192.168.0.0/16"
end
end
EOF
启动虚拟机,启动之前请确保其它虚拟机/ Kata 容器没有启动。如果启动失败,可以尝试的工作是(1)杀掉其他占用 KVM 的进程,比如Kata 容器。(2)重启机器。
$ vagrant destroy -f
$ vagrant up
通过 SSH 连接虚拟机。
# 如果你本地有一个 http 代理监听在 localhost:7890
# `-R` 是反向端口转发, guest 访问 localhost:7890 会被转发到 host 的 7890 端口;
# `-L` 是正向端口转发,host 访问 localhost:7890 -> guest:7890。
$ vagrant ssh -- -R 7890:localhost:7890
# 如果你不希望使用本机代理
$ vagrant ssh
构建测试环境
访问 workflows/ci-on-push.yaml 找到失败的 CI 测试项目,进入 "Summary" 页面,找到 "kata-static-tarball-amd64" 开头的文件,下载到本地并解压缩,最终获得 "kata-static.tar.xz" 文件。
将 tarball 上传到虚拟环境的 /vagrant
,vagrant 自动建立了一个共享路径,host 上是 Vagrantfile 的目录,guest 上是 /vagrant
。这一步的目的是把 kata-static-tarball-xxx.zip 文件解压缩获得 kata-static.tar.xz 文件,然后上传到 host 的当前虚拟机根目录($HOME/vagrant/kata-ubuntu-2304-small
)。
# on macOS(这是我自己的方案)
$ unzip ~/Downloads/kata-static-tarball* -d ~/Downloads
$ scp ~/Downloads/kata-static.tar.xz devant:/home/nxw/vagrant/kata-ubuntu-2304-small
$ rm -rf ~/Downloads/kata-static-tarball* && rm -rf ~/Downloads/kata-static.tar.xz
初始化 git 仓库。
# on Guest
$ BRANCH=
$ git clone --branch $BRANCH https://github.com/justxuewei/kata-containers.git
$ cd kata-containers
$ git remote add upstream https://github.com/kata-containers/kata-containers
$ git remote update
$ git config --global user.email "you@example.com"
$ git config --global user.name "Your Name"
$ git rebase upstream/main
拷贝 tarball 到指定目录。
# on Guest
$ mkdir kata-artifacts
$ cp /vagrant/kata-static.tar.xz $(pwd)/kata-artifacts
编译并替换组件
安装 Golang
$ cd $HOME
$ wget https://go.dev/dl/go1.21.3.linux-amd64.tar.gz
$ sudo sh -c "rm -rf /usr/local/go && tar -C /usr/local -xzf go1.21.3.linux-amd64.tar.gz"
$ echo "export PATH=$PATH:/usr/local/go/bin" >> $HOME/.profile
$ source $HOME/.profile
$ go version
编译 Runtime-go
$ pushd src/runtime
$ make
$ sudo cp containerd-shim-kata-v2 /usr/local/bin
$ sudo mkdir -p /etc/kata-containers
$ sudo ln -s /opt/kata/share/defaults/kata-containers/configuration.toml /etc/kata-containers
$ popd
非 k8s 测试
不同的测试都需要下面两种 URL,这里以我自己的一个失败的 workflow 为例,请自行替换为自己需要的地址。
测试步骤记录在 run-docker-tests-on-garm.yaml。
安装 Kata Containers 依赖
# 任选一种 hypervisor
$ export KATA_HYPERVISOR=qemu
$ export KATA_HYPERVISOR=clh
# runtime-rs
$ export KATA_HYPERVISOR=dragonball
$ export KATA_HYPERVISOR=cloud-hypervisor
# 安装 docker
$ sudo apt-get install docker-ce docker-ce-cli
$ sudo mkdir -p /etc/systemd/system/docker.service.d
$ sudo sh -c 'cat > /etc/systemd/system/docker.service.d/http-proxy.conf <<EOF
[Service]
Environment="HTTP_PROXY=http://127.0.0.1:7890"
Environment="HTTPS_PROXY=http://127.0.0.1:7890"
Environment="NO_PROXY=$NO_PROXY,10.0.0.0/8,192.168.0.0/16"
EOF'
$ sudo systemctl daemon-reload \
&& sudo systemctl restart docker
$ bash tests/integration/docker/gha-run.sh install-dependencies
$ bash tests/integration/docker/gha-run.sh install-kata kata-artifacts
启动 debug 日志
# 启用 debug 日志
$ sudo chmod +w /opt/kata/share/defaults/kata-containers/runtime-rs/configuration.toml
$ sudo sed -i 's/#enable_debug = true/enable_debug = true/' /opt/kata/share/defaults/kata-containers/configuration.toml
$ sudo sh -c "echo '[debug]
level = \"debug\"' >> /etc/containerd/config.toml"
$ sudo systemctl restart containerd
开始调试。
$ bash tests/integration/docker/gha-run.sh run
导出 containerd 日志。
$ sudo journalctl -xe --unit containerd > /tmp/containerd.txt
$ vim /tmp/containerd.txt
导出 shim 日志。
$ sudo journalctl -t kata > /tmp/kata.txt
$ vim /tmp/kata.txt
清理
$ vagrant destroy -f
$ rm ./kata-static.tar.xz
K8s 测试
仅测试了 Kubernetes on AKS,其他的等待补充。
使用 kubeadm 创建单节点 k8s 集群。
# 安装 containerd
$ CONTAINERD_VERSION="1.6.8"
$ wget https://github.com/containerd/containerd/releases/download/v$CONTAINERD_VERSION/containerd-$CONTAINERD_VERSION-linux-amd64.tar.gz
$ sudo tar Cxzvf /usr/local containerd-$CONTAINERD_VERSION-linux-amd64.tar.gz
$ sudo sh -c "wget -qO - https://raw.githubusercontent.com/containerd/containerd/main/containerd.service > /lib/systemd/system/containerd.service"
$ sudo vim /lib/systemd/system/containerd.service
# 添加两行
# Environment="HTTP_PROXY=http://127.0.0.1:7890"
# Environment="HTTPS_PROXY=http://127.0.0.1:7890"
# Environment="NO_PROXY=localhost,127.0.0.1,.example.com,10.0.0.0/8,192.168.0.0/16"
$ sudo systemctl daemon-reload
$ sudo systemctl enable --now containerd
$ sudo mkdir -p /etc/containerd
$ sudo sh -c "containerd config default > /etc/containerd/config.toml"
$ sudo systemctl restart containerd
# 安装 runc
$ sudo apt install runc
# 安装 kubectl & kubeadm
$ sudo apt-get install -y apt-transport-https ca-certificates curl gpg
$ curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.26/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
$ echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.26/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
$ sudo apt-get update
$ sudo apt-get install -y kubelet kubeadm kubectl
$ sudo apt-mark hold kubelet kubeadm kubectl
# 设置网络
$ cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
$ sudo modprobe -a overlay br_netfilter
$ cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
$ sudo sysctl --system
# 降级 cgroup 版本至 v1
$ sudo vim /etc/default/grub
向 GRUB_CMDLINE_LINUX 插入一条 systemd.unified_cgroup_hierarchy=0
$ sudo update-grub
$ sudo reboot
$ cat /sys/fs/cgroup/cgroup.controllers
cat: /sys/fs/cgroup/cgroup.controllers: No such file or directory
# 安装 CNI
$ git clone https://github.com/containernetworking/plugins.git cni-plugins
$ cd cni-plugins
$ git checkout tags/v1.4.1 -b v1.4.1
$ ./build_linux.sh
$ sudo mkdir -p /opt/cni/bin
$ sudo cp bin/* /opt/cni/bin/
# CNI 配置
$ sudo mkdir -p /etc/cni/net.d
$ sudo sh -c 'cat > /etc/cni/net.d/10-mynet.conf <<EOF
{
"cniVersion": "0.2.0",
"name": "mynet",
"type": "bridge",
"bridge": "cni0",
"isGateway": true,
"ipMasq": true,
"ipam": {
"type": "host-local",
"subnet": "172.19.0.0/24",
"routes": [
{ "dst": "0.0.0.0/0" }
]
}
}
EOF'
启动 k8s 集群
# 一定要进入 root 之后再设置 proxy
$ sudo su
$ export no_proxy="$no_proxy,10.0.0.0/8,192.168.0.0/16" \
&& export NO_PROXY="$NO_PROXY,10.0.0.0/8,192.168.0.0/16" \
&& echo "no_proxy: $no_proxy" \
&& echo "NO_PROXY=$NO_PROXY"
$ swapoff -a
$ kubeadm config images pull \
--image-repository=registry.cn-hangzhou.aliyuncs.com/google_containers
$ kubeadm init \
--image-repository=registry.cn-hangzhou.aliyuncs.com/google_containers \
--pod-network-cidr=192.168.0.0/16
# 设置 kubectl 配置
$ mkdir -p $HOME/.kube
$ cp -i /etc/kubernetes/admin.conf $HOME/.kube/config \
&& sudo chown $(id -u):$(id -g) $HOME/.kube/config
# 清除污点
$ kubectl taint nodes --all node-role.kubernetes.io/control-plane-
# 安装 CNI
# calico
$ kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.4/manifests/tigera-operator.yaml
$ kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.4/manifests/custom-resources.yaml
# 等待所有 pod running
$ watch kubectl get pods -n calico-system
# 安装 yq(需要有代理的环境)
$ cd go/to/kata-containers
$ ./ci/install_yq.sh
# 安装 bats
$ sudo apt install bats
安装 Kata 环境
# 任选一种 hypervisor
$ export KATA_HYPERVISOR=qemu
$ export KATA_HYPERVISOR=clh
# runtime-rs
$ export KATA_HYPERVISOR=dragonball
$ export KATA_HYPERVISOR=cloud-hypervisor
$ cd go/to/kata-containers
# 记得修改 sleep 240s -> sleep 60s
$ bash tests/integration/kubernetes/gha-run.sh deploy-kata-aks
不知道为什么,有时候运行完脚本后 runtimeclass 不能够正确被配置,因此需要手动检查配置是否正确(以 cloud-hypervisor 为例)。
$ rm -rf /usr/local/bin/containerd-shim-kata-v2; \
rm -rf /usr/local/bin/containerd-shim-kata-runtime-rs-v2
$ ln -s /opt/kata/runtime-rs/bin/containerd-shim-kata-v2 \
/usr/local/bin/containerd-shim-kata-runtime-rs-v2; \
ln -s /opt/kata/bin/containerd-shim-kata-v2 \
/usr/local/bin/containerd-shim-kata-v2
$ kubectl get runtimeclass
NAME HANDLER AGE
kata kata-cloud-hypervisor 109m
kata-cloud-hypervisor kata-cloud-hypervisor 109m
$ kubectl describe runtimeclass kata
Handler: kata-cloud-hypervisor
$ kubectl describe runtimeclass kata-cloud-hypervisor
Handler: kata-cloud-hypervisor
$ vim /etc/containerd/config.toml
# 1. 搜索 "containerd.runtimes"
# 2. 如果没有 [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.kata-cloud-hypervisor] 就需要添加
# 3.添加以下东西:
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.kata-cloud-hypervisor]
runtime_type = "io.containerd.kata-runtime-rs.v2"
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.kata-cloud-hypervisor.options]
ConfigPath = "/opt/kata/share/defaults/kata-containers/runtime-rs/configuration-cloud-hypervisor.toml"
# 最后重启 containerd 和 kubelet
$ sudo systemctl restart containerd && sudo systemctl restart kubelet
常见的集中 hypervisors 的配置项
- cloud-hypervisor
- runtime_type:
io.containerd.kata-runtime-rs.v2
- ConfigPath:
/opt/kata/share/defaults/kata-containers/runtime-rs/configuration-cloud-hypervisor.toml
- runtime_type:
启动测试(需要根据 CI 测试执行什么命令来确定)
$ bash tests/integration/kubernetes/gha-run.sh run-tests
如果虚拟机重启需要做的事情
$ sudo su
# 关闭 swap
$ swapoff -a
$ systemctl restart kubelet
# 禁用 proxy envs
$ export no_proxy="$no_proxy,10.0.0.0/8,192.168.0.0/16" \
&& export NO_PROXY="$NO_PROXY,10.0.0.0/8,192.168.0.0/16" \
&& echo "no_proxy: $no_proxy" \
&& echo "NO_PROXY=$NO_PROXY"
# 任选一种 hypervisor
$ export KATA_HYPERVISOR=qemu
$ export KATA_HYPERVISOR=clh
# runtime-rs
$ export KATA_HYPERVISOR=dragonball
$ export KATA_HYPERVISOR=cloud-hypervisor