在 Docker 容器内使用 Docker:完整指南

本文介绍通过挂载宿主机Docker Socket,在容器内安装Docker CLI即可操作宿主机Docker Daemon,无需额外运行Daemon。涵盖原理、适用场景、环境准备、安装步骤、权限配置、验证方法、完整脚本及常见问题,强调安全注意事项。

作者:zhuge··预计阅读 28 分钟·5 阅读·0 评论
在 Docker 容器内使用 Docker:完整指南

你不需要在容器里再跑一个 Docker Daemon——通过挂载宿主机的 Docker Socket,容器内的 Docker CLI 可以直接调用宿主机的 Docker 守护进程,轻量、高效、零冗余。

适用场景

  • 在 CI/CD 容器(如 GitLab Runner、Jenkins Agent)中构建 Docker 镜像
  • 在开发容器(Dev Container)中进行容器化开发
  • 在沙箱容器中临时操作宿主机 Docker
  • 任何需要"容器内跑 Docker 命令"的场景

核心原理

很多人直觉上会想:"那我再在容器里装一个 Docker Engine 吧?"

不需要。 Docker 采用客户端-服务端架构:

┌──────────────────────────────────────────────────────────┐
│  宿主机                                                   │
│                                                          │
│  ┌────────────────────────────────────────────────────┐  │
│  │  Docker Daemon (dockerd)                            │  │
│  │  负责拉取镜像、创建容器、管理网络等                   │  │
│  └────────────────────────┬───────────────────────────┘  │
│                           │  Unix Socket                 │
│              /var/run/docker.sock                         │
└───────────────────────────┼──────────────────────────────┘
                            │ bind mount
┌───────────────────────────┼──────────────────────────────┐
│  容器内                     │                              │
│  ┌─────────────────────────▼──────────────────────────┐  │
│  │  Docker CLI(docker 命令)                          │  │
│  │  只是客户端,通过 socket 把请求发给宿主机 daemon      │  │
│  └────────────────────────────────────────────────────┘  │
│                                                          │
│  容器内所有 docker 操作,本质上都是在宿主机上执行          │
└──────────────────────────────────────────────────────────┘

关键点:Docker CLI 只是一个几百 KB 的命令行工具,不需要后台进程。 它通过 /var/run/docker.sock 与 Docker Daemon 通信。你只需要把这个 socket 文件挂进容器,再把 CLI 装进去就够了。


环境准备

宿主机的 Docker Compose 配置

在你的 Compose 文件中,确保以下两个关键配置:

services:
  dev:
    image: your-image:latest
    # 【关键1】使用 host 网络模式(让容器能访问宿主机网络)
    network_mode: host
    # 【关键2】挂载 Docker 套接字(让容器内能操作宿主机的 Docker)
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

network_mode: host 的原因:宿主机 Docker 创建的容器默认走宿主机网络栈。如果不用 host 模式,你的容器里虽然能看到这些容器,但网络拓扑会不同,端口映射关系也会混乱。开启后,localhost 的视角与宿主机一致。


第一步:确认挂载点

进入容器后,先确认 socket 文件已经存在:

ls -la /var/run/docker.sock

预期输出:

srw-rw---- 1 root root 0 Jul 16 03:50 /var/run/docker.sock

看到这个文件就说明挂载成功。srw- 开头的 Unix Socket 类型是正确的。


第二步:安装 Docker CLI

容器内有两种方式安装 Docker CLI:

方式 A:通过 Docker 官方 apt 源安装(推荐)

这个方式安装的 CLI 版本与宿主机高度一致,且同时获得 docker composedocker buildx 插件。

# 1. 安装基础依赖
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg

# 2. 添加 Docker 官方 GPG 密钥
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | \
  sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

# 3. 添加 Docker 官方 apt 源
echo "deb [arch=$(dpkg --print-architecture) \
  signed-by=/etc/apt/keyrings/docker.gpg] \
  https://download.docker.com/linux/debian \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# 4. 更新包索引并安装 docker-ce-cli(仅 CLI,不含 daemon)
sudo apt-get update
sudo apt-get install -y docker-ce-cli

安装完成后会同时得到三个包:

说明
docker-ce-cliDocker 主客户端(docker 命令)
docker-compose-plugin提供 docker compose 命令(V2 语法)
docker-buildx-plugin提供 docker buildx 命令(多平台构建)

方式 B:通过系统自带源安装(够用即可)

sudo apt-get update
sudo apt-get install -y docker.io

系统源的版本通常较旧,但 docker rundocker ps 等基础功能都能正常使用。如果不需要最新特性,这种方式更简单。


第三步:解决权限问题

3.1 当前状态

默认情况下,/var/run/docker.sock 的权限如下:

srw-rw---- 1 root root ... /var/run/docker.sock

只有 root 用户能直接访问。普通用户执行 docker ps 会报错:

Got permission denied while trying to connect to the Docker daemon socket

3.2 解决方案

方法一:修改 socket 所属组(推荐)

# 创建 docker 用户组(如果不存在)
sudo groupadd -f docker

# 将当前用户加入 docker 组
sudo usermod -aG docker $USER

# 修改 socket 文件所属组为 docker,权限设为 660
sudo chown root:docker /var/run/docker.sock
sudo chmod 660 /var/run/docker.sock

修改后确认:

ls -la /var/run/docker.sock
# 预期输出:srw-rw---- 1 root docker ... /var/run/docker.sock

660 权限的含义:owner(root)可读写,group(docker)可读写,others 无权限。加入 docker 组的用户即可直接访问。

