Section 01 - Vagrant
Vagrant is a tool for building and managing virtual machine environments in a single workflow. With an easy-to-use workflow and focus on automation, Vagrant lowers development environment setup time, increases production parity, and makes the "works on my machine" excuse a relic of the past.
Vagrant是一个构建和管理虚拟机的工具,使用Vagrant可以非常方便的构建、启动、关闭或者复制多个相同的虚拟机环境
使用Vagrant + VirtualBox可以非常快速的搭建两台或者多台虚拟机集群
Vagrant常用命令
vagrant up # 启动当前目录下Vagrantfile中设置的虚拟机 vagrant halt # 关闭虚拟机 vagrant reload # 重启虚拟机 vagrant ssh # 连接虚拟机 vagrant status # 查看虚拟机启动状态 vagrant suspend # 挂起虚拟机 vagrang destroy # 销毁当前虚拟机 vagrant reload --provision # 按照Vagrantfile配置重新启动虚拟机 vagrant up --provision # 按照其他配置启动虚拟机 vagrant init # 初始化 vagrant box list # 查看本地box列表 vagrant box add # 添加到box列表 vagrant box remove # 从boxe列表中移除 复制代码
# 创建两台机器 docker-node1 docker-node2 vagrant up vagrant status vagrant ssh docker-node1 # 修改Linux主机名 sudo hostnamectl set-hostname docker-node1 exit vagrant ssh docker-node1 docker version exit vagrant ssh docker-node2 docker veresion sudo hostnamectl set-hostname docker-node2 exit vagrant ssh docker-node2 # 互相 ping,查看是否能够ping通 复制代码
Section 02 - Docker网络
相关网络概念
- Public IP:互联网上的唯一标识,可以访问Internet
- Private IP:不可以在互联网上使用,仅限内部网络访问
相关网络命令
- ping:用于验证IP的可达性
- telnet:验证服务的可用性
Linux的网络命名空间
docker run -d --name test1 busybox /bin/sh -c "while true; do sleep 3600; done" # 进入到容器中,fb是Container ID的简写 docker exec -it fb /bin/sh # 获取网络命名空间 ip a # 退出容器 exit # 创建第二个容器 docker run -d --name test2 busybox /bin/sh -c "while true; do sleep 3600; done" # 交互式执行命令,查看网路Namespace, 25ea是Container ID的简写 docker exec -it 25ea ip a 复制代码
创建容器时就会创建一个Namespace,这个Namespace跟主机的Namespace是隔离的
这是第一个网络的Namespace
第二个容器的网络命名空间
创建和管理Linux 网络的Namespace,并使两个network namespace相通
Docker Network Namespace实践
vagrant up docker-node1 vagratn up docker-node2 vagrant status vagrant ssh docker-node1 # 查看本机有的network namespace, netns是network namespace的简写 sudo ip netns list # 删除network namespace sudo ip netns delete test1 # 添加network namespace sudo ip netns add test1 sudo ip netns add test2 # 查看network namespace的IP地址 sudo ip netns exec test1 ip a # 让lo端口up sudo ip netns exec test1 ip link set dev lo up sudo ip link add veth-test1 type veth peer name veth-test2 ip link # 将veth-test1添加到test1 sudo ip link set veth-test1 netns test1 sudo ip netns exec test1 ip link # 将veth-test2添加到test2 sudo ip link set veth-test2 netns test2 sudo ip netns exec test2 ip link # 分配 IP 地址 sudo ip netns exec test1 ip addr add 192.168.1.1/24 dev veth-test1 sudo ip netns exec test2 ip addr add 192.168.1.2/24 dev veth-test2 # 查看是否有IP地址 sudo ip netns exec test1 ip link sudo ip netns exec test2 ip link # 启动veth sudo ip netns exec test1 ip link set dev veth-test1 up sudo ip netns exec test2 ip link set dev veth-test2 up # 查看是否有IP地址 sudo ip netns exec test1 ip a sudo ip netns exec test2 ip a # 执行ping,查看是否有数据传输 sudo ip netns exec test1 ping 192.168.1.2 sudo ip netns exec test2 ping 192.168.1.1 复制代码
sudo ip netns exec test1 ip a 复制代码
Linux container 中用到一个叫做veth的东西,这是一种新的设备,专门为 container 所建。veth 从名字上来看是 Virtual ETHernet 的缩写,它的作用很简单,就是要把从一个 network namespace 发出的数据包转发到另一个 namespace。veth 设备是成对的,一个是 container 之中,另一个在 container 之外,即在真实机器上能看到的。
VETH设备总是成对出现,送到一端请求发送的数据总是从另一端以请求接受的形式出现。创建并配置正确后,向其一端输入数据,VETH会改变数据的方向并将其送入内核网络子系统,完成数据的注入,而在另一端则能读到此数据。(Namespace,其中往veth设备上任意一端上RX到的数据,都会在另一端上以TX的方式发送出去)veth工作在L2数据链路层,veth-pair设备在转发数据包过程中并不串改数据包内容。
两个namespace之间互相通信
Docker Bridge
docker start test1 docker start test2 docker exec -it test1 ip a docker exec -it test2 ip a # 进入test1 docker exec -it test1 /bin/sh # ping另外一个容器的ip ping 172.17.0.2 复制代码
Docker中是通过bridge0代替veth链接两个容器
docker stop test2 docker rm test2 # 列举当前机器上的网络,test1正在运行中 docker network ls # 查看网络详情 docker network inspect 28af3c328fe0 ip a # 查看test1容器的网络 docker exec -it test1 ip a # 验证veth是连到docker0上的 brctl show # 在创建一个容器test2 docker run -d --name test2 busybox /bin/sh -c "while true; do sleep 3600; done" docker network ls docker network inspect bridge # 多出了一个veth,用来与test2 brctl show # docker0 连了两个接口 bridge name bridge id STP enabled interfaces docker0 8000.0242f0fecf55 no vethb22ca59 vethd2fffa8 复制代码
下图说明test1容器连到birdge上
ip a命令展示
vethd2fffa8@if7 和 eth0@if8是一对
container 通过这一对端口可以连接到主机的网络上面及连接到了docker0上
验证veth是连接在docker0上的
docker network inspect bridge有两个容器连到了bridge网络
两个容器之间的连接方式
容器与外网通信
容器之间的Link
建立link之后,可以直接通过容器名字访问该容器
# 首先删除test2 docker stop test2 doker rm test2 # 再次创建test2,通过添加--link参数, --link test1 docker run -d --name test2 --link test1 busybox /bin/sh -c "while true; do sleep 3600; done" # 进入容器中 docker exec -it test2 /bin/sh # 可以用容器名字代替ip ping test1 复制代码
新建容器的网络使用自定义的网络,不使用bridge
# -d bridge表示使用bridge为驱动,my-bridge为创建的网络的名字 docker network create -d bridge my-bridge docker network ls brctl show # 新建一个容器,并指定使用新创建的网络 docker run -d --name test3 --network my-bridge busybox /bin/sh -c "while true; do sleep 3600; done" # 查看容器网络 docker inpect test3 brctl show # 已运行的容器连到具体网络 docker network connect my-bridge test2 docker inpect my-bridge 复制代码
容器之间的端口映射
如果两个容器连接到同一个网络(自定义的网路,系统默认网络不可以)上面,可以通过容器名字ping通,除了通过命令行访问docker部署的应用,还有其他方式,通过暴露端口给外界(不仅仅是在docker宿主机上)提供服务,将端口映射到宿主机的端口上面。
实践,以Nginx为例
docker run -d --name web nginx docker exec -it web /bin/bash # 容器默认连接到bridge上,通过查看bridge,确定容器的IP docker network inspect bridge # 确定容器的80端口是否可以访问 telnet 172.17.0.4 80 curl http://172.17.0.4 # 删除web容器,重新创建一个 容器 -p 80:80, 第一个80是容器的端口,第二个是宿主机的端口 docker run -d --name web -p 80:80 nginx # 访问本机的80端口,显示nginx信息 curl 127.0.0.1:80 复制代码
容器网络之host和none
没有独立的network namespace,与主机共享network namespace,可能会出现端口冲突
docker run -d --name test2 --network host busybox /bin/sh -c "while true; do sleep 3600; done" docker network inspect host docker exec -it test2 /bin/bash ip a 复制代码
none网络是一个孤立的网络,只能通过docker exec -it 访问容器,用来存储密码等敏感信息
# 创建一个容器,使用none网络 docker run -d --name test1 --network none busybox /bin/sh -c "while true; do sleep 3600; done" docker network inspect none docker exec -it test1 /bin/bash ip a