4.《Docker 从入门到实践》数据挂载与网络配置

1 数据管理

1.1 数据卷

数据卷 是一个可供一个或多个容器使用的特殊目录

  • 数据卷 绕过了 UnionFS,可以在容器之间共享和重用
  • 数据卷 的修改会立马生效;对 数据卷 的更新,不会影响镜像
  • 数据卷 默认会一直存在,即使容器被删除(类似于 mount 命令)

数据卷的常见操作:

docker volume create my-vol # 创建一个数据卷
docker volume ls # 查看所有的数据卷
docker volume inspect my-vol # 查看指定数据卷的信息

# 创建一个名为`web`的容器,并加载`数据卷`到容器的`/usr/share/nginx/html`目录
docker run -d -P \
    --name web \
    # -v my-vol:/usr/share/nginx/html \
    --mount source=my-vol,target=/usr/share/nginx/html \
    nginx:alpine

docker volume rm my-vol # 删除一个数据卷
docker volume prune # 批量清理无主的数据卷

1.2 挂载主机目录

挂载一个主机目录:

docker run -d -P \
    --name web \
    # -v /src/webapp:/usr/share/nginx/html \
    --mount type=bind,source=/src/webapp,target=/usr/share/nginx/html \
    nginx:alpine
  • 本地目录的路径必须是绝对路径,本地目录不存在时以上命令会报错
  • 挂载目录的默认权限是 读写,用户可以通过参数 readonly 指定为 只读
  • 使用 docker inspect 命令可以查看容器的挂载目录(”Mounts“下的内容)

--mount命令也支持挂载单个文件到容器中:

docker run --rm -it \
   # -v $HOME/.bash_history:/root/.bash_history \
   --mount type=bind,source=$HOME/.bash_history,target=/root/.bash_history \
   ubuntu:18.04 \
   bash

root@2affd44b4667:/# history
1  ls
2  diskutil list

2 使用网络

Docker 允许通过外部访问容器或容器互联的方式来提供网络服务

2.1 容器端口映射

容器通过 -P-p 参数来指定端口映射,以方便从外部访问应用

常见端口映射命令:

docker run -d -p 80:80 nginx:alpine # 端口映射80:80
docker run -d -p 127.0.0.1:80:80 nginx:alpine # 端口映射指定ip
docker run -d -p 127.0.0.1::80 nginx:alpine # 自动分配外部端口

docker run -d -p 127.0.0.1:80:80/udp nginx:alpine # 指定udp端口
docker port fa 80 # 查看当前映射的端口配置
docker run -d -p 80:80 -p 443:443 nginx:alpine # 绑定多个端口

2.2 容器互联

使用 --link 参数可以实现容器互联,但现在更建议荐通过 Docker 网络来连接多个容器

通过自定义的 Docker 网络实现容器互联:

docker network create -d bridge my-net # 创建一个新的Docker网络

# 运行两个容器并同时连接到新建的 `my-net` 网络
docker run -it --rm --name busybox1 --network my-net busybox sh
docker run -it --rm --name busybox2 --network my-net busybox sh

# 在 `busybox1` 容器输入以下命令来证明容器实现了互联
ping busybox2
# 同理在 `busybox2` 容器执行 `ping busybox1`,也会成功连接到
# 这样 `busybox1` 容器和 `busybox2` 容器建立了互联关系
  • -d 参数指定 Docker 网络类型,比如 bridge overlay
  • 其中 overlay 网络类型用于 Swarm mode
  • 多个容器之间需要互相连接,推荐使用 Docker Compose

2.3 配置DNS

在容器中使用 mount 命令可以看到挂载信息:

$ mount
/dev/disk/by-uuid/1fec...ebdf on /etc/hostname type ext4 ...
/dev/disk/by-uuid/1fec...ebdf on /etc/hosts type ext4 ...
tmpfs on /etc/resolv.conf type tmpfs ...
  • 以上三个配置文件的挂载,使得宿主 DNS 信息更新后,容器的 DNS 配置可以直接通过 /etc/resolv.conf 文件立刻得到更新

更新 /etc/docker/daemon.json 文件,可以实现全部容器的DNS配置:

{
  "dns" : [
    "114.114.114.114",
    "8.8.8.8"
  ]
}

使用以下命令验证 DNS 配置是否生效:

docker run -it --rm ubuntu:18.04 cat etc/resolv.conf

