docker之libnetwork插件化网络功能

1. 背景

docker的版本不断迭代,从1.7开始,docker将网络的部分以插件化的方式剥离出来,允许用户通过命令实现不同的后端,增加了docker的灵活性。剥离出来的网络叫做libnetwork,显而易见,它希望将来为不同的容器定义统一网络层的规范。

2. 容器的网络模型(CNM)

容器网络模型(Container Networking Model,CNM)最开始的提出者是思科公司员工Erik,设计了一个docker扩展的网桥模型。后来,他将这个模型反馈给docker的团队,得到了docker的极大的认可,也是libnetwork的雏形。

CNM主要包含三点sandbox、endpoint和network。

之前有篇文章是DOCKER之命名空间 ,文章简要说了一下网络的隔离,讲述了一些docker的网络基本知识。其实也是libnetwork的一个缩影。

sandbox相当于网卡配置、路由表、dns配置、网络命名空间等

endpoint相当于容器内部的虚拟网卡(eth0等)

network代表一个或者多个网络

当然,这些概念并不是对等,这里只是有一个类比的关系。

可见,具体底层网络如何实现,每个容器的endpoint所连接的network,以及sandbox如何进行隔离,都可以不用关心。只要libnetwork提供网络和接入点,只需要容器给街上或者拔下(这里指的是endpoint和network的链接和断开),剩下的都是直接由驱动自己实现。

3. docker网络bridge

docker自带了查看网络的命令

localhost:~ feilong$ docker network ls
NETWORK ID          NAME                  DRIVER              SCOPE
5adfcce2b464        bridge                bridge              local
c2d85093b647        docker_default        bridge              local
0eec2b9c7d57        go_default            bridge              local
604e2a13b930        host                  host                local
bded596e1021        marvin2_default       bridge              local
6c006e90b785        marvin_code-network   bridge              local
ef31b0632a2f        marvin_default        bridge              local
72169048d0e7        none                  null                local
6eb2e51b63e2        redis_default         bridge              local
6c6e4cc36312        registry_default      bridge              local
localhost:~ feilong$

从查询结果,可以看出,我的电脑上面,有很多的网络信息。docker默认是携带3种网络:bridge、host、none,这三个网络是不能被删除的

ocalhost:~ feilong$ docker network rm host
Error response from daemon: host is a pre-defined network and cannot be removed
localhost:~ feilong$ docker network rm bridge
Error response from daemon: bridge is a pre-defined network and cannot be removed
localhost:~ feilong$ docker network rm none
Error response from daemon: none is a pre-defined network and cannot be removed
localhost:~ feilong$

我们在运行容器的时候,指定的网络类型(–network=bridge|–network=host|–network=none)其实就是来源于这里,又由于docker默认是使用bridge的网络类型,通常是省略这个参数。

使用docker-compose发生了什么?

我们在使用docker-compose的时候,通常是不用设置–link参数的,那是因为,docker会认为使用docker-compose启动多个容器,但是这几个容器是组成了一个service,会自动创建一个bridge类型的网络,然后将启动的容器,放到这个网络中,和其他的网络进行隔离。

# docker-compose.yaml
version: '3'

services: 
  busybox1:
    image: busybox
    container_name: busybox1
  busybox2:
    image: busybox
    container_name: busybox2
  busybox3:
    image: busybox
    container_name: busybox3

查看docker的网络

localhost:test feilong$ docker network ls
NETWORK ID          NAME                  DRIVER              SCOPE
5adfcce2b464        bridge                bridge              local
c2d85093b647        docker_default        bridge              local
0eec2b9c7d57        go_default            bridge              local
604e2a13b930        host                  host                local
bded596e1021        marvin2_default       bridge              local
6c006e90b785        marvin_code-network   bridge              local
ef31b0632a2f        marvin_default        bridge              local
72169048d0e7        none                  null                local
6eb2e51b63e2        redis_default         bridge              local
6c6e4cc36312        registry_default      bridge              local
localhost:test feilong$

运行docker-compose,然后查看网络

