freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

从vmware到docker 02-vmware和docker的网络配置
2023-04-08 19:42:12
所属地 香港

先介绍vmware的网络配置

VMware的网络配置

Vmware 为我们提供了三种网络工作模式,分别是:Bridged(桥接模式)、NAT(网络地址转换模式)、Host-only(仅主机模式)。

VMware 的虚拟交换机与虚拟网卡

打开 VMware --> Edit(编辑)--> VirtualNetworkEditor(虚拟网络编辑器),如图:

image-20230407104706742

默认是3个虚拟交换机

VMnet0:用于虚拟桥接网络下的虚拟交换机

VMnet1:用于虚拟 Host-only 网络下的虚拟交换机

VMnet8:用于虚拟 NAT 网络下的虚拟交换机

虚拟网卡

设置----网络-----更改网络适配器

可以看出仅主机模式和nat模式都有虚拟网卡,桥接模式没有

VMware Network AdepterVMnet1:Host 用于与 Host-only 虚拟网络进行通信的虚拟网卡

VMware Network Adepter VMnet8:Host 用于与 NAT虚拟网络进行通信的虚拟网卡

image-20230407105616700

桥接模式的直接连物理网卡

image-20230407105528400

VMware三种网络模式介绍

bridge 桥接模式

虚拟机桥接网络的网关默认和物理网卡的网关相同。在这种模式下,VMware 虚拟出来的操作系统就像是局域网中的一台独立的主机,它可以访问网内任何一台机器。

这种模式下要想与宿主机通信,需要手工为虚拟系统配置 IP 地址、子网掩码,而且还要和宿主机器处于同一网段。这样才能实现通过局域网的网关或路由器访问互联网。

桥接模式网络模型如下:

image-20230407114341219

Host-only 独立主机模式

在 Host-only 模式下,虚拟网络是一个全封闭的网络,它唯一能够访问的就是主机,当然多个虚拟机之间也可以互相访问。

主机和虚拟机之间的通信是通过 VMware Network Adepter VMnet1 虚拟网卡来实现的。

主机可以访问该虚拟机,但是虚拟机无法访问主机,也不能访问互联网,除非本地主机共享网络。

此时网络模型如下:

image-20230407114515080

VMware 的 host-only 还可以配置是否让仅主机模式的虚拟机和宿主机机通信。只要勾选【将主机虚拟适配器连接到此网络】,就会在宿主机上创建一个虚拟网卡 (不勾选就不会创建虚拟网卡),并将这个虚拟网卡连接在 host-only 的虚拟交换机上,这样就能让物理机和各 host-only 内的虚拟机进行通信。

勾选【将主机虚拟适配器连接到此网络】时的 host-only 网络模型如下:

image-20230407115025796

对于 host-only 网络模式,当勾选了【将主机虚拟适配器连接到此网络】时,宿主机上有一个虚拟网卡连接到了 host-only 的虚拟交换机上,因此虚拟机之间和宿主机之间可以互相通信,但此时虚拟机无法访问外网。

如果想要让 host-only 模式下的虚拟机访问外网,需要在宿主机上将可访问外网的物理网卡共享给宿主机上的虚拟网卡,并将所有虚拟机的网关设置为宿主机虚拟网卡的地址即可。

具体方法:

1.“编辑”>“虚拟网络编辑器”这一步是确认虚拟网卡host-only的网卡名称VMnet1以及网段192.168.15.0

image-20230407210029061

2.设置----网络-----更改网络适配器,选择本地的物理网卡,右击-属性-共享,选那个仅主机模式的虚拟网卡

image-20230407115927704

3.点击确认之后VMnet1网卡ip会变成192.168.137.1

image-20230407210501098


4.鼠标右键将VMnet1还原成图1中的192.168.15.1段填入IP地址和网关,其他可以不填。

image-20230407210714170

5.设置虚拟机的ip为192.168.15.2,网关和DNS都指向192.168.15.1。这个虚拟机的系统不同,具体方法也不同。ubuntu是在右上角设置这里改,配置文件也能改。

image-20230407215757807

7.然后重启,大功告成,Host-only模式能连互联网了。

image-20230407215707473

能连接外网的host-only网络模型如下:

image-20230407220843291


NAT 网络地址转换

其实 NAT网络和 Host-only网络很相似,不同的地方就是 Host-only 网络没有 NAT 服务,所以Host-only虚拟网络不能连接到 Internet。

使用 NAT 模式,就是让虚拟系统借助 NAT(网络地址转换)功能,通过宿主机器所在的网络来访问公网。也就是说,使用 NAT 模式可以实现在虚拟系统里访问互联网,但前提是宿主机可以访问互联网。

NAT 模式下的虚拟系统的 TCP/IP 配置信息是由 VMnet8(NAT)虚拟网络的 DHCP 服务器提供的,无法进行手工修改,因此虚拟系统也就无法和本局域网中的其他真实主机进行通讯。

如果没有勾选【将主机虚拟适配器连接到此网络】,虚拟机之间可以互相通信且可以和宿主机通信,但宿主机无法访问 NAT 隔离的私网,即宿主机无法和虚拟机通信。

image-20230407221541585

如果勾选了【将主机虚拟适配器连接到此网络】,将在宿主机上创建一个虚拟网卡并连接到此虚拟交换机上,此时,宿主机上的虚拟网卡也是被 NAT 隔离在私网中的一个节点。因此,虚拟机之间和宿主机之间都可以互相通信。

image-20230407221933033

下面再介绍docker的网络配置

Docker容器命名

01里忘了讲,当我们创建一个容器的时候,docker 会自动对它进行命名。另外,我们也可以使用 --name标识来命名容器,例如:

docker run -d -P --name {自定义容器名} {镜像名}

Docker的网络配置

这次我们拿dvwa靶场的docker做个演示

image-20230408163906142

image-20230408163943192

Docker 容器连接

Docker端口映射(-P与-p)

我们创建了一个 dvwa 应用的容器

sudo docker run -d -P astronaut1712/dvwa

我们使用 -P绑定端口号,使用 docker ps可以看到容器端口 80绑定主机端口 32769。

sudo docker ps

image-20230408165115369

我们也可以使用 -p标识来指定容器端口绑定到主机端口。

两种方式的区别是:

  • -P :是容器内部端口随机映射到主机的端口。

  • -p :是容器内部端口绑定到指定的主机端口。

docker run -d -p 5000:5000 astronaut1712/dvwa

image-20230408165637852

另外,我们可以指定容器绑定的网络地址,比如绑定 127.0.0.1。

docker run -d -p 127.0.0.1:5001:5000 astronaut1712/dvwa

这样我们就可以通过访问 127.0.0.1:5001 来访问容器的 5000 端口。

上面的例子中,默认都是绑定 tcp 端口,如果要绑定 UDP 端口,可以在端口后面加上 /udp

docker run -d -p 5000:5000/udp astronaut1712/dvwa

docker port命令可以让我们快捷地查看端口的绑定情况。

image-20230408170313354

Docker 容器互联

以后面的用户自定义模式来做个简单的入门。

新建网络

下面先创建一个新的 Docker 网络。

docker network create -d bridge test-net

参数说明:

-d:参数指定 Docker 网络类型,有三种模式(bridge、overlay、macvlan),后面会详细讲。这里我用bridge(桥接)先做个演示。

test-net 是为新建的网络命的名。

安装完 Docker,宿主机默认会创建三个网络,分别是bridge网络,host网络,none网络,可以使用docker network ls命令查看。

现在我们新建了一个名叫test-net的bridge类型网络。

image-20230408171627215

运行一个容器并连接到新建的 test-net 网络

为了方便演示,我们用astronaut1712/dvwa镜像运行二个容器,分别命名为test1,test2,把他们连到刚建的test-net网络

image-20230408172235783

运行test1容器并连接到新建的 test-net 网络

docker run -itd --name test1 --network test-net astronaut1712/dvwa

打开新的终端,再运行test2容器并加入到 test-net 网络:

docker run -itd --name test2 --network test-net astronaut1712/dvwa

image-20230408173528169

分别进入容器,下面通过 ping 来证明 test1 容器和 test2 容器建立了互联关系。

