BPF を使うプログラムはコンテナで動かすには特権が必要であったり、Linux カーネルの特定のコンフィグが ON になっていないと(CONFIG_BPF=yとか)動かないなどあり、Circle CI や Travis CI のような有名どころの CI では十分にテストすることができない。
Semaphore CI は CI 環境として VM が提供されるので、Docker などの実行が可能である。
ただ、VMが使えるだけでは Linux カーネルのコンフィグ問題は解決しないのだが、rkt の KVM Stage1 が使える。
自前でビルドした Stage1 Image を KVM で動かし、その上で Pod を動かすことができる。
この方法は https://kinvolk.io/blog/2017/02/using-custom-rkt-stage1-images-to-test-against-various-kernel-versions/ に書いてある。
上記ブログでは ACI のビルドをしているが、 stage1-builder で作成されたイメージがあるので、それを使うのが楽。
カーネルのヘッダは /lib/modules/${kernel_version}-kinvolk-v1/source/include
などにあるため、それを C_INCLUDE_PATH
に追加しておく。あとは、ホスト側にあるリポジトリのパスをマウントしてあげれば良い。
--environment=C_INCLUDE_PATH="${kernel_header_dir}/arch/x86/include:${kernel_header_dir}/arch/x86/include/generated:/lib/modules/${kernel_version}-kinvolk-v1/include" \
また、使う Docker Image で bcc がソースからビルドされている場合は BCC_KERNEL_MODULES_SUFFIX
を source
にしておく必要がある。
ref : https://github.com/iovisor/bcc/pull/430/files
困っているのは、たまに rkt から名前解決ができないことがあり、依存パッケージのダウンロードに失敗してしまうということ。
これはどういう問題なのだろうな… というのを調べるために、手元で環境を作って再現するまでがちょっと面倒。
cxray だと、こんな感じで CI 上でのビルドとテストができた。
#!/bin/bash
set -eu
set -o pipefail
# The kernel versions we want to run the tests on
readonly kernel_versions=("4.9.96")
# The rkt version which is set as a dependency for
# the custom stage1-kvm images
readonly rkt_version="1.30.0"
# Download rkt if not available yet as Semaphore CI
# doesn't have rkt at the time of writing
if [[ ! -f "./rkt/rkt" ]] ||
[[ ! "$(./rkt/rkt version | awk '/rkt Version/{print $3}')" == "${rkt_version}" ]]; then
curl -LsS "https://github.com/coreos/rkt/releases/download/v${rkt_version}/rkt-v${rkt_version}.tar.gz" \
-o rkt.tgz
mkdir -p rkt
tar -xvf rkt.tgz -C rkt --strip-components=1
fi
# Pre-fetch stage1 dependency due to rkt#2241
# https://github.com/coreos/rkt/issues/2241
sudo ./rkt/rkt image fetch --insecure-options=image "coreos.com/rkt/stage1-kvm:${rkt_version}" >/dev/null
for kernel_version in "${kernel_versions[@]}"; do
kernel_header_dir="/lib/modules/${kernel_version}-kinvolk-v1/source/include"
# The stage1-kvm image to use for the tests
stage1_name="kinvolk.io/aci/rkt/stage1-kvm:${rkt_version},kernelversion=${kernel_version}"
# Make sure there's no stale rkt-uuid file
rm -f ./rkt-uuid
# You most likely want to provide source code to the
# container in order to run the tests. You can do this
# with volumes:
# https://coreos.com/rkt/docs/latest/subcommands/run.html#mounting-volumes
# Depending on the level of privileges you need,
# `--insecure-options=all-run` might be necessary:
# https://coreos.com/rkt/docs/latest/commands.html#global-options
# timeout can be used to make sure tests finish in
# a reasonable amount of time
sudo timeout --foreground --kill-after=10 20m \
./rkt/rkt \
run --interactive \
--uuid-file-save=./rkt-uuid \
--insecure-options=image,all-run \
--dns=8.8.8.8 \
--stage1-name="${stage1_name}" \
--volume=cxray,kind=host,source="$PWD" \
--mount=volume=cxray,target=/go/src/github.com/mrtc0/cxray \
docker://mrtc0/bcc-docker:latest \
--memory=1024M \
--environment=GOPATH=/go \
--environment=GO111MODULE=on \
--environment=C_INCLUDE_PATH="${kernel_header_dir}/arch/x86/include:${kernel_header_dir}/arch/x86/include/generated:/lib/modules/${kernel_version}-kinvolk-v1/include" \
--environment=BCC_KERNEL_MODULES_SUFFIX="source"
--exec=/bin/sh -- -c \
'printf "\n\nKernel Environment (on kernel $(uname -r))\n\n" &&
cd /go/src/github.com/mrtc0/cxray &&
mount -t tmpfs tmpfs /tmp &&
mount -t debugfs debugfs /sys/kernel/debug/ &&
make test'
# Determine exit code from pod status due to rkt#2777
# https://github.com/coreos/rkt/issues/2777
test_status=$(sudo ./rkt/rkt status "$(<rkt-uuid)" | awk '/app-/{split($0,a,"=")} END{print a[2]}')
if [[ $test_status -ne 0 ]]; then
exit "$test_status"
fi
sudo ./rkt/rkt gc --grace-period=0
echo "Test successful on ${kernel_version}"
done