localhost:test feilong$ docker-compose up -d
Creating network "test_default" with the default driver
Creating busybox2 ... done
Creating busybox3 ... done
Creating busybox1 ... done
localhost:test feilong$ docker network ls
NETWORK ID          NAME                  DRIVER              SCOPE
5adfcce2b464        bridge                bridge              local
c2d85093b647        docker_default        bridge              local
0eec2b9c7d57        go_default            bridge              local
604e2a13b930        host                  host                local
bded596e1021        marvin2_default       bridge              local
6c006e90b785        marvin_code-network   bridge              local
ef31b0632a2f        marvin_default        bridge              local
72169048d0e7        none                  null                local
6eb2e51b63e2        redis_default         bridge              local
6c6e4cc36312        registry_default      bridge              local
fca18d6c1259        test_default          bridge              local

从上面,我们看出,在运行docker-compose的时候,就已经创建了一个网络,叫做 test_default

–link ?

我们知道,想要将两个容器链接起来,可以使用–link参数(在使用命令行 docker run的时候)。其实,我们在进行docker run的时候,创建的容器,加入了一个默认的网络“bridge”,但是在“bridge”中,默认是不能进行连接的,需要加上–link,使bridge内部的容器进行连接。这样也是为了隔离容器。试想一下,如果不采用这个机制,那么网络空间就不再是隔离的状态了,就和docker的设计不太相符。

我们分别运行一个test1和test2容器

feilongdeMacBook-Pro:~ feilong$ docker run -itd --name test1 busybox
bfca24444ce4ee16d6e2af76cf0967d0923dbbed4310c811cdbefef5d6b5b67f
feilongdeMacBook-Pro:~ feilong$ docker run -itd --name test2 busybox
48a5c7e9c042de472ed5edd328a53952fe9552357eff7b1c81f4d9e3bbed1c8c
feilongdeMacBook-Pro:~ feilong$ docker ps | grep test
48a5c7e9c042        busybox                              "sh"                     6 seconds ago       Up 5 seconds                                  test2
bfca24444ce4        busybox                              "sh"                     10 seconds ago      Up 9 seconds                                  test1
b742b60be6a0        registry:latest                      "/entrypoint.sh /etc…"   22 hours ago        Up 3 hours          0.0.0.0:32768->5000/tcp   thirsty_almeida
feilongdeMacBook-Pro:~ feilong$

然后我们进入test1,ping一下test2

feilongdeMacBook-Pro:~ feilong$ docker exec -it test1 sh
/ # ping test2
ping: bad address 'test2'
/ #

结果很明显,是不通的!

但是他们是在同一个网络里面的

4. 总结

libnetwork通过CNM,抽象了下层网络的实现让docker可以根据需要,实现不同的网络技术,docke将swarm引擎加到了新的版本中,以提供集群网络的更好支持。

Docker之安全防护与配置

1. 风险的来源

docker的安全性,在很大程度上来自于Linux的本身。目前,我们考虑到的安全性时,主要考虑下面几个方面:

  • Linux内核的命名空间机制提供的容器隔离安全
  • Linux控制组机制对容器资源的控制能力安全
  • Linux内核的能力机制所带来的操作权限安全
  • docker程序(尤其是服务端)本身的抗攻击性
  • 其他安全增强机制(包括APPArmor、SELinux等)对容器安全的影响
  • 通过第三方工具(包括docker bench工具)对docker环境的安全性的评估

2. 风险的分析

2.1 命名空间隔离的安全

当我们在运行docker run的时候,docker会对针对容器创建一个隔离的命名空间,通过这个命名空间,将容器之间的进程和网络进行隔离,这就意味着容器不能独立的访问其他容器的接口或者套接字。

我们知道,所有容器的网络都是通过docker0进行桥接,当然,如果宿主机上面做一些特殊的配置,可以实现 container1->宿主机->container2 网络的交互方式。

那么,命名空间的架构设计本身,是否是足够安全呢?

其实,命名空间出现的历史很长了,从Linux内核2.6.15的版本(大概是2008年)就已经开始引用了命名空间,但是实际上,“命名空间”这个含义要更早,最开始是从2005年开始提出来的,所以设计和实现足够成熟。

当然,和虚拟机相比,命名空间并不是绝对。因为命名空间,实际上是“假隔离”,虚拟机是“真隔离”。运行在容器内的应用,会直接访问宿主机上面的内核和部分文件。所以,归根结底,我们应该保证的是镜像是足够安全的,只有镜像是安全的,才能保证我们能够在Linux运行安全可信的服务。

