Docker学习笔记

一、Docker基础知识
1、Docker,作为一个开源的应用容器引擎,让开发者可以打包他们的应用及依赖环境到一个可移植的容器中,然后发布运行任何有Docker引擎的机器上。
Docker在每台宿主机上都启动一个Docker的守护进程,守护进程屏蔽了与具体平台相关的信息,对上层应用提供统一的接口,Docker化的应用,可以在多个平台下运行,它会针对不同的平台,解析给不同平台下的执行驱动、存储驱动和网络驱动去执行。

2、Docker是一个C/S的架构,它的Docker Deamon作为Server段,在宿主机上以后台守护进程的形式运行;Docker Client既可以在本机上以bin命令的形式发送命令,也可以在远端通过RESTful API的形式发送指令;Docker的Server端接收指令并把指令分解为一系列任务去执行。

3、Docker把应用依赖的环境(包括操作系统和共享库等)、依赖的配置文件打包在一起,以虚拟机的形式放到仓库;为了解决这样打包文件过大的问题,引入了分层的概念,把引用分为任意多个层,如操作系统是第一层,依赖的库和第三方软件是第二层,应用的软件包和配置文件是第三层,如果两个应用有相同的底层,就可以共享这些层;若要修改共享层的数据,可将要修改层的文件拷贝到优先级最高的优先级,然后修改,上层会覆盖下层,数据以上层为准,这样就不会造成冲突;

4、Docker使用LXC(后来推出libcontainer)让虚拟机变得轻量化,称为虚拟容器,它的资源消耗和一个普通的进程差不多;在Docker官方仓库里,只需要它有完整的文件系统和程序包,没有动态生成新文件的需求,这种状态称为镜像(image);当把它下载到宿主机上运行提供服务时,则需要有空白层用于写时拷贝,这种状态称为容器(container)。镜像指的是以分层的、可以被LXC/libcontainer理解的文件存储格式。

5、Docker对变更的管理,若有一个镜像,分为三层,想要对这三层的文件分别进行变更,Docker会新增一个第四层,针对更改进行处理,发布时由于原来的镜像已存在仓库,只需上传第四层即可,其他想更新版本的用户也只需下载第四层即可,也就是说,Docker具有版本控制,还可以利用分层特性做到增量更新。

二、Docker基本操作
1、docker run --name db --env MYSQL_ROOT_PASSWORD=example -d mariadb
docker run是一条docker指令,后面所有的是指令的参数;最后的mariadb告诉docker run启动的是mariadb数据库,通过--env MYSQL_ROOT_PASSWORD=example设置传入环境变量MYSQL_ROOT_PASSWORD的值为example,这样就会在初始化mariadb数据库时把root密码设置为example;通过-d参数,把启动的数据库设置到后台运行。否则会在前台运行;通过--name db给这个数据库容器起名;-p 8080:80,把原服务的80端口映射到8080上;--link db:mysql,建立数据库的连接。

2、在ubuntu系统中使用docker,通过sudo apt-get install curl    
curl -sSL https://get.docker.com/ | sh
通过如下命令启动Docker守护进程:sudo service docker start
GitLab是一个类GitHub的开源的代码管理工具,实现了GitHub大部分功能,它可以实现本地部署,搭建公司内部的版本控制系统;
Docker指令中的参数标示符可以重复使用,如要传递多个环境变量,就连续使用多个--env。

3、使用docker ps查看进程,其中有IMAGES和NAMES,对应docker run命令的最后一列mariadb和--name参数,这两个对应着镜像和容器;
仓库、镜像、容器,是Docker的三大基础组件;输入docker,可以看到Docker的指令用法及支持的指令。使用docker run --help来了解用法。Docker指令还支持赋值、解析变量、嵌套等使用;docker version查看docker版本,docker search xxx在仓库查询镜像,docker pull xx/xxx下载镜像,docker run用来创建和运行Docker容器,它需要两个参数,一个是镜像名,一个是在容器中需要运行的命令;docker ps -l查看本机上所有容器的信息,
docker commit 容器ID 新镜像名  ,使用docker inspect 容器ID的前3到4个字符  来查看单个容器信息;docker images查看本机的镜像列表,docker push xx/xxx即可把镜像推送到Docker官方仓库。

