docker 基础之网络管理

docker网络基础

docker使用到的与linux网络有关的主要技术

  • Network Namespace(网络命名空间)
  • Veth设备对
  • Iptables/NetFilter
  • 网桥
  • 路由

标准的dokcer支持以下4种网络模式

  • host模式: 使用--net=host指定
  • container模式:使用--net=container:NAME_or_ID指定
  • none模式: 使用 --net=none指定
  • bridge模式:使用--net=bridge指定,为默认设置
    • docker第一次启动时会创建一个虚拟网桥,默认为docker0,在私有网络空间中给这个网桥分配一个子网,由docker创建出来的每一个容器,会创建一个虚拟的以太网设备(veth设备对),其中一端关联到网桥,一端使用linux的网络命名空间技术映射为容器内的eth0设备,然后从网桥的地址段内给eth0接口分配一个ip地址  

容器访问外部网络

器要想访问外部网络,需要本地系统的转发支持。在Linux 系统中,检查转发是否打开。

$sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1

如果为 0,说明没有开启转发,则需要手动打开。

从外部访问容器

容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过 -P 或 -p 参数来指定端口映射。

当使用 -P 标记时,Docker 会随机映射一个 49000~49900 的端口到内部容器开放的网络端口。
-p(小写的)则可以指定要映射的端口,并且,在一个指定端口上只可以绑定一个容器。支持的格式有 

ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort。

映射所有接口地址

使用 hostPort:containerPort 格式本地的 5000 端口映射到容器的 5000 端口,可以执行

$ sudo docker run -d -p 5000:5000 training/webapp python app.py

此时默认会绑定本地所有接口上的所有地址。


映射到指定地址的指定端口
可以使用 ip:hostPort:containerPort 格式指定映射使用一个特定地址,比如 localhost 地址 127.0.0.1

$ sudo docker run -d -p 127.0.0.1:5000:5000 training/webapp python app.py

映射到指定地址的任意端口

使用 ip::containerPort 绑定 localhost 的任意端口到容器的 5000 端口,本地主机会自动分配一个端口。

$ sudo docker run -d -p 127.0.0.1::5000 training/webapp python app.py

还可以使用 udp 标记来指定 udp 端口

$ sudo docker run -d -p 127.0.0.1:5000:5000/udp training/webapp python app.py

查看映射端口配置

使用 docker port 来查看当前映射的端口配置,也可以查看到绑定的地址

$ docker port nostalgic_morse 5000    #container NAMES
127.0.0.1:49155.

注意:
容器有自己的内部网络和 ip 地址(使用 docker inspect 可以获取所有的变量,Docker 还可以有一个可变的网络配置。)

-p 标记可以多次使用来绑定多个端口,例如:

$ sudo docker run -d -p 5000:5000 -p 3000:80 training/webapp python app.py

容器互联

官网示例

先创建一个新的 Docker 网络。

$ docker network create -d bridge my-net
-d 参数指定 Docker 网络类型,有 bridge overlay。其中 overlay 网络类型用于 Swarm mode


连接容器,运行一个容器并连接到新建的 my-net 网络

$ docker run -it --rm --name busybox1 --network my-net busybox sh

打开新的终端,再运行一个容器并加入到 my-net 网络

$ docker run -it --rm --name busybox2 --network my-net busybox sh

进入容器,通过互相ping 容器名称来判断是否互联

  

自己测试示例

#查看所有网络:
docker network ls

#创建自己的网络
docker network create -d bridge my-bridge-network

#检查网络(如果你检查网络,会发现里面什么都没有)
docker network inspect my-bridge-network

添加一个容器到自定义的网络

#指定网络 运行(将db添加为自定义的网络)
docker run -d --net=my-bridge-network --name db training/postgres     #--name 为定义的名字

#再次检查网络(会发现多了一个容器)
docker network inspect my-bridge-network

#查看网络情况
docker inspect --format='{{json .NetworkSettings.Networks}}' db

#查看ip地址
docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' db

#启动另一个容器:并不在一个网段,未加入到自定义的网络 名称为web
docker run -d --name web training/webapp python app.py

进入交互模式,并且ping web的地址进行测试

docker exec -it db bash #此时是ping 不通的

#将web加入自定义的网络
$ docker network connect my-bridge-network web

