Docker主要就是借助 Linux 内核技术Namespace来做到隔离的,Linux Namespaces机制提供一种资源隔离方案。PID,IPC,Network等系统资源不再是全局性的,而是属于某个特定的Namespace。每个namespace下的资源对于其他namespace下的资源都是透明,不可见的。因此在操作系统层面上看,就会出现多个相同pid的进程。系统中可以同时存在两个进程号为0,1,2的进程,由于属于不同的namespace,所以它们之间并不冲突。而在用户层面上只能看到属于用户自己namespace下的资源,例如使用ps命令只能列出自己namespace下的进程。这样每个namespace看上去就像一个单独的Linux系统。
启动一个容器
docker run -it -p 8080:8080 --name pai-sn pai-sn:snapshot /bin/bash
-it 交互启动,-p端口映射 ,–name 容器名称 后面是镜像名称,打开shell,启动之后就进入到了容器
查看进程
ps -ef
使用top命令查看进程资源
在宿主机查看下当前执行容器的进程ps -ef|grep pai-sn
由此,我们可以知道docker run命令启动的只是一个进程,它的pid是4677。而对于容器程序本身来说,它被隔离了,在容器内部都只能看到自己内部的进程。Docker是借助了Linux内核的Namespace技术来实现的。
容器内部根目录执行ls命令
容器内部已经包含了这些文件夹了
宿主机执行docker info 来看看我们的 Docker 用到的文件系统是什么
Docker版本是20.10.6,存储驱动是overlay2,不同的存储驱动在 Docker 中表现不一样,但是原理类似。
Docker文件系统是通过mount去挂载的,执行docker ps命令器实例id
执行docker inspect container_id | grep Mounts -A 20找到挂载在宿主机的目录,查看目录列表
发现这个和我们容器的目录是一致的,我们在这个目录下创建一个新的目录,然后看看容器内部是不是会出现新的目录。其实文件的隔离,资源的隔离都是在新的命名空间下通过mount挂载的方式来隔离的。
Docker 可以限制资源使用,比如 CPU 和内存等,它通过Linux的Cgroups技术实现,Cgroups是为进程设置资源限制的重要手段,在Linux 中,一切皆文件,所以Cgroups技术也会体现在文件中,我们执行mount -t cgroup 就可以看到Cgroups的挂载情况
cpu限制信息就是在/sys/fs/cgroup/cpu这个文件夹下面配置的了,进入/sys/fs/cgroup/cpu/system.slice,查看文件
进入容器cpu的配置目录
查看cpu.cfs_period_us、cpu.cfs_quota_us
100000为默认值代表cpu可使用值,-1代表不做限制,即cpu使用率可以达到100%
Docker通过进程隔离、文件隔离和资源隔离,来实现容器间的隔离。而进程、文件和资源的隔离又是依赖Linux的内核隔离技术Namespace和Cgroup来实现的。本质来说:运行在容器的应用对宿主机来说还是一个普通的进程,还是直接由宿主机来调度的,性能的损耗就很少,这也是 Docker 技术的重要优势。
Docker的本地网络实现其实就是利用了Linux上的网络命名空间和虚拟网络设备。Docker容器网络就很好地利用了Linux虚拟网络技术,在本地主机和容器内分别创建一个虚拟接口,并让它们彼此连通(这样的一对接口叫做veth pair)。
安装Docker时,它会自动创建三个网络。你可以使用以下docker network ls命令列出这些网络:
Docker内置bridge、host、null三个网络,运行容器时,你可以使用该–network标志来指定容器应连接到哪些网络。
bridge网络代表docker0所有Docker安装中存在的网络。除非你使用该docker run --network=选项指定,否则Docker守护程序默认将容器连接到此网络。
我们在使用docker run创建Docker容器时,可以用 --net 选项指定容器的网络模式,Docker可以有以下4种网络模式:
相当于Vmware中的桥接模式,与宿主机在同一个网络中,但没有独立IP地址。Docker使用PID Namespace隔离进程,Mount Namespace隔离文件系统,Network Namespace隔离网络等。一个Network Namespace提供了一份独立的网络环境,包括网卡、路由、Iptable规则等都与其他的Network Namespace隔离。一个Docker容器一般会分配一个独立的Network Namespace。但如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。
这个模式指定新创建的容器和已经存在的一个容器共享一个Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器#除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过lo网卡设备通信。
该模式将容器放置在它自己的网络栈中,但是并不进行任何配置。实际上,该模式关闭了容器的网络功能,在以下两种情况下是有用的:容器并不需要网络(例如只需要写磁盘卷的批处理任务)。
相当于Vmware中的Nat模式,容器使用独立network Namespace,并连接到docker0虚拟网卡(默认模式)。通过docker0网桥以及Iptables nat表配置与宿主机通信;bridge模式是Docker默认的网络设置,此模式会为每一个容器分配Network Namespace、设置IP等,并将一个主机上的Docker容器连接到一个虚拟网桥上
默认Bridge模式下,容器可以通过ip直接通信,但还是不够灵活。因为我们在部署应用之前可能无法确定 IP,部署之后再指定要访问的 IP 会比较麻烦。对于这个问题,可以通过 docker 自带的 DNS 服务解决。使用 docker DNS 有个限制:只能在 user-defined 网络中使用。也就是说,默认的 bridge 网络是无法使用 DNS 的。
docker network create -d bridge --ip-range=192.168.1.0/24 --gateway=192.168.1.1 --subnet=192.168.1.0/24 bridge2
dokcer network ls查看网络,发现bridge2创建成功
docker run -it --network=bridge2 --name sn1 pai-sn:snapshot
docker run -it --network=bridge2 --name sn2 pai-sn:snapshot
ping sn1
sn1 和 sn2 可以相互ping通。这个做法是在容器创建时通过 --network 指定网络bridge2 。也可以通过 docker network connect bridge2 containerID 将现有容器加入到指定网络bridge2 。