三、Docker进阶知识
1、docker容器管理。每个容器都有一个CONTAINER ID作为唯一标示符,我们使用它的简略形式16位(共有128位);使用docker stop 容器ID  来停止容器运行,使用docker start 容器ID  来再次启动容器,也可以通过容器的别名--name来操作;可以通过docker inspect -f {{.xx.xxx}} 容器名字 来提取指定部分的信息;使用docker logs 容器名字 来查看容器的日志,使用docker stats 容器名字  实时查看容器所占用的系统资源;通过docker exec 容器名 容器内执行的命令  来在容器内执行命令,通过docker exec -it 容器名 /bin/bash   相当以root身份登入容器,可以连续执行命令,执行完成后通过
“exit”退出;容器之间的数据交互在同一台主机下,run命令提供
--link contrainerA选项建立容器间的互联,但必须先创建容器A并启动运行,所以容器启动是按顺序的;
使用Docker Compose来将同一个服务中的多个容器依次创建和启动;在项目文件夹(~/服务)下创建一个名字叫做docker-compose.yml的文件,其中配置了需要启动的容器信息,然后就可以通过docker-compose up命令来创建和启动这个服务,docker-compoese start/stop来启动或停止这个服务(需要在该配置文件的路径下,否则通过docker-compose -f 配置文件 start/stop来操作,down是删除项目);通过docker ps -a查看已停止运行的容器,然后通过docker rm 容器名来删除容器(加上-f参数可以强制把正在运行的容器删除);

2、Docker镜像管理。docker images可以查到本机所有镜像,镜像有Image ID,也可以用16位缩略形式,可以使用镜像名字和版本号(TAG)组合唯一标示,若省略版本号,默认使用最新版本;
镜像采用分层,联合文件系统让用户并感觉不到分层的存在,通过docker history命令可以查询镜像分了多少层,每层具体做了什么操作,加上--tree可以打印出完整的内容。已有的分层只能读不能改,上层镜像的优先级高于底层镜像。
联合文件系统允许最多分层为128层,一直叠加容易到达极限,万一底层库需要修改,维护的工作量太大,可以用Dockerfile来维护更新镜像。Dockerfile语法规则:每行都以一个关键字为行首,若一行过长,使用“\”把多行连接到一起。FROM表示镜像的基础:底层镜像是什么,MAINTAINER表示创建者,ENV环境变量,RUN运行shell命令,可用&&连接,COPY将本地文件拷贝到镜像文件系统中,ENTRYPOINT指定将来创建的新容器使用xx来启动这个服务,xx脚本中有启动服务的语句。
通过Dockerfile编译生成镜像,先创建一个镜像文件xx,再把镜像文件放入xx/Dockerfile文件下,再创建一个xx/entrypoint.sh文件,然后,用
docker build -t xx:v1.0来编译Dockerfile,编译过程中每一步对应一个Dockerfile的关键字,每执行完异步都会生成一个临时镜像。之后,维护镜像只要修改Dockerfile中的某条语句,通过docker build重新构建即可。
使用debootstrap工具,可以定制自己需要的最小化的Linux基础镜像。

3、Docker仓库管理。可运行docker login登录Docker Hub账户;
通过docker push xx:1.0来上传镜像,docker pull xxx下载镜像;
需要使用docker-registry组件来构建自己的私有镜像仓库;可直接从官方下载该镜像registry;也可以通过yum install docker-registry -y来下载。
默认情况下,docker-registry使用config_sample.yml进行配置,rpm方式则使用/etc/docker-registry.yml,docker-registry可以针对不同环境选择不同的模板;
docker-registry没有提供安全认证,可以使用Nginx构建一个带认证功能的私有仓库;yum install nginx -y下载nginx,创建/etc/nginx/conf.d/registry.conf文件并完成相应配置,创建/etc/nginx/docker-registry.conf文件,用htpasswd创建认证的用户和密码,命令如下:htpasswd -bc /etc/nginx/docker-registry.htpasswd username password;还需要给Nginx配置SSL证书,先通过命令创建一个自己的CA,然后为Nginx创建证书:使用opensslgenrsa为Nginx创建证书,配置完之后,启动Nginx即可。
在客户端的配置中,需要先安装CA(一系列命令),然后重启Docker,登录Nginx,这会在$home/目录下生成一个.dockercfg文件,保存认证信息,然后就可以上传自己的镜像了,通过docker tag IMAGEID 仓库/repository信息     把本地镜像标记,归入某一仓库,然后docker push 仓库/repository信息 上传