docker exec -it db bash   #然后在去交互模式ping web,就可以通信了

容器互联-linking系统 

docker有一个linking 系统可以连接多个容器。它会创建一对父子关系,父容器可以看到所选择的 子容器的信息。

注意
容器的名 称 是 唯 一的。如果 你 命名了一个 叫 web的容器,当 你 要 再次 使用 web这个名 称 的 时候 , 你 需要用 docker rm来 删 除之前创建的容器,也可以 再 执行 docker run的 时候 加--rm标记来 停止旧 的容器, 并删 除, rm 和 -d 参 数是 不兼 容的

使用--name标记可以为容器命名

$ sudo docker run -d -P --name web training/webapp python app.py

使用docker ps -l 来验证我们设定的命名

$ sudo docker ps -l

links可以让容器之间安全的交互,使用--link标记。

#先创建一个新的数据库容器,
$ sudo docker run -d --name db training/postgres


#创建一个新的web容器,并将它link到db容器 
$ docker run -d -P --name web --link db:db training/webapp python app.py

# --link标记的格式:--link name:alias,name是我们要链接的容器的名称,alias是这个链接的别名(会在新建的容器中/etc/hosts添加一条记录 ip db 此处的db为指定的alias别名

使用docker ps来查看容器的链接

 可以看到命名的容器,db和web,db容器的names列有db也有web/db。这表示web容 器链接到db容器,他们是一个父子关系。在这个link中,2个容器中有一对父子关系。docker在2个 容器之间创建了一个安全的连接,而且不用映射他们的端口到宿主主机上。在启动db容器的时候也不 用-p和-P标记。使用link之后我们就可以不用暴露数据库端口到网络上。

docker 通过2种方式为父子关系的容器公开连接信息:

• 环境变量
• 更新/etc/hosts文件

#使用env命令来查看容器的环境变量 
$ sudo docker run --rm --name web2 --link db:db training/webapp env

#除了环境变量,docker还添加host信息到父容器的/etc/hosts的文件。下面是父容器web的hosts文件 
$ sudo docker run -t -i --rm --link db:db training/webapp /bin/bash 
root@aed84ee21bde:/opt/webapp# cat /etc/hosts

这里有2个hosts,第一个是web容器,web容器用id作为他的主机名,第二个是db容器的ip和主机名

root@aed84ee21bde:/opt/webapp# apt-get install -yqq inetutils-ping 
root@aed84ee21bde:/opt/webapp# ping db 
PING db (172.17.0.5): 48 data bytes 
56 bytes from 172.17.0.5: icmp_seq=0 ttl=64 time=0.267 ms 
56 bytes from 172.17.0.5: icmp_seq=1 ttl=64 time=0.250 ms 
56 bytes from 172.17.0.5: icmp_seq=2 ttl=64 time=0.256 ms 
用ping来ping db容器,它会解析成172.17.0.5

注意:官方的ubuntu镜像默认没有安装ping
注意:你可以链接多个子容器到父容器,比如我们可以链接多个web到db容器上。

docker高级网络配置

快速配置指南

下面是一个跟docker网络相关的命令列表,有些命令选项只有 在docker服务启动的时候才可以执行,而且不能马上生效。

• -b BRIDGE or --bridge=BRIDGE —   桥接配置--bip=CIDR —              定制docker0的掩码-H SOCKET... or --host=SOCKET... — 它告诉docker从哪个通道来接收run container stop container这样的命令,也是docker api的地址--icc=true|false           
• --ip-forward=true|false      
• --iptables=true|false         
• --mtu=BYTES —            
• --dns=IP_ADDRESS...         
• --dns-search=DOMAIN...       
• -h HOSTNAME or --hostname=HOSTNAME — 主机名配置--link=CONTAINER_NAME:ALIAS     — link 系统--net=bridge|none|container:NAME_or_ID|host     —桥接配置-p SPEC or --publish=SPEC       — 映射容器端口到宿主主机-P or --publish-all=true|false     — 映射容器端口到宿主主机

