docker的基础镜像中包含父镜像对还是错_Docker技术核心原理讲解

54cc9984b9970e7d97f2982640194ba5.png

云计算的到来推动了一波高薪就业岗位,其中最热门的无疑是微服务开发运维岗位,而对于微服务的开发落地与部署上线,最重要的技术便是docker技术,今天就好好给大家唠嗑唠嗑这docker容器的核心技术原理~

什么是docker容器呢?官方解释:通过镜像提供软件运行需要的条件,包括代码、运行时环境、系统工具、系统库、设置等,在镜像上拉取容器,保障测试环境和开发环境的一致性,减少因环境导致的运行软件冲突。通俗的理解,镜像就好像是做好了的半成品,保障了材料的一致性(比如500g面条,200g汤汁,10g食盐,8g小料),只要把这些调料按照顺序放到锅里煮就好了,无论是有经验的厨师、还是不会做菜的妹纸、还是只会敲代码的程序猿都可以做一锅美食了。

那么大家平时都是怎么使用容器呢?研发人员在将代码开发完成后,会将代码、相关运行环境构建镜像,测试人员在宿主机上下载服务的镜像,使用容器启动镜像后即可运行服务进行测试;测试无误后运维人员申请机器,拉取服务器的镜像,在一台或多台宿主机上可以同时运行多个容器,对用户提供服务。在这个过程中每个服务都在独立的容器里运行,每台机器上都运行着相互不关联的容器,所有容器共享宿主机的cpu、磁盘、网络、内存等,即实现了进程隔离(每个服务独立运行)、文件系统隔离(容器目录修改不影响主机目录)、资源隔离(CPU内存磁盘网络资源独立)。

Docker容器的实现原理就是通过Namespace命名空间实现进程隔离、UnionFilesystem联合文件系统实现文件系统隔离、ControlGroups控制组实现资源隔离。那么每部分又是怎么实现的呢?

Namespace

我们知道运行的服务即一个进程,进程提供了服务运行需要的软硬件环境,在一台宿主机上同时启动多个服务时,可能就会出现资源的争夺、进程互相影响等,因此通过namespace就可以将宿主机上同时运行的多个服务划分成每个独立的服务,自己单独进程运行。

Linux提供的命名空间机制包含clone_newcgroup、clone_newipc、clone_newnet、clone_newns、clone_newpid、clone_newuser、clone_newuts。对于进程的隔离采用的是clone_newpid来实现的。在宿主机上可获取一组pid、ppid,其中pid是容器内进程在宿主机上的pid,ppid是容器内进程在宿主机上的父进程pid,类似容器内运行的服务是一个进程,它拥有一个pid号,而整个运行的容器又是一个进程,它拥有一个ppid号。在容器内也有一组pid、ppid, 其中pid是容器服务的进程,ppid是容器外部的进程,如果为0则表示父进程是容器外部的进程。

c9d8381a6c837f0c973f9277d94562ad.png

从主机的进程来看,1->29407->2554->5006,这其实是存在一个一颗进程树的,主机进程ppid为1是表明进程29407正在使用主机上的sbin/init进程,负责执行内核的初始化工作和系统配置,容器内进程pid为1表明/bin/bash的进程正在运行,并且父进程(ppid为0)是容器外部的进程。

57305fdeef184e3148211a268d68aed7.png

通过Linux的命名空间clone_newpid创建新进程,在底层的setNamespaces方法中传入进程、用户、网络等,创建新docker容器时把对应的隔离参数传递进去,从而实现了与宿主机、与各个容器的进程、用户、网络隔离。

这其实就和小区里不同楼层不同房间住着不同的业主是一个道理,早期在房子修建的时候,开发商提供了不同栋的不同楼层的不同房间,业主们通过购房拥有了不同房间的入住权,与每栋每楼层每房间都是独立的业主。

CGroups

对于物理资源的隔离,如cpu、内存、磁盘IO、网络IO等,采用CGroups进行实现,这样虽然所有的容器都共享宿主机的资源,但是却互不影响。每一个CGroup都可以为容器进行资源的分配,通过修改对应的参数就可以修改资源。下面这些参数是CGroups的子系统,对于docker来说,是通过参数调用子系统实现对资源的分配与控制,我们只需要关注如何配置参数即可,底层的大牛们早已写好,不用重复造轮子了哈。

da9bab227fa645b9f79d17db00e7bf1d.png

比如对于CPU的控制,在docker中使用cpu-shares参数指定容器所使用的CPU份额值(默认1024)。注:CPU-shares是一个权重值,只有多个容器存在的时候才有效,比如有三个容器,container1的cpu-shares是1000,container2是500,container3是500,那么在CPU进行时间分配的时候,对于container1的时间就会比container2、container3多一倍。配置好之后在sys/fs/cgroup/cpu/docker/<containerid>/cpu.shares中可以找到生成的值。

这就和房子装修是一个道理,整个房子买下来后,整体的面积已经固定,我们可以去设计不同卧室的面积,比如整个房子100平米可用面积,卧室空间默认是20平米,那么主卧参数100,次卧参数50,就表明了主卧面积是次卧的一倍,主卧20平米,次卧10平米。

UnionFS

通过namespace、CGroups我们实现了容器的进程隔离、网络隔离、文件系统隔离、CPU内存磁盘网络等资源隔离,但是还有个最核心的内容即镜像,它又是怎么实现的呢?

我们知道镜像是把应用程序运行需要的操作系统环境、开发语言的依赖库、系统lib库等都打包在一起,作为容器启动时的根目录(rootfs),保障容器进程的各种依赖调用都在这个目录里,从而保障了环境的一致性。

聪明的小伙伴可能已经发现一个问题了,按这样的操作的话,那是不是每开发一个应用,都要制作一个根目录呢?比如现在我用Linux的操作系统的ISO做了一个rootfs,然后又在上面安装了java运行环境,最后在上面运行我的java程序1,我的另一个小伙伴,他也开发了java程序2,是不是还需要来一遍呢?其实不然,java程序2完全可以引用java程序1的rootfs,共用操作系统环境和java运行环境。

这就是通过我们的联合文件系统UnionFS(union file system)实现的,它就是把多个目录联合放在同一个目录下,而这些目录的物理位置是分开的。在docker的镜像设计中,用户制作镜像的每一步操作就是多增加一个目录(docker中称之为层layer),这个java程序1和java程序2所在的容器就引用相同的操作系统层、java环境层,再结合应用程序层,启动docker容器时通过UnionFS把相关的层全放在一个目录里,作为容器的根文件系统,而容器的启动就是可写层,来对docker镜像进行操作。

ea19210f69da4d9e41c20679640b2294.png

这种感觉就像修房子一样,一个房子里的20层里住着不同的业主,他们有不同的装修风格、家电配置(这是最上层),但第二层(第1到19层住着一样的业主)、第三层(一楼有一样的公共设施、环境)、最底层(相同的地基)都是一样的。

通过上述讲解,对于docker容器、docker容器核心技术,你是不是已经清晰了呢?在云计算时代,最重要的技术热潮之一便是docker容器了,依托docker容器又有了新一代的领军技术— kubernetes,但其实底层的原理实现都是一样的,所以掌握1个,便可举一反三进行学习应用,docker的使用也很简单,依据官网教程便可快速搭建docker环境,赶快行动起来吧

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值