4、Docker网络。
默认情况下,Docker使用网桥(bridge)+NAT的通信模型,Docker在启动时默认会自动创建网桥设备Docker0,并配置IP,可用ifconfig docker0查看;
启动容器时,会创建一对veth虚拟网络设备,并将其中一个veth网络设备附加到docker0网桥,另一个加入容器的网络命名空间,并改名为eth0,这样,同一个Host的容器与容器之间就可以通过docker0通信。
为了与外部网络之间通信,容器引入NAT:
(1)容器与外部网络通信,Docker创建MASQUERADE规则:
-tnat -A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
它将所有从容器(172.17.0.0/16)发出去的、目的地址为Host外部网络的包的IP都修改成Host的IP,并由Host发送出去。
(2)外部网络访问容器,Docker会创建SNAT规则。
可以修改Docker进程的网络配置或容器的网路配置,前者会影响所有的容器;
Docker进程的网络配置,可以指定Docker使用的网桥设备(默认docker0);
可指定网桥设备的IP和掩码;可以配置容器的DNS(在启动某个具体容器时指定DNS);
容器的网路配置,在执行docker run时提供给具体容器的,可以指定容器使用的网络通信方式(默认bridge,none无,container:使用其他容器的网络栈,host使用Host的网络)。

5、Docker数据管理。容器被删除时里面的所有数据也会被删除。
Docker提供了数据卷来持久化数据和容器间共享数据;其中有参数-v,有变量host-dir:  Host上的目录,不存在会创建;container-dir容器内部对应目录,不存在会创建;re|ro控制读写权限;可以不指定host-dir,在容器内部创建一个数据卷;这样会在Host的/var/lib/docker/vfs/dir/目录随机生成一个目录,然后挂载容器的数据卷;用这种方式创建,容器被删除后对应的Host目录也会被删除,不想被删除需要指定Host的目录。默认拥有读写权限。
也可以挂载Host的文件作为容器的数据卷,这种方式主要用于在Host与容器之间共享配置文件,可以将配置文件放在Host上,然后挂载到容器,这样可以随时更改。
为了容器之间共享数据,我们可以创建一个命名的数据卷容器,然后供其他容器挂载;先创建一个包含数据卷的容器,然后通过--volumes-from在其他容器中挂载数据卷;还可以从其他已经挂载容器卷的容器挂载数据卷,这样,删除挂载了数据卷的容器,数据卷并不会被删除,要删除,必须在删除最后一个引用该数据卷的容器时调用dockerrm -v显式删除数据卷。我们可以创建一个日志容器专门用来收集其他容器的日志,可以集中管理日志信息。
可以通过--volumes-from从数据卷挂载数据卷,然后备份数据;恢复数据也是一样。

6、Docker存储驱动。历史:device mapper。。。btrfs。。。overlayfs
将overlayfs作为第一选择。它将lowerdir指向image layer,将upperdir指向container layer,merged将lowerdir和upperdir整合起来提供统一的视图给容器,作为根文件系统。lowerdir和upperdir可以包含相同的文件,upperdir会隐藏lowerdir的文件;读文件时优先读upperdir,写文件时若upperdir不存在,则发起copy_up操作,从lowerdir拷贝文件到upperdir,会拷贝整个文件;删除文件时,upperdir会创建一个whiteout文件,它会隐藏lowerdir的文件(不会删除),删除目录时,生成opaque directory;
可在docker daemon中指定overlay driver启动,然后下载镜像可看到镜像有五个layer,每个layer对应一个目录,创建容器后,可看到容器对应的目录有三个(merged、upper、work),work用于实现copy_up操作,lower-id保存imageID。在容器中创建文件后,文件出现在upper目录;

7、Docker日常维护
安装docker后,需要把Docker的数据目录转移到大的磁盘分区上:
mkdir /data/dockerData/     mv /var/lib/docker /data/dockerData/
ln -s /data/dockerData/ /var/lib/docker;
升级docker到最新版本;在/etc/sysctl.conf添加net.ipv4.ip_forward=1,然后sysctl -p使配置生效;
默认网络配置的是NAT模式,如果要配置网桥模式,需要三步:
(1)宿主机配网桥:备份网卡配置,修改eth1配置文件,修改br1配置文件,重启网卡;
(2)安装pipework脚本,用于给container指定IP;
(3)更新iproute,yum install iproute
备份通过在docker run后面加 gitlab:backup:create,备份的文件在-v后面的路径加/backups下(还要修改--name,增加一个--rm);通过gitlab:backup:restore BACKUP=xxx指定要恢复到哪个版本;不同版本备份的文件不能相互使用;不能在运行时备份;备份生成的是xxx_gitlab_backup.tar,xxx为版本号;

