DataWhale & Docker(网络)
学习大纲:
开源内容
目录
补充内容:
Linux在网络栈引入了Network Namespace,这些独立的协议栈被隔离到不同的Namespace中,处于不同Namespace中的网络栈是完全隔离的,彼此无法通信。在建立了新的Network Namespace,并将某个进程关联到这个网络命名空间后,就出现了以上的命名空间下的内核数据结构,所有网络栈变量都放入了Network Namespace的数据结构中,这个Network Namespace是属于它进程组私有的,与其他进程组不冲突。
四类网络模式
Docker网络模式 配置 说明 host模式 –net=host 容器和宿主机共享Network namespace。 container模式 –net=container:NAME_or_ID 容器和另外一个容器共享Network namespace。 kubernetes中的pod就是多个容器共享一个Network namespace。 none模式 –net=none 容器有独立的Network namespace,但并没有对其进行任何网络设置,如分配veth pair 和网桥连接,配置IP等。 bridge模式 –net=bridge (默认为该模式) host模式
如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。
使用host模式的容器可以直接使用宿主机的IP地址与外界通信,容器内部的服务端口也可以使用宿主机的端口,不需要进行NAT,host最大的优势就是网络性能比较好,但是docker host上已经使用的端口就不能再用了,网络的隔离性不好。
container模式
这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。
none模式
使用none模式,Docker容器拥有自己的Network Namespace,但是,并不为Docker容器进行任何网络配置。也就是说,这个Docker容器没有网卡、IP、路由等信息。需要我们自己为Docker容器添加网卡、配置IP等。
这种网络模式下容器只有lo回环网络,没有其他网卡。none模式可以在容器创建时通过--network=none来指定。这种类型的网络没有办法联网,封闭的网络能很好的保证容器的安全性。
bridge模式
当Docker进程启动时,会在主机上创建一个名为docker0的虚拟网桥,此主机上启动的Docker容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。
从docker0子网中分配一个IP给容器使用,并设置docker0的IP地址为容器的默认网关。在主机上创建一对虚拟网卡veth pair设备,Docker将veth pair设备的一端放在新创建的容器中,并命名为eth0(容器的网卡),另一端放在主机中,以vethxxx这样类似的名字命名,并将这个网络设备加入到docker0网桥中。可以通过brctl show命令查看。
bridge模式是docker的默认网络模式,不写--net参数,就是bridge模式。使用docker run -p时,docker实际是在iptables做了DNAT规则,实现端口转发功能。可以使用iptables -t nat -vnL查看。
一、网络
- Docker 允许通过外部访问容器或容器互联的方式来提供网络服务。
1.1外部访问容器
通过
-P
或-p
参数来指定端口映射$ docker run -d -P nginx:alpine
使用
docker container ls
可以看到,本地主机的 32768 被映射到了容器的 80 端口。$ docker container ls -l
通过
docker logs
命令来查看访问记录。$ docker logs fa
支持的格式有
ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort
注意:
在一个指定端口上只可以绑定一个容器
1.1.1映射所有接口地址
使用
hostPort:containerPort
格式本地的 80 端口映射到容器的 80 端口$ docker run -d -p 80:80 nginx:alpine
此时默认会绑定本地所有接口上的所有地址。
1.1.2映射到指定地址的指定端口
可以使用
ip:hostPort:containerPort
格式指定映射使用一个特定地址$ docker run -d -p 127.0.0.1:80:80 nginx:alpine
1..1.3映射到指定地址的任意端口
使用
ip::containerPort
绑定 localhost 的任意端口到容器的 80 端口,本地主机会自动分配一个端口。$ docker run -d -p 127.0.0.1::80 nginx:alpine
还可以使用
udp
标记来指定udp
端口$ docker run -d -p 127.0.0.1:80:80/udp nginx:alpine
1.1.4查看映射端口配置
使用
docker port
来查看当前映射的端口配置,也可以查看到绑定的地址$ docker port fa 80 0.0.0.0:32768
注意:
容器有自己的内部网络和 ip 地址(使用
docker inspect
查看,Docker 还可以有一个可变的网络配置。)
-p
标记可以多次使用来绑定多个端口
1.2容器互联
1.2.1新建网络
$ docker network create -d bridge my-net
-d
参数指定 Docker 网络类型,有bridge
overlay
。
1.2.2连接容器
运行一个容器并连接到新建的
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
再打开一个新的终端查看容器信息
$ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES b47060aca56b busybox "sh" 11 minutes ago Up 11 minutes busybox2 8720575823ec busybox "sh" 16 minutes ago Up 16 minutes busybox1
下面通过
ping
来证明busybox1
容器和busybox2
容器建立了互联关系。在
busybox1
容器输入以下命令/ # ping busybox2 PING busybox2 (172.19.0.3): 56 data bytes 64 bytes from 172.19.0.3: seq=0 ttl=64 time=0.072 ms 64 bytes from 172.19.0.3: seq=1 ttl=64 time=0.118 ms
用 ping 来测试连接
busybox2
容器,它会解析成172.19.0.3
。同理在
busybox2
容器执行ping busybox1
,也会成功连接到。/ # ping busybox1 PING busybox1 (172.19.0.2): 56 data bytes 64 bytes from 172.19.0.2: seq=0 ttl=64 time=0.064 ms 64 bytes from 172.19.0.2: seq=1 ttl=64 time=0.143 ms
这样,
busybox1
容器和busybox2
容器建立了互联关系。
1.2.3Docker Compose
有多个容器之间需要互相连接,推荐使用 Docker Compose。
1.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 信息发生更新后,所有 Docker 容器的 DNS 配置通过
/etc/resolv.conf
文件立刻得到更新。配置全部容器的 DNS ,也可以在
/etc/docker/daemon.json
文件中增加以下内容来设置。{ "dns" : [ "114.114.114.114", "8.8.8.8" ] }
这样每次启动的容器 DNS 自动配置为
114.114.114.114
和8.8.8.8
。使用以下命令来证明其已经生效。$ docker run -it --rm ubuntu:18.04 cat etc/resolv.conf nameserver 114.114.114.114 nameserver 8.8.8.8
如果用户想要手动指定容器的配置,可以在使用
docker run
命令启动容器时加入如下参数:
-h HOSTNAME
或者--hostname=HOSTNAME
设定容器的主机名,它会被写到容器内的/etc/hostname
和/etc/hosts
。但它在容器外部看不到,既不会在docker container ls
中显示,也不会在其他的容器的/etc/hosts
看到。--dns=IP_ADDRESS
添加 DNS 服务器到容器的/etc/resolv.conf
中,让容器用这个服务器来解析所有不在/etc/hosts
中的主机名。--dns-search=DOMAIN
设定容器的搜索域,当设定搜索域为.example.com
时,在搜索一个名为 host 的主机时,DNS 不仅搜索 host,还会搜索host.example.com
。注意:如果在容器启动时没有指定最后两个参数,Docker 会默认用主机上的
/etc/resolv.conf
来配置容器。
二、总结
docker学习过半,继续坚持,直至胜利。