Docker已经上市很多年,不是什么新鲜事物了,很多企业或者开发同学以前也不多不少有所接触,但是有实操经验的人不多,本系列教程主要偏重实战,尽量讲干货,会根据本人理解去做阐述,具体官方概念可以查阅官方教程,本章目标如下

本系列教程导航:

Docker深入浅出系列 | 容器初体验

Docker深入浅出系列 | Image实战演练

教程目标

  • 了解Docker容器网络通信原理
  • 了解Linux网络虚拟化技术的原理
  • 了解容器在Linux上怎么进行网络隔离
  • 了解Docker端口映射配置
  • 了解Docker的网络模式
  • 了解如何在Docker使用自定义网络
  • 了解Docker网络操作的一些常用指令

准备工作

本教程是基于第一章创建的虚拟机、操作系统和Docker演示

  • 虚拟机 - VirtualBox-6.0.14-133895-OSX.dmg
  • 虚拟机管理工具 - Vagrant_2.2.6_x86_64.dmg
  • 操作系统 - Centos7
  • 容器技术 - Docker

带着问题开车

同一主机两个容器如何相互通信?

在同一台主机内的两个容器是怎么通信的呢?

两个容器是怎么做到网络隔离的呢?

怎么从服务器外访问容器

我怎样才能在服务器外通过浏览器访问到服务器里的端口为8080的容器的资源?

Docker的三种网络模式是什么

Docker的三种网络模式是什么,都有什么特点呢?


Docker网络通信原理

计算机网络模型回顾

在互联网世界,两台主机要进行通信,是通过两个网卡/网络接口连接起来,接收和发送数据包都经过网卡,两个网卡之间相当于建立了一条通信管道。

Linux中的网卡

查看网卡接口信息

1.查看链路层网卡信息

ip link show

  1. [root@10 /]# ip link show
  2. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
  3. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  4. 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
  5. link/ether 52:54:00:8a:fe:e6 brd ff:ff:ff:ff:ff:ff
  6. 3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
  7. link/ether 08:00:27:ba:0a:28 brd ff:ff:ff:ff:ff:ff
  8. 4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
  9. link/ether 02:42:12:9a:b1:a7 brd ff:ff:ff:ff:ff:ff

2.显示应用层网卡信息,可以看到更多详细信息,例如ip地址

ip a

  1. [root@10 /]# ip a
  2. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
  3. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  4. inet 127.0.0.1/8 scope host lo
  5. valid_lft forever preferred_lft forever
  6. inet6 ::1/128 scope host
  7. valid_lft forever preferred_lft forever
  8. 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
  9. link/ether 52:54:00:8a:fe:e6 brd ff:ff:ff:ff:ff:ff
  10. inet 10.0.2.15/24 brd 10.0.2.255 scope global noprefixroute dynamic eth0
  11. valid_lft 57001sec preferred_lft 57001sec
  12. inet6 fe80::5054:ff:fe8a:fee6/64 scope link
  13. valid_lft forever preferred_lft forever
  14. 3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
  15. link/ether 08:00:27:ba:0a:28 brd ff:ff:ff:ff:ff:ff
  16. inet 192.168.100.12/24 brd 192.168.100.255 scope global noprefixroute dynamic eth1
  17. valid_lft 143401sec preferred_lft 143401sec
  18. inet6 fe80::a00:27ff:feba:a28/64 scope link
  19. valid_lft forever preferred_lft forever
  20. 4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
  21. link/ether 02:42:12:9a:b1:a7 brd ff:ff:ff:ff:ff:ff
  22. inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
  23. valid_lft forever preferred_lft forever

3.显示系统所有的网卡

ls /sys/class/net

  1. [root@10 /]# ls /sys/class/net
  2. docker0 eth0 eth1 lo

网卡的操作

ip a核心信息详解

  1. 3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
  2. link/ether 08:00:27:ba:0a:28 brd ff:ff:ff:ff:ff:ff
  3. inet 192.168.100.12/24 brd 192.168.100.255 scope global noprefixroute dynamic eth1
  4. valid_lft 143401sec preferred_lft 143401sec
  5. inet6 fe80::a00:27ff:feba:a28/64 scope link
  6. valid_lft forever preferred_lft forever

<BROADCAST,MULTICAST,UP,LOWER_UP>这个配置串告诉我们:

BROADCAST 该接口支持广播

MULTICAST 该接口支持多播

UP 网络接口已启用

LOWER_UP 网络电缆已插入,设备已连接至网络

其他配置信息:

mtu 1500 最大传输单位(数据包大小)为1,500字节

qdisc pfifo_fast 用于数据包排队

state UP 网络接口已启用

group default 接口组

qlen 1000 传输队列长度

link/ether 08:00:27:ba:0a:28 接口的 MAC(硬件)地址

brd ff:ff:ff:ff:ff:ff 广播地址

inet 192.168.100.12/24 绑定的IPv4 地址

brd 192.168.0.255 广播地址

scope global 全局有效

dynamic eth1 地址是动态分配的

valid_lft 143401sec IPv4 地址的有效使用期限

preferred_lft 143401sec IPv4 地址的首选生存期

inet6 fe80::a00:27ff:feba:a28/64 IPv6 地址

scope link 仅在此设备上有效

valid_lft forever IPv6 地址的有效使用期限

preferred_lft forever IPv6 地址的首选生存期

网卡的配置文件

通过以下命令,可以查看对应网卡的配置信息,ifcfg-*文件

cat /etc/sysconfig/network-scripts/ifcfg-eth0

修改网卡配置,绑定一个新ip地址

这里可以修改配置文件ifcfg-*直接复制一份新的ip配置添加,但是我默认网络用的是动态ip,通过命令会更方便

  1. [root@10 /]# ip addr add 192.168.0.100/24 dev eth0

