🐳

QEMUとのVirtfsを使ったファイル共有を実現するDockerfile

に公開

成果

VirtfsでQEMU上で動くカーネルとホストでファイル共有する最小に近い構成をdockerで再現可能な形で示した。

前提

  • docker or podman が動く

手順

後に添付するファイルを同じディレクトリに配置して、以下を実行。

ls
# expect:> Dockerfile init linux-config.sh

docker image build --target output -t virtfs-sample .
docker container run --rm -it --device=/dev/kvm:/dev/kvm virtfs-sample /bin/bash
# 以下 docker container の中

mkdir /root/shared
touch /root/shared/hello-virtfs
qemu-system-x86_64 \
    -enable-kvm \
    -k ja \
    -m 2048 \
    -cpu host \
    -smp 4 \
    -net nic \
    -device pci-testdev,membar=1M \
    -kernel /out/bzImage \
    -initrd /out/initrd.cpio.gz \
    -append 'console=ttyS0 nokaslr' \
    -virtfs local,path=/root/shared,mount_tag=hostshare,security_model=passthrough,id=shared0 \
    -nographic

# 以下VM上のカーネル内
ls /mnt/host
# expect: hello-virtfs

ファイル

  1. Dockerfile
FROM mirror.gcr.io/ubuntu:24.04 AS build_base

RUN --mount=type=cache,target=/var/cache/apt \
    --mount=type=cache,target=/var/lib/apt \
    rm -f /etc/apt/apt.conf.d/docker-clean \
    && apt-get update && apt-get install -y --no-install-recommends \
        build-essential ncurses-dev flex bison bc libelf-dev libssl-dev \
        wget cpio\
        git libglib2.0-dev libfdt-dev libpixman-1-dev zlib1g-dev ninja-build libnfs-dev libiscsi-dev python3-pip python3-venv


# Linux Kernel
FROM build_base AS kernel_build
WORKDIR /src/kernel

ARG KERNEL_URL="https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.14.tar.xz"
ARG KERNEL_CONFIG_SH="/src/kernel/scripts/config.sh"
ARG KERNEL_GCC="gcc-10"

RUN wget ${KERNEL_URL} -O linux.tar.gz \
    && mkdir linux \
    && tar Jxfv linux.tar.gz -C linux --strip-components 1

COPY ./linux-config.sh ${KERNEL_CONFIG_SH}

RUN --mount=type=cache,target=/var/cache/apt \
    --mount=type=cache,target=/var/lib/apt \
    rm -f /etc/apt/apt.conf.d/docker-clean \
    && apt-get update && apt-get install -y --no-install-recommends \
        ${KERNEL_GCC}

RUN cd linux \
    && make defconfig \
    && chmod +x ${KERNEL_CONFIG_SH} \
    && ${KERNEL_CONFIG_SH} \
    && make olddefconfig \
    && make HOSTCC=${KERNEL_GCC} CC=${KERNEL_GCC} -j$(nproc) bzImage vmlinux


# Busybox + initrd
FROM build_base AS initrd
WORKDIR /src/initrd

RUN mkdir -p \
        /src/initrd/rootfs/bin \
        /src/initrd/rootfs/sbin \
        /src/initrd/rootfs/etc \
        /src/initrd/rootfs/proc \
        /src/initrd/rootfs/sys \
        /src/initrd/rootfs/new_root \
        /src/initrd/rootfs/dev

ARG BUSYBOX_URL="https://busybox.net/downloads/busybox-1.35.0.tar.bz2"
ARG BUSYBOX_GCC="gcc-10"

RUN --mount=type=cache,target=/var/cache/apt \
    --mount=type=cache,target=/var/lib/apt \
    rm -f /etc/apt/apt.conf.d/docker-clean \
    && apt-get update && apt-get install -y --no-install-recommends \
        ${BUSYBOX_GCC}


RUN wget ${BUSYBOX_URL} -O busybox.tar.bz2 \
    && mkdir busybox \
    && tar -jxvf busybox.tar.bz2 -C busybox --strip-components 1 \
    && cd busybox \
    && make defconfig \
    && sed -i 's/# CONFIG_STATIC is not set/CONFIG_STATIC=y/' .config \
# Couldn't build `tc` (https://lists.busybox.net/pipermail/busybox-cvs/2024-January/041752.html)
    && sed -i 's/CONFIG_TC=y/# CONFIG_TC is not set/' .config \
    && make HOSTCC=${BUSYBOX_GCC} CC=${BUSYBOX_GCC} -j$(nproc) \
    && make CONFIG_PREFIX=/src/initrd/rootfs install

COPY ./init /src/initrd/rootfs/init
RUN chmod +x /src/initrd/rootfs/init \
    && cd /src/initrd/rootfs \
    && find . | cpio -o -H newc | gzip > /src/initrd/initrd.cpio.gz


# QEMU with custom device
FROM build_base AS qemu_build
WORKDIR /src/qemu

ARG QEMU_GIT_REMOTE_URL="https://gitlab.com/qemu-project/qemu.git"

RUN git clone ${QEMU_GIT_REMOTE_URL} \
    && cd qemu \
    && ./configure --target-list=x86_64-softmmu --enable-debug \
    && make -j$(nproc) \
    && make DESTDIR=/src/qemu install


FROM mirror.gcr.io/ubuntu:24.04 AS output
COPY --from=kernel_build /src/kernel/linux/arch/x86/boot/bzImage /out/bzImage
COPY --from=kernel_build /src/kernel/linux/vmlinux /out/vmlinux
COPY --from=initrd /src/initrd/initrd.cpio.gz /out/initrd.cpio.gz
COPY --from=qemu_build /src/qemu/usr/ /usr/

RUN --mount=type=cache,target=/var/cache/apt \
    --mount=type=cache,target=/var/lib/apt \
    rm -f /etc/apt/apt.conf.d/docker-clean \
    && apt-get update && apt-get install -y --no-install-recommends \
        gdb libnfs-dev libiscsi-dev libfdt-dev libpixman-1-dev
  1. init
#!/bin/sh

mount -t proc none /proc
mount -t sysfs none /sys

echo "[init] Try to mount virtfs ..."
mkdir -p /mnt/host
mount -t 9p -o trans=virtio hostshare /mnt/host

echo "[init] Contents of '/mnt/host'"
ls /mnt/host

echo "[init] Enter to shell"
exec setsid cttyhack sh
  1. linux-config.sh

# Debug
./scripts/config --enable DEBUG_INFO
./scripts/config --enable DEBUG_KERNEL

# Virtfs
./scripts/config --enable CONFIG_NET_9P
./scripts/config --enable CONFIG_NET_9P_VIRTIO
./scripts/config --enable CONFIG_NET_9P_DEBUG
./scripts/config --enable CONFIG_9P_FS
./scripts/config --enable CONFIG_9P_FS_POSIX_ACL
./scripts/config --enable CONFIG_PCI
./scripts/config --enable CONFIG_VIRTIO_PCI

Discussion