Differences
This shows you the differences between two versions of the page.
| Both sides previous revision Previous revision Next revision | Previous revision | ||
| docs:guide-user:virtualization:docker_openwrt_image [2021/12/30 20:20] – Add OpenWrt in QEMU in Docker jwmullally | docs:guide-user:virtualization:docker_openwrt_image [2022/06/23 18:07] (current) – [OpenWrt in QEMU in Docker: Advanced Example] Simplify supplying custom config jwmullally | ||
|---|---|---|---|
| Line 310: | Line 310: | ||
| ===== OpenWrt in QEMU in Docker ===== | ===== OpenWrt in QEMU in Docker ===== | ||
| - | This provides all the power and configurability of regular | + | This section provides example Docker files to run OpenWrt inside QEMU inside a Docker container. |
| + | |||
| + | This provides all the power and configurability of regular | ||
| + | |||
| + | Example build and usage: | ||
| + | |||
| + | <code bash> | ||
| + | docker build . -t openwrt_in_qemu | ||
| + | docker run --name my_openwrt -p 30022:30022 -p 30080:30080 openwrt_in_qemu | ||
| + | </ | ||
| + | |||
| + | <code bash> | ||
| + | docker exec -ti my_openwrt /bin/sh | ||
| + | socat -, | ||
| + | </ | ||
| + | |||
| + | ==== OpenWrt in QEMU in Docker: Simple Example ==== | ||
| < | < | ||
| # syntax=docker/ | # syntax=docker/ | ||
| # | # | ||
| - | # This Dockerfile creates a container running | + | # This Dockerfile creates a container |
| # https:// | # https:// | ||
| # | # | ||
| Line 321: | Line 337: | ||
| # and execute this command: | # and execute this command: | ||
| # | # | ||
| - | # socat -, | + | # socat -, |
| + | # socat -, | ||
| # | # | ||
| # To enable remote admin, set a password on the root account: | # To enable remote admin, set a password on the root account: | ||
| Line 339: | Line 356: | ||
| # | # | ||
| - | FROM docker.io/ | + | FROM docker.io/ |
| - | # Install QEMU. Remove large unnecessary files | ||
| RUN apk add --no-cache \ | RUN apk add --no-cache \ | ||
| curl \ | curl \ | ||
| qemu-system-x86_64 \ | qemu-system-x86_64 \ | ||
| qemu-img \ | qemu-img \ | ||
| + | socat \ | ||
| + | && \ | ||
| + | rm -f / | ||
| + | |||
| + | ENV IMAGE_URL=" | ||
| + | ENV IMAGE_FILE=" | ||
| + | ENV IMAGE_SHA256=" | ||
| + | |||
| + | WORKDIR / | ||
| + | RUN curl -L " | ||
| + | sh -x -c '[ " | ||
| + | |||
| + | RUN echo -e '# | ||
| + | set -ex \n\ | ||
| + | if [ ! -f / | ||
| + | gunzip --stdout "/ | ||
| + | qemu-img convert -f raw -O qcow2 / | ||
| + | rm / | ||
| + | qemu-img resize / | ||
| + | fi \n\ | ||
| + | exec / | ||
| + | -nodefaults \\\n\ | ||
| + | -display none \\\n\ | ||
| + | -m 256M \\\n\ | ||
| + | -smp 2 \\\n\ | ||
| + | -nic " | ||
| + | -nic " | ||
| + | -chardev socket, | ||
| + | -serial chardev: | ||
| + | -monitor unix:/ | ||
| + | -drive file=/ | ||
| + | \n' > / | ||
| + | chmod +x / | ||
| + | |||
| + | EXPOSE 30022 | ||
| + | EXPOSE 30080 | ||
| + | EXPOSE 30443 | ||
| + | VOLUME / | ||
| + | WORKDIR /tmp | ||
| + | USER 1001 | ||
| + | CMD ["/ | ||
| + | </ | ||
| + | |||
| + | |||
| + | ==== OpenWrt in QEMU in Docker: Advanced Example ==== | ||
| + | |||
| + | This Docker image is similar to the above, with a few more features: | ||
| + | |||
| + | * Support arbitrary container user IDs | ||
| + | * Tunable QEMU configuration | ||
| + | * A SPICE console + USB redirection | ||
| + | * KVM acceleration support | ||
| + | * Custom VM initialization scripts (e.g. from a Kubernetes ConfigMap) | ||
| + | * Default admin firewall rules and disk resizing | ||
| + | * Healthchecks | ||
| + | |||
| + | < | ||
| + | # syntax=docker/ | ||
| + | # | ||
| + | # This Dockerfile creates a container image running OpenWRT in a QEMU VM. | ||
| + | # https:// | ||
| + | # This can be run on regular container clusters (e.g. Kubernetes, | ||
| + | # without any special permissions. | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # For VGA console access and USB redirection, | ||
| + | # (e.g. " | ||
| + | # | ||
| + | # To connect to the VM serial console, connect to the running container | ||
| + | # and execute one of these commands: | ||
| + | # | ||
| + | # socat -, | ||
| + | # socat -, | ||
| + | # | ||
| + | # To use KVM acceleration, | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # Volumes: | ||
| + | # | ||
| + | # / | ||
| + | # The VM disk image. | ||
| + | # | ||
| + | # / | ||
| + | # You can use a shared volume/ | ||
| + | # | ||
| + | # which you can use to provide other files. For testing, start docker | ||
| + | # with " | ||
| + | # | ||
| + | # | ||
| + | # vm.d: Scripts run on the VM | ||
| + | |||
| + | FROM docker.io/ | ||
| + | |||
| + | # Install QEMU, remove large unnecessary files | ||
| + | RUN apk add --no-cache \ | ||
| + | curl \ | ||
| + | make \ | ||
| + | qemu-chardev-spice \ | ||
| + | qemu-hw-display-virtio-vga \ | ||
| + | qemu-hw-usb-redirect \ | ||
| + | qemu-img \ | ||
| + | qemu-system-x86_64 \ | ||
| + | qemu-ui-spice-core \ | ||
| socat \ | socat \ | ||
| && \ | && \ | ||
| Line 351: | Line 473: | ||
| # Download OpenWRT image | # Download OpenWRT image | ||
| - | ENV IMAGE_URL=" | + | ENV IMAGE_URL=" |
| - | ENV IMAGE_FILE=" | + | ENV IMAGE_FILE=" |
| - | ENV IMAGE_SHA256=" | + | ENV IMAGE_SHA256=" |
| WORKDIR / | WORKDIR / | ||
| + | |||
| RUN curl -L " | RUN curl -L " | ||
| sh -x -c '[ " | sh -x -c '[ " | ||
| Line 364: | Line 487: | ||
| if ! whoami &> /dev/null; then \n\ | if ! whoami &> /dev/null; then \n\ | ||
| if [ -w /etc/passwd ]; then \n\ | if [ -w /etc/passwd ]; then \n\ | ||
| - | echo " | + | echo " |
| echo " | echo " | ||
| fi \n\ | fi \n\ | ||
| fi \n\ | fi \n\ | ||
| - | \n' > / | + | \n' > / |
| - | chmod +x / | + | chmod +x / |
| chmod g=u /etc/passwd && \ | chmod g=u /etc/passwd && \ | ||
| chmod g=u /etc/group | chmod g=u /etc/group | ||
| Line 376: | Line 499: | ||
| RUN echo -e '# | RUN echo -e '# | ||
| set -ex \n\ | set -ex \n\ | ||
| - | if [ ! -f image.qcow2 ]; then \n\ | + | if [ ! -f / |
| - | gunzip --stdout "/ | + | gunzip --stdout "/ |
| - | qemu-img convert -f raw -O qcow2 image.raw image.qcow2 \n\ | + | qemu-img convert -f raw -O qcow2 / |
| - | rm image.raw \n\ | + | rm / |
| fi \n\ | fi \n\ | ||
| if [ -n " | if [ -n " | ||
| - | qemu-img resize image.qcow2 " | + | qemu-img resize |
| fi \n\ | fi \n\ | ||
| \n' > / | \n' > / | ||
| chmod +x / | chmod +x / | ||
| - | # Start VM in QEMU | + | # Create default |
| + | RUN mkdir -p / | ||
| + | |||
| + | RUN echo -e '# | ||
| + | set -e \n\ | ||
| + | cat > vm.d/ | ||
| + | #!/bin/sh \n\ | ||
| + | set -e \n\ | ||
| + | uci set system.@system[0].hostname=" | ||
| + | uci commit system \n\ | ||
| + | EOF\n\ | ||
| + | chmod +x vm.d/ | ||
| + | \n\' > / | ||
| + | chmod +x / | ||
| + | |||
| + | RUN echo -e '# | ||
| + | set -e \n\ | ||
| + | cat > vm.d/ | ||
| + | #!/bin/sh \n\ | ||
| + | set -e \n\ | ||
| + | echo -e " | ||
| + | EOF\n\ | ||
| + | chmod +x vm.d/ | ||
| + | \n\' > / | ||
| + | chmod +x / | ||
| RUN echo -e '# | RUN echo -e '# | ||
| set -ex \n\ | set -ex \n\ | ||
| + | uci add firewall rule \n\ | ||
| + | uci set firewall.@rule[-1].name=" | ||
| + | uci set firewall.@rule[-1].enabled=" | ||
| + | uci set firewall.@rule[-1].src=" | ||
| + | uci set firewall.@rule[-1].proto=" | ||
| + | uci set firewall.@rule[-1].dest_port=" | ||
| + | uci set firewall.@rule[-1].target=" | ||
| + | uci commit firewall \n\ | ||
| + | \n\' > / | ||
| + | chmod +x / | ||
| + | |||
| + | RUN echo -e '# | ||
| + | set -ex \n\ | ||
| + | ubus wait_for network.interface.wan \n\ | ||
| + | sleep 3 \n\ | ||
| + | opkg update \n\ | ||
| + | \n\' > / | ||
| + | chmod +x / | ||
| + | |||
| + | RUN echo -e '# | ||
| + | set -ex \n\ | ||
| + | opkg install partx-utils resize2fs sfdisk tune2fs \n\ | ||
| + | echo "- +" | sfdisk --force -N 2 /dev/vda \n\ | ||
| + | partx -u /dev/vda \n\ | ||
| + | mount -o remount,ro / \n\ | ||
| + | tune2fs -O^resize_inode /dev/vda2 \n\ | ||
| + | e2fsck -y -f /dev/vda2 || true \n\ | ||
| + | mount -o remount,rw / \n\ | ||
| + | resize2fs /dev/vda2 \n\ | ||
| + | \n\' > / | ||
| + | chmod +x / | ||
| + | |||
| + | # Write VM configuration archive as serial console commands to STDOUT | ||
| + | RUN echo -e '# | ||
| + | set -e \n\ | ||
| + | cat << | ||
| \n\ | \n\ | ||
| - | provision-user.sh \n\ | + | echo " |
| - | provision-image.sh \n\ | + | lua / |
| + | EOF\n\ | ||
| + | tar -zcv -C " | ||
| + | cat <<EOF\n\ | ||
| \n\ | \n\ | ||
| + | mkdir / | ||
| + | tar -zxvf / | ||
| + | sleep 5 \n\ | ||
| + | (cd / | ||
| + | poweroff \n\ | ||
| + | EOF\n\ | ||
| + | \n' > / | ||
| + | chmod +x / | ||
| + | |||
| + | # Send configuration archive to VM using serial console | ||
| + | RUN echo -e '# | ||
| + | set -ex \n\ | ||
| + | echo " | ||
| + | find / | ||
| + | sleep 5 \n\ | ||
| + | rm -rf / | ||
| + | cp -rv / | ||
| + | mkdir -p / | ||
| + | if [ -z " | ||
| + | cp / | ||
| + | cp / | ||
| + | fi \n\ | ||
| + | (cd / | ||
| + | run-vm.sh & \n\ | ||
| + | QEMU_PID=" | ||
| + | sleep 5 \n\ | ||
| + | socat STDOUT unix-connect:/ | ||
| + | serialize-vm-config.sh / | ||
| + | VM_CONFIG_RESULT=" | ||
| + | if test " | ||
| + | exit 1 \n\ | ||
| + | fi \n\ | ||
| + | wait " | ||
| + | \n' > / | ||
| + | chmod +x / | ||
| + | |||
| + | # Start VM in QEMU | ||
| + | RUN echo -e '# | ||
| + | set -e \n\ | ||
| + | printf " | ||
| + | set -x \n\ | ||
| exec / | exec / | ||
| -nodefaults \\\n\ | -nodefaults \\\n\ | ||
| - | -display none \\\n\ | ||
| - | -m " | ||
| -smp "" | -smp "" | ||
| + | -m " | ||
| + | -drive file=/ | ||
| + | -chardev socket, | ||
| + | -serial chardev: | ||
| + | -monitor unix:/ | ||
| -nic " | -nic " | ||
| -nic " | -nic " | ||
| - | -chardev socket,id=chr0,path=qemu-console.sock,mux=on,logfile=/dev/stdout,signal=off,server=on,wait=off \\\n\ | + | -object secret,id=secvnc0,format=raw, |
| - | -serial | + | -display none \\\n\ |
| - | -drive file=image.qcow2,if=virtio | + | -device virtio-vga \\\n\ |
| + | -spice port=5900,password-secret=secvnc0 \\\n\ | ||
| + | -device intel-hda \\\n\ | ||
| + | -device hda-duplex \\\n\ | ||
| + | -device ich9-usb-ehci1,id=usb \\\n\ | ||
| + | -device ich9-usb-uhci1,masterbus=usb.0,firstport=0, | ||
| + | -device ich9-usb-uhci2, | ||
| + | -chardev | ||
| + | -device usb-redir, | ||
| + | -chardev spicevmc, | ||
| + | -device usb-redir, | ||
| + | $QEMU_ARGS \\\n\ | ||
| + | \n' > / | ||
| + | chmod +x / | ||
| + | |||
| + | # Healthcheck | ||
| + | RUN echo -e '# | ||
| + | set -ex \n\ | ||
| + | [ -e / | ||
| + | curl -sSf -m 5 http:// | ||
| + | \n' > / | ||
| + | chmod +x / | ||
| + | |||
| + | # Entrypoint | ||
| + | RUN echo -e '# | ||
| + | set -ex \n\ | ||
| + | create-container-user.sh \n\ | ||
| + | provision-image.sh \n\ | ||
| + | if [ ! -f / | ||
| + | timeout -s SIGINT " | ||
| + | touch / | ||
| + | chmod g+rw / | ||
| + | fi \n\ | ||
| + | exec run-vm.sh | ||
| \n' > / | \n' > / | ||
| chmod +x / | chmod +x / | ||
| Line 411: | Line 675: | ||
| ENV QEMU_STORAGE=" | ENV QEMU_STORAGE=" | ||
| ENV QEMU_SMP=" | ENV QEMU_SMP=" | ||
| - | ENV QEMU_LAN_OPTIONS=" | + | ENV QEMU_LAN_OPTIONS="" |
| ENV QEMU_WAN_NETWORK=" | ENV QEMU_WAN_NETWORK=" | ||
| ENV QEMU_WAN_OPTIONS=" | ENV QEMU_WAN_OPTIONS=" | ||
| + | ENV QEMU_PASSWORD=" | ||
| + | ENV QEMU_CONFIG_TIMEOUT=" | ||
| + | ENV QEMU_CONFIG_NO_DEFAULTS="" | ||
| + | ENV QEMU_HOSTNAME=" | ||
| + | ENV QEMU_ARGS="" | ||
| - | EXPOSE 30022 | + | EXPOSE 5900/tcp |
| - | EXPOSE 30080 | + | EXPOSE 30022/tcp |
| + | EXPOSE 30080/tcp | ||
| + | EXPOSE 30443/tcp | ||
| EXPOSE 51820/udp | EXPOSE 51820/udp | ||
| - | WORKDIR | + | HEALTHCHECK --interval=30s --timeout=30s --start-period=120s --retries=3 CMD [ "/ |
| + | VOLUME | ||
| VOLUME / | VOLUME / | ||
| + | WORKDIR /tmp | ||
| USER 1001 | USER 1001 | ||
| CMD ["/ | CMD ["/ | ||
| - | </ | ||
| - | |||
| - | Example build and usage: | ||
| - | |||
| - | <code bash> | ||
| - | docker build . -t openwrt_in_qemu | ||
| - | docker run -p 30022:30022 -p 30080:30080 -ti openwrt_in_qemu | ||
| - | </ | ||
| - | |||
| - | <code bash> | ||
| - | docker exec -ti elastic_hofstadter /bin/sh | ||
| - | socat -, | ||
| </ | </ | ||