从下面可以看到,通过ip a查看,新的ip已经成功绑定

  1. 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
  2. link/ether 52:54:00:8a:fe:e6 brd ff:ff:ff:ff:ff:ff
  3. inet 10.0.2.15/24 brd 10.0.2.255 scope global noprefixroute dynamic eth0
  4. valid_lft 54131sec preferred_lft 54131sec
  5. inet 192.168.0.100/24 scope global eth0
  6. valid_lft forever preferred_lft forever
  7. inet6 fe80::5054:ff:fe8a:fee6/64 scope link
  8. valid_lft forever preferred_lft forever

可以通过以下指定,把新增的ip清理掉

ip addr delete 192.168.0.100/24 dev eth0

网卡的重启与启动

重启网卡

service network restart / systemctl restart network

启动或者关闭网卡

ifup/ifdown eth0 or ip link set eth0 up/down

Linux网络虚拟化技术

从上文我们可以知道,两个主机通信是通过两个网卡连接起来,那在同一个Linux系统,怎么模拟多个网络环境,两个容器是怎么做到网络隔离呢?

在Linux系统中,是通过network namespace来进行网络隔离,Docker也是利用该技术,创建一个完全隔离的新网络环境,这个环境包括一个独立的网卡空间,路由表,ARP表,ip地址表,iptables,ebtables,等等。总之,与网络有关的组件都是独立的。

ip命令提供了ip netns exec子命令可以在对应的network namesapce进行操作,要执行的可以是任何命令,不只是和网络相关的,创建network namesapce后可以通过ip ntns exec+namespace名+shell指令进行操作。例如在对应namespace查看网卡信息ip ntns exec nsn1 ip a

创建虚拟网络环境

常用的一些network namespace指令如下:

  1. ip netns list #查看network namespace
  2. ip netns add ns1 #添加network namespace
  3. ip netns delete ns1 #删除network namespace

创建namespace - ns1

1.创建network namespace - ns1

  1. [root@10 /]# ip netns add ns1

2.查看ns1网卡信息

  1. [root@10 /]# ip netns exec ns1 ip a
  2. 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
  3. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

可以看到这时候网卡状态是Down,此时只有一个lo网卡

3.启动ns1上的lo网卡

  1. [root@10 /]# ip netns exec ns1 ifup lo

4.查看网卡状态

  1. [root@10 /]# ip netns exec ns1 ip a
  2. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state unk group default qlen 1000
  3. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  4. inet 127.0.0.1/8 scope host lo
  5. valid_lft forever preferred_lft forever
  6. inet6 ::1/128 scope host
  7. valid_lft forever preferred_lft forever

此时网卡状态已经变成UNKOWN,lo网卡上也绑定了一个本地回环地址127.0.0.1/8

创建namespace - ns2

重复上面步骤,按照上面的指令把ns1改为ns2执行一边,最后可以看到网卡状态也为UNKOWN

  1. [root@10 /]# ip netns exec ns2 ip a
  2. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
  3. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  4. inet 127.0.0.1/8 scope host lo
  5. valid_lft forever preferred_lft forever
  6. inet6 ::1/128 scope host
  7. valid_lft forever preferred_lft forever

经过上面的一系列步骤,两个network namespace的网络结构如下:



此时两个Network Namespace只有lo设备,互相之间是没有关联,无法通信,只能同一Network Namesapce内的应用访问。

连通两个Network Namespace

Linux提供Virtual Ethernet Pair技术,分别在两个namespace建立一对网络接口,类似在两个name space之间建立一条pipe,好像拉一条网线一样,让彼此之间可以通信,简称veth pair

veth pair是成对出现,删除其中一个,另一个也会自动消失。

1.创建连一对veth虚拟网卡,类似pipe,发给veth-ns1的数据包veth-ns2那边会收到,发给veth2的数据包veth0会收到。就相当于给机器安装了两个网卡,并且之间用网线连接起来了,两个虚拟网卡分别为veth-ns1、veth-ns2

  1. [root@10 /]# ip link add veth-ns1 type veth peer name veth-ns2

2.查看link,可以看到连接已经建立

  1. [root@10 /]# ip link
  2. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
  3. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  4. 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
  5. link/ether 52:54:00:8a:fe:e6 brd ff:ff:ff:ff:ff:ff
  6. 3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
  7. link/ether 08:00:27:ba:0a:28 brd ff:ff:ff:ff:ff:ff
  8. 4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
  9. link/ether 02:42:12:9a:b1:a7 brd ff:ff:ff:ff:ff:ff
  10. 5: veth-ns2@veth-ns1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
  11. link/ether 2a:96:f4:e3:00:d2 brd ff:ff:ff:ff:ff:ff
  12. 6: veth-ns1@veth-ns2: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
  13. link/ether da:89:0e:56:03:3f brd ff:ff:ff:ff:ff:ff

3.把两个虚拟网卡分别加到两个network name space ns1、ns2中

  1. [root@10 /]# ip link set veth-ns1 netns ns1
  2. [root@10 /]# ip link set veth-ns2 netns ns2

4.分别查看宿主机器和两个network namesapce的情况

  1. ip link ip netns exec ns1 ip link ip netns exec ns2 ip link

ns1上的虚拟网卡信息

  1. 6: veth-ns1@if5: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
  2. link/ether da:89:0e:56:03:3f brd ff:ff:ff:ff:ff:ff link-netnsid 1

ns2上的虚拟网卡信息

  1. 5: veth-ns2@if6: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
  2. link/ether 2a:96:f4:e3:00:d2 brd ff:ff:ff:ff:ff:ff link-netnsid 0

