linux-Docker那些奇奇怪怪的知识

"linux"

Posted by yangsir on December 9, 2025

“docker”

Docker的那些奇奇怪怪的知识

Docker-in-Docker问题

在docker容器中启动docker时,要有足够权限

1
2
3
4
5
6
#普通容器报错
failed to mount overlay: operation not permitted #overlay2 挂载失败
exec: "fuse-overlayfs": executable file not found #fuse-overlayfs 找不到

failed to create NAT chain DOCKER:
iptables: can't initialize iptables table `nat': Permission denied #iptables NAT 表创建失败

方案一:用宿主机 Docker + containerd

如果你只是想构建镜像、运行容器,可以在容器中安装 docker-cli,使用宿主机 docker socket

1
docker run -v /var/run/docker.sock:/var/run/docker.sock -ti centos bash

容器只是调用宿主机 Docker,不需要 docker daemon

方案二:要加足够权限

1
2
3
4
5
docker run -d \
  --privileged \
  --name mydocker \
  -v /var/lib/docker \
  docker:dind

主要作用参数:--privileged,表示开启了特权模式

什么是特权模式?

特权模式会让容器拥有所有 Linux Capabilities(内核能力)、直接访问宿主机的设备(/dev/*)、可以修改内核参数、管理 cgroups 等。

哪些命令在--privileged 容器里会直接影响宿主机?

  • iptables

    1
    2
    
    iptables -F
    iptables -t nat -A ...
    
  • 挂载(mount)某些文件系统

    1
    2
    
    mount -t overlay ...
    mount /dev/sda /mnt
    
  • 修改宿主机 sysctl 参数

    1
    
    sysctl -w net.ipv4.ip_forward=1
    
  • 直接访问宿主机设备(/dev)

    1
    2
    
    cat /dev/sda
    dd if=/dev/zero of=/dev/sda
    
  • 加载内核模块(modprobe)

    1
    
    modprobe br_netfilter
    

方案三:在 Kubernetes 里运行, 需要特权 Pod

1
2
securityContext:
  privileged: true

官方最佳实践(最小权限)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
docker run -d \
  --name dind \
  --privileged=false \
  --security-opt seccomp=unconfined \ #Docker 的默认 seccomp 禁掉了 clone3, mount, setns 等关键 syscalls
  --security-opt apparmor=unconfined \ #dockerd 无法正常启动 overlay2,更不能创建容器。
  --cap-add SYS_ADMIN \ #挂载 overlay2 文件系统(核心,Docker 必须)
  --cap-add NET_ADMIN \ #配置网桥、veth、iptables
  --cap-add NET_RAW \ #ping、ARP、网络底层
  --cap-add MKNOD \ #创建设备文件
  --cap-add SYS_MODULE \ #某些情况下加载内核模块(多数系统允许)
  --cap-add SYS_PTRACE \ #dockerd 某些监控功能需要
  --tmpfs /run \
  --tmpfs /var/run \
  -v dind-storage:/var/lib/docker \
  docker:dind

Docker 创建/挂载存储卷

Docker 容器本质是“无状态”的,一旦容器删除,容器内数据就会消失。为了实现数据持久化,就必须使用 Volume(卷)绑定挂载(Bind Mount)

创建Volume:Docker 官方推荐的持久化方式

1
docker volume create mydata #创建卷
1
docker volume ls #查看卷
1
2
3
4
5
6
docker volume inspect mydata #查看卷的详细信息
#类似输出
{
  "Mountpoint": "/var/lib/docker/volumes/mydata/_data"
}

容器删除后(docker rm -f),数据仍在 mydata 里。

Bind Mount:把宿主机目录挂进去容器

适合 开发环境需要直接操作宿主机文件 的场景

1
2
3
4
docker run -d \
  -v /opt/app/data:/data \
  --name app \
  busybox
  • /opt/app/data 是宿主机目录
  • /data 是容器内目录

适用于

  • 修改宿主机配置文件并让容器实时使用
  • 宿主机与容器共享日志
  • 持久化数据库数据到宿主机指定目录(生产环境也常用)

Docker资源限制

(在启动容器时,可以对以下资源进行限制)

限制内存

1
2
3
4
docker run -d \
  --memory=512m \ #容器可用的最大内存
  --memory-swap=512m \ #内存 + swap 总量
  nginx

限制 CPU 使用

1
2
3
docker run -d \
  --cpus=1.5 \ #最多使用 1.5 个 CPU 核心
  nginx

绑定指定 CPU 核心

1
2
3
docker run -d \
  --cpuset-cpus="0,1" \ #只能用 CPU 0 和 1
  nginx

限制进程数

1
2
3
docker run -d \
  --pids-limit=200 \
  nginx

限制磁盘 IO

1
2
3
4
docker run -d \
  --device-read-bps /dev/sda:10mb \
  --device-write-bps /dev/sda:5mb \
  nginx

对于已经启动的容器

凡是走 cgroup 的,大多能在线改;

凡是涉及 namespace / 启动参数的,必须重建容器

1
2
3
4
5
docker update \
  --cpus 2 \
  --memory 1g \
  --memory-swap 2g \
  容器名或ID

除此之外,端口映射,磁盘映射,网络模式不可进行在线修改