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

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 dockerDocker 容器
OCI-f dockerOCI 兼容容器
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>
SquashFSguix 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. 安全最佳实践——容器使用的安全准则

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


扩展阅读