如果 test1、test2 容器内中无 ping 命令,则在容器内执行以下命令安装 ping,我的容器里已经有ping命令了,只是在这里提一嘴。

apt-get update
apt install iputils-ping

image-20230408174043811

image-20230408174129912

这样,test1 容器和 test2 容器建立了互联关系。

Docker的网络模式

Docker的网络模式大概可以分为5种类型。

  • bridge

  • host

  • container模式

  • none

  • 用户自定义模式(bridge、overlay、macvlan)

可以使用docker network ls命令查看。

bridge方式(默认)

容器的默认网络模式,docker在安装时会创建一个名为docker0的Linux bridge,在不指定--network的情况下,创建的容器都会默认挂到docker0上面。bridge模式为容器创建独立的网络栈,保证容器内的进程使用独立的网络环境,使容器之间,容器和docker host之间实现网络隔离。

Host IP为192.168.15.2, 容器网络为172.18.0.3/16 (由于是默认设置,这里没指定网络--net="bridge"。另外可以看到容器内创建了eth0)

root@daaaea194772:/var/www/html# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
  valid_lft forever preferred_lft forever
17: eth0@if18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:12:00:03 brd ff:ff:ff:ff:ff:ff
inet 172.18.0.3/16 brd 172.18.255.255 scope global eth0
  valid_lft forever preferred_lft forever
root@daaaea194772:/var/www/html#

容器与Host网络是连通的:

root@daaaea194772:/var/www/html# ping 192.168.15.2
PING 192.168.15.2 (192.168.15.2): 56 data bytes
64 bytes from 192.168.15.2: icmp_seq=0 ttl=64 time=0.161 ms
# eth0实际上是veth pair的一端,另一端(veth6becb52)连在br-676e34ddebcb网桥上:
hen@chen-virtual-machine:~/Desktop$ brctl show
bridge name       bridge id STP enabled   interfaces
br-676e34ddebcb 8000.0242dc88df74 no veth6becb52

docker0       8000.0242f770a1bf no vethb3141b4
chen@chen-virtual-machine:~/Desktop$ ethtool -S veth6becb52
NIC statistics:
peer_ifindex: 15
rx_queue_0_xdp_packets: 0
rx_queue_0_xdp_bytes: 0
rx_queue_0_drops: 0
rx_queue_0_xdp_redirect: 0
rx_queue_0_xdp_drops: 0
rx_queue_0_xdp_tx: 0
rx_queue_0_xdp_tx_errors: 0
tx_queue_0_xdp_xmit: 0
tx_queue_0_xdp_xmit_errors: 0

原理

通过Iptables实现容器内访问外部网络:

chen@chen-virtual-machine:~/Desktop$ sudo iptables-save |grep 172.18.0.*
-A POSTROUTING -s 172.18.0.0/16 ! -o br-676e34ddebcb -j MASQUERADE

none方式

指定方法: --net="none" 可以看到,这样创建出来的容器完全没有网络:

chen@chen-virtual-machine:~/Desktop$ sudo docker run -it --net="none" --name test3 astronaut1712/dvwa 
chen@chen-virtual-machine:~/Desktop$ sudo docker exec -it test3 /bin/bash
root@d5bfe30d8ff2:/var/www/html# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
  valid_lft forever preferred_lft forever
root@d5bfe30d8ff2:/var/www/html# ping 192.168.15.2
PING 192.168.15.2 (192.168.15.2): 56 data bytes
ping: sending packet: Network is unreachable

那这种方式,有什么用途呢? 这种方式将网络创建的责任完全交给用户。 可以实现更加灵活复杂的网络。 另外这种容器可以可以通过link容器实现通信。

host方式

指定方法:--net="host" 使用host模式的容器可以直接使用docker host的IP地址与外界通信,容器内部的服务端口也可以使用宿主机的端口,不需要进行NAT,host最大的优势就是网络性能比较好,但是docker host上已经使用的端口就不能再用了,网络的隔离性不好。这个host方式跟VMware的host-only半毛钱关系都没有。

chen@chen-virtual-machine:~/Desktop$ sudo docker run -it --net="host" --name test4 astronaut1712/dvwa
chen@chen-virtual-machine:~/Desktop$ sudo docker exec -it test4 /bin/bash
[sudo] password for chen:
root@chen-virtual-machine:/var/www/html# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
  valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
  valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:0c:29:14:00:c9 brd ff:ff:ff:ff:ff:ff