配置容器dns服务的方法

  • -h HOSTNAME or --hostname=HOSTNAME 设定容器的主机名,它会被写到/etc/hostname,/etc/hosts中的ip地址自动写成分配的ip地址, 在/bin/bash中显示该主机名。但它不会在docker ps中显示,也不会在其他的容器的/etc/hosts中显示。
  • --link=CONTAINER_NAME:ALIAS 这选项会在创建容器的时候添加一个其他容器CONTAINE_NAME的主机名到/etc/hosts文件中, 让新容器的进程可以使用主机名ALIAS就可以连接它。
  • --dns=IP_ADDRESS 添加dns服务器到容器的/etc/resolv.conf中,让容器用这ip地址来解析所有不在/etc/hosts中的主 机名。 
  • --dns-search=DOMAIN 设定容器的搜索域,当设定搜索域为.example.com时,会在搜索一个host主机名时,dns不仅搜索 host,还会搜索host.example.com

注意:如果 没 有上 述最 后 2个 选 项, docker会用主机上的 /etc/resolv.conf来配置容器, 它 是 默 认配置。


创建自己的桥接

#停止旧网桥并删除 
$ sudo service docker stop 
$ sudo ip link set dev docker0 down 
$ sudo brctl delbr docker0

# 创建自己的网桥 
$ 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桥接设置,并启动docker服务(在ubuntu上) 
$ echo 'DOCKER_OPTS="-b=bridge0"' >> /etc/default/docker 
$ sudo service docker start

docker服务启动成功并绑定容器到新的网桥,建一个容器,你会看到它的ip是我们的设置的新ip 段,docker会自动检测到它。

用brctl show可以看到容器启动或则停止后网桥的配置变化,在容器中使 用ip a 和ip r 来查看ip地址配置和路由信息


创建一个点到点连接(network namespace)

#创建一个名为nestest的 network namespace
ip netns add netest

#列出系统中存在的network namespace
ip netns list

#删除一个network namespace
ip netns delete nstest

#在network namespace中执行一条命令
ip netns exec <network namespace name > command

如:
ip netns exec <network namespace name > ip addr

#在network namespace中启动一个bash
ip netns exec <network namespace name > /bin/bash

默认docker会将所有容器连接到由docker0提供的虚拟子网,你也可以使用自己创建的网桥。但如 果你想要2个特殊的容器之间可以直连通信,而不用去配置复杂的主机网卡桥接。
解决办法很简单:创建一对接口,把2个容器放到这对接口中,配置成点到点链路类型。这2个容 器就可以直接通信了。配置如下:

# 在2个终端中启动2个容器 
$ sudo docker run -i -t --rm --net=none base /bin/bash 
root@1f1f4c1f931a:/#
$ sudo docker run -i -t --rm --net=none base /bin/bash 
root@12e343489d2f:/#


#找到他们的process IDs ,然后创建他们的 namespace entries
$ sudo docker inspect -f '{{.State.Pid}}' 1f1f4c1f931a 
2989 
$ sudo docker inspect -f '{{.State.Pid}}' 12e343489d2f 
3004 
$ sudo mkdir -p /var/run/netns 
$ sudo ln -s /proc/2989/ns/net /var/run/netns/2989 
$ sudo ln -s /proc/3004/ns/net /var/run/netns/3004
# 创建”peer“接口,然后配置路由

#在主机上创建虚拟网卡 $ sudo ip link add A type veth peer name B
$ sudo ip link set A netns
2989           #2989为一个network namespace此处是将网卡放到network namespace中的命令 $ sudo ip netns exec 2989 ip addr add 10.1.1.1/32 dev A $ sudo ip netns exec 2989 ip link set A up       #启动网卡 $ sudo ip netns exec 2989 ip route add 10.1.1.2/32 dev A    #分配ip $ sudo ip link set B netns 3004 $ sudo ip netns exec 3004 ip addr add 10.1.1.2/32 dev B $ sudo ip netns exec 3004 ip link set B up $ sudo ip netns exec 3004 ip route add 10.1.1.1/32 dev B

现在这2个容器就可以相互ping通,并成功建立连接。点到点链路不需要子网和子网掩码,使用ip route 来连接单个ip地址到指定的网络接口。

如果 没 有 特 殊 需要 你不 需要指定 --net=none来创建点到点 链路 。 还有一个办法就是创建一个只跟主机通信的容器,除非有特殊需求,你可以仅用--icc=false来限制 主机间的通信。

 

原文地址:https://www.cnblogs.com/FRESHMANS/p/8425804.html