2.2 控制组资源控制的安全

CGroups有一个重要的作用就是资源审计和资源限制

当我们再运行docker run的时候,docker会通过Linux的相关调用,在后台创建一个控制组,用来控制容器对宿主机的资源消耗,比如控制容器使用内存、CPU等。

控制组有很多重要的作用。比如确保每个容器能够合理的使用共享资源,最重要的是可以通过控制组限制资源的使用,这一点在防止DDoS的时候尤其重要。

对于PaaS、容器云这样的容器服务平台,运行着成千上万个容器的实例,如果一旦某个容器被DDoS攻击,那么就会控制组的作用就显现出来,这样可以防止单个容器抢占过多资源,导致整个服务平台出现雪崩!

2.3 内核能力机制

传统的Unix系统对进程的权限其实只有root权限和非root权限两种粗粒度。

后来,随着Linux内核的升级,开始对权限的粒度越来越灵活,例如,可以给用户分配某个文件的修改权限、可以给某个用户操作某个进程的权限等等。

默认情况下,docker在运行容器的时候,只使用Linux内核的一部分能力,而且,容器的一些能力往往也是由宿主机上面的一些服务进行支持,比如网络的管理等。所以docker其实并不需要获取真正的“root权限”,此外,容器还能禁用一些不必要的权限,比如:

  • 禁止任何文件挂载操作(挂载实际上是宿主机,而不是容器本身);
  • 禁止访问宿主机上面的套接字;
  • 禁止访问一些文件系统的操作,比如创建新设备;
  • 禁止模板加载

所以,及时攻击者入侵到容器内部,在容器内部获取了root权限,也并不是真正的宿主机上面的“root权限”,能进行的破坏也是有限的。

2.4 Docker服务端的防护

使用docker最核心的就是docker服务器了。由于现在启动docker服务器需要使用root权限,所以服务端的权限显得尤其重要。

首先,我们应该确保运行docker的用户是可信的人。由于容器的内部一般都是root权限,如果某个恶意的用户,将宿主机上面的/目录映射到容器内部,那么容器理论上就会有修改根目录下面的权限。因此,在创建容器的时候,我们应该详细检查运行的参数。

尽量将容器映射到非root权限的用户目录下面,这样,可以有效减轻容器和宿主机上面因为权限而导致的安全隐患。

允许docker服务端在非root权限下运行,利用安全可靠的子进程限制特殊权限的操作。比如,这些子进程只能负责文件管理、配置等操作。

2.5 更多安全特性的使用

除了docker能力机制之外,我们可以使用一些安全软件增加docker的安全性。比如APParmor等。

docker默认只启用了能力机制。用户还可以启用更多的方案加强docker安全:

此外,将宿主机的文件挂载到容器内部的时候,可以通过设置一些只读(read-only)权限来避免容器对宿主机文件系统的破坏,特别是一些系统运行状态的目录,包括/proc/sys、/proc/irq、/proc/bus等等。

2.6 使用第三方检测工具

前面说了很多加强docker安全性的方式,但是注意去检查,会比较繁琐。幸亏现在有一些自动化的检测工具,比较出名的就是docker bench和Clair。

2.6.1 docker bench

docker bench其实是一个docker的镜像,仓库地址:https://hub.docker.com/r/docker/docker-bench-security/ 通过运行docker bench,可以对docker的一些配置做自动化安全检测。检测的标准是CIS Docker,检测项包括主机配置、Docker引擎、配置文件权限、镜像管理、容器运行时环境、安全项等6大方面。

docker run -it --net host --pid host --userns host --cap-add audit_control \
    -e DOCKER_CONTENT_TRUST=$DOCKER_CONTENT_TRUST \
    -v /var/lib:/var/lib \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -v /usr/lib/systemd:/usr/lib/systemd \
    -v /etc:/etc --label docker_bench_security \
    docker/docker-bench-security

在输出的结果中,会给出响应的提示信息,然后用户可以根据对应的提示,进行一些配置的更改等操作。一般是避免出现WARN或以上的问题。

3. 总结

docker其实自身携带的一些基本的抵御安全风险的机制,配合APParmor等安全机制,可以让docker容器更加安全。任何技术层面的实现,都需要合理的使用才能等到巩固,特别是生产环境,可能遭遇很多位置的安全风险,所以需要配合完善的监控系统来加强管理。

