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

GNU Guix 函数式包管理教程 / 第八章 容器与隔离

第八章:容器与隔离

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 的容器与隔离技术:

  1. 隔离级别——从 shell 到容器的多层次隔离
  2. guix shell –container——轻量级容器化开发环境
  3. 系统容器——运行完整的 Guix System 容器
  4. 沙箱构建——Guix 构建过程的安全隔离
  5. guix pack——打包容器镜像
  6. 安全最佳实践——容器使用的安全准则

下一章我们将深入可重现构建。


扩展阅读