通过上面指令执行结果可以看到原来宿主机的一对虚拟网卡已经移到两个network namespace那,当前的网卡状态还是DOWN,两个网卡的序列号是按顺序成对的@if5、@if6

5.分别启动这两个虚拟网卡

  1. [root@10 /]# ip netns exec ns1 ip link set veth-ns1 up
  2. [root@10 /]# ip netns exec ns2 ip link set veth-ns2 up

执行结果分别如下:

  • ns1
  1. 6: veth-ns1@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
  2. link/ether da:89:0e:56:03:3f brd ff:ff:ff:ff:ff:ff link-netnsid 1
  • ns2
  1. 5: veth-ns2@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
  2. link/ether 2a:96:f4:e3:00:d2 brd ff:ff:ff:ff:ff:ff link-netnsid 0

可以看到此时两个虚拟网卡状态为UP,都已经启动,但还没有IP地址,因此还不能通信

6.给虚拟网卡配置IP地址

  1. [root@10 /]# ip netns exec ns1 ip addr add 192.168.0.11/24 dev veth-ns1
  2. [root@10 /]# ip netns exec ns2 ip addr add 192.168.0.12/24 dev veth-ns2

7.通过ip a查看ip地址是否配置成功

  1. root@10 /]# ip netns exec ns1 ip a
  1. root@10 /]# ip netns exec ns2 ip a

8.测试ns1和ns2是否可以互相连通

  1. [root@10 /]# ip netns exec ns1 ping 192.168.0.12
  2. PING 192.168.0.12 (192.168.0.12) 56(84) bytes of data.
  3. 64 bytes from 192.168.0.12: icmp_seq=1 ttl=64 time=0.048 ms
  1. [root@10 /]# ip netns exec ns2 ping 192.168.0.11
  2. PING 192.168.0.11 (192.168.0.11) 56(84) bytes of data.
  3. 64 bytes from 192.168.0.11: icmp_seq=1 ttl=64 time=0.041 ms
  4. 64 bytes from 192.168.0.11: icmp_seq=2 ttl=64 time=0.039 ms
  5. 64 bytes from 192.168.0.11: icmp_seq=3 ttl=64 time=0.041 ms

这时候,两个network namespace已经成功连通了

通过Bridege建立多个namesapce通信

以上的veth pair只能解决两个namesapce之间的通信问题,但是多个namesapce是不能直接互相通信,因为处于不同的网络,在日常生活中,我们会用到交换机去连接不同的网络,而在Linux,我们可以通过bridege去实现。



在上图可以看到,这时候连个namespace ns3、ns4并不是直接通过veth pair连接,而是通过bridge间接连接,接下来我会一步步教大家怎么按照上图设置

1.创建Network Space

为了避免跟上面混淆,我们重新创建新的namespace

  1. [root@10 /]# ip netns add ns3
  2. [root@10 /]# ip netns add ns4
  3. [root@10 /]# ip netns add bridge

2.创建一对veth pair网卡

  1. [root@10 /]# ip link add type veth

3.查看宿主机上生成的一对虚拟网卡

  1. [root@10 /]# ip link
  2. ...
  3. 7: veth0@veth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
  4. link/ether 36:8e:bc:43:f0:4a brd ff:ff:ff:ff:ff:ff
  5. 8: veth1@veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
  6. link/ether 92:c0:44:18:64:93 brd ff:ff:ff:ff:ff:ff

可以看到,宿主机已经存在一对网卡veth1、veth0

4.让veth0加入到ns3中,让veth1加入到bridge中,并分别把虚拟网卡重命名为ns3-bridge、bridge-ns3

  1. [root@10 /]# ip link set dev veth0 name ns3-bridge netns ns3
  2. [root@10 /]# ip link set dev veth1 name bridge-ns3 netns bridge

5.在创建一对veth pair,让veth0加入到ns4中,让veth1加入到bridge中,并分别把虚拟网卡重命名为ns4-bridge、bridge-ns4

  1. [root@10 /]# ip link add type veth
  2. [root@10 /]# ip link set dev veth0 name ns4-bridge netns ns4
  3. [root@10 /]# ip link set dev veth1 name bridge-ns4 netns bridge

6.分别进入各个namespace查看网卡信息

  • ns4
  1. [root@10 /]# ip netns exec ns4 ip a
  2. ...
  3. 9: ns4-bridge@if10: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
  4. link/ether ea:53:ea:e6:2e:2e brd ff:ff:ff:ff:ff:ff link-netnsid 1
  • ns3
  1. [root@10 /]# ip netns exec ns3 ip a
  2. ...
  3. 7: ns3-bridge@if8: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
  4. link/ether 36:8e:bc:43:f0:4a brd ff:ff:ff:ff:ff:ff link-netnsid 1
  • bridge
  1. [root@10 /]# ip netns exec bridge ip a
  2. ...
  3. 8: bridge-ns3@if7: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
  4. link/ether 92:c0:44:18:64:93 brd ff:ff:ff:ff:ff:ff link-netnsid 0
  5. 10: bridge-ns4@if9: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
  6. link/ether 9e:f4:57:43:2e:2b brd ff:ff:ff:ff:ff:ff link-netnsid 1

可以看到ns3与bridge、ns4与bridge的网卡序号是连续的,证明是同一对veth pair

7.在bridge namespace中创建br设备(网桥)

在对bridge进行操作,需要用到bridge-utils,可以通过以下命令安装

  1. yum install bridge-utils

接下来创建br设备

  1. [root@10 /]# ip netns exec bridge brctl addbr br

8.启动br设备

  1. [root@10 /]# ip netns exec bridge ip link set dev br up

9.启动bridge中的两个虚拟网卡

  1. [root@10 /]# ip netns exec bridge ip link set dev bridge-ns3 up
  2. [root@10 /]# ip netns exec bridge ip link set dev bridge-ns4 up