inet 192.168.15.2/24 brd 192.168.15.255 scope global noprefixroute ens33
  valid_lft forever preferred_lft forever
inet6 fe80::6cb9:2e4:fe81:5578/64 scope link noprefixroute
  valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:f7:70:a1:bf brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
  valid_lft forever preferred_lft forever
inet6 fe80::42:f7ff:fe70:a1bf/64 scope link
  valid_lft forever preferred_lft forever
8: br-676e34ddebcb: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:dc:88:df:74 brd ff:ff:ff:ff:ff:ff
inet 172.18.0.1/16 brd 172.18.255.255 scope global br-676e34ddebcb
  valid_lft forever preferred_lft forever
inet6 fe80::42:dcff:fe88:df74/64 scope link
  valid_lft forever preferred_lft forever
16: veth6becb52@if15: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-676e34ddebcb state UP group default
link/ether de:52:47:27:c4:8d brd ff:ff:ff:ff:ff:ff
inet6 fe80::dc52:47ff:fe27:c48d/64 scope link
  valid_lft forever preferred_lft forever
18: vethb3141b4@if17: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-676e34ddebcb state UP group default
link/ether 3e:39:64:b6:25:f5 brd ff:ff:ff:ff:ff:ff
inet6 fe80::3c39:64ff:feb6:25f5/64 scope link
  valid_lft forever preferred_lft forever
root@chen-virtual-machine:/var/www/html#


container复用方式

指定方法: --net="container:name or id" 如下例子可以看出来,两者的网络完全相同。就是复制指定ID的容器的网络配置方式。

chen@chen-virtual-machine:~/Desktop$ sudo docker run -it --name test5 astronaut1712/dvwa
chen@chen-virtual-machine:~/Desktop$ sudo docker exec -it test5 /bin/bash
root@cf7a433b6e89:/var/www/html# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
  valid_lft forever preferred_lft forever
19: eth0@if20: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
  valid_lft forever preferred_lft forever
chen@chen-virtual-machine:~/Desktop$ sudo docker run -it --net="container:cf7a433b6e89" --name test6 astronaut1712/dvwa
chen@chen-virtual-machine:~/Desktop$ sudo docker exec -it test6 /bin/bash
[sudo] password for chen:
root@cf7a433b6e89:/var/www/html# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
  valid_lft forever preferred_lft forever
19: eth0@if20: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
  valid_lft forever preferred_lft forever

这样的好处是如果部署一个应用,可以将应用的不同组件部署在不同的容器中,对外可以看上出是一个整体

user-defined模式

用户自定义模式主要可选的有三种网络驱动:bridge、overlay、macvlan。bridge驱动用于创建类似于前面提到的bridge网络;overlay和macvlan驱动用于创建跨主机的网络、IP等。

overlay、macvlan跨主机网络后面我会专门写一篇文章,来讲这个,我现在也搞不太懂,先挖个坑。

以bridge驱动为例



水平分割线括住的这一块我没做,之前Docker容器互联那里已经做过了,后面我用那个。

可以在启动容器之前在Docker中创建网络。这可以使用以下命令完成 语法: (--driver改成-d也可以,这里是上面容器互联部分的细化)

docker network create --driver drivername name 

选项:

  • drivername - 这是用于网络驱动程序名称。有bridge、overlay、macvlan

  • name - 这是给网络的名称。

这边用bridge举例:

[root@tuling ~]$ docker network create --driver bridge new_nw
c88bc38133ea9c8a9657d915294b4aa42525240096f40e607b4819ff5e1539ee

查看:

[root@tuling ~]$ docker network ls
NETWORK ID         NAME               DRIVER             SCOPE
99fe18249fa6       bridge             bridge             local
e60bf8b6ed5b       host               host               local
c88bc38133ea       new_nw             bridge             local
3a142d398cf9       none               null               local

现在可以在启动容器时附加新网络。所以让我们使用以下命令启动ubuntu容器

sudo docker run -it --net="new_nw" --name test9 astronaut1712/dvwa



