docker linux 快速开窗口_和我一起学docker(二)docker的进程隔离

402ecb2be1f2394af6ff7a3075e4787f.png

docker

作者:DevOps旭

来自:DevOps探路者

一、容器是什么

1、传统虚拟化和容器

在传统VM时代,我们要解决的核心问题是资源调配。在这一阶段,通过HyperV层抽象底层设施资源,提供互相隔离的机制,实现了统一管理、统一配置、计算资源的可运维性和资源利用率,让一台物理机能够同时运行多台虚拟主机,实现了资源利用率的有效提升。而到了容器时代,可以直接使用宿主机操作系统调度硬件资源,使得资源利用率远超传统VM,同时秒级的创建速度,使得核心问题转变成了应用开发、测试和部署。而docker则是容器时代用户最多的容器引擎之一。

2、初始docker

docker是由GO语言开发的,基于Linux内核的CGroup和Namespace以及UnionFS技术,实现的对进程进行封装隔离的虚拟化技术。docker通过虚拟化、共享内核,可以把应用需要的运行环境,缓存环境,数据库环境等进行封装,以最简化的方式运行应用,以追求最佳的性能。但是由于共享内核,所以在安全性和隔离性上远低于虚拟机。

那么,docker在解决应用开发测试和部署方面的优势有哪些呢?

首先、简化了配置。可以无缝迁移到任何环境中运行,实现了应用运行环境和底层支持环境的解耦。

第二、开发环境生产化,可以使代码从开发者机器上无缝发布到测试和生产环境,极大程度上避免了因为环境不一致导致的各种问题出现,这也是云原生实现的基础。

第三、作为云计算的多租户容器,可以更容易得为每一个租户创建,运行实例。

第四、快速部署,快速的启停容器,实现了秒级的系统启动,为服务实现灰度发布,滚动发布奠定了基础。

第五、进程级别的隔离,大规模微服务集群的最优选择。

第六,降低了运维成本。

二、深入理解docker的进程隔离

使用容器的同学都知道,容器的基石为namespace和cgroup,那么namespace和cgroup是什么呢?又怎么帮助容器技术实现隔离的呢?那么我们需要先认识一下namespace和cgroup,严格地讲,cgroup也是namespace之一,实现的是资源的隔离

db6cd544ffb5c109d6b30a3b4181d385.png

那么,容器技术既然是实现进程级别的隔离,就先谈谈PID NAMESPACE吧。

1、docker的进程模型

当我们在centos7的主机上启动了docker之后,查询进程,可以看到

[root@k8s-master ~]# ps -ef | grep docker root       1022      1  0 8月19 ?       00:00:33 /usr/bin/dockerdroot       1198   1022  0 8月19 ?       00:00:03 containerd --config /var/run/docker/containerd/containerd.toml --log-level inforoot       1924   1198  0 8月19 ?       00:00:00 containerd-shim -namespace moby -workdir /var/lib/docker/containerd/daemon/io.containerd.runtime.v1.linux/moby/ca3a70c6cab9fd9b25d5f608460b5463a2b83369bc4e1efef2ee1556ed88da15 -address /var/run/docker/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runcroot      13766   1198  0 8月19 ?       00:00:00 containerd-shim -namespace moby -workdir /var/lib/docker/containerd/daemon/io.containerd.runtime.v1.linux/moby/661aa0b4186b09bbe1ad986c56515bbe1d5bdd54579b9511d4967f398968166f -address /var/run/docker/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runcroot      14388   1198  0 8月19 ?       00:00:00 containerd-shim -namespace moby -workdir /var/lib/docker/containerd/daemon/io.containerd.runtime.v1.linux/moby/1a52099eac9fdaa12a13943d9ca779d4ea1801e9b3566b422c9bae717bd8f42a -address /var/run/docker/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runcroot      14444   1198  0 8月19 ?       00:00:00 containerd-shim -namespace moby -workdir /var/lib/docker/containerd/daemon/io.containerd.runtime.v1.linux/moby/94350e389f3d6968a43cfe44b86a92d240f1b55345dd12fe5105f04148f7270c -address /var/run/docker/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runcroot      14515   1198  0 8月19 ?       00:00:00 containerd-shim -namespace moby -workdir /var/lib/docker/containerd/daemon/io.containerd.runtime.v1.linux/moby/e5d09f22e24935bbff8e0b21a2755ef2fecaadd50c25675a42e55331d0632053 -address /var/run/docker/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runcroot      14622   1198  0 8月19 ?       00:00:00 containerd-shim -namespace moby -workdir /var/lib/docker/containerd/daemon/io.containerd.runtime.v1.linux/moby/c1ee8c758c8f05671871a198062facdaa33f90683dce561f0c9c0eb9cff050e2 -address /var/run/docker/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runcroot      14686   1198  0 8月19 ?       00:00:00 containerd-shim -namespace moby -workdir /var/lib/docker/containerd/daemon/io.containerd.runtime.v1.linux/moby/8c6ad25b86a8b9a6462adf863a96fcb1d141efbb5c1440c5089d88fe32410b69 -address /var/run/docker/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runcroot      14882   1198  0 8月19 ?       00:00:00 containerd-shim -namespace moby -workdir /var/lib/docker/containerd/daemon/io.containerd.runtime.v1.linux/moby/70567de818e599482930c663e7a8546a2eee5d4426c6b35a788463da6c2fa7dc -address /var/run/docker/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runcroot      14911   1198  0 8月19 ?       00:00:00 containerd-shim -namespace moby -workdir /var/lib/docker/containerd/daemon/io.containerd.runtime.v1.linux/moby/6afb44ca8c2c26997de0b4b484bb65b4095396bc961e3a80e2cb0565bd75f04d -address /var/run/docker/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runcroot      15106   1198  0 8月19 ?       00:00:00 containerd-shim -namespace moby -workdir /var/lib/docker/containerd/daemon/io.containerd.runtime.v1.linux/moby/001a68c9f11b5fd91dcd1cbe7c1949b5517be4f69cdfa56e1e1ab7e497610410 -address /var/run/docker/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runcroot      15287   1198  0 8月19 ?       00:00:00 containerd-shim -namespace moby -workdir /var/lib/docker/containerd/daemon/io.containerd.runtime.v1.linux/moby/c9cc60f7bf49b3aa7a6b82a4f20ccff0352558bdcdf52c0aad1d5806d28f2838 -address /var/run/docker/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runcroot      35432  35286  0 00:32 pts/0    00:00:00 grep --color=auto docker