8、Docker Swarm容器集群。主要学习Docker Swarmkit。
Docker内嵌Swarmkit提供集群管理,集群所有节点对等,可成为Manager或Worker,Manager节点内嵌raft协议实现高可用并存储集群状态;Service表示作业,Task表示作业的副本,一个Service可以包含多个Task,每个Task是一个容器,同一个Service的所有Task状态对等,支持Task的缩容和扩容,自动容错,一个Worker节点挂了,容器自动迁移到其他Worker节点;每个节点使用对等的TLS通信,由Manager下发;支持跨主机的网络模型;
在Manager节点,使用docker swarm init --advertise-addr managerip 创建Swarm集群,可以使用docker info和docker node ls查看节点状态;然后在worker节点,执行docker swarm join -token xxx加入集群,token的参数由manager节点执行docker swarm join-token worker获取,成功后可看到所有节点的状态;
Swrmkit的基本功能;在manager节点使用docker service create创建service,用--replicas n参数指定创建若n个保持运行的task;可用docker service ls查看所有的service,用docker service rm servicename可以删除service;
使用docker service scale servicename=x对service进行扩容或缩容;
在docker service create中--update-delay xs参数配置service灰度升级的时间间隔,可以使用--update-parallelism配置并打升级的task数;使用docker service update将使用的镜像升级,--image参数指定升级的版本;
创建service时用--publish参数配置容器NAT网络的端口映射;使用docker network create --driver overlay name创建overlay网络,之后可以在创建service时使用--network 网络name  参数配置容器加入这个网络;将service接入Overlay网络时,Swarm会给service分配一个VIP,还会将所有访问VIP的流量均衡到所有的task上,直接查询nslookup servicename返回这个service的VIP,查询tasks.servicename返回所有task的IP;
使用docker node update --availability drain workern 对worker进行下线操作,scheduler会把drain状态的节点上的task迁移到其他节点;用--availability active可以重新使节点可用,用docker node inspect --pretty workern可查看状态;
使用docker node promote/demote xxx可将节点升级或降级;用docker swarm leave可将节点的docker退出swarm状态;容器之间使用LVS做NAT负载均衡,通过配置iptables和ipvs规则;

9、Docker插件;docker daemon进程通过查询插件目录发现插件进程,支持.sock,.spec,.json文件,.sock文件必须位于/run/docker/plugins目录下,.spec和.json必须位于/etc/docker/plugins或/usr/lib/docker/plugins目录下,文件名字就是插件名字;
可以利用systemd的socket activiation功能管理插件的启动顺序,需要编写两个文件,service文件和socket文件(/lib/systemd/system/your-plugins.socket),service文件(/lib/systemd/system/your-plugins.service)这样将在docker daemon去连接socket时才启动;
Docker官方提供了一个插件的SDK工具,定义好了各插件的API接口和参数,可以用它快速开发插件。
使用docker volume create --driver local --name xx  利用local插件创建名为xx的volume,还有docker volume rm/ls/inspect;使用sdk包和cgroupfs包来实现cgroupfs-volume volume插件,在docker volume create时增加cidfile=/tmp/containerid,在docker run/create 时增加--cidfile /tmp/containerid即可获取到containerid;

四、Docker案例
1、一个Docker的离线系统应用案例,借助于Clip名字服务工具,可以非常方便的管理海量服务器,并且可以通过服务混合部署充分利用机器的各项资源,有效地降低机房的运营成本。

2、Etcd(服务发现的键值存储系统),Kubernetes(Docker的容器集群管理平台),Cadvisor(容器监控平台);
Etcd,主要用于分享配置和服务发现,具有简单、安全、快速、可靠的特点。创建etcdserver时,参数--peer--addr指定与其他节点通信的地址(这是集群数据交互端口),参数--addr指定服务监听地址(这是服务端口),参数-data-dir为指定数据存储目录;需要为Etcd服务配置防火墙;
提供了两种操作方法,基于HTTP的RESTful API(通过curl来操作)和通过命令etcdctl操作:
(1)设置键值
(2)获取键值
(3)更新键值
(4)删除键
(5)创建目录
(6)删除目录
(7)捕捉key的vlaue更新事件 :执行命令后会处于等待状态,直到key的值发生改变才退到系统提示符;