现在,如果我们通过以下命令检查网络名称,您现在将看到容器已连接到新的网桥。

chen@chen-virtual-machine:~/Desktop$ sudo docker network inspect test-net
[sudo] password for chen:
[
{
   "Name": "test-net",
   "Id": "676e34ddebcb87e2162096000b234c0510d0e4f0a7a677db86f30416a249ed63",
   "Created": "2023-04-08T17:13:43.50905915+08:00",
   "Scope": "local",
   "Driver": "bridge",
   "EnableIPv6": false,
   "IPAM": {
       "Driver": "default",
       "Options": {},
       "Config": [
          {
               "Subnet": "172.18.0.0/16",
               "Gateway": "172.18.0.1"
          }
      ]
  },
   "Internal": false,
   "Attachable": false,
   "Ingress": false,
   "ConfigFrom": {
       "Network": ""
  },
   "ConfigOnly": false,
   "Containers": {
       "8d1d2f954596de39da31444ed35578982979388b4a02525bf763e0b5cf05d479": {
           "Name": "test1",
           "EndpointID": "753f51eaa11d1281f2365c6a8c4183a5826b4793fa4ffda0cc89c6880bdef0a4",
           "MacAddress": "02:42:ac:12:00:02",
           "IPv4Address": "172.18.0.2/16",
           "IPv6Address": ""
      },
       "daaaea194772723709343979c8748bf867318304601e90eb7bd8ffa1bced877b": {
           "Name": "test2",
           "EndpointID": "5e5118939a5ac95b0560ca7539ebac16c2bd1fb87fae62424ec5b0bfc95c3a63",
           "MacAddress": "02:42:ac:12:00:03",
           "IPv4Address": "172.18.0.3/16",
           "IPv6Address": ""
      }
  },
   "Options": {},
   "Labels": {}
}
]
chen@chen-virtual-machine:~/Desktop$

发现两个容器已经链接到网桥。

user-defined模式,

配置 DNS

如何自定义配置容器的主机名和 DNS 呢?秘诀就是 Docker 利用虚拟文件来挂载容器的 3 个相关配置文件。

在容器中使用mount命令可以看到挂载信息:

$ mount
/dev/disk/by-uuid/1fec...ebdf on /etc/hostname type ext4 ...
/dev/disk/by-uuid/1fec...ebdf on /etc/hosts type ext4 ...
tmpfs on /etc/resolv.conf type tmpfs ...

这种机制可以让宿主主机 DNS 信息发生更新后,所有 Docker 容器的 DNS 配置通过/etc/resolv.conf文件立刻得到更新。

配置全部容器的 DNS ,也可以在/etc/docker/daemon.json文件中增加以下内容来设置。

{
"dns" : [
"114.114.114.114",
"8.8.8.8"
]
}

这样每次启动的容器 DNS 自动配置为114.114.114.1148.8.8.8。使用以下命令来证明其已经生效。

$ docker run -it --rm test10  cat etc/resolv.conf

nameserver 114.114.114.114
nameserver 8.8.8.8

如果用户想要手动指定容器的配置,可以在使用docker run命令启动容器时加入如下参数:

-h HOSTNAME或者--hostname=HOSTNAME设定容器的主机名,它会被写到容器内的/etc/hostname/etc/hosts。但它在容器外部看不到,既不会在docker container ls中显示,也不会在其他的容器的/etc/hosts看到。

--dns=IP_ADDRESS添加 DNS 服务器到容器的/etc/resolv.conf中,让容器用这个服务器来解析所有不在/etc/hosts中的主机名。

--dns-search=DOMAIN设定容器的搜索域,当设定搜索域为.example.com时,在搜索一个名为 host 的主机时,DNS 不仅搜索 host,还会搜索host.example.com

注意:如果在容器启动时没有指定最后两个参数,Docker 会默认用主机上的/etc/resolv.conf来配置容器。

参考文档

http://docker.baoshu.red/network/mode.html

https://www.runoob.com/docker/docker-container-connection.html

https://www.junmajinlong.com/virtual/network/vmware_net/

https://www.cnblogs.com/cnjavahome/p/11266931.html

# Docker # Docker容器
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录