可以看到,docker启动的第一个进程为/usr/bin/dockerd,这个是整个docker服务的入口。而dockerd的子进程docker-containerd,则是docker服务端的核心进程,负责与docker客户端进行通信交互,fork出docker容器进程。

那么每个容器内可以启动几个进程呢?每个容器内的进程号是不是隔离的?容器内的应用又是怎么启动的呢?容器内是否会有僵尸进程呢?针对这些问题,我想先谈一下容器内启动进程的两种方式:shell和exec。

在shell模式下,1号进程是以/bin/sh -c "command parameter1 parameter2 ..."的方式启动的。而exec模式下,则是 command parameter1 parameter2 ...的形式启动1号进程。下面我将构建两个镜像,以便更直观的看到这一现象。

dockerfile_shell

FROM redis:v1CMD redis-server

dockerfile_exec

FROM redis:v1CMD ["redis-server"]

然后基于以上内容构建镜像

[root@harbor dockerfile]# docker build -t redis:shell -f dockerfile_shell .Sending build context to Docker daemon  401.9MBStep 1/2 : FROM redis:v1 ---> 6f28a7e0584fStep 2/2 : CMD redis-server ---> Running in 25ab7fc5450fRemoving intermediate container 25ab7fc5450f ---> 75fc5d056605Successfully built 75fc5d056605Successfully tagged redis:shell[root@harbor dockerfile]# docker build -t redis:exec -f dockerfile_exec .Sending build context to Docker daemon  401.9MBStep 1/2 : FROM redis:v1 ---> 6f28a7e0584fStep 2/2 : CMD ["redis-server"] ---> Running in ad8a324c4b5eRemoving intermediate container ad8a324c4b5e ---> 528277f613e8Successfully built 528277f613e8Successfully tagged redis:exec

接下来分别运行两个镜像,我们观察一下进程

[root@harbor dockerfile]# docker ps --no-truncCONTAINER ID                                                       IMAGE               COMMAND                     CREATED             STATUS              PORTS               NAMES9f1d971b25f26084450f8c8a74c818372e11f98337d5c52d54b162ff5c0fe4b7   redis:exec          "redis-server"              18 seconds ago      Up 17 seconds                           adoring_dhawanb29e9823bd53be5c569f49393f15aa44ad3f1b1ff4fe7ba03dadd94aae5d272a   redis:shell         "/bin/sh -c redis-server"   21 seconds ago      Up 20 seconds                           objective_mcnulty

我们可以看到 shell模式下,COMMAND为"/bin/sh -c redis-server",在容器内又fork出了/usr/bin/tail进程,而exec模式下为 "redis-server"。

此时,我们在宿主机层面关注一下进程,在宿主机上执行一下ps 命令