Docker使用的时候需要注意:

  1. 容器自身携带的隔离,并不是很完善,需要加强对容器的安全审查。
  2. 尽量使用官方的镜像,降低安全风险。
  3. 采用专门的服务器用来管理docker服务,加强对容器的监控机制。
  4. 随着容器的大规模使用,甚至构成容器集群的时候,需要考虑容器网络上必备的安全防护,比如DDoS攻击等。

 

docker之控制组

1. 作用

控制度(CGroups) 其实是Linux内核的一个特性,主要是用来控制共享资源,比如限制内存、CPU的的一些使用等。容器使用的CPU、内存等硬件信息,其实就是使用的宿主机上面的硬件设备,所以合理的分配资源,也是为了避免不同容器之间、容器和宿主机进程之间,产生资源的抢占。

2. 容器控制组

2.1 资源限制

比如我们要限制容器的使用内存,可以在run的时候加上–memory的参数

feilongdeMBP:~ feilong$ docker run -it --rm --name test --memory 10m busybox

然后新打开一个窗口,可以实时查看下容器的内存使用情况

TIP:

使用docker-compose的时候需要注意一下,设置内存限制的参数是mem_limit,但是在docker-compose的3.x版本之后,不支持这个参数,所以在写docker-compose.yaml 的时候,会出现 Unsupported config option for xxxx: ‘mem_limit’ 的错误信息,所以需要指定 version: ‘2’

2.2 优先级

docker run的时候支持使用-c 或者 –cpu-shares 用来指定容器使用CPU的加权值。如果不指定,那么就是使用的是默认值,一般是1024。

-c 或者 –cpu-shares并不能指定容器能够使用多少CPU或者多少GHz,而是一个加权值。有点类似nginx的负载均衡配置。

这个配置在少量容器的时候,并没有太大的实际意义。只有CPU资源比较紧缺的时候,这个配置参数才会展现出来。

比如,一个容器的加权值是100,另一个加权值是50,那么加权值为100的容器,获取CPU时间片的概率就是另一个的2倍

如果只有一个容器,那么CPU时间片肯定都会给这个容器使用。

创建一个容器,安装stress软件,然后开启10个进程,看下CPU占用情况

localhost:marvin feilong$ docker run -itd --name cpu512  --cpu-shares 512 ubuntu
localhost:marvin feilong$ docker exec -it cpu512
# apt update
# apt install stress
# stress -c 10
stress: info: [250] dispatching hogs: 10 cpu, 0 io, 0 vm, 0 hdd

打开一个新窗口,然后登录到这个容器,使用top查看下CPU占用情况

localhost:~ feilong$ docker exec -it cpu512 sh

可以从截图看到cpu大概占用了3.3%左右

新打开另一个窗口,创建新容器,一样的操作,安装stress,然后开10个进程,查看下CPU占用情况

localhost:~ feilong$ docker run -itd --name cpu1024  --cpu-shares 1024 ubuntu
# apt update
# apt install stress
# stress -c 10
stress: info: [241] dispatching hogs: 10 cpu, 0 io, 0 vm, 0 hdd

新开窗口,进入cpu1024容器,然后使用top查看CPU占用情况

可以看出CPU占用情况大概是6.6%左右,基本上是cpu是cpu512的两倍。

2.3 资源审计

资源审计主要是做一些审计操作,用来统计系统实际上把多少资源用到适合的目的上,可以使用cpuacct子系统记录某个进程组使用的CPU时间

2.4 隔离

为组隔离命名空间,这样一个组不会看到另一个组的进程、网络连接和文件系统

2.5 控制

挂起、恢复和重启动等操作

 

docker之命名空间

1. 基本架构

docker目前采用了标准的C/S架构。客户端和服务端既可以运行在一个机器上,又可以通过socket或者restful API来进行通信。

1.1 服务端

docker服务端一般都是在宿主机上,来接受客户端的命令。docker默认使用套接字的方式,但是也是允许使用tcp进行端口的监听,可以使用docker daemon -H IP:PORT的方式进行监听。

1.2 客户端

docker的客户端主要作用是向服务端发送操作的指令。客户端默认也是采用套接字的方式,向本地的docker服务端发送命令。当然,客户端也是可以使用tcp的方式进行发送指令,使用docker -H tcp://IP:PORT,用来指定接收命令的docker服务端。

