Docker 用户级指南 第二弹

正文索引 [隐藏]

一、exec 解决终端卡死问题(垃圾 attach 毁我青春)

之前进入一个 up 的 container 时都是用的 attach,来来回顾一下

docker attach [id]

然后。。。哦吼,终端根本起不来,直接死掉:

1566372792250

可能是因为别的管理员建容器时一些神奇的操作,导致终端本身就已经被卡住,这样 attach 进去直接卡死。。。

解决方案就是使用 exec,这个命令是在容器内重新启动一个终端,注意这个得和 run 一样要加 -it

docker exec -it d1d /bin/sh
# -i: 以交互模式运行容器
# -t: 为容器重新分配一个伪输入终端

1566373039660

搞定,下面总结对比一下 exec 和 attach 之间的差异:

exec:容器内重新启动一个终端,exit 退出时不会导致容器 exit

attach:直接进入上一次进入容器时的终端,exit 退出时导致容器 exit,想要不 exit 需要使用 Ctrl + P + Q

so,以后直接用 exec 叭,别用 attach 了(手动捂脸)

二、docker 容器通信

这部分主要一下 container 和外界、container 和 container 间的通信问题

1. container 网络状态 与 通信简介

首先要对 container 的网络状态有一个宏观的了解:

和虚拟机类似, docker container 可以有以下 5 种 网络模式:

  • none:不设置网络,相当于容器内没有配置网卡,用户可以手动配置
  • host:与宿主机共享网络,此时容器没有使用网络的 namespace,宿主机的所有设备,如Dbus会暴露到容器中,因此存在安全隐患。
  • bridge:默认设置。此时docker引擎会创建一个veth对,一端连接到容器实例并命名为eth0,另一端连接到指定的网桥中(比如docker0),因此同在一个主机的容器实例由于连接在同一个网桥,所处网端 172.17.0.0/16
  • container:指定与某个容器实例共享网络
  • 自定义:使用自定义网络,可以使用docker network create创建,并且默认支持多种网络驱动,用户可以自由创建桥接网络或者overlay网络

配置示例:

docker run -net=none -it ubuntu
docker run -net=host -it ubuntu
docker run -it ubuntu
docker run -net=container:[container_name|container_id] -it ubuntu

最最最常用的当然是默认设置咯,理解一下桥接模式下 container 的网络状态:

1566981202560

图源戳这里

桥接模式网络配置步骤(自动):

  1. Docker server 启动时,在主机上创建 docker0 (虚拟网桥)

    1566981599965

  2. 此主机上启动的 Docker container 连接到 docker0

    虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。

  3. container 连接到 docker0 的同时会创建了一对 veth pair 接口。这对接口一端在容器内,即 eth0;另一端在本地并被挂载到 docker0 网桥,名称以 veth 开头。

    1566981616118

    当数据包发送到一个接口时,另外一个接口也可以收到相同的数据包,通过这种方式,主机可以跟容器通信,容器之间也可以相互通信。

  4. 分配 IP ,从 RFC1918 所定义的私有 IP 网段中,选择一个和宿主机不同的IP地址和子网分配给 docker0,连接到 docker0 的容器就从这个子网中选择一个未占用的 IP 使用。

    如一般 Docker 会使用 172.17.0.0/16 这个网段,并将 172.17.42.1/16 分配给 docker0 网桥(在主机上使用 ifconfig 命令是可以看到 docker0 的,可以认为它是网桥的管理接口,在宿主机上作为一块虚拟网卡使用)

1566981760799

上图是张 container 的 ifconfig 回显

2. 端口绑定实现 container 和外界的通信

开启端口映射所需参数

-p: 指定端口进行映射
-P: 随机映射一个端口

端口映射格式

ip:hostport:containerport
ip::containerport
hostport:container

举例:

# 将 host 的 8080 口映射到 container 的 80 口
docker run -p 8080:80/server -d -it server

# 多次使用多次绑定
docker run -p 8000:80 -p 2200:22 -d -it server

1566909461121

我们再进入容器瞅瞅看看生效没,使用 python simplehttpserver 模块简单搭一个网站,放到 container 的 80 口:

1566909511857

用外界浏览器看看:

1566909576136

OK,完美。

3. 宿主机 iptables 流量转发实现 container 和外界的通信

为什么会出现这种蛋疼的操作,因为 -p 端口映射仅能在 run 的时候进行,无法修改,如果忘了。。。直接 GG,非要补救,就只用宿主机的 iptables 进行 NAT 转发来实现咯。

。。。。这个是真的顶不住了,iptables NAT 转发本身就不熟,偷个懒以后再研究叭,参考资料戳这里