10.把bridge中两个虚拟网卡加入到br设备中

  1. [root@10 /]# ip netns exec bridge brctl addif br bridge-ns3
  2. [root@10 /]# ip netns exec bridge brctl addif br bridge-ns4

11.启动ns3、ns4中的虚拟网卡,并加入ip

  1. [root@10 /]# ip netns exec ns3 ip link set dev ns3-bridge up
  2. [root@10 /]# ip netns exec ns3 ip address add 192.168.0.13/24 dev ns3-bridge
  3. [root@10 /]# ip netns exec ns4 ip link set dev ns4-bridge up
  4. [root@10 /]# ip netns exec ns4 ip address add 192.168.0.14/24 dev ns4-bridge

12.测试两个namespace的连通性

  1. [root@10 /]# ip netns exec ns3 ping 192.168.0.14
  2. PING 192.168.0.14 (192.168.0.14) 56(84) bytes of data.
  3. 64 bytes from 192.168.0.14: icmp_seq=1 ttl=64 time=0.061 ms
  4. 64 bytes from 192.168.0.14: icmp_seq=2 ttl=64 time=0.047 ms
  5. 64 bytes from 192.168.0.14: icmp_seq=3 ttl=64 time=0.042 ms
  1. [root@10 /]# ip netns exec ns4 ping 192.168.0.13
  2. PING 192.168.0.13 (192.168.0.13) 56(84) bytes of data.
  3. 64 bytes from 192.168.0.13: icmp_seq=1 ttl=64 time=0.046 ms
  4. 64 bytes from 192.168.0.13: icmp_seq=2 ttl=64 time=0.076 ms
  5. 64 bytes from 192.168.0.13: icmp_seq=3 ttl=64 time=0.081 ms

Docker容器的网络



Docker常见的网络模式有三种bridge、none和host

  • bridge - Docker的默认网络模式,有独立的命名空间,能够支持各种自定义网络, 以及实现网络隔离,能够满足容器网络隔离的要求
  • host - 容器与主机在相同的网络命名空间下面,使用相同的网络协议栈,容器可以直接使用主机的所有网络接口,最简单和最低延迟的模式
  • none - 使用none模式,Docker容器拥有自己的Network Namespace,但是,并不为Docker容器进行任何网络配置,即Docker容器没有网卡、IP、路由等信息,让开发者可以自由按需定制

Docker网络相关指令

  • docker network ls - 查询可用网络

  • docker network create - 新建一个网络

  • docker network rm - 移除一个网络

  • docker network inspect - 查看一个网络

  • docker network connect - 连接容器到一个网络

  • docker network disconnect - 把容器从一个网络断开

bridge网络模式实现

bridge是docker容器默认的网络模式,它的实现原理跟我们网络虚拟化的多namespace例子一样,通过veth pair和bridge进行间接连接,当 Docker 启动时,会自动在主机上创建一个 docker0 虚拟网桥,实际上是 Linux 的一个 bridge,可以理解为一个软件交换机。它会在挂载到它的网口之间进行转发,创建了在主机和所有容器之间一个虚拟共享网络

接下来,我们以上图tomcat容器为例,来展示下bridge模式的操作

1.启动两个tomcat容器(使用我们在第一章创建的tomcat镜像)

  1. [root@10 vagrant]# docker run -d --name tomcat01 -p 8081:8080 tomcat
  2. [root@10 /]# docker run -d --name tomcat03 -p 8082:8080 tomcat

2.查看两个tomcat容器的网络接口信息

  1. [root@10 /]# docker exec -it tomcat01 ip a
  2. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
  3. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  4. inet 127.0.0.1/8 scope host lo
  5. valid_lft forever preferred_lft forever
  6. 11: eth0@if12: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
  7. link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
  8. inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
  9. valid_lft forever preferred_lft forever
  1. [root@10 /]# docker exec -it tomcat03 ip a
  2. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
  3. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  4. inet 127.0.0.1/8 scope host lo
  5. valid_lft forever preferred_lft forever
  6. 15: eth0@if16: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
  7. link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
  8. inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
  9. valid_lft forever preferred_lft forever

可以看到tomcat01和tomcat03的ip分别为172.17.0.2/16172.17.0.3/16,并且有一对不连续的基于veth pair创建的虚拟网卡eth0@if12eth0@if16,很明显,根据我们上面学过的内容,这两个不是成对出现的虚拟网卡不能直接通信,应该是通过bridge来进行连接

3.查看宿主机centos系统的网卡信息,验证是否存在与tomcat容器对应的虚拟网卡

  1. [root@10 /]# ip a
  2. ...
  3. 4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
  4. link/ether 02:42:12:9a:b1:a7 brd ff:ff:ff:ff:ff:ff
  5. inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
  6. valid_lft forever preferred_lft forever
  7. inet6 fe80::42:12ff:fe9a:b1a7/64 scope link
  8. valid_lft forever preferred_lft forever
  9. 12: veth068cc5c@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
  10. link/ether 66:1c:13:cd:b4:78 brd ff:ff:ff:ff:ff:ff link-netnsid 5
  11. inet6 fe80::641c:13ff:fecd:b478/64 scope link
  12. valid_lft forever preferred_lft forever
  13. 16: veth92816fa@if15: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
  14. link/ether 0a:cf:a0:8e:78:7f brd ff:ff:ff:ff:ff:ff link-netnsid 6
  15. inet6 fe80::8cf:a0ff:fe8e:787f/64 scope link
  16. valid_lft forever preferred_lft forever

果然,我们可以看到宿主机上确实存在与两个tomcat容器相对应的虚拟网卡,并且还有一个虚拟网桥docker0的网络接口,这种连接方法叫bridge模式