2. 命名空间

大家在平时使用Linux或者macos的时候,我们并没有拆分多个环境的需求。但是在服务器上面,加入一台服务器运行多个进程,进程之间是相互影响的,比如共享内存,操作相同的文件。我们其实更希望能够将这些进程分离开,这样情况下,如果服务受到攻击,不会影响其他的服务。

docker目前主要有6命名空间的隔离方式

2.1 进程空间隔离

进程在操作系统中是一个很重要的概念,也就是大家认为的正在运行中的程序。

feilongdeMBP:~ feilong$ ps -ef
UID PID PPID C STIME TTY TIME CMD
0 1 0 0 9:31下午 ?? 0:10.07 /sbin/launchd
0 44 1 0 9:31下午 ?? 0:00.65 /usr/sbin/syslogd
0 45 1 0 9:31下午 ?? 0:01.37 /usr/libexec/UserEventAgent (System)
0 48 1 0 9:31下午 ?? 0:00.25 /System/Library/PrivateFrameworks/Uninstall.framework/Resources/uninstalld
0 49 1 0 9:31下午 ?? 0:02.57 /usr/libexec/kextd
0 50 1 0 9:31下午 ?? 0:02.40 /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/FSEvents.framework/Versions/A/Support/fseventsd
0 52 1 0 9:31下午 ?? 0:00.16 /System/Library/PrivateFrameworks/MediaRemote.framework/Support/mediaremoted
55 55 1 0 9:31下午 ?? 0:00.38 /System/Library/CoreServices/appleeventsd --server
0 56 1 0 9:31下午 ?? 0:00.75 /usr/sbin/systemstats --daemon

可见当前系统运行了很多“程序”。

我们现在新建一个容器,然后进入容器看下,docker容器里面的进程列表

feilongdeMBP:~ feilong$ docker run -it --rm --name test busybox
/ # ps -ef
PID   USER     TIME  COMMAND
    1 root      0:00 sh
    6 root      0:00 ps -ef

对比很明显,容器内部只有很少的几个正在运行的进程。

我们新建一个窗口,然后看下宿主机上面和docker相关的进程

localhost:~ feilong$ ps -ef | grep docker
    0    82     1   0  9:31下午 ??         0:00.02 /Library/PrivilegedHelperTools/com.docker.vmnetd
  501   918   879   0 10:26下午 ??         0:00.14 /Applications/Docker.app/Contents/MacOS/com.docker.supervisor -watchdog fd:0
  501   920   918   0 10:26下午 ??         0:03.32 com.docker.osxfs serve --address fd:3 --connect vms/0/connect --control fd:4 --log-destination asl
  501   921   918   0 10:26下午 ??         0:00.73 com.docker.vpnkit --ethernet fd:3 --port fd:4 --diagnostics fd:5 --pcap fd:6 --vsock-path vms/0/connect --host-names host.docker.internal,docker.for.mac.host.internal,docker.for.mac.localhost --gateway-names gateway.docker.internal,docker.for.mac.gateway.internal,docker.for.mac.http.internal --vm-names docker-for-desktop --listen-backlog 32 --mtu 1500 --allowed-bind-addresses 0.0.0.0 --http /Users/feilong/Library/Group Containers/group.com.docker/http_proxy.json --dhcp /Users/feilong/Library/Group Containers/group.com.docker/dhcp.json --port-max-idle-time 300 --max-connections 2000 --gateway-ip 192.168.65.1 --host-ip 192.168.65.2 --lowest-ip 192.168.65.3 --highest-ip 192.168.65.254 --log-destination asl --udpv4-forwards 123:127.0.0.1:59434 --gc-compact-interval 1800
  501   922   918   0 10:26下午 ??         0:01.17 com.docker.driver.amd64-linux -addr fd:3 -debug
  501   928   922   0 10:26下午 ??         2:40.08 com.docker.hyperkit -A -u -F vms/0/hyperkit.pid -c 2 -m 2048M -s 0:0,hostbridge -s 31,lpc -s 1:0,virtio-vpnkit,path=vpnkit.eth.sock,uuid=246fb3f9-3ad5-4683-837a-33ac39f57f25 -U 5a3669ae-b209-443a-a074-312cd32a258a -s 2:0,ahci-hd,/Users/feilong/Library/Containers/com.docker.docker/Data/vms/0/Docker.raw -s 3,virtio-sock,guest_cid=3,path=vms/0,guest_forwards=2376;1525 -s 4,ahci-cd,/Applications/Docker.app/Contents/Resources/linuxkit/docker-for-mac.iso -s 5,ahci-cd,vms/0/config.iso -s 6,virtio-rnd -s 7,virtio-9p,path=vpnkit.port.sock,tag=port -l com1,autopty=vms/0/tty,asl -f bootrom,/Applications/Docker.app/Contents/Resources/uefi/UEFI.fd,,
  501  2074  1102   0 11:21下午 ??         0:00.50 /Applications/Visual Studio Code.app/Contents/Frameworks/Code Helper.app/Contents/MacOS/Code Helper /Users/feilong/.vscode/extensions/peterjausovec.vscode-docker-0.1.0/node_modules/vscode-languageclient/lib/utils/electronForkStart /Users/feilong/.vscode/extensions/peterjausovec.vscode-docker-0.1.0/node_modules/dockerfile-language-server-nodejs/lib/server.js --node-ipc --node-ipc --clientProcessId=1102
  501  2100  1065   0 11:24下午 ttys001    0:00.12 docker run -it --rm --name test busybox
  501  2086  2083   0 11:21下午 ttys002    0:00.19 docker exec -it 910aa64a312b3a884f4efb059e47ee601bbd3ba3d62f4c92abd4120cff770828 /bin/sh
  501  2090  2087   0 11:21下午 ttys003    0:00.12 docker exec -it 73f8fbcc50651fd4fea9fe0be7fe4066ea78efd7e9b2438fe657a3e7725e7903 /bin/sh
  501  2115  2111   0 11:27下午 ttys004    0:00.00 grep docker

