努力
加油

在CentOS或Ubuntu系统中如何隔离部署两个Docker环境用于开发和测试?

在 CentOS 或 Ubuntu 上隔离部署两套独立的 Docker 环境,核心思路其实不是“装两个 Docker 守护进程”(那样太折腾且容易冲突),而是利用 Docker 的命名空间(Namespaces)和 cgroups 资源控制,结合 不同的 Socket 路径、数据目录和端口映射 来实现逻辑上的完全隔离。

简单来说,我们要跑两个 dockerd 实例,或者更优雅地——使用 Docker-in-Docker (DinD) 配合不同的上下文,但最稳妥、生产级常用的方案是:通过自定义 daemon.json 启动第二个 Docker 守护进程,绑定不同的 Unix Socket 和数据存储路径。

以下是具体操作步骤,以 Ubuntu 22.04 / CentOS Stream 9 为例:


一、 核心原理

默认情况下,Docker 使用 /var/run/docker.sock 作为通信接口,镜像和容器数据存放在 /var/lib/docker。
要隔离两套环境,我们需要:

  1. 第二套 Docker 守护进程:监听不同的 socket 文件(如 /var/run/docker-test.sock)。
  2. 独立的数据目录:避免镜像、容器、卷互相污染。
  3. 独立的网络命名空间:防止 IP 冲突。
  4. CLI 客户端切换:通过 DOCKER_HOST 环境变量或 Docker Context 来切换使用哪一套环境。

二、 详细部署步骤

第一步:安装基础 Docker(用于开发环境)

假设你已经安装了标准的 Docker CE,这将成为你的 Dev 环境。

# Ubuntu/Debian
sudo apt update
sudo apt install -y docker.io

# CentOS/RHEL
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install -y docker-ce docker-ce-cli containerd.io

# 启动并设为开机自启
sudo systemctl enable --now docker

此时,docker ps 看到的是 Dev 环境的容器。


第二步:创建测试环境(Test Environment)

我们不再安装另一个 Docker 软件包,而是手动启动一个额外的 dockerd 实例。

1. 创建独立的数据目录和配置
# 创建测试环境的专用目录
sudo mkdir -p /opt/docker-test/data
sudo mkdir -p /etc/docker-test

# 生成测试环境的 daemon.json
cat > /etc/docker-test/daemon.json <<EOF
{
  "data-root": "/opt/docker-test/data",
  "exec-root": "/opt/docker-test/exec",
  "log-driver": "json-file",
  "storage-driver": "overlay2"
}
EOF

⚠️ 注意:data-root 是关键,它决定了镜像、容器层、卷都存哪里,彻底隔离文件系统。

2. 编写 systemd 服务文件(推荐方式,便于管理)

创建 /etc/systemd/system/docker-test.service:

[Unit]
Description=Docker Test Environment Daemon
Requires=docker.socket
After=network.target

[Service]
Type=notify
ExecStart=/usr/bin/dockerd 
  --config-file=/etc/docker-test/daemon.json 
  --host=unix:///var/run/docker-test.sock 
  --containerd=/run/containerd-test/containerd.sock
ExecReload=/bin/kill -s HUP $MAINPID
Restart=always
RestartSec=5
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TimeoutStopSec=0
KillMode=process
HasDirectories=/opt/docker-test/data
HasDirectories=/opt/docker-test/exec

[Install]
WantedBy=multi-user.target

💡 说明:

  • --host=unix:///var/run/docker-test.sock:指定新的 socket 路径,避免与主 Docker 冲突。
  • --containerd=...:为 test 环境单独运行一个 containerd 实例,避免共享状态导致的问题。
3. 启动测试环境
# 重新加载 systemd
sudo systemctl daemon-reload

# 启动测试环境的 Docker
sudo systemctl enable --now docker-test

# 检查是否正常运行
sudo systemctl status docker-test

验证新 socket 是否存在:

ls -l /var/run/docker-test.sock

第三步:切换和使用两套环境

现在你有两套 Docker 环境:

  • Dev 环境:默认,使用 /var/run/docker.sock
  • Test 环境:使用 /var/run/docker-test.sock
方法 1:使用 DOCKER_HOST 环境变量(临时切换)
# 查看 dev 环境容器
docker ps

# 查看 test 环境容器
DOCKER_HOST=unix:///var/run/docker-test.sock docker ps

# 在 test 环境中拉取镜像
DOCKER_HOST=unix:///var/run/docker-test.sock docker pull nginx
方法 2:使用 Docker Context(推荐,更优雅)

Docker CLI 支持 Context,可以像切换数据库连接一样切换环境。

# 创建 test context
docker context create test-env 
  --description "Test Environment" 
  --docker-host unix:///var/run/docker-test.sock

# 查看所有 context
docker context ls

# 切换到 test 环境
docker context use test-env

# 现在直接运行 docker 命令,默认就是 test 环境
docker ps

# 切回 dev 环境
docker context use default

第四步:网络隔离(可选但重要)

如果两个环境中的容器使用了相同的内部 IP 段(如 172.17.0.0/16),虽然它们在不同 network namespace 中不会冲突,但如果你希望完全隔离网络策略,可以为 test 环境指定不同的 bridge 网段。

在 /etc/docker-test/daemon.json 中添加:

{
  "bip": "172.20.0.1/16",
  "default-address-pools": [
    {
      "base": "172.20.0.0/16",
      "size": 24
    }
  ]
}

然后重启 docker-test 服务:

sudo systemctl restart docker-test

这样,test 环境的容器将使用 172.20.x.x 网段,而 dev 环境保持默认的 172.17.x.x,从网络层面也实现了隔离。


三、 常见问题与注意事项

1. 权限问题

确保运行 docker-test 服务的用户有权限访问 /opt/docker-test/data 和 socket 文件。通常 systemd 会以 root 运行,所以没问题。但如果用非 root 用户操作,需确保该用户属于 docker 组,并且对 test socket 有读权限。

sudo chmod 660 /var/run/docker-test.sock
sudo chown root:docker /var/run/docker-test.sock

2. 资源限制

两个 Docker 守护进程会竞争 CPU、内存和磁盘 I/O。建议在 systemd 服务文件中添加资源限制:

[Service]
MemoryMax=4G
CPUQuota=80%

3. 为什么不用 Portainer 或其他 UI?

Portainer 等工具可以管理多个 Docker 主机,但它们本质上是远程 API 调用。对于本地双环境隔离,上述方案更轻量、更安全,且不依赖第三方 Web 服务。

4. 性能影响

由于是两个独立的 dockerd + containerd 实例,系统开销会比单实例略高。但在开发和测试场景下,这种开销完全可以接受。


四、 替代方案对比

方案 优点 缺点
双 dockerd 实例(本文方案) 完全隔离,灵活,可分别配置网络、存储、插件 配置稍复杂,需手动管理服务
Docker-in-Docker (DinD) 适合 CI/CD 流水线,嵌套容器 性能损耗大,特权模式要求,不适合日常开发
Podman / Rootless Docker 无需守护进程,更安全 生态兼容性略差,部分企业级功能缺失
虚拟机/容器化整个 Docker 最强隔离 资源消耗极大,运维复杂度高

总结

在 Linux 上隔离两套 Docker 环境,最务实的做法是:

  1. 保留默认 Docker 作为 Dev 环境。
  2. 通过 systemd 启动第二个 dockerd 实例,绑定不同 socket 和数据目录。
  3. 使用 docker context 或 DOCKER_HOST 变量切换环境。

这种方式既保证了开发和测试环境的完全独立(镜像、容器、网络、数据互不干扰),又避免了重装系统或虚拟机的沉重开销,是工程师日常工作中非常实用的技巧。