4.通过docker network inspect bridge命令查看下bridge的配置

  1. [root@10 /]# docker network inspect
  2. ...
  3. "Containers": {
  4. "2f3c3081b8bd409334f21da3441f3b457e243293f3180d54cfc12d5902ad4dbc": {
  5. "Name": "tomcat03",
  6. "EndpointID": "2375535cefdbccd3434d563ef567a1032694bdfb4356876bd9d8c4e07b1f222b",
  7. "MacAddress": "02:42:ac:11:00:03",
  8. "IPv4Address": "172.17.0.3/16",
  9. "IPv6Address": ""
  10. },
  11. "c13db4614a49c302121e467d8aa8ea4f008ab55f83461430d3dd46e59085937f": {
  12. "Name": "tomcat01",
  13. "EndpointID": "99a04efa9c7bdb0232f98d25f490682b065de1ce076b31487778fa257552a2ba",
  14. "MacAddress": "02:42:ac:11:00:02",
  15. "IPv4Address": "172.17.0.2/16",
  16. "IPv6Address": ""
  17. }
  18. },

可以看到两个container已经绑定到bridge中

5.分别测试两个tomcat容器相互连通

  1. [root@10 /]# docker exec -it tomcat01 ping 172.17.0.3
  2. PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
  3. 64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.054 ms
  4. 64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.040 ms
  5. 64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=0.039 ms
  1. [root@10 /]# docker exec -it tomcat03 ping 172.17.0.2
  2. PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
  3. 64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.046 ms
  4. 64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.042 ms
  5. 64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.039 ms

可以看到这两个容器可以互相访问

6.在容器访问互联网网站

docker容器是可以通过brige与host主机网络连通,因此可以间接通过iptables实现NAT转发进行互联网访问,能够让多个内网用户通过一个外网地址上网,解决了IP资源匮乏的问题

接下来选择其中刚才其中一个tomcat容器进行测试,如果发现不能访问互联网,可能需要重启下docker服务systemctl restart docker

  1. [root@10 /]# docker exec -it tomcat01 curl -I https://www.baidu.com
  2. HTTP/1.1 200 OK
  3. Accept-Ranges: bytes
  4. Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
  5. Connection: keep-alive
  6. Content-Length: 277
  7. Content-Type: text/html
  8. Date: Thu, 06 Feb 2020 06:03:48 GMT
  9. Etag: "575e1f72-115"
  10. Last-Modified: Mon, 13 Jun 2016 02:50:26 GMT
  11. Pragma: no-cache
  12. Server: bfe/1.0.8.18

从上面返回信息可以看到,容器成功访问百度网站

host网络模式实现

host模式是共享宿主机器网络,因此使用的是同一个network namespace

1.创建一个容器,命名为tomcat-host,网络模式选择host

  1. [root@10 /]# docker run -d --name tomcat-host --network host tomcat
  2. ee3c6d2a5f61caa371088f40bc0c5d11101d12845cdee24466322a323b11ee11

2.查看容器的网络接口信息会发现跟宿主centos的一样

  1. [root@10 /]# docker exec -it tomcat-host ip a
  2. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
  3. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  4. inet 127.0.0.1/8 scope host lo
  5. valid_lft forever preferred_lft forever
  6. inet6 ::1/128 scope host
  7. valid_lft forever preferred_lft forever
  8. 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
  9. link/ether 52:54:00:8a:fe:e6 brd ff:ff:ff:ff:ff:ff
  10. inet 10.0.2.15/24 brd 10.0.2.255 scope global noprefixroute dynamic eth0
  11. valid_lft 50028sec preferred_lft 50028sec
  12. inet6 fe80::5054:ff:fe8a:fee6/64 scope link
  13. valid_lft forever preferred_lft forever
  14. 3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
  15. link/ether 08:00:27:ba:0a:28 brd ff:ff:ff:ff:ff:ff
  16. inet 192.168.100.12/24 brd 192.168.100.255 scope global noprefixroute dynamic eth1
  17. valid_lft 156886sec preferred_lft 156886sec
  18. inet6 fe80::a00:27ff:feba:a28/64 scope link
  19. valid_lft forever preferred_lft forever
  20. 4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
  21. link/ether 02:42:12:9a:b1:a7 brd ff:ff:ff:ff:ff:ff
  22. inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
  23. valid_lft forever preferred_lft forever
  24. inet6 fe80::42:12ff:fe9a:b1a7/64 scope link
  25. valid_lft forever preferred_lft forever

3.查看容器的网络信息,会发现容器没有被单独分配ip地址

  1. "Containers": {
  2. "ee3c6d2a5f61caa371088f40bc0c5d11101d12845cdee24466322a323b11ee11": {
  3. "Name": "tomcat-host",
  4. "EndpointID": "53565ff879878bfd10fc5843582577d54eb68b14b29f4b1ff2e213d38e2af7ce",
  5. "MacAddress": "",
  6. "IPv4Address": "",
  7. "IPv6Address": ""
  8. }
  9. }

none网络模式实现

上面提到,none网络模式是有一个独立的namesapce,默认情况下没有任何初始化网络配置,与外界网络隔离,需要自己去定制

1.创建容器tomcat-none,并设置网络为none

  1. [root@10 /]# docker run -d --name tomcat-none --network none tomcat
  2. d90808e0b7455c2f375c3d88fa18a1872b4a03e2112bff3db0b3996d16523b1a

2.查看网络接口信息

  1. [root@10 /]# docker exec -it tomcat-none ip a
  2. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
  3. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  4. inet 127.0.0.1/8 scope host lo
  5. valid_lft forever preferred_lft forever