[root@harbor ~]# ps -ef | grep docker root       1524      1  0 17:09 ?        00:00:41 /usr/bin/dockerdroot       1815   1524  0 17:09 ?        00:00:26 containerd --config /var/run/docker/containerd/containerd.toml --log-level inforoot       4211   1815  0 17:40 ?        00:00:00 containerd-shim -namespace moby -workdir /mnt/docker-lib/containerd/daemon/io.containerd.runtime.v1.linux/moby/b29e9823bd53be5c569f49393f15aa44ad3f1b1ff4fe7ba03dadd94aae5d272a -address /var/run/docker/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runcroot       4277   1815  0 17:40 ?        00:00:00 containerd-shim -namespace moby -workdir /mnt/docker-lib/containerd/daemon/io.containerd.runtime.v1.linux/moby/9f1d971b25f26084450f8c8a74c818372e11f98337d5c52d54b162ff5c0fe4b7 -address /var/run/docker/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runcroot       5824   5784  0 20:00 pts/0    00:00:00 grep --color=auto docker[root@harbor ~]# docker ps CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES9f1d971b25f2        redis:exec          "redis-server"           2 hours ago         Up 2 hours                              adoring_dhawanb29e9823bd53        redis:shell         "/bin/sh -c redis-se…"   2 hours ago         Up 2 hours                              objective_mcnulty[root@harbor ~]# ps -ef | grep redis root       4229   4211  0 17:40 pts/0    00:00:08 redis-server *:6379root       4293   4277  0 17:40 pts/0    00:00:08 redis-server *:6379root       5832   5784  0 20:00 pts/0    00:00:00 grep --color=auto redis

我们可以清晰地看到容器9f1d971b25f2在宿主机上的进程为4277,容器b29e9823bd53的进程为4211是,而这也是其中redis的父进程。

但是当我们进入到两个容器内,执行ps -ef 命令时,可以看到

[root@9f1d971b25f2 /]# ps -ef    UID         PID   PPID  C STIME TTY          TIME CMDroot          1      0  0 09:40 pts/0    00:00:00 redis-server *:6379root          8      0  0 09:42 pts/1    00:00:00 bashroot         21      8  0 09:42 pts/1    00:00:00 ps -ef[root@9f1d971b25f2 /]# exitexit[root@harbor dockerfile]# docker exec -it b29e9823bd53be5c569f49393f15aa44ad3f1b1ff4fe7ba03dadd94aae5d272a bash [root@b29e9823bd53 /]# ps -ef UID         PID   PPID  C STIME TTY          TIME CMDroot          1      0  0 09:40 pts/0    00:00:00 redis-server *:6379root          8      0  0 09:42 pts/1    00:00:00 bashroot         21      8  0 09:42 pts/1    00:00:00 ps -ef

可以很直观的看到,在每个容器内都是独立计算PID的,这就是docker容器所实现的进程级别的隔离。

2、PID NameSpace

那么docker是怎么实现的进程级别的隔离呢?这个是依托于linux内核提供的PID NameSpaced。我们在日常应用中可以发现,当linux在启动一个进程时,会为进程分配一个唯一的进程号。

当创建一个新的PID NameSpace后,在这个PID NameSpace中进程从1开始计算,当然,这个不是真正的PID=1,下面可以用命令更直观的看一下

# 在宿主机[root@harbor ~]# ps -ef | grep docker root       1524      1  0 17:09 ?        00:00:41 /usr/bin/dockerdroot       1815   1524  0 17:09 ?        00:00:26 containerd --config /var/run/docker/containerd/containerd.toml --log-level inforoot       4211   1815  0 17:40 ?        00:00:00 containerd-shim -namespace moby -workdir /mnt/docker-lib/containerd/daemon/io.containerd.runtime.v1.linux/moby/b29e9823bd53be5c569f49393f15aa44ad3f1b1ff4fe7ba03dadd94aae5d272a -address /var/run/docker/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runcroot       4277   1815  0 17:40 ?        00:00:00 containerd-shim -namespace moby -workdir /mnt/docker-lib/containerd/daemon/io.containerd.runtime.v1.linux/moby/9f1d971b25f26084450f8c8a74c818372e11f98337d5c52d54b162ff5c0fe4b7 -address /var/run/docker/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runcroot       5824   5784  0 20:00 pts/0    00:00:00 grep --color=auto docker[root@harbor ~]# docker ps CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES9f1d971b25f2        redis:exec          "redis-server"           2 hours ago         Up 2 hours                              adoring_dhawanb29e9823bd53        redis:shell         "/bin/sh -c redis-se…"   2 hours ago         Up 2 hours                              objective_mcnulty[root@harbor ~]# ps -ef | grep redis root       4229   4211  0 17:40 pts/0    00:00:08 redis-server *:6379root       4293   4277  0 17:40 pts/0    00:00:08 redis-server *:6379root       5832   5784  0 20:00 pts/0    00:00:00 grep --color=auto redis# 在容器内[root@harbor dockerfile]# docker exec -it b29e9823bd53be5c569f49393f15aa44ad3f1b1ff4fe7ba03dadd94aae5d272a bash [root@b29e9823bd53 /]# ps -ef UID         PID   PPID  C STIME TTY          TIME CMDroot          1      0  0 09:40 pts/0    00:00:00 redis-server *:6379root          8      0  0 09:42 pts/1    00:00:00 bashroot         21      8  0 09:42 pts/1    00:00:00 ps -ef

进程模拟图如下,可以看出来,在不同的级别的namespace中,分配的PID是不同的,而这也正是docker实现进程级别隔离的基石。

03eaf09782363bcb6e2a9321f3ece632.png

进程模拟图

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值