linux的namespace、docker网络模式

1.linux Namespace

  docker容器本质上是宿主机的进程,Docker通过namespace实现了资源隔离.

 1.概念

  namespace 是 Linux 内核用来隔离内核资源的方式。通过 namespace 可以让一些进程只能看到与自己相关的一部分资源,而另外一些进程也只能看到与它们自己相关的资源,这两拨进程根本就感觉不到对方的存在。具体的实现方式是把一个或多个进程的相关资源指定在同一个 namespace 中。

  Linux namespaces 是对全局系统资源的一种封装隔离,使得处于不同 namespace 的进程拥有独立的全局系统资源,改变一个 namespace 中的系统资源只会影响当前 namespace 里的进程,对其他 namespace 中的进程没有影响。

 

2.用途

  实际上,Linux 内核实现 namespace 的一个主要目的就是实现轻量级虚拟化(容器)服务。在同一个 namespace 下的进程可以感知彼此的变化,而对外界的进程一无所知。这样就可以让容器中的进程产生错觉,认为自己置身于一个独立的系统中,从而达到隔离的目的。也就是说 linux 内核提供的 namespace 技术为 docker 等容器技术的出现和发展提供了基础条件。
  我们可以从 docker 实现者的角度考虑该如何实现一个资源隔离的容器。比如是不是可以通过 chroot 命令切换根目录的挂载点,从而隔离文件系统。为了在分布式的环境下进行通信和定位,容器必须要有独立的 IP、端口和路由等,这就需要对网络进行隔离。同时容器还需要一个独立的主机名以便在网络中标识自己。接下来还需要进程间的通信、用户权限等的隔离。最后,运行在容器中的应用需要有进程号(PID),自然也需要与宿主机中的 PID 进行隔离。也就是说这六种隔离能力是实现一个容器的基础,下面是linux提供的能力:

 

 上表中的前六种 namespace 正是实现容器必须的隔离技术。

 

2.docker网络模式

1.实现原理

  Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。

  Docker网桥是宿主机虚拟出来的,并不是真实存在的网络设备,外部网络是无法寻址到的,这也意味着外部网络无法通过直接Container-IP访问到容器。如果容器希望外部访问能够访问到,可以通过映射容器端口到宿主主机(端口映射),即docker run创建容器时候通过 -p 或 -P 参数来启用,访问容器的时候就通过[宿主机IP]:[容器端口]访问容器。

 

2.四类网络模式

1. bridge模式 --net=bridge  (默认值)

  当Docker进程启动时,会在主机上创建一个名为docker0的虚拟网桥,此主机上启动的Docker容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中,容器直接通过ip可以互相通信(可以通过ping测试)

  从docker0子网中分配一个IP给容器使用,并设置docker0的IP地址为容器的默认网关。在主机上创建一对虚拟网卡veth pair设备,Docker将veth pair设备的一端放在新创建的容器中,并命名为eth0(容器的网卡),另一端放在主机中,以vethxxx这样类似的名字命名,并将这个网络设备加入到docker0网桥中。可以通过brctl show命令查看。

  bridge模式是docker的默认网络模式,不写--net参数,就是bridge模式。使用docker run -p时,docker实际是在iptables做了DNAT规则,实现端口转发功能。可以使用iptables -t nat -vnL查看。

如下图:

例如:

(1)启动nginx

docker run -p 80:80 nginx

(2)检查容器

docker inspect a5

网络信息如下:

 

2. host模式  --net=host

  如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。

  使用host模式的容器可以直接使用宿主机的IP地址与外界通信,容器内部的服务端口也可以使用宿主机的端口,不需要进行NAT,host最大的优势就是网络性能比较好,但是docker host上已经使用的端口就不能再用了,网络的隔离性不好。

 Host模式如下图所示:

 

例如:(直接启动,无需用-p指定端口。直接使用和宿主机同一个端口和IP。)

docker@default:~$ docker run -d --net=host nginx
fe607548d6f1faca06b0d9e02f1305f2d0d5c4691202c18f82000b42fa4a6732

inspect检查容器信息:

 

3.none模式 --net=none

  使用none模式,Docker容器拥有自己的Network Namespace,但是,并不为Docker容器进行任何网络配置。也就是说,这个Docker容器没有网卡、IP、路由等信息。需要我们自己为Docker容器添加网卡、配置IP等。

  这种网络模式下容器只有lo回环网络,没有其他网卡。none模式可以在容器创建时通过--network=none来指定。这种类型的网络没有办法联网,封闭的网络能很好的保证容器的安全性。

示意图如下:

 例如:

docker@default:~$ docker run -d --net=none nginx
371686158b33958ec3c71b6fb3db2c5309f8515e07b0d76aac0bc8b0745d293a
docker@default:~$ docker inspect 37

 

查看网络信息如下:

 

4.container模式 --net=container:容器ID或name

  这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。

示意图如下:

 例如:

docker run -d --net=container:371686158b33 nginx

 

补充:docker的隔离是指容器与容器直接隔离,比如两个容器直接的进程相互隔离,但是宿主机是能看到docker内部进程的。容器内的进程,与相对应的宿主进程,有相同的uid、gid拥有

 (1)宿主机查看rabbitmq进程

docker@default:~$ ps aux | grep rabbitmq | grep -v grep
999       2953  0.0  0.1   4292  1508 ?        Ss   13:43   0:00 /bin/sh /usr/lib/rabbitmq/bin/rabbitmq-server
999       3213  2.8  7.1 2218532 72236 ?       Sl   13:43   0:57 /usr/lib/erlang/erts-8.2.1/bin/beam -W w -A 64 -P 1048576 -t 5000000 -stbt db -zdbbl 128000 -K true -B i -- -root /usr/lib/erlang -progname erl -- -home /var/lib/rabbitmq -- -pa /usr/lib/rabbitmq/lib/rabbitmq_server-3.6.11/ebin -noshell -noinput -s rabbit boot -sname rabbit@my-rabbit -boot start_sasl -config /etc/rabbitmq/rabbitmq -kernel inet_default_connect_options [{nodelay,true}] -sasl errlog_type error -sasl sasl_error_logger tty -rabbit error_logger tty -rabbit sasl_error_logger tty -rabbit enabled_plugins_file "/etc/rabbitmq/enabled_plugins" -rabbit plugins_dir "/usr/lib/rabbitmq/plugins:/usr/lib/rabbitmq/lib/rabbitmq_server-3.6.11/plugins" -rabbit plugins_expand_dir "/var/lib/rabbitmq/mnesia/rabbit@my-rabbit-plugins-expand" -os_mon start_cpu_sup false -os_mon start_disksup false -os_mon start_memsup false -mnesia dir "/var/lib/rabbitmq/mnesia/rabbit@my-rabbit" -kernel inet_dist_listen_min 25672 -kernel inet_dist_listen_max 25672

(2)docker容器内部查看进程

root@my-rabbit:/# ps aux | grep rabbitmq | grep -v grep
rabbitmq     1  0.0  0.1   4292  1508 ?        Ss   13:43   0:00 /bin/sh /usr/lib/rabbitmq/bin/rabbitmq-server
rabbitmq   115  0.0  0.0  30540   252 ?        S    13:43   0:00 /usr/lib/erlang/erts-8.2.1/bin/epmd -daemon
rabbitmq   233  3.0  7.1 2218532 72236 ?       Sl   13:43   0:56 /usr/lib/erlang/erts-8.2.1/bin/beam -W w -A 64 -P 1048576 -t 5000000 -stbt db -zdbbl 128000 -K true -B i -- -root /usr/lib/erlang -progname erl -- -home /var/lib/rabbitmq -- -pa /usr/lib/rabbitmq/lib/rabbitmq_server-3.6.11/ebin -noshell -noinput -s rabbit boot -sname rabbit@my-rabbit -boot start_sasl -config /etc/rabbitmq/rabbitmq -kernel inet_default_connect_options [{nodelay,true}] -sasl errlog_type error -sasl sasl_error_logger tty -rabbit error_logger tty -rabbit sasl_error_logger tty -rabbit enabled_plugins_file "/etc/rabbitmq/enabled_plugins" -rabbit plugins_dir "/usr/lib/rabbitmq/plugins:/usr/lib/rabbitmq/lib/rabbitmq_server-3.6.11/plugins" -rabbit plugins_expand_dir "/var/lib/rabbitmq/mnesia/rabbit@my-rabbit-plugins-expand" -os_mon start_cpu_sup false -os_mon start_disksup false -os_mon start_memsup false -mnesia dir "/var/lib/rabbitmq/mnesia/rabbit@my-rabbit" -kernel inet_dist_listen_min 25672 -kernel inet_dist_listen_max 25672
rabbitmq   322  0.3  0.1   4184  1304 ?        Ss   13:43   0:06 erl_child_setup 1048576
rabbitmq   347  0.0  0.0  11428   984 ?        Ss   13:44   0:00 inet_gethost 4
rabbitmq   348  0.0  0.1  13548  1548 ?        S    13:44   0:00 inet_gethost 4

 

posted @ 2020-02-26 11:43  QiaoZhi  阅读(1104)  评论(0编辑  收藏  举报