这里只有lo设备,没有其他网卡,只有本地回环ip地址

3.查看docker网络信息

  1. "Containers": {
  2. "d90808e0b7455c2f375c3d88fa18a1872b4a03e2112bff3db0b3996d16523b1a": {
  3. "Name": "tomcat-none",
  4. "EndpointID": "4ea757bbd108ac783bd1257d33499b7b77cd7ea529d4e6c761923eb596dc446c",
  5. "MacAddress": "",
  6. "IPv4Address": "",
  7. "IPv6Address": ""
  8. }
  9. }

容器没有被分配任何地址

自定义网络模式custom实现

我们可以创建自己的网络模式,这里默认是bridge模式,接下来我们演示如何让不同网络的容器连通起来

1.创建一个新网络,名字为custom,默认模式是bridge

  1. [root@10 /]# docker network create custom
  2. af392e4739d810b2e12219c21f505135537e95ea0afcb5075b3b1a5622a66112

2.查看下当前docker网络列表

  1. [root@10 /]# docker network ls
  2. NETWORK ID NAME DRIVER SCOPE
  3. ce20377e3f10 bridge bridge local
  4. af392e4739d8 custom bridge local
  5. afc6ca3cf515 host host local
  6. 94cfa528d194 none null local

3.查看下自定义网络的一些信息

  1. 94cfa528d194 none null local
  2. [root@10 /]# docker network inspect custom
  3. [
  4. {
  5. "Name": "custom",
  6. "Id": "af392e4739d810b2e12219c21f505135537e95ea0afcb5075b3b1a5622a66112",
  7. "Created": "2020-02-05T23:49:08.321895241Z",
  8. "Scope": "local",
  9. "Driver": "bridge",
  10. "EnableIPv6": false,
  11. "IPAM": {
  12. "Driver": "default",
  13. "Options": {},
  14. "Config": [
  15. {
  16. "Subnet": "172.18.0.0/16",
  17. "Gateway": "172.18.0.1"
  18. }
  19. ]
  20. },
  21. "Internal": false,
  22. "Attachable": false,
  23. "Ingress": false,
  24. "ConfigFrom": {
  25. "Network": ""
  26. },
  27. "ConfigOnly": false,
  28. "Containers": {},
  29. "Options": {},
  30. "Labels": {}
  31. }
  32. ]

4.创建一个容器tomcat-custom,容器网络模式为custom

  1. [root@10 /]# docker run -d --name tomcat-custom --network custom tomcat
  2. 2e77115f42e36827646fd6e3abacc0594ff71cd1847f6fbffda28e22fb55e9ea

5.查看tomcat-custom的网络接口信息

  1. [root@10 /]# docker exec -it tomcat-custom ip a
  2. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
  3. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  4. inet 127.0.0.1/8 scope host lo
  5. valid_lft forever preferred_lft forever
  6. 22: eth0@if23: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
  7. link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
  8. inet 172.18.0.2/16 brd 172.18.255.255 scope global eth0
  9. valid_lft forever preferred_lft forever

6.测试tomcat-custom去连接上面我们创建的tomcat01容器

  1. [root@10 /]# docker exec -it tomcat-custom ping 192.17.0.2
  2. PING 192.17.0.2 (192.17.0.2) 56(84) bytes of data.
  3. --- 192.17.0.2 ping statistics ---
  4. 4 packets transmitted, 0 received, 100% packet loss, time 3001ms

从上面执行结果可以看出,默认情况下,tomcat-custom跟tomcat01是不能连通,因为处于不同的网络custom、bridge。

7.把tomcat01加到自定义网络custom

  1. [root@10 /]# docker network connect custom tomcat01

8.查看当前custom网络信息

  1. "Containers": {
  2. "2e77115f42e36827646fd6e3abacc0594ff71cd1847f6fbffda28e22fb55e9ea": {
  3. "Name": "tomcat-custom",
  4. "EndpointID": "bf2b94f3b580b9df0ca9f6ce2383198961711d1b3d19d33bbcf578d81157e47f",
  5. "MacAddress": "02:42:ac:12:00:02",
  6. "IPv4Address": "172.18.0.2/16",
  7. "IPv6Address": ""
  8. },
  9. "c13db4614a49c302121e467d8aa8ea4f008ab55f83461430d3dd46e59085937f": {
  10. "Name": "tomcat01",
  11. "EndpointID": "f97305672ae617f207dfef1b3dc250d2b8d6a9ec9b36b1b0115e2456f18c44c6",
  12. "MacAddress": "02:42:ac:12:00:03",
  13. "IPv4Address": "172.18.0.3/16",
  14. "IPv6Address": ""
  15. }
  16. }

可以看到两个容器都已经配置到custom网络中,tomcat-custom 172.18.0.2/16,tomcat01 172.18.0.3/16

9.配置完网络后,在用tomcat01尝试连接tomcat-custom

  1. [root@10 /]# docker exec -it tomcat01 ping 172.18.0.3
  2. PING 172.18.0.3 (172.18.0.3) 56(84) bytes of data.
  3. 64 bytes from 172.18.0.3: icmp_seq=1 ttl=64 time=0.032 ms
  4. 64 bytes from 172.18.0.3: icmp_seq=2 ttl=64 time=0.080 ms
  5. 64 bytes from 172.18.0.3: icmp_seq=3 ttl=64 time=0.055 ms

从执行结果可以看到,现在tomcat01已经可以跟tomcat-custom通信了,因为处于同一个网络中

