强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

Qt 与 GTK 图形框架教程 / 15 - Docker 容器化 / Docker

Docker 容器化 GUI 开发 / Docker for GUI Development

在 Docker 容器中开发、测试和运行 Qt/GTK 图形应用。 Develop, test, and run Qt/GTK GUI applications inside Docker containers.


15.1 为什么容器化 GUI? / Why Containerize GUI?

优势 / Advantage说明 / Description
环境一致性所有开发者使用相同依赖版本 / Consistent dependencies
CI/CD 集成自动化编译和测试 / Automated build & test
隔离性不污染宿主系统 / No host pollution
多版本测试同时测试不同 Qt/GTK 版本 / Test multiple versions
复现性一键搭建完整开发环境 / One-click dev environment
局限 / Limitation说明 / Description
GPU 加速需要额外配置 / Requires extra config
X11/Wayland 转发需要显示服务器权限 / Needs display server access
性能GUI 渲染有轻微开销 / Minor rendering overhead
文件系统音视频设备访问受限 / Limited device access

15.2 X11 转发 / X11 Forwarding

基本原理 / Basic Principle

┌──────────────┐     X11 Socket     ┌──────────────┐
│   Container  │ ◄────────────────► │  X Server    │
│   (App)      │   /tmp/.X11-unix   │  (Host)      │
└──────────────┘                    └──────────────┘

Dockerfile (Qt)

# Dockerfile.qt - Qt 开发环境
FROM ubuntu:24.04

# 避免交互式安装
ENV DEBIAN_FRONTEND=noninteractive

# 安装基础依赖
RUN apt-get update && apt-get install -y \
    build-essential \
    cmake \
    pkg-config \
    git \
    qt6-base-dev \
    qt6-declarative-dev \
    qt6-tools-dev \
    qt6-l10n-tools \
    libgl1-mesa-dev \
    libfontconfig1-dev \
    libfreetype6-dev \
    libx11-dev \
    libx11-xcb-dev \
    libxext-dev \
    libxfixes-dev \
    libxi-dev \
    libxrender-dev \
    libxcb1-dev \
    libxcb-cursor-dev \
    libxcb-glx0-dev \
    libxcb-keysyms1-dev \
    libxcb-image0-dev \
    libxcb-shm0-dev \
    libxcb-icccm4-dev \
    libxcb-sync-dev \
    libxcb-xfixes0-dev \
    libxcb-shape0-dev \
    libxcb-randr0-dev \
    libxcb-render-util0-dev \
    libxcb-xinerama0-dev \
    libxcb-xkb-dev \
    x11-apps \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /app
COPY . /app

# 构建
RUN cmake -B build -DCMAKE_BUILD_TYPE=Release \
    && cmake --build build

# 运行
CMD ["./build/myapp"]

运行命令 / Run Commands

# X11 转发运行 Qt 应用
docker build -f Dockerfile.qt -t myqtapp .

# Linux 宿主机
xhost +local:docker
docker run -it --rm \
    -e DISPLAY=$DISPLAY \
    -v /tmp/.X11-unix:/tmp/.X11-unix \
    -v $HOME/.Xauthority:/root/.Xauthority:ro \
    --net=host \
    myqtapp

# macOS (使用 XQuartz)
# 先启动 XQuartz,然后:
xhost +localhost
docker run -it --rm \
    -e DISPLAY=host.docker.internal:0 \
    myqtapp

15.3 Wayland 转发 / Wayland Forwarding

# Wayland 转发
docker run -it --rm \
    -e WAYLAND_DISPLAY=$WAYLAND_DISPLAY \
    -e XDG_RUNTIME_DIR=/tmp/xdg \
    -v $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY:/tmp/xdg/$WAYLAND_DISPLAY \
    -v $XDG_RUNTIME_DIR/pulse:/tmp/xdg/pulse \
    --user $(id -u):$(id -g) \
    myqtapp

15.4 完整开发环境 / Complete Dev Environment

Docker Compose 多服务

# docker-compose.yml
version: "3.9"

services:
  # Qt 开发环境
  qt-dev:
    build:
      context: .
      dockerfile: Dockerfile.qt-dev
    volumes:
      - .:/app
      - /tmp/.X11-unix:/tmp/.X11-unix
      - $HOME/.Xauthority:/root/.Xauthority:ro
    environment:
      - DISPLAY=$DISPLAY
    network_mode: host
    stdin_open: true
    tty: true

  # GTK 开发环境
  gtk-dev:
    build:
      context: .
      dockerfile: Dockerfile.gtk-dev
    volumes:
      - .:/app
      - /tmp/.X11-unix:/tmp/.X11-unix
    environment:
      - DISPLAY=$DISPLAY
    network_mode: host
    stdin_open: true
    tty: true

  # 测试服务 (headless)
  test:
    build:
      context: .
      dockerfile: Dockerfile.test
    volumes:
      - .:/app
    environment:
      - QT_QPA_PLATFORM=offscreen
      - DISPLAY=

Qt 开发 Dockerfile

# Dockerfile.qt-dev
FROM ubuntu:24.04

ENV DEBIAN_FRONTEND=noninteractive
ENV QT_QPA_PLATFORM=xcb

RUN apt-get update && apt-get install -y \
    build-essential cmake pkg-config gdb \
    qt6-base-dev qt6-declarative-dev qt6-tools-dev \
    qt6-base-dev-tools qt6-l10n-tools \
    libgl1-mesa-dev \
    libxkbcommon-dev libxkbcommon-x11-dev \
    libxcb-cursor0 libxcb-cursor-dev \
    libfontconfig1-dev libfreetype6-dev \
    vim nano git curl \
    x11-apps \
    && rm -rf /var/lib/apt/lists/*

# 设置 Qt 环境
ENV CMAKE_PREFIX_PATH=/usr/lib/qt6
ENV QT_PLUGIN_PATH=/usr/lib/qt6/plugins
ENV QML2_IMPORT_PATH=/usr/lib/qt6/qml

WORKDIR /app
CMD ["bash"]

GTK 开发 Dockerfile

# Dockerfile.gtk-dev
FROM ubuntu:24.04

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update && apt-get install -y \
    build-essential meson ninja-build pkg-config \
    libgtk-4-dev libadwaita-1-dev \
    libglib2.0-dev libgirepository1.0-dev \
    python3 python3-pip python3-gi python3-gi-cairo \
    gir1.2-gtk-4.0 gir1.2-adw-1 \
    vim nano git \
    x11-apps \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /app
CMD ["bash"]

15.5 Headless 测试容器 / Headless Testing

# Dockerfile.test - 无头测试环境
FROM ubuntu:24.04

ENV DEBIAN_FRONTEND=noninteractive
ENV QT_QPA_PLATFORM=offscreen
ENV DISPLAY=

# 安装 Qt 测试依赖
RUN apt-get update && apt-get install -y \
    build-essential cmake pkg-config \
    qt6-base-dev qt6-tools-dev \
    libqt6test6 \
    xvfb \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /app
COPY . /app

# 构建并运行测试
RUN cmake -B build -DBUILD_TESTING=ON \
    && cmake --build build

CMD ["xvfb-run", "ctest", "--test-dir", "build", "--output-on-failure"]
# 运行测试
docker build -f Dockerfile.test -t myapp-test .
docker run --rm myapp-test

15.6 GPU 加速 / GPU Acceleration

# NVIDIA GPU 转发
docker run -it --rm \
    --gpus all \
    -e DISPLAY=$DISPLAY \
    -v /tmp/.X11-unix:/tmp/.X11-unix \
    -v $HOME/.Xauthority:/root/.Xauthority:ro \
    --net=host \
    myqtapp

# 通用 GPU 转发 (DRM/DRI)
docker run -it --rm \
    --device /dev/dri:/dev/dri \
    -e DISPLAY=$DISPLAY \
    -v /tmp/.X11-unix:/tmp/.X11-unix \
    myqtapp

# Mesa 3D (软件渲染回退)
docker run -it --rm \
    -e LIBGL_ALWAYS_SOFTWARE=1 \
    -e GALLIUM_DRIVER=llvmpipe \
    -e QT_QPA_PLATFORM=offscreen \
    myqtapp

15.7 CI/CD 集成 / CI/CD Integration

GitHub Actions

# .github/workflows/test.yml
name: Test GUI App

on: [push, pull_request]

jobs:
  test-qt:
    runs-on: ubuntu-latest
    container:
      image: ubuntu:24.04
    steps:
      - uses: actions/checkout@v4

      - name: Install dependencies
        run: |
          apt-get update
          apt-get install -y build-essential cmake \
            qt6-base-dev qt6-tools-dev libqt6test6

      - name: Build
        run: |
          cmake -B build -DBUILD_TESTING=ON
          cmake --build build

      - name: Test
        env:
          QT_QPA_PLATFORM: offscreen
        run: ctest --test-dir build --output-on-failure

  test-gtk:
    runs-on: ubuntu-latest
    container:
      image: ubuntu:24.04
    steps:
      - uses: actions/checkout@v4

      - name: Install dependencies
        run: |
          apt-get update
          apt-get install -y meson ninja-build \
            libgtk-4-dev libadwaita-1-dev

      - name: Build and Test
        env:
          GDK_BACKEND: offscreen
        run: |
          meson setup build
          meson test -C build

注意事项 / Important Notes

⚠️ X11 安全性 / X11 Security

xhost +local:docker 允许任何本地 Docker 容器访问 X Server。 生产环境应使用更安全的方式(如 Xephyr 或 VNC)。

xhost +local:docker allows any local Docker container to access X Server. Use Xephyr or VNC for production.

⚠️ 用户权限 / User Permissions

容器内的 UID/GID 应与宿主机匹配,避免文件权限问题。 Use --user $(id -u):$(id -g) for proper file permissions.

⚠️ offscreen 平台 / Offscreen Platform

Qt: QT_QPA_PLATFORM=offscreen GTK: GDK_BACKEND=offscreen 可以在无显示器环境中运行,但无法测试真实渲染。 Cannot test actual rendering with offscreen backend.


扩展阅读 / Further Reading

资源 / Resource链接 / Link
Docker GUI 教程https://github.com/mviereck/x11docker
Qt Docker 示例https://github.com/niclasr/docker-qt
Docker Compose 文档https://docs.docker.com/compose/

14 - UI 测试 | 16 - 最佳实践