在进程列表中,我们没有看到容器内部运行的进程,说明相对于容器的“外部”,容器“内部”的进程是隔离的。但是我们也可以发现,刚刚创建的名字为test的容器,实质上就是宿主机上面的一个PID为2090的进程。

所以,我们可以理解docker的进程树是这个状态:

2.2 网络空间隔离

容器其实不能完全和宿主机器隔离网络,要不然的话容器就没办法通过外部进行访问,那么也就没有实际的意义。但是容器之间是网络隔离的,这种隔离的方式,就是通过网络命名空间实现的。

docker有四种不同的网络模式:Host、Container、None和bridge

docker默认的是桥接模式。

docker在创建容器的时候, 不仅会给容器创建IP地址,还会在宿主机上面创建一个虚拟网桥docker0,在运行的时候,将容器和该网桥进行相连。

在默认的情况下,创建容器的时候,都会创建一对虚拟网卡,两个虚拟网卡组成数据通道,一个在容器内部,另外一个加入到docker0的网桥中。

打开两个窗口,分别创建redis和redis2容器

[root@izj6c9b96ia369l2i47yq3z feilong]# docker run -it --rm --name redis  -p 6379:6379 redis:latest /bin/bash
root@d89535b59b0b:/data#
[root@izj6c9b96ia369l2i47yq3z feilong]# docker run -it --rm --name redis2 -p 6378:6379 redis:latest /bin/bash
root@7736850135af:/data#

打开第三个窗口,查看网桥的状态

[feilong@izj6c9b96ia369l2i47yq3z ~]$ brctl show
bridge name     bridge id               STP enabled     interfaces
docker0         8000.024219a15f9d       no              veth8331b03
                                                        vethc5f3cb9

docker0 会为每一个容器分配一个新的 IP 地址并将 docker0 的 IP 地址设置为默认的网关。网桥 docker0 通过 iptables 中的配置与宿主机器上的网卡相连,所有符合条件的请求都会通过 iptables 转发到 docker0 并由网桥分发给对应的机器。同时也会在防火墙加上一条新的规则。

[root@izj6c9b96ia369l2i47yq3z feilong]# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination
DOCKER-USER  all  --  anywhere             anywhere
DOCKER-ISOLATION-STAGE-1  all  --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
DOCKER     all  --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Chain DOCKER (1 references)
target     prot opt source               destination
ACCEPT     tcp  --  anywhere             172.17.0.2           tcp dpt:6379
ACCEPT     tcp  --  anywhere             172.17.0.3           tcp dpt:6379
ACCEPT     tcp  --  anywhere             172.17.0.4           tcp dpt:http
......