10.此时查看centos中的网络接口信息,可以看到存在对应的虚拟网卡

  1. [root@10 /]# ip a
  2. ...
  3. 23: vethc30bd52@if22: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-af392e4739d8 state UP group default
  4. link/ether 2e:a1:c8:a2:e5:83 brd ff:ff:ff:ff:ff:ff link-netnsid 5
  5. inet6 fe80::2ca1:c8ff:fea2:e583/64 scope link
  6. valid_lft forever preferred_lft forever
  7. 25: veth69ea87b@if24: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
  8. link/ether 92:eb:8f:65:fe:7a brd ff:ff:ff:ff:ff:ff link-netnsid 6
  9. inet6 fe80::90eb:8fff:fe65:fe7a/64 scope link
  10. valid_lft forever preferred_lft forever
  11. 27: veth068cc5c@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-af392e4739d8 state UP group default
  12. link/ether ea:44:90:6c:0d:49 brd ff:ff:ff:ff:ff:ff link-netnsid 6
  13. inet6 fe80::e844:90ff:fe6c:d49/64 scope link
  14. valid_lft forever preferred_lft forever

自定义网络中的嵌入式DNS

当用户创建了自定义网络,docker引擎默认会对加入该网络的容器启动嵌入式DNS,因此同一网络的容器可以互相通过容器名称进行通信,避免因下游系统有ip需要重新发布

对于非自定义网络,具体配置,可以查阅官网配置容器DNS

1.通过上面我们创建号的自定义网络和容器进行测试

  1. [root@10 /]# docker exec -it tomcat01 ping tomcat-custom
  2. PING tomcat-custom (172.18.0.2) 56(84) bytes of data.
  3. 64 bytes from tomcat-custom.custom (172.18.0.2): icmp_seq=1 ttl=64 time=0.031 ms
  4. 64 bytes from tomcat-custom.custom (172.18.0.2): icmp_seq=2 ttl=64 time=0.038 ms
  5. 64 bytes from tomcat-custom.custom (172.18.0.2): icmp_seq=3 ttl=64 time=0.040 ms
  1. [root@10 /]# docker exec -it tomcat-custom ping tomcat01
  2. PING tomcat01 (172.18.0.3) 56(84) bytes of data.
  3. 64 bytes from tomcat01.custom (172.18.0.3): icmp_seq=1 ttl=64 time=0.031 ms
  4. 64 bytes from tomcat01.custom (172.18.0.3): icmp_seq=2 ttl=64 time=0.038 ms
  5. 64 bytes from tomcat01.custom (172.18.0.3): icmp_seq=3 ttl=64 time=0.040 ms

可以看到tomcat01和tomcat-custom可以互相通过容器名进行通信

Docker端口映射

端口映射对于我们来说不陌生,平时访问服务,例如tomcat,都是通过ip+服务端口进行访问,如:localhost:8080,但是容器是寄生在宿主机器上,因此,如果我们想被外部访问,还需要映射到宿主的端口上,通过宿主的ip+port进行访问,如下如图所示:



接下来我们来实践下docker端口映射相关操作

1.创建一个tomcat-port容器,指定宿主端口映射8999

  1. [root@10 /]# docker run -d --name tomcat-port -p 8999:8080 tomcat
  2. 0b5b014ae2552b85aff55b385ba20518b38509b5670a95ad9eea09475ea26629

2.进入容器,在容器中访问

  1. [root@10 /]# docker exec -it tomcat-port curl -i localhost:8080
  2. HTTP/1.1 404
  3. Content-Type: text/html;charset=utf-8
  4. Content-Language: en
  5. Content-Length: 713
  6. Date: Thu, 06 Feb 2020 07:43:59 GMT

从上面结果可以看到,实际上已经访问成功,但是由于我没有配置tomcat管理页面,所以这里是报404

3.在centos访问容器

这时候我们就需要通过容器ip+port的方式进行访问

  1. [root@10 /]# curl -I 172.17.0.4:8080
  2. HTTP/1.1 404
  3. Content-Type: text/html;charset=utf-8
  4. Content-Language: en
  5. Transfer-Encoding: chunked
  6. Date: Thu, 06 Feb 2020 07:49:41 GMT

可以看到,这里也访问成功

4.在主体机器访问,也就是我的主机MacOS操作系统上访问

这时候需要用虚拟机上centos IP+映射端口 进行访问

  1. 192:centos7 evan$ curl -I 192.168.100.12:8999
  2. HTTP/1.1 404
  3. Content-Type: text/html;charset=utf-8
  4. Content-Language: en
  5. Transfer-Encoding: chunked
  6. Date: Thu, 06 Feb 2020 07:52:52 GMT

可以看到,这里也能正常访问


总结

上文讲解了Docker的单机网络通信原理以及Linux虚拟化技术,最后我们回顾下一开始的那几个问题,相信大家心中都已经有答案了

1.同一个主机两个容器如何通信?

Docker基于Virtual Ethernet Pair技术实现了容器之间的通信,但并非直接端对端对接,在默认网络bridge模式下,Docker引擎会分别在每个容器和宿主网络建立一对虚拟网卡veth pair,通过bridge间接实现通信,通过network namespace实现网络隔离。

2.怎么从服务器外访问容器?

从服务器外访问容器是通过端口映射方式,访问的IP地址和端口并非容器的真实IP和端口,而是宿主机器的端口映射,所以要从服务器外部访问容器,需要通过宿主机器的IP/域名+宿主端口进行访问。

3.Docker的三种网络模式是什么?

Docker常见的网络模式有三种bridge、none和host

bridge - Docker的默认网络模式,有独立的命名空间,能够支持各种自定义网络, 以及实现网络隔离,能够满足容器网络隔离的要求

host - 容器与主机在相同的网络命名空间下面,使用相同的网络协议栈,容器可以直接使用主机的所有网络接口,最简单和最低延迟的模式

none - 使用none模式,Docker容器拥有自己的Network Namespace,但是,并不为Docker容器进行任何网络配置,即Docker容器没有网卡、IP、路由等信息,让开发者可以自由按需定制