3、Cadvisor是google用来分析运行中的Docker容器的资源占用及性能特性的工具。它是一个运行中的守护进程,用来收集、聚合、处理和导出运行容器相关信息;它提供前段UI及API接口,以供第三方程序进行调用;
Cadvisor提供了远程REST API,可以调用UI看到的所有数据;
获取容器性能数据,访问格式:http://hostname:port/api/version/containers(所有容器)/docker/containerID(指定容器),返回json格式数据;
获取宿主机性能数据:http://hostname:port/api/v1.0/machine,一样是json;

4、Kubernetes是google开源的容器集群管理系统,基于Docker构建一个容器调度服务,提供资源调度、均衡容灾、服务这侧、动态扩缩容等功能套件;
基本概念:
(1)Nodes:代表Kubernetes平台中的工作节点,如一台宿主机;
(2)Pods:在Kubernetes调度的最小颗粒,Pod是一个可以被创建、销毁、调度、管理的最小单元如一个或一组容器;
(3)The Life of a Pod:Pod的状态、事件及重启生命周期策略、复制控制器等;
(4)Replication Controllers:实现复制多个Pod副本,可以通过repcon末班来创建多个Pod副本,也可以直接复制已存在的Pod,需要通过Label selector来关联;
(5)Service:Kubernetes最外围的单元,通过虚拟一个访问IP及服务端口,可以访问我们定义好的Pod资源;
(6)Volumes:一个能被容器访问的目录,可能还包括一些数据;
(7)Labels:用于区分Pod、Service、Replication Controller的键值对,用于关系识别,对这些单元操作时要用到name标签;
(8)Accessing the API:Kubernetes中端口、IP、代理服务器和防火墙规则;
(9)Kubernetes Web Interface:访问Kubernetes Web接口;
(10)Kubectl Command Line Interface:Kubernetes命令行接口,如kubectl;
Kubernetes调度流程:
kubernetes调度器通过API Server查找还未分配主机的Pod,并尝试为这些Pod分配主机:
客户端提交创建请求,可以通过API Server的Restful API,也可以使用kubectl命令行工具。支持的数据类型包括JSON和YAML。
API Server处理用户请求,存储Pod数据到etcd。
调度器通过API Server查看未绑定的Pod。尝试为Pod分配主机。
过滤主机:调度器用一组规则过滤掉不符合要求的主机。比如Pod指定了所需要的资源量,那么可用资源比Pod需要的资源量少的主机会被过滤掉。
主机打分:对第一步筛选出的符合要求的主机进行打分,在主机打分阶段,调度器会考虑一些整体优化策略,比如把容一个Replication Controller的副本分布到不同的主机上,使用最低负载的主机等。
选择主机:选择打分最高的主机,进行binding操作,结果存储到etcd中。
所选主机对于的kubelet根据调度结果执行Pod创建操作。

在Master节点上配置Kubernetes,运行三个组件:apiserver、scheduler(调度器,负责收集和分析当前Kubernetes集群中所有Minion节点的资源的负载情况)、controller-manager;配置完之后启动服务;
在Minion主机上运行两个组件:kubelet、proxy,配置完后启动;
Kubernetes提供了两种API操作方式:kubectl命令行,HTTP REST方式;第二种可在非master主机上通过HTTP方式调用操作,且及时性更高;
Kubernetes中支持json格式来描述资源或对象,如pod、replication、service等;pod的json描述中有两个关键的配置项,“container”标签定义一个完整的容器描述,“labels”标签,定义该pod的引用描述(name等);
创建replication时,它的json文件中,“replicas”指定复制的分数,“replicaSelector”为复制选择器,即复制的pod对象,与pod模板的labels标签一致,在DesiredState.desiredState节点中定义完整的容器描述信息;这个replication创建完之后会出现pod副本,平均分配到不同宿主机上,都处于运行状态;
创建service,通过指定selector的“name”:podname 与pods进行关联;通过“protocol”指定服务的协议,“containerPort”为指定容器的服务端口,“port”为映射的服务端口;启动后,任意一台Minion主机通过iptables将所有访问的目标IP的端口映射值代理端口,这个代理端口为该service定义pods所对应的容器服务端口;