2.3 挂载点命名空间

docker已经可以通过命名空间将网络和进程进行隔离。挂载命名空间,允许不同的容器,查看到不同的文件结构,这样,每个命名空间的进程所看到的文件目录彼此被隔离。每个容器内的进程只会更改容器内部的文件目录。

2.4 IPC命名空间

容器中的进程交互采用的是Linux中常见的进程间交互方式(Interprocess Communication, IPC),包括信号量、消息队列和内存共享等。IPC命名空间和PID命名空间可以组合使用,同一个IPC命名空间的进程可以彼此可见,允许进行交互,不同空间的进程无法交互。

2.5 UTS 命名空间

UTS(Unix time-sharing system)命名空间允许每个容器拥有一个独立的主机名和域名,从而可以虚拟出一个独立的主机名和网络空间的环境,就可以跟网络上的一台独立主机一样。

默认情况下,docker的主机名是容器的id

2.6 用户命名空间

每个容器内部都有不同的用户组和组id,也就是说可以在容器内部使用特定的内部用户执行程序,而不是宿主机上的用户。每个容器都有root账号,但是和宿主机都不在一个命名空间。通过使用命名空间隔离,来保证容器内部用户无法操作容器外部的操作权限。

3. 总结

6种命名空间让容器之间松耦合,也让容器与宿主机松偶尔。同时,也保证了安全性。容器内部不能操作其他容器内部的东西,docker的这种命名空间隔离的方式,也比较符合Linux的系统设计。

docker之link的使用

Docker功能可以说是非常强大,但是如果想要短时间掌握docker的使用,还是有一些难度的。之前有了解一些docker的知识,但是大多数都是囫囵吞枣。并没有从最基础的知识学起,所以现在想要系统的学习一下docker的知识。

通信的痛点

link的主要作用是实现不同容器之间的连接。
举个例子,我现在有个PHP的容器,我又创建了一个mysql的容器,这个时候,如果我想要使用PHP连接mysql的容器,最常规的方式就是通过ip连接。但是这样的话,如果mysql的容器一旦重启或者重新编译,那么ip就会有可能变动,我们就需要手动更改PHP容器内连接的ip,这样的维护成本太高了。
link的作用就是要解决这个痛点问题。

link的实现

我们首先pull一个busybox的镜像,busybox是一个非常小巧的Linux镜像,占用的空间只有几MB,但是相比较Ubuntu的镜像,要小很多倍,而且也集成了很全的Linux命令

创建test1容器

从截图中,我们可以看出test1的ip是172.17.0.2

创建test2容器

我们需要新打开一个窗口,然后创建test2容器

这个时候我们ping test1的容器,是不能ping通的。

使用link关联test1和test2

我们推出test2,删除test2容器,重新run一个容器

这个时候我们发现test2里面是可以通过别名test1去进行连接,

所以,比如test1里面运行了mysql,test2里面运行了PHP,那么,连接mysql的地方,完全可以把主机的地址写成test1

总结

使用link的作用显而易见,我们可以通过别名,直接让两个容器进行通信,使用容器名称通信的优势:

  1. 不用担心ip的变动,因为name是唯一的
  2. 极大的增加了可读性
  3. 降低了运维成本

使用docker搭建lnmp (二)

docker 名为容器。何为容器,也就是所谓的瓶子,罐子。用可以容纳东西的容器,不同容器之间互不影响。比如,一个瓶子装酒精,一个瓶子装水,非人为状态下,两个瓶子是没有关联的。

同样,docker也就是这个作用,每个docker可以作为叫做一个“瓶子”,每个”瓶子”可以当做PHP的运行环境,可以当做Java的运行环境。环境完全独立。外部的环境(内存,操作系统,CPU等)相当于柜子,承载着这些”瓶子”。

Read More »

使用docker搭建lnmp环境

docker是一个开源的容器引擎,随着“微服务架构”正在变得越来越重要,docker也变得越来越火。但是网上的文章中,要么是很有借鉴意义的干货,要么就是使用高端术语来讲述什么叫做微服务架构。今天我就通过文章来记述一下传统lnmp迁移docker的过程。

Read More »