单独容器的 DNS 相关配置:

  • 通过参数 -h--hostname 配置单独容器的主机名(该主机名仅在容器内部生效)
  • 通过参数--dns来单独添加 DNS 服务器,解析不在 /etc/hosts 中的主机名
  • 通过参数--dns-search设定搜索域;当设定搜索域为 .example.com 并搜索一个名为 host 的主机时,DNS 不仅搜索 host,还会搜索 host.example.com

3 高级网络配置

3.1 配置网桥

Docker 服务默认会创建一个 docker0 网桥(其上有一个 docker0 内部接口),它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络

  • 参数--bip=CIDR 设定 docker0 的掩码,例如 192.168.1.5/24
  • 参数--mtu=BYTES 设定容器网络中的 MTU(接口允许接收的最大传输单元)
  • Docker 网桥作为一种 Linux 网桥,可以使用 brctl show 来查看网桥和端口信息
  • 本地主机上 docker0 接口的 IP ,会作为所有容器的默认网关

除了默认网桥,还可用-b BRIDGE--bridge=BRIDGE 指定容器挂载的网桥:

sudo systemctl stop docker # 停止docker访问
sudo ip link set dev docker0 down # 停止网桥
sudo brctl delbr docker0 # 删除旧的网桥

# 创建一个网桥 `bridge0`
sudo brctl addbr bridge0
sudo ip addr add 192.168.5.1/24 dev bridge0
sudo ip link set dev bridge0 up

ip addr show bridge0 # 查看确认

将新创建的网桥配置docker的默认网桥:

# 在配置文件 `/etc/docker/daemon.json` 中添加如下内容
{
"bridge": "bridge0",
}

3.2 容器访问控制

容器的访问控制,主要通过 Linux 上的 iptables 防火墙来进行管理和实现

容器要想访问外部网络,需要本地系统的转发支持:

  • sysctl net.ipv4.ip_forward 查看转发设置(0表示关闭转发)
  • sysctl -w net.ipv4.ip_forward=1 手动开启转发
  • 启动 Docker 服务时设定 --ip-forward=true,实现自动开启转发

容器间相互访问的两个条件:网络互通+ iptables 防火墙允许

  • 默认情况下,同容器之间是允许网络互通的(icc=true
  • 在Docker 访问启动时,可以手动关闭网络访问:--icc=false
  • 也可以在/etc/docker/daemon.json 文件中配置 {"icc": false} 来关闭
  • 如果手动指定 --iptables=false 则不会添加 iptables 规则
  • 同时使用 icc=false --iptables=true 参数来实现网络访问的控制
  • 关闭网络访问后,还可以通过 --link 选项来访问容器的开放端口

3.3 配置网络代理

配置网络代理的3个常见场景:

  1. 为 Docker 服务配置网络代理:在配置文件中添加相关环境变量后重启 Docker 服务
# 编辑/etc/systemd/system/docker.service.d/http-proxy.conf
[Service]
Environment="HTTP_PROXY=http://proxy.example.com:8080/"
Environment="HTTPS_PROXY=http://proxy.example.com:8080/"
Environment="NO_PROXY=localhost,127.0.0.1,.example.com"

# 重启 Docker 服务
sudo systemctl daemon-reload
sudo systemctl restart docker
  1. 为 Docker 容器配置网络代理:更改 docker 客户端配置,或者指定环境变量(--env)
# ~/.docker/config.json
{
 "proxies":
 {
   "default":
   {
     "httpProxy": "http://proxy.example.com:8080/",
     "httpsProxy": "http://proxy.example.com:8080/",
     "noProxy": "localhost,127.0.0.1,.example.com"
   }
 }
}

# 运行 "docker run" 命令时,指定相关环境变量
docker run --env HTTP_PROXY="http://proxy.example.com:8080/"
  1. 为 docker build 过程设置网络代理:在docker buildDockerfile中指定环境变量
# 使用 "--build-arg" 指定 "docker build" 的相关环境变量
docker build \
    --build-arg "HTTP_PROXY=http://proxy.example.com:8080/" \
    --build-arg "HTTPS_PROXY=http://proxy.example.com:8080/" \
    --build-arg "NO_PROXY=localhost,127.0.0.1,.example.com" .

# 在 Dockerfile 中指定相关环境变量
ENV HTTP_PROXY="http://proxy.example.com:8080/"

3.4 其他网络配置

容器的临时网络配置:

  • Docker 1.2.0 开始支持在运行中的容器里编辑配置文件
  • 配置文件主要包括 /etc/hosts, /etc/hostname/etc/resolv.conf
  • 这些修改是临时的,只在运行的容器中保留,也不会被docker commit 提交

实例:创建一对 peer 接口,实现两个容器的点对点连接

往年同期文章