5、Docker构建方案,有Kubernetes和CoreOS,还有Haproxy+Etcd+Confd;
由Haproxy+Etcd+Confd+Docker构建的基础服务平台简称“HECD”架构,
Etcd负责存储容器的注册信息;
Confd是一个轻量级的配置管理工具,通过查询Etcd,结合配置末班引擎,保持本地配置最新。负责读取Etcd集群中容器的注册信息并刷新接入层Haproxy的配置;
Haproxy是提供高可用性、负载均衡及基于TCP和HTTP应用的代理,支持虚拟主机;作为业务的接入层,包括容器服务的负载均衡、故障迁移等功能;
构架流程:管理员通过Shell或API操作容器,如创建或销毁容器;然后将容器创建、销毁信息提交至Etcd集群集群,使之变更;Confd组件通过定时向Etcd集群发送查询请求,获得最新提交至Etcd中的容器信息,通过Confd的模板引擎生成Haproxy配置文件,最后刷新Haproxy配置使之服务生效,流程结束。
接入层需要安装haproxy和Confd;主宿机需要安装docker;存储层需要安装Etcd;
Confd的配置有两类,一类为Confd资源配置文件,定义外部应用程序的基本信息,默认路径为“/etc/confd/conf.d”目录,另一类为配置模板文件,默认路径为“/etc/confd/templates”
Confd模板引擎常用语法及结果输出:
(1)base函数
作为path.Base函数的别名,获取URI路径的最后一段;
(2)get函数
返回一对匹配的KV,找不到则返回错误
(3)gets函数
返回所有匹配的KV,找不到则返回错误;
(4)getv函数
返回一个匹配key的字符串型Value,找不到则返回错误;
(5)getvs函数
返回所有匹配key的字符串行Value,找不到则返回错误;
(6)split函数
对输入的字符串做split处理,按指定分隔符拆分成数组;
(7)ls函数
返回所有的字符串型subkey,找不到则返回错误;
(8)lsdir函数
返回所有的字符串型子目录,找不到则返回一个空列表;
启动Confd命令行中,参数“interval”指定探测Etcd的频率,单位为秒,参数“-node”为指定Etcd监听服务地址,以获取容器注册的信息;

对容器的操作会即时注册到Etcd组件中,是通过curl命令以REST-API方式提交的,可通过Shell及Python-API两种方式实现;
shell的原理是通过获取docker run ***的命令输出的containerid,再通过docker inspect containerid得到更详细的信息,以“/app/server/容器名称”作为Key,“主宿机:映射端口”作为Value注册到Etcd中,其中/app/servers与“/etc/confd/conf.d/haproxy.toml”中的keys参数保持一致;shell脚本写完后,只需xx.sh run 镜像名(启动一个容器),xx.sh stop 容器名(停止一个容器)
Python-API实现,需对Docker启动文件exec进行修改;然后分别编写docker_start.py和docker_stop.py两个文件来完成操作;


6、Docker Overlay Network实践
启动docker:docker daemon --cluster-store=etcd://xxx.xx:xxxx --cluster-advertise=eth0:xxxx  --cluster-store参数指定docker daemon使用的键值服务的地址,--cluster-advertise参数决定了所使用网卡及docker daemon端口信息;当docker daemon启动后,会自动创建三个网络:bridge、host、none,可通过docker network ls查看;
通过docker network create --internal -d overlay --subnet=xxx.xx.xx.x/xx overlay  subnet参数指定使用的网段;
启动容器在docker run后加参数--net=overlay,容器之间就可以互相访问;
Docker会为每个Overlay Network创建一个独立的network namespace,名称为
1-$ID的形式,可通过ip netns ls查看;再用ip netns exe 1-$ID ip a查看详细信息,用ip netns exe 1-$ID brctl show查看信息,其中veth2连接容器内部的Veth网络设备(eth0),vxlan1为VXLAN设备,负责VXLAN协议的封装和解封;
我们可以给VXLAN设备配置IP/MAC映射关系,这样就不需要下层的IP组播网络了。VXLAN内部维护了一张的转发表(FDB),Docker在创建容器时,就会将容器对应的MAC地址和Host IP信息,加到转发表中,用ip netns exe 1-$ID bridge fdb show dev vxlan1查看;
Overlay网络无法直接与外部网络通信,假设容器vm1需要访问外部主机,我们可以将vm1加入bridge网络(docker network connect bridge vm1),然后通过vm1主机上的NAT实现与node3的通信;

你可能感兴趣的:(Dcoker)