参考资料

linux 网络虚拟化: network namespace 简介

网络虚拟化技术(一): Linux网络虚拟化


有兴趣的朋友,欢迎加我公众号一起交流,有问题可以留言,平时工作比较忙,我也抽时间尽量回复每位朋友的留言,谢谢!

Docker深入浅出系列 | 单节点多容器网络通信的更多相关文章

  1. Docker深入浅出系列 | 容器数据持久化

    Docker深入浅出系列 | 容器数据持久化 Docker已经上市很多年,不是什么新鲜事物了,很多企业或者开发同学以前也不多不少有所接触,但是有实操经验的人不多,本系列教程主要偏重实战,尽量讲干货,会 ...

  2. Docker深入浅出系列 | Docker Compose多容器实战

    目录 前期准备 Docker Compose是什么 为什么要用Docker Compose Docker Compose使用场景 Docker Compose安装 Compose Yaml文件结构 C ...

  3. Docker深入浅出系列 | Swarm多节点实战

    目录 前期准备 Swarm基本概念 什么是Docker Swarm 为什么要用Swarm Swarm的网络模型 Swarm的核心实现机制 服务发现机制 负载均衡机制Routing Mesh Docke ...

  4. Docker深入浅出系列 | 单机Nginx+Springboot实战

    目录 Nginx+Springboot实战 前期准备 实战目标 实战步骤 创建Docker网络 搭建Mysql容器 搭建额度服务集群 搭建Nginx服务 验证额度服务 附录 Nginx+Springb ...

  5. Docker深入浅出系列 | 5分钟搭建你的私有镜像仓库

    Docker已经上市很多年,不是什么新鲜事物了,很多企业或者开发同学以前也不多不少有所接触,但是有实操经验的人不多,本系列教程主要偏重实战,尽量讲干货,会根据本人理解去做阐述,具体官方概念可以查阅官方 ...

  6. Docker深入浅出系列 | 容器初体验

    目录 Docker深入浅出系列 | 容器初体验 教程目标 预备工作 容器与虚拟化技术 什么是Docker 为什么要用Docker 事例 什么是容器镜像和容器 容器与虚拟机的区别 Vagrant与Doc ...

  7. Docker深入浅出系列 | Image实战演练

    目录 课程目标 Container与Image核心知识回顾 制作Docker Image的两种方式 Dockerfile常用指令 Image实战篇 通过Dockerfile制作Image 通过Dock ...

  8. 老司机实战Windows Server Docker:3 单节点Windows Docker服务器简单运维(上)

    经过上两篇实战Windows Server Docker系列文章,大家对安装Windows Docker服务以及如何打包现有IIS应用为docker镜像已经有了基本认识.接下来我们来简单讲讲一些最基本 ...

  9. 老司机实战Windows Server Docker:4 单节点Windows Docker服务器简单运维(下)

    上篇中,我们主要介绍了使用docker-compose对Windows Docker单服务器进行远程管理,编译和部署镜像,并且设置容器的自动启动.但是,还有一些重要的问题没有解决,这些问题不解决,就完 ...

随机推荐

  1. Jquery为动态添加的元素添加事件

    $("tbody").on("click","button", function() { var text = $(this).parent ...

  2. d3.js制作条形时间范围选择器

    此文章为原创文章,原文地址:https://www.cnblogs.com/eagle1098/p/12146688.html 效果如上图所示. 本项目使用主要d3.js v4制作,可以用来选择两年的 ...

  3. 【uuid】- 唯一标识

    2020-01-02 UUID ,Universally Unique Identifier ,通用唯一标识符. //定义一个生成 uuid 的方法const getUuid = () => { ...

  4. shell正则表达式和cut命令

    正则表达式 符号 描述 $ 匹配输入字符串的结尾位置 () 标记一个子表达式的开始和结束位置 * 匹配前面的子表达式零次或多次 + 匹配前面的子表达式一次或多次 . 匹配除换行符(\n)之外的任何单字 ...

  5. echo 传义序列

    echo 传义序列:\a 警示字符\b 退格\c 输出中忽略最后的换行符\f 清屏\n 换行\r 回车\t 水平制表符\v 垂直制表符\\ 反斜杠字符\0ddd 将字符表示成1到3位的八进制数值

  6. [Windows10]记一次修复注册表相关血案:该文件没有与之关联的应用来执行该操作。请安装应用,若已经安装应用,请在“默认应用设置”页面中创建关联。

    今天闲得蛋疼清理了一下右键菜单,于是在之后某时刻使用Everything的“双击路径列打开目录”功能时发现异常: [Window Title] Everything.exe [Content] 该文件 ...

  7. 【转】常见Java面试题 – 第二部分:equals与==

    ImportNew注: 本文是ImportNew编译整理的Java面试题系列文章之一.你可以从这里查看全部的Java面试系列. Q2.下面的代码片段的输出是什么? Object s1 = new St ...

  8. Scanner使用方法

    import java.util.Scanner; //导入包 public void main (String args[]){ Scanner a=new Scanner(System.in); ...

  9. ubuntu下使用APT安装和卸载MySQL5.7

    安装方式一: 向系统的软件仓库中列表中添加MySQL APT  仓库 去http://dev.mysql.com/downloads/repo/apt/.下载MySQL APT repository ...

  10. APICloud联合腾讯云推出“云主机解决方案“,各种福利等你拿

    为了帮助开发者一站式打通云.开发.运维全流程服务,更全面提供基于自身业务情况的云服务器.数据库.存储等基础设施服务,APICloud联合腾讯云重磅推出“云主机解决方案“.开发者可通过控制台简单清晰的购 ...