docker 基础之网络管理

docker网络基础

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

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

 

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

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

 

容器访问外部网络

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

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

若是为 0,说明没有开启转发,则须要手动打开。docker

 

从外部访问容器

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

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

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

 

映射全部接口地址ubuntu

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

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

此时默认会绑定本地全部接口上的全部地址。安全


映射到指定地址的指定端口
能够使用 ip:hostPort:containerPort 格式指定映射使用一个特定地址,好比 localhost 地址 127.0.0.1bash

$ 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来限制 主机间的通讯。

相关文章
相关标签/搜索