docker网络:
主要介绍 docker 网络相关知识。
Docker 服务安装完成之后,默认在每个宿主机会生成一个名称为 docker0 的网卡
其 IP 地址都是 172.17.0.1/16,并且会生成三种不能类型的网络,如下图:
docker 结合负载实现网站高可用:
整体规划图:
下图为一个小型的网络架构图,其中 nginx 使用 docker 运行
服务器名 | 系统 | ip
- | -
server1 |centos 7.6 | 192.168.99.101
server2 | centos 7.6 | 192.168.99.102
docker1 | ubuntu 18.04 | 192.168.99.22
docker2 | ubuntu 18.04 | 192.168.99.23
1. 安装并配置 keepalived
- Server1 安装
yum install keepalived haproxy -y
配置
vim /etc/keepalived/keepalived.conf
...
! Configuration File for keepalived
global_defs {
notification_email {
root@localhost
}
notification_email_from root@localhost
smtp_server localhost
smtp_connect_timeout 30
router_id LVS_DEVEL1
vrrp_skip_check_adv_addr
#vrrp_strict
vrrp_iptables
vrrp_garp_interval 0
vrrp_gna_interval 0
}
vrrp_instance MAKE_VIP_INT {
state MASTER
interface eth0
virtual_router_id 1
priority 100
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.99.10 dev eth0 label eth0:1
}
}
启动
systemctl restart keepalived
systemctl enable keepalived
- Server2 安装
yum install keepalived haproxy –y
配置
vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
notification_email {
root@localhost
}
notification_email_from root@localhost
smtp_server localhost
smtp_connect_timeout 30
router_id LVS_DEVEL2
vrrp_skip_check_adv_addr
#vrrp_strict
vrrp_iptables
vrrp_garp_interval 0
vrrp_gna_interval 0
}
vrrp_instance MAKE_VIP_INT {
state BACKUP
interface eth0
virtual_router_id 1
priority 50
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.99.10 dev eth0 label eth0:1
}
}
启动
systemctl restart keepalived
systemctl enable keepalived
2. 安装并配置 haproxy
- 各服务器配置内核参数
echo "net.ipv4.ip_nonlocal_bind=1" >> /etc/sysctl.conf
sysctl -p
- Server1 配置 haproxy
vim /etc/haproxy/haproxy.cfg
global
maxconn 100000
uid 99
gid 99
daemon
nbproc 1
log 127.0.0.1 local0 info
defaults
option http-keep-alive
#option forwardfor
maxconn 100000
mode tcp
timeout connect 500000ms
timeout client 500000ms
timeout server 500000ms
listen stats
mode http
bind 0.0.0.0:9999
stats enable
log global
stats uri /haproxy-status
stats auth haadmin:q1w2e3r4ys
#================================================================
frontend docker_nginx_web
bind 0.0.0.0:80
mode http
default_backend docker_nginx_hosts
backend docker_nginx_hosts
mode http
balance roundrobin
server 192.168.99.22 192.168.99.22:81 check inter 2000 fall 3 rise 5
server 192.168.99.23 192.168.99.23:81 check inter 2000 fall 3 rise 5
启动 haproxy
systemctl enable haproxy
systemctl restart haproxy
- Server2 配置 haproxy
vim /etc/haproxy/haproxy.cfg
global
maxconn 100000
uid 99
gid 99
daemon
nbproc 1
log 127.0.0.1 local0 info
defaults
option http-keep-alive
#option forwardfor
maxconn 100000
mode tcp
timeout connect 500000ms
timeout client 500000ms
timeout server 500000ms
listen stats
mode http
bind 0.0.0.0:9999
stats enable
log global
stats uri /haproxy-status
stats auth haadmin:q1w2e3r4ys
#================================================================
frontend docker_nginx_web
bind 0.0.0.0:80
mode http
default_backend docker_nginx_hosts
backend docker_nginx_hosts
mode http
balance roundrobin
server 192.168.99.22 192.168.99.22:81 check inter 2000 fall 3 rise 5
server 192.168.99.23 192.168.99.23:81 check inter 2000 fall 3 rise 5
启动 haproxy
systemctl enable haproxy
systemctl restart haproxy
3. docker服务器启动 nginx 容器并验证
- dcoekr1 启动 Nginx 容器
docker1:192.168.99.22
# 先下载nginx镜像
docker pull nginx
docker run --name nginx-web1 -d -p 81:80 nginx
验证 web 访问
- docker2 启动 nginx 容器
docker2:192.168.99.23
# 先下载nginx镜像
docker pull nginx
docker run --name nginx-web1 -d -p 81:80 nginx
验证 web 访问
-
访问 VIP
-
Server1 haproxy 状态页面:192.168.99.101:9999/haproxy-status
-
Server2 haproxy 状态页面:192.168.99.102:9999/haproxy-status
容器之间的互联
通过容器名称互联:
即在同一个宿主机上的容器之间可以通过自定义的容器名称相互访问,比如一个业务前端静态页面是使用 nginx,动态页面使用的是 tomcat, 由于容器在启动的时候其内部 IP 地址是 DHCP 随机分配的,所以如果通过内部访问的话,自定义名称是相对比较固定的,因此比较适用于此场景。
- 先创建第一个容器,后续会使用到这个容器的名称:
docker run -it -d --name app1 -p 88:80 nginx
- 查看当前 hosts 文件内容
docker exec -it app1 bash
root@be6f8876b2ae:/# cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.3 be6f8876b2ae
- 创建第二个容器
docker run -it -d -p 89:80 --name app2 --link app1 nginx
- 查看第二个容器的 hosts 文件内容
docker exec -it app2 bash
root@150ce96afe52:/# cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.3 app1 be6f8876b2ae #连接的对方容器的 ID 和容器名称
172.17.0.4 150ce96afe52
- 检测通信
ping app1
可能需要先安装ping工具
apt install iputils-ping
通过自定义容器别名互联:
上一步骤中,自定义的容器名称可能后期会发生变化, 那么一旦名称发生变化,程序之间也要随之发生变化,比如程序通过容器名称进行服务调用, 但是容器名称发生变化之后再使用之前的名称肯定是无法成功调用, 每次都进行更改的话又比较麻烦, 因此可以使用自定义别名的方式解决,即容器名称可以随意更,只要不更改别名即可,具体如下:
命令格式:
docker run -d --name 新容器名称 \
--link 目标容器名称:自定义的名称 \
-p 本地端口:容器端口 镜像名称 shell命令
- 启动第三个容器
docker run -it -d -p 90:80 --name app3 --link app1:web1 nginx
- 查看当前容器的 hosts 文件
docker exec -it app3 bash
root@c28c27a48883:/# cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.3 web1 be6f8876b2ae app1 #多了一个别名
172.17.0.5 c28c27a48883
- 检查自定义别名通信
ping web1
- docker 网络类型:
Docker 的网络使用 docker network ls 命令看到有三种类型,下面将介绍每一种类型的具体工作方式:
使用参数–net=网络类型
指定, 不指定默认就是 bridge 模式。
查看当前 docke 的网卡信息:
docker network list
Bridge: 桥接,使用自定义 IP
Host: 不获取 IP 直接使用物理机 IP, 并监听物理机 IP 监听端口
None: 没有网络
(1)、Host 模式: 使用参数 –net=host 指定。
启动的容器如果指定了使用 host 模式,那么新创建的容器不会创建自己的虚拟网卡,而是直接使用宿主机的网卡和 IP 地址, 因此在容器里面查看到的 IP 信息就是宿主机的信息,访问容器的时候直接使用宿主机 IP+容器端口即可,不过容器的其他资源们必须文件系统、 系统进程等还是和宿主机保持隔离。此模式的网络性能最高,但是各容器之间端口不能相同, 适用于运行容器端口比较固定的业务。
- 为避免端口冲突, 先删除所有的容器:
docker rm -f `docker ps -a -q`
- 启动一个新容器,并指定网络模式为 host
docker run -d --name app1 --net=host nginx
- 访问宿主机验证
因为是host模式,所以直接访问宿主机的IP:192.168.99.23
Host 模式不支持端口映射, 当指定端口映射的时候会提示如下警告信息:
使用主机网络模式时,将丢弃已指定的端口
docker run -d --name app2 -p 81:80 --net=host nginx
(2)、None 模式:使用参数 –net=none 指定
在使用 none 模式后, Docker 容器不会进行任何网络配置,其没有网卡、没有 IP也没有路由,因此默认无法与外界通信, 需要手动添加网卡配置 IP 等,所以极少使用
命令使用方式:
docker run -it -d --name net_none -p 80:80 --net=none nginx
(3)、Container 模式:使用参数 –net=container:名称 或 ID。
使用此模式创建的容器需指定和一个已经存在的容器共享一个网络,而不是和宿主机共享网,新创建的容器不会创建自己的网卡也不会配置自己的 IP,而是和一个已经存在的被指定的容器东西 IP 和端口范围,因此这个容器的端口不能和被指定的端口冲突, 除了网络之外的文件系统、进程信息等仍然保持相互隔离,两个容器的进程可以通过 lo 网卡及容器 IP 进行通信。
- 先起一个容器
docker run -it -d --name app1 -p 80:8080 nginx
- 另一个容器直接使用对方的网络
docker run -it -d --name app2 --net=container:app1 tomcat
- nginx的默认端口为80,而8080是tomcat的默认端口,所以,如果我们直接访问宿主机192.168.99.23:80,应该是访问到tomcat才对。如果图
(4)、bridge 模式:
docker 的默认模式即不指定任何模式就是 bridge 模式, 也是使用比较多的模式,此模式创建的容器会为每一个容器分配自己的网络 IP 等信息,并将容器连接到一个虚拟网桥与外界通信
查看bridge模式的信息
docker network inspect bridge
docker 跨主机互联之简单实现:
夸主机互联是说 A 宿主机的容器可以访问 B 主机上的容器,但是前提是保证各宿主机之间的网络是可以相互通信的, 然后各容器才可以通过宿主机访问到对方的容器, 实现原理是在宿主机做一个网络路由就可以实现 A 宿主机的容器访问 B主机的容器的目的, 复杂的网络或者大型的网络可以使用 google 开源的 k8s 进行互联。
修改各宿主机网段:
Docker 的默认网段是 172.17.0.x/24,而且每个宿主机都是一样的,因此要做路由的前提就是各个主机的网络不能一致,具体如下:
服务器A:192.168.99.22
服务器B:192.168.99.23
- 服务器 A 更改网段
vim /lib/systemd/system/docker.service
在ExecStart
结尾追加--bip=10.10.0.1/24
,ip是你想设置的网络的网关ip
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --bip=10.10.0.1/24
- 重启 docker 服务
systemctl daemon-reload
systemctl restart docker
- 验证 A 服务器网卡
ifconfig docker0
如果你的系统是Centos,需要打开ipforward
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -p
- 启动一个容器
docker run -it -p 81:80 nginx bash
[root@781e7f053c20 /]# ifconfig eth0
- 添加静态路由(宿主机上)
route add -net 10.20.0.0/24 gw 192.168.99.23
iptables -A FORWARD -s 192.168.99.0/24 -j ACCEPT
- 服务器 B 更改网段
vim /lib/systemd/system/docker.service
在ExecStart
结尾追加--bip=10.20.0.1/24
,注意不能跟服务器A一样
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --bip=10.20.0.1/24
- 重启 docker 服务
systemctl daemon-reload
systemctl restart docker
- 验证网卡
ifconfig docker0
- 如果你的系统是Centos,需要打开ipforward
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -p
- 启动一个容器
docker run -it -p 82:80 nginx bash
[root@781e7f053c20 /]# ifconfig eth0
- 添加静态路由
route add -net 10.10.0.0/24 gw 192.168.99.22
iptables -A FORWARD -s 192.168.99.0/24 -j ACCEPT
测试容器间互联
两服务器分别起动两个容器进行测试:10.10.0.0网段是服务器A内的容器,10.20.0.0网段是服务器B内的容器
创建自定义网络:
可以基于 docker 命令创建自定义网络, 自定义网络可以自定义 IP 地范围和网关等信息。
帮助
docker network create –help
- 创建自定义 docker 网络
docker network create -d bridge --subnet 10.100.0.0/24 \
--gateway 10.100.0.1 my-net
- 查看网络
docker network list
- 使用自定义网络创建容器
docker run -it --net=my-net jibill/nginx:v1 bash
[root@42dba1061dd1 /]# ifconfig eth0
[root@42dba1061dd1 /]# ping www.baidu.com
- 创建默认网络容器
docker run -it jibill/nginx:v1 bash
[root@ed06c2785c92 /]# ifconfig eth0
[root@ed06c2785c92 /]# ping www.baidu.com
-
如何与使用默认网络的容器通信:
现在有一个docker0(10.10.0.0/24)网络一个自定义的my-net(10.100.0.0/24)网络, 每个网络上分别运行了不同数量的容器,那么怎么才能让位于不同网络的容器可以相互通信呢? -
保存下iptbales
iptables-save > iptables.sh
- 修改iptables.sh
vim iptables.sh
把DOCKER-ISOLATION-STAGE-2除了RETURN
结尾的都注释了
- 重新导入 iptables
iptables-restore < iptables.sh
- 验证通信