方法二:当前 shell 立即生效

加入新组后,需要重新登录才能在当前终端生效:

newgrp docker

如果 newgrp 不方便,也可以在单条命令中使用:

sg docker -c "docker ps"

方法三:临时使用 sudo(立即可用)

在权限还没配好之前,随时可以用:

sudo docker ps
sudo docker run --rm hello-world

第四步:验证安装

4.1 查看版本

docker version

预期输出(展示 Client 与 Server 分别对应什么):

Client: Docker Engine - Community
 Version:           29.6.2                         ← 容器内装的 CLI 版本
 API version:       1.55
 ...

Server: Docker Engine - Community
 Engine:
  Version:          29.6.1                         ← 宿主机的 Docker 版本
  OS/Arch:           linux/amd64
 ...

Client 和 Server 版本可以有微小差异(29.6.2 vs 29.6.1),只要 API 版本兼容即可正常使用。

4.2 查看宿主机 Docker 信息

docker info --format "OS: {{.OperatingSystem}}
Arch: {{.Architecture}}
Kernel: {{.KernelVersion}}
Containers: {{.Containers}} total
Images: {{.Images}} total
CPUs: {{.NCPU}}"

你会看到宿主机的真实信息,而不是容器内的信息。

4.3 运行一个测试镜像

docker run --rm hello-world

如果看到:

Hello from Docker!
This message shows that your installation appears to be working correctly.

说明一切正常。

4.4 查看宿主机上的容器

docker ps -a

你会看到宿主机上所有的容器,包括你当前所在的容器。


完整安装脚本

把以下脚本在容器内执行,即可一键完成全部配置:

#!/usr/bin/env bash
set -e

echo "=== 检查 Docker Socket ==="
if [ ! -S /var/run/docker.sock ]; then
  echo "错误:/var/run/docker.sock 不存在,请检查挂载配置"
  exit 1
fi
echo "Socket 存在: $(ls -la /var/run/docker.sock)"

echo ""
echo "=== 安装 Docker CLI ==="
sudo apt-get update -qq
sudo apt-get install -y ca-certificates curl gnupg

sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | \
  sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
  https://download.docker.com/linux/debian \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt-get update -qq
sudo apt-get install -y docker-ce-cli

echo ""
echo "=== 配置权限 ==="
sudo groupadd -f docker
sudo usermod -aG docker $USER
sudo chown root:docker /var/run/docker.sock
sudo chmod 660 /var/run/docker.sock

echo ""
echo "=== 验证安装 ==="
sudo docker version --format 'Client: {{.Client.Version}} | Server: {{.Server.Version}}'

echo ""
echo "=== 安装完成!==="
echo "执行以下命令使 docker 组生效:"
echo "  newgrp docker"
echo ""
echo "然后就可以直接使用 docker 命令了:"
echo "  docker ps"
echo "  docker run --rm hello-world"

常见问题

Q1:为什么不能直接 apt install docker 而不加 -ce

可以,但系统源里的 docker.io 版本较旧,且默认会附带 Docker Daemon(dockerd),体积更大、启动更慢。而我们只需要 CLI,用 docker-ce-cli 更精准。

Q2:容器内创建的容器,宿主机的 docker ps 能看到吗?

能。 因为容器内和宿主机操作的是同一个 Docker Daemon,创建的容器、网络、卷都是宿主机级的,完全共享。

Q3:容器内 localhost:8080 能访问到宿主机上的容器吗?

如果宿主机上的容器使用了端口映射(如 -p 8080:80),那么在容器内访问 localhost:8080 是可以的,因为 network_mode: host 让容器和宿主机共享网络栈。

Q4:docker compose 能用吗?

装好 docker-ce-cli 后,docker-compose-plugin 会一并安装,docker compose(V2 语法,带空格的版本)可以直接使用。

Q5:如果容器内没有 newgrp 命令怎么办?

sg 替代:

sg docker -c "docker ps"

Q6:Docker Socket 权限改回 root:root 了怎么办?

如果容器重启后 socket 权限被重置,可以在容器启动脚本中自动修复:

sudo chown root:docker /var/run/docker.sock 2>/dev/null || true
sudo chmod 660 /var/run/docker.sock 2>/dev/null || true

Q7:这种方法支持 Docker 桌面版(Mac/Windows)吗?

不支持。 Docker 桌面版使用虚拟机,没有直接暴露 /var/run/docker.sock。请使用 Docker Engine 的 Linux 发行版环境。


安全提示

持有 Docker Socket 的访问权限 ≈ 拥有宿主机的 root 权限:

  • 可以通过 docker run -v /:/host ... 挂载宿主机根目录
  • 可以访问宿主机上的所有网络和进程
  • 可以执行任意特权操作

因此:

✅ 建议❌ 避免
在可信环境(个人开发机、内部 CI)中使用不要在生产环境随意暴露 Docker Socket
使用专用的 Docker 用户组管理权限不要将 Socket 挂载给不受信任的用户
容器网络尽量使用 host 模式时评估安全风险不要把 Docker Socket 挂载到公共镜像中

总结

步骤操作一句话
1挂载 /var/run/docker.sock让容器能"看到"宿主机的 Docker
2安装 docker-ce-cli装一个 Docker 客户端,不需要 daemon
3将用户加入 docker解决 socket 权限问题
4docker ps 验证看到宿主机容器列表即为成功

容器内没有 Docker Daemon,容器内也不需要 Docker Daemon。宿主机上的那个才是真的,容器内的 CLI 只是它的远程控制面板。

相关文章

评论

加载中...