说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家!
接着上一篇博客继续往下写 :https://blog.csdn.net/qq_41782425/article/details/105335943
一、Container Port Map
1.运行nginx容器
- 首先是从docker hub上拉去nginx image,然后创建并运行名为web的容器
2.拉取nginx页面
- 查看基于nginx容器web的ip地址,因为创建容器默认是连接到bridge network的,所以通过查看bridge network数据即看到web容器的ip地址
- ping web容器的ip肯定是可以ping通的,因为创建的容器的bridge是连接到本机的docker0接口的,验证端口能够可达即可
- 现在则通过curl命令工具拉取(下载)nginx主页,这里说明一下80端口为默认,可以不写
- 以上是通过容器的IP地址来拉取nginx主页,那么在linux本机ip localhost拉取则会失败
3.端口映射到本机
说明: 运行nginx容器,nginx服务默认绑定到容器172.17.0.4 ip上,将172.17.0.4端口映射到本机linux端口,就不用访问172.17.0.4了,直接访问本地localhost 127.0.0.1即可,同理还可以通过博主这台centos7虚拟机的ip来访问
- 首先删除web容器,然后重新创建,并将容器的80端口映射到本机linux localhost 80端口上
- 现在就可以通过127.0.0.1来拉取nginx主页了
- 在博主的电脑windows系统上去访问以上centos机器的ip地址192.168.88.212,也是能访问nginx主页
- 以下端口映射图,从linux虚拟机中通过nginx容器的ip访问nginx主页,以及端口映射到linux虚拟机本机端口可通过linux本机ip访问nginx主页,最后是windows本机通过linux虚拟机ip来访问到nginx主页
如果将上面的linux虚拟机换成阿里云的ecs或亚马逊aws公网linux机器上,那么所有人都可以通过这个公网IP来进行访问了,如在阿里云上创建一个ecs主机(参考文章),然后重复以上的步骤(在阿里云ecs上面创建运行容器,并将容器端口映射到ecs本机端口),通过ecs公网ip就可以实现所有人访问了,最终就是一个web服务了
二、Docker Host && None Network
1.docker none network
- 查看目前docker network
- 创建一个基于none network的容器
- 查看none的网络数据,可以看到test1容器没有mac地址以及ip
- 那么现在进入test1容器中,查看网络接口,结果发现只有一个lo回环口,并没有其他的端口,那么这种情况则表示该容器所在的network namespace是孤立的,只能通过exec方式来访问到该容器,没有其他的方式,对于此基于none网络的容器那么它的应用则可以存放一些只能通过本地访问的数据文档
2.docker host network
- 删除test1容器,创建一个基于host network的容器
- 查看host的网络数据,跟none network 一样,test1容器也没有mac和ip地址
- 进入test1容器中,查看网络接口,结果发现与本机linux的网络接口是一样的,因为host network没有自己独立的network namespace,它是跟主机所在的network namespace共享的,所以就会导致在容器里面和容器外面看到网络接口都是一样的,因为容器和主机的网络接口是一样的,所以就会导致端口冲突,比如创建两个连接到host的nginx容器,就会出现端口com冲突,第一个容器运行就绑定了本地的80端口,当再启第二个时本地的80端口就已经被第一个容器占用了,所以就会出问题
三、多容器复杂应用的部署
1.创建app应用
- 之前博主在Docker的镜像和容器(三)文章中创建过一个简单的flask web app程序,现在在此app程序基础上添加redis数据的读写操作,包括一些环境变量和hostname读取,代码比较简单就不多说了
2.创建容器
- 创建Dockerfile文件,查看app.py以及Dockerfile内容
- 在app.py程序中,需要有一个运行redis服务容器,所以需要去创建这个容器,说明一下在Dockerfile中安装的redis是依赖包也就是说python和redis服务进行交互的包
- 通过以上Dockerfile构建image
- 基于cdtaogang/flask-redis image创建flask-redis容器,将此容器link到name为redis的redis容器上,这样直接通过这个redis容器的name redis就可以直接访问redis服务了,并且通过-e 命令设置flask-redis容器的环境变量REDIS_HOST等于redis的host
3.测试访问
- 进入创建的flask-redis容器bash中,查看环境变量,并且ping redis(基于redis服务的容器name)也能成功,这样大家明白了之所以创建flask-redis容器时使用–link命令是让这个容器可以通过redis服务容器name redis进行访问,而设置flask-redis容器的REDIS_HOST环境变量是为了在app.py中获取这个REDIS_HOST环境变量的值也就是redis,即则可以通过redis:6379来访问redis数据库了
- 在容器中,通curl命令工具则可以访问127.0.0.1:5000(因为flask-redis容器运行状态),容器的hostname则就是@后面的数据
- 退出容器,在linux本机curl,则提示访问拒绝,原因是在创建flask-redis容器时没有将容器的5000端口映射到linux本机
- 删除容器,重新创建,并进行端口映射
- 再次在linux本机上访问没有问题,因为redis容器没有重启,所以这里写入的hits键的值不是从1开始
如上在实际项目中前后端分离,那么就可以将后端的各个关系模块或者是服务部署到不同的容器中,只需要清除每个容器之间的访问关系就可以了
四、Overlay && Underlay
1.概念
UnderLay指的是物理网络,它由物理设备和物理链路组成。常见的物理设备有交换机、路由器、防火墙、负载均衡、入侵检测、行为管理等,这些设备通过特定的链路连接起来形成了一个传统的物理网络,这样的物理网络,我们称之为UnderLay网络。
OverLay其实就是一种隧道技术,VXLAN,NVGRE及STT是典型的三种隧道技术,它们都是通过隧道技术实现大二层网络。将原生态的二层数据帧报文进行封装后在通过隧道进行传输。总之,通过OverLay技术,我们在对物理网络不做任何改造的情况下,通过隧道技术在现有的物理网络上创建了一个或多个逻辑网络即虚拟网络,有效解决了物理数据中心,尤其是云数据中心存在 的诸多问题,实现了数据中心的自动化和智能化。
UnderLay是底层网络,负责互联互通而Overlay是基于隧道技术实现的,overlay的流量需要跑在underlay之上。
参考文章《浅谈SDN中的OverLay与UnderLay技术》&&《Underlay、Overlay、大二层介绍》
2.多机器通信原理
说明:在上一节中通过在同一个docker同一台linux机器上实现不同的容器redis和flask-redis是如何进行通信的,那么这两个容器在不同的linux机器上(分别部署在不同的linux机器上)试想能不能进行通信,其实是肯定可以通信的。
列举:有两台linux机器,要想让这两台linux机器中的docker container进行互相通信的前提是这两台linux机器是能够相互ping通的,那么linux1机器会向linux2机器发送数据包,这个数据包包含的网络分层为三层即HTTP层——TCP层——IP层,IP层包含src ip也就是192.168.88.212;dst ip为linux2机器的ip也就是192.168.88.211,在linux1机器上部署的redis容器(ip 172.17.0.2)要想访问部署在linux2机器上的flask-redis容器(ip 172.17.0.3)则将redis容器的数据包(src ip 172.17.0.2 dst ip 172.17.0.3 )放到linux1机器向linux2机器发送的数据包网络分层中的HTTP层,这样的话redis容器的数据包就会随着linux1机器的数据包发送到linux2机器上,到linux2机器上后,则会将linux1机器发送的数据包进行解包,解包后发现http层的redis数据包中的dst ip 172.17.0.3为本机linux2机器中的flask-redis容器的ip,则就会将这个数据包转发到flask-redis容器中,同理linux2机器上的flask-redis容器访问linux1机器上的redis容器也是这个道理,即这两个容器在不同的linux机器上实现了互相通信,以上过程的则是通过VXLAN方式实现的隧道技术
3.docker overlay + etcd实现多机器通信
说明: 要实现多机器中的不同容器进行互相通信需要借助etcd(分布式键值数据库),之所以需要借助etcd的原因很简单,因为防止在不同的机器上创建的不同的容器所产生的IP地址不会被占用,通过etcd分布式存储就会帮我们去查看容器的IP以及name是被占用,占用的话会提示的。
3.1 搭建etcd cluster
1. 首先需要保证这两台linux机器的主机名不能一致,之前博主通过VMware 创建的centos7和centos7_2两台机器的主机名同为localhost,这样会导致手动运行dockerd指定cluster store参数会提示host name不唯一,所以博主将主机分别改为docker-node1和docker-node2
sudo hostnamectl set-hostname docker-node1
sudo hostnamectl set-hostname docker-node2
2. 保证两台linux机器能够互相ping通
3. 在centos7和centos7_2两台机器上下载解压etcd-v3.0.12压缩包并进入解压目录中,因为是从github上下载速度很慢,建议大家用迅雷进行下载
wget https://github.com/coreos/etcd/releases/download/v3.0.12/etcd-v3.0.12-linux-amd64.tar.gz
tar zxvf etcd-v3.0.12-linux-amd64.tar.gz
cd etcd-v3.0.12-linux-amd64
4. 在centos7机器上运行一个名为docker-node1进程,192.168.88.212为centos7的IP,然后在centos7_2机器上运行一个名为docker-node2进程,192.168.88.211为centos7_2的IP
# 在centos7上
nohup ./etcd --name docker-node1 --initial-advertise-peer-urls http://192.168.88.212:2380 \
--listen-peer-urls http://192.168.88.212:2380 \
--listen-client-urls http://192.168.88.212:2379,http://127.0.0.1:2379 \
--advertise-client-urls http://192.168.88.212:2379 \
--initial-cluster-token etcd-cluster \
--initial-cluster docker-node1=http://192.168.88.212:2380,docker-node2=http://192.168.88.211:2380 \
--initial-cluster-state new&
# 在centos7_2上
nohup ./etcd --name docker-node2 --initial-advertise-peer-urls http://192.168.88.211:2380 \
--listen-peer-urls http://192.168.88.211:2380 \
--listen-client-urls http://192.168.88.211:2379,http://127.0.0.1:2379 \
--advertise-client-urls http://192.168.88.211:2379 \
--initial-cluster-token etcd-cluster \
--initial-cluster docker-node1=http://192.168.88.212:2380,docker-node2=http://192.168.88.211:2380 \
--initial-cluster-state new&
3.2 检查cluster状态
1. 先查看docker-node1的状态,没有问题健康的状态
./etcdctl cluster-health
2. 然后docker-node2状态,结果发现连接不上docker-node2 192.168.88.212 host
./etcdctl cluster-health
3. 导致docker-node2无法访问到docker-node1,说明docker-node1所在的centos7机器运行了防火墙,所以将其关闭,再次,检查cluster状态,都是健康的,搭建etcd集群成功
systemctl stop firewalld.service
firewall-cmd --state
4. 查看集群成员
sudo ./etcdctl member list
3.3 重启docker服务
1. 停止docke-node1的docker服务,如果停止不了,则通过ps -ef | grep dockerd查看进程pid,使用sudo kill -9 pid直接杀死进程即可
sudo service docker stop
2. 启动docker-node1主机的docker服务,使用其本地的cluster store
# centos7
sudo /usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --cluster-store=etcd://192.168.88.212:2379 --cluster-advertise=192.168.88.212:2375&
3. 查看docker-node1主机的docker server服务启动成功
4. 停止docke-node2的docker服务
sudo service docker stop
5. 启动docker-node2的docker服务,使用其本地的cluster store,然后在docker-node1主机上会显示info信息docker-node2加入进来,也就是说docker-node1和docker-node2主机双方都知道了对方的存在
# centos7_2
sudo /usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --cluster-store=etcd://192.168.88.211:2379 --cluster-advertise=192.168.88.211:2375&
3.4 创建overlay network
1. 在docker-node1主机上创建一个overlay的网络,然后在docker-node2主机上,查看网络,通过在docker-node1主机上创建的网络已经同步过来了,这是因为etcd的原因
sudo docker network create -d overlay my-overlay
2. 在docker-node2主机上通过./etcdctl 查看/docker/network/v1.0/network目录下的NETWORK ID,这个网络ID则是在docker-node1主机上创建的overlay的网络ID
3.5 验证docker-node1和docker-node2容器连通性
1. 首先在创建redis容器之前,先查看test-demo的网络数据
sudo docker network inspect my-overlay
2. 在docker-node1主机上创建名为redis的redis服务容器,结果发现出错了提示Failed to deserialize netlink ndmsg: invalid argument 参数失效,即使提示这样,但容器是创建成功的,当在docker-node2主机上创建相同的容器则会提示容器已存在,此错误提示最终会导致在docker-node1和docker-node2两天主机上创建的容器不能通过容器name 互相ping通,即无法实现多容器应用的部署
docker run -d --name redis --net my-overlay redis
3. 为了解决该错误,博主试了很多种办法都不行,最终决定尝试升级CentOS内核版本为最新版本再进行验证
# 载入公钥
sudo rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
# 安装ELRepo
sudo rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-3.el7.elrepo.noarch.rpm
# 载入elrepo-kernel元数据
sudo yum --disablerepo=\* --enablerepo=elrepo-kernel repolist
# 查看可用的rpm包
sudo yum --disablerepo=\* --enablerepo=elrepo-kernel list kernel*
# 安装最新版本的kernel
sudo yum --disablerepo=\* --enablerepo=elrepo-kernel install -y kernel-ml.x86_64
# 删除旧版本工具包
sudo yum remove kernel-tools-libs.x86_64 kernel-tools.x86_64
# 安装新版本工具包
sudo yum --disablerepo=\* --enablerepo=elrepo-kernel install -y kernel-ml-tools.x86_64
4. 进行从头开始重复操作,在docker-node1主机上创建基于overlay的redis容器没有提示Failed to deserialize netlink ndmsg: invalid argument 错误,并且在docker-node2上创建相同network 及容器name同为redis的容器,提示在my-overlay网络中容器name已存在(因为在etcd cluster key-value中已经存在my-overlay network中已经存在名为redis的容器了)
docker run -d --name redis -net my-overlay redis
5. 博主现在在docker-node主机上创建基于centos image my-overlay network的 test1的容器,同理测试在docker-node2上创建相同name network的容器(为了不出现etcd的日志,这里重新连接docker-node1和docker-node2主机),那么和上面一样,在docker-node2主机上无法创建test1容器,因为已存在与my-overlay网络
docker run -d --name test1 --network my-overlay centos /bin/sh -c "while true; do sleep 3000; done"
6. 在docker-node2上创建overlay network test2容器,即肯定会创建成功
docker run -d --name test2 --network my-overlay centos /bin/sh -c "while true; do sleep 3000; done"
7. 此时查看overlay network元数据,容器中就存在redis、test1和test2,并能看到他们的ip地址
docker network inspect my-overlay
8. 通过容器ip及name来验证test1和test2容器连通性,因为redis容器也是基于my-overlay network的所以也是可以ping通的
docker exec test1 ping 10.0.0.4
docker exec test2 ping 10.0.0.3
docker exec test1 ping test2
docker exec test2 ping test1
docker exec test1 ping redis
docker exec test2 ping redis
4.多机器通信实现多容器复杂应用的部署
4.1 在docker-node1上创建redis容器
在上一章节中,博主在docker-node1主机上已经创建并运行了redis容器,所以这里就不用再创建了
docker run -d --name redis -net my-overlay redis
4.2 在docker-node2上创建flask-redis容器
1. 现在则需要在docker-node2主机上通过Dockerfile 构建一个image(也就是在第三章节多容器复杂应用的部署中的操作,只是将redis容器部署在docker-node1上而flask-redis容器部署在docker-node2主机上)
docker build -t cdtaogang/flask-redis .
2. 紧接着通过cdtaogang/flask-redis image创建基于my-overlay network的flask-redis容器
docker run -d --name flask-redis --network my-overlay -e REDIS_HOST=redis cdtaogang/flask-redis
4.3 测试访问
1. 首先查看my-overlay network container 数据,在docker-node2主机上创建的flask-redis容器存在于my-overlay network
docker network inspect my-overlay
2. 进入flask-redis容器中,通过ping docker-node1主机上的redis容器name测试连通性没有问题,并且通过curl工具可以拉取到flask-redis容器运行app程序数据
docker exec -it flask-redis /bin/bash
3. 因为博主在创建flask-redis容器时没有做端口映射,所以当退出容器在使用curl工具拉取数据,则显示被拒绝
4. 删除容器,重新创建flask-redis容器并进行端口映射,测试在docker-node2主机上通过curl工具能够拉取到app数据
docker run -d -p 5000:5000 --name flask-redis --network my-overlay -e REDIS_HOST=redis cdtaogang/flask-redis
5. 现在测试在docker-node1主机上来通过curl工具拉取docker-node2主机上的运行flask-redis容器运行的app数据,也是可以拉取到的,没有任何问题
6. 现在查看docker-node1主机和docke-node2主机上查看本地network 会发现多了一个docker_gwbridge network,这个bridge network是链接到eth1网络接口的,具体可以在github上查看overlay network的架构说明
评论前必须登录!
注册