第八章 容器与隔离
第八章:容器与隔离
8.1 容器概述
Guix 提供了多种隔离机制,从轻量的环境隔离到完整的操作系统级容器。这些功能基于 Linux 内核的命名空间(namespaces)和 cgroups 技术实现。
8.1.1 隔离级别对比
| 工具 | 隔离程度 | 用途 |
|---|---|---|
guix shell | 无隔离 | 临时添加包到 PATH |
guix shell --pure | 轻度隔离 | 排除系统包的影响 |
guix shell --container | 强隔离 | 完整的文件系统和进程隔离 |
guix container | 系统级隔离 | 运行完整操作系统环境 |
guix pack -f docker | 镜像化 | 生成 Docker/OCI 镜像 |
8.1.2 Linux 容器技术基础
| 命名空间 | 隔离内容 |
|---|---|
| PID | 进程 ID,容器内进程看不到宿主进程 |
| Mount | 文件系统挂载点 |
| Network | 网络接口和路由 |
| UTS | 主机名 |
| IPC | 进程间通信 |
| User | 用户和组 ID |
8.2 guix shell --container
8.2.1 基本用法
# 创建容器化环境
guix shell --container python python-numpy -- python3
# 指定工作目录
guix shell --container --share=$HOME/project python -- \
python3 main.py
# 带网络访问的容器
guix shell --container --network python python-requests -- \
python3 -c "import requests; print(requests.get('https://httpbin.org/get').status_code)"
8.2.2 容器选项详解
| 选项 | 说明 |
|---|---|
--container / -C | 启用容器隔离 |
--network / -N | 允许网络访问 |
--share=PATH | 将宿主机路径挂载到容器(读写) |
--expose=PATH | 将宿主机路径挂载到容器(只读) |
--no-cwd | 不自动挂载当前目录 |
--user=USER | 指定容器内用户 |
--emulate-fhs | 模拟 FHS 目录结构 |
8.2.3 文件系统映射
# 共享当前目录(读写)
guix shell --container --share=$(pwd) gcc make -- make
# 只读挂载数据目录
guix shell --container --expose=/data/readonly python -- \
python3 analyze.py /data/readonly/input.csv
# 挂载到不同路径
guix shell --container \
--share=$HOME/code:/workspace \
--share=$HOME/data:/data \
python -- python3 /workspace/script.py
容器内外文件系统映射:
宿主机 容器内
─────────────────────────────────────
$HOME/code/ → /workspace/
$HOME/data/ → /data/
$HOME/project/ → /home/user/project/ (默认)
/gnu/store/ → /gnu/store/ (共享,只读)
8.2.4 容器隔离的实际场景
场景一:安全运行不可信代码
# 隔离环境运行学生提交的代码
guix shell --container --no-cwd \
--expose=$HOME/submissions:/submissions \
python -- \
python3 /submissions/student_homework.py
场景二:干净的构建环境
# 确保构建不依赖系统环境
guix shell --container gcc make autoconf automake pkg-config -- \
bash -c "./configure --prefix=/tmp/build && make && make install"
场景三:测试不同版本
# Python 3.11 环境
guix shell --container --manifest=python311.scm -- python3 --version
# Python 3.12 环境
guix shell --container --manifest=python312.scm -- python3 --version
8.3 guix container 命令
8.3.1 运行容器
# 从包集合创建并运行容器
guix container exec $(guix system container config.scm) -- \
/run/current-system/profile/bin/bash
8.3.2 系统容器
Guix 可以运行一个完整的 Guix System 作为容器:
;; container-config.scm
(use-modules (gnu)
(gnu system linux-container))
(operating-system
(host-name "container")
(timezone "Asia/Shanghai")
(locale "zh_CN.utf8")
;; 容器不需要 bootloader
(bootloader (bootloader-configuration
(bootloader grub-bootloader)
(targets '("/dev/null"))))
(file-systems
(cons* (file-system
(device "tmpfs")
(mount-point "/")
(type "tmpfs"))
%base-file-systems))
(packages (list vim git python))
(services
(cons* (service openssh-service-type
(openssh-configuration
(port-number 2222)))
%base-services)))
# 构建容器系统
guix system container container-config.scm
# 输出一个可执行脚本路径
# 运行容器
sudo /gnu/store/...-run-container
# 在另一个终端查看
sudo guix container exec <PID> bash
8.4 沙箱构建
8.4.1 Guix 构建的沙箱特性
Guix 的每次构建都在沙箱中执行,这是可重现构建的基础:
沙箱特性:
├── 网络隔离(默认无网络)
├── 文件系统隔离(只能访问 /gnu/store 和构建目录)
├── 无 HOME 目录
├── 固定的 UID/GID
├── 时间固定(epoch 时间)
└── 环境变量清理
8.4.2 构建沙箱配置
# 查看构建日志
guix build vim -v 3
# 构建时允许网络(用于下载依赖,不推荐)
guix build my-package --no-grafts --substitute-urls=''
# 调试构建失败
guix build my-package --keep-failed
# 构建失败的目录会保留在 /tmp/guix-build-*
8.4.3 验证可重现性
# 在不同时间构建同一包
guix build vim --no-substitutes
# 记录 store 路径
# 数周后再次构建
guix build vim --no-substitutes
# 路径应该完全相同(如果包定义未改变)
8.5 guix pack — 打包容器
8.5.1 打包为 Docker 镜像
# 生成 Docker 镜像
guix pack -f docker -o my-image.tar.gz \
python python-flask python-requests
# 加载并运行
docker load < my-image.tar.gz
docker run --rm -it <image-id> python3
8.5.2 打包为 OCI 镜像
# 生成 OCI 兼容镜像
guix pack -f docker --entry-point=/bin/python3 \
-o myapp.tar.gz python python-flask
8.5.3 使用 Manifest 打包
;; manifest.scm
(specifications->manifest
'("python"
"python-flask"
"python-gunicorn"
"openssl"))
guix pack -f docker \
--entry-point=/bin/gunicorn \
--manifest=manifest.scm \
-o webapp.tar.gz
8.5.4 打包格式对比
| 格式 | 选项 | 用途 |
|---|---|---|
| Docker | -f docker | Docker 容器 |
| OCI | -f docker | OCI 兼容容器 |
| SquashFS | -f squashfs | 只读文件系统镜像 |
| tarball | -f tarball | 压缩包(可解压使用) |
| self-contained | --relocatable | 可重定位的自包含包 |
8.6 网络隔离与配置
8.6.1 容器网络模式
# 无网络(默认)
guix shell --container python -- python3
# 共享宿主网络
guix shell --container --network python -- python3
# 注意:Guix 容器不支持自定义网络命名空间
# 如需复杂网络配置,建议使用 Docker
8.6.2 端口映射
Guix 原生容器的网络功能相对简单。如需端口映射等高级功能:
# 方法一:使用 guix pack + Docker
guix pack -f docker python python-flask -o webapp.tar.gz
docker load < webapp.tar.gz
docker run -p 8080:5000 <image-id>
# 方法二:使用系统容器 + 共享网络
# 系统容器默认共享宿主网络
8.7 存储与卷管理
8.7.1 持久化数据
# 挂载数据目录
guix shell --container \
--share=/data/postgres:/var/lib/postgresql \
postgresql -- \
pg_ctl -D /var/lib/postgresql/data start
8.7.2 构建缓存
# 容器内构建时共享缓存
guix shell --container \
--share=$HOME/.cache:/home/user/.cache \
--share=$(pwd):/workspace \
gcc make -- \
bash -c "cd /workspace && make"
8.8 安全考虑
8.8.1 容器安全最佳实践
| 实践 | 说明 |
|---|---|
| 最小权限 | 只暴露必要的路径和权限 |
| 只读挂载 | 使用 --expose 而非 --share |
| 无网络 | 默认不使用 --network |
| 专用用户 | 使用 --user 指定非 root 用户 |
| 资源限制 | 配合 cgroups 限制 CPU 和内存 |
8.8.2 容器 vs 虚拟机
| 特性 | 容器 | 虚拟机 |
|---|---|---|
| 启动速度 | 秒级 | 分钟级 |
| 资源开销 | 极低 | 较高 |
| 隔离程度 | 共享内核 | 完全隔离 |
| 安全性 | 较弱 | 较强 |
| 适用场景 | 构建环境、开发测试 | 生产隔离、多租户 |
⚠️ 注意:容器共享宿主内核,隔离性不如虚拟机。不要在容器中运行不受信任的需要 root 权限的程序。
8.9 开发工作流中的容器
8.9.1 项目目录中的容器化开发
# 项目结构
myproject/
├── manifest.scm # 依赖声明
├── .guix-container # 容器配置(可选)
└── src/
# manifest.scm
(specifications->manifest
'("gcc-toolchain"
"cmake"
"pkg-config"
"python"
"boost"))
# 一键进入容器化开发环境
cd myproject
guix shell --container \
--share=$(pwd):/project \
--manifest=manifest.scm -- \
bash -c "cd /project && mkdir -p build && cd build && cmake .. && make"
8.9.2 VS Code / 编辑器集成
# 启动容器化环境,共享编辑器所需路径
guix shell --container \
--share=$(pwd) \
--share=$HOME/.vscode-server \
--share=/tmp/.X11-unix \
gcc clangd -- \
bash
# 在容器内启动编辑器或语言服务器
8.10 容器操作速查表
| 操作 | 命令 |
|---|---|
| 基本容器 | guix shell -C <packages> |
| 带网络容器 | guix shell -C -N <packages> |
| 共享目录 | guix shell -C --share=PATH |
| 只读挂载 | guix shell -C --expose=PATH |
| Docker 镜像 | guix pack -f docker <packages> |
| SquashFS | guix pack -f squashfs <packages> |
| 系统容器 | guix system container config.scm |
| 调试构建 | guix build pkg --keep-failed |
8.11 总结
本章介绍了 Guix 的容器与隔离技术:
- 隔离级别——从 shell 到容器的多层次隔离
- guix shell –container——轻量级容器化开发环境
- 系统容器——运行完整的 Guix System 容器
- 沙箱构建——Guix 构建过程的安全隔离
- guix pack——打包容器镜像
- 安全最佳实践——容器使用的安全准则
下一章我们将深入可重现构建。