温故知新:docker基础知识知多少(代码片段)

edisonchou edisonchou     2023-03-18     491

关键词:

记得之前曾经粗略的写过一篇Docker的基础及ASP.NET Core部署Docker示例的入门文章,但那个时候刚刚学习Docker对Docker的认知还比较浅,现在重新来温故知新一下。此外,本篇已加入《.NET Core on K8S学习实践系列文章索引》,可以点击查看更多容器化技术相关系列文章。

一、容器的用途

  首先,我们来温习一下Docker的几个用途,亦或者说Docker到底帮我们解决什么问题?

1、标准化打包

  记得在容器技术出来之前,我们开发者进行打包一般都依赖于各自开发语言平台独有的打包机制,比如.NET和Java平台下都会依赖于各自不同的发布部署技术,但在容器技术出来之后,不管是.NET还是Java都会将其发布为容器镜像推送到镜像仓库中来进行复用。

技术图片

2、隔离

  每个容器在运行时都会认为自己是独自占有了一台机器,即一个独立的环境互不干扰。其实,容器的本质是一个进程,进程与进程之间相互隔离造就了容器与容器互不影响的特性。在启动一个容器(即创建一个进程时),通过 Namespace 技术实现容器的隔离、通过 Cgroups 来实现容器的资源控制

技术图片

  关于Namespace 和 Cgroups 可以继续浏览本文3.3小节。

3、标准化部署

  在容器技术出来之前,和打包机制一样,我们都依赖于具体开发语言平台的部署机制,比如IIS、Tomcat等。但是,容器技术出来之后,即使我们使用不同的开发语言都可以使用同样的部署技术,例如Mesos或Kubernetes。至此,之前的运维人员也不在需要学习多套部署技术,只需要了解如K8s一类的标准化容器编排平台即可。

技术图片

二、容器与集装箱的关系

   提到容器要解决的问题,就不得不提一下运输业以及集装箱。几十年前,运输业面临着因货物类型不同而导致损失,又或者在运输过程中使用不同的交通工具也会让整个过程痛苦不堪。幸运的是,集装箱的发明帮助运输业解决了这个问题:

  (1)任何货物,无论是钢琴还是玛莎拉蒂,都被放到各自的集装箱中。

  (2)集装箱在整个运输过程中都是密封的,只有到达最终目的地才被打开。

  (3)集装箱可以被高效地装卸、重叠和长途运输。例如:现代化的起重机可以自动在卡车、轮船和火车之间移动集装箱。

技术图片

  容器的核心思想其实也就是将集装箱的思想应用到了软件的打包和部署上,为各类不同的代码提供了一个基于容器的标准化运输系统。换句话说,容器可以将任何应用及其依赖环境打包为一个轻量级、可移植、自包含的独立运行环境,容器可以运行在几乎所有的操作系统之上。

  不得不说,Docker的Logo就是一堆集装箱放在海豚上,作为海豚的docker就是一个标准化的运输系统:

技术图片

三、容器核心技术揭秘

1、Linux操作系统内核一窥

  为了进一步理解Docker,我们先来看看Linux操作系统及其内核,如下图所示:

技术图片

   从上图可知,最底层为硬件层,包含了内存、磁盘、CPU、网卡等;往上一层是内核空间,Kernel就是操作系统内核,负责管理硬件层中的各种资源 以及 调度进程 等工作;顶层是用户空间,用户程序就在此空间内运行,并调用内核空间提供的服务;

2、虚拟机和容器的差别

  大概了解了操作系统的内核之后,我们再来看看老生常谈的容器和虚拟机的差异,如下图所示:

技术图片

   虚拟机:主要是由硬件虚拟化+内核虚拟化技术来实现,它在宿主机操作系统或硬件层的基础之上引入一层Hypervisor来虚拟出磁盘、CPU等资源,然后在虚拟出来的资源的基础之上运行Guest OS进而实现最终的虚拟机。

  容器:直接在宿主机操作系统之上构建一个Docker Engine,共享宿主机操作系统内核,在此基础之上只引入了少量的Guest OS来实现。

  对比:

  (1)虚拟机的隔离性比容器好,因为虚拟机是一种强隔离机制;

  (2)虚拟机比较重量级,启动时速度比较慢,消耗资源也比较多;

  (3)容器的隔离性不如虚拟机,它是一种软件隔离机制,但它比较轻量级,引入的东西较少,所以速度快消耗资源少;因此,在同一个物理机上能够启动的容器的数量远远多于虚拟机的数量;

3、容器的核心技术

   了解了操作系统的内核以及和虚拟机的差异,现在我们可以正式了解一下基于Linux内核的Docker容器核心技术到底有哪些(当然,本文只是粗略的介绍一下,更详细的部分请浏览本文的参考资料文章),如下图所示:

技术图片

  (1)CGroups:

  容器进程创建好后,若不进行其他处理,该进程运行时所消耗及占用的资源(如 CPU、内存)等,是可以被其他宿主机进程或其他容器进程享用的。为了解决这个问题,Linux 容器设计中引入了 Cgroups 的概念。

  Linux CGroups 的全称是 Linux Control Group,它的主要作用就是限制一个进程(这里也可以指容器)能够使用的资源上限(如 Cpu、内存、网络等等)。关于Docker的资源限制,可以阅读我这一篇《Docker资源限制学习与验证》文章。

  (2)Namespaces:

  刚刚提到,容器的本质是一个进程,进程与进程之间相互隔离造就了容器与容器互不影响的特性。在启动一个容器(即创建一个进程时),通过 Namespaces 技术实现容器的隔离。

  容器进程的创建通过 Linux 平台下的 Clone 方法创建,在调用该方法创建进程时,通过指定额外的 Namespace 参数,使得刚创建的进程属于一个独立的空间。

int pid = clone(main_function, stack_size, CLONE_NEWPID | SIGCHLD, NULL)

  指定额外参数 CLONE_NEWPID 创建的新进程,有一个自己的 独立进程空间,在这个空间里,它的进程 ID 为 1。它既看不到其在宿主机的真正进程、也看不到其他容器的进程。

  (3)Networking

  容器的创建还需要网络的支持,Networking这一块主要是虚拟网卡、网桥及iptables为容器提供组网支持;

  (4)Storage

  最后,容器的创建还需要存储的支持,Storage这一块提供了容器支持的一些文件系统,如Device Mapper、Btrfs 及 Aufs 等等;

4、容器的镜像

  刚刚提到,容器镜像为标准化打包提供了基础。容器镜像采用的是分层的方式来组织的,如下图所示:

技术图片

   可以看到,底层的是基础镜像,称为Base Image,例如Ubuntu、CentOS等,它可以和宿主机的OS是不一样的,但是它会共享宿主机操作系统的内核;在基础镜像之上,可以有多层镜像,例如Java JDK的依赖,.NET Core Runtime依赖等;依赖层之上呢,可以是具体的应用程序的Release。

  综上所述,容器镜像采用分层的方式,可以很方便地实现镜像层的复用。如果两个容器所依赖的底层镜像层是相同的,可以共同应用同一个Hash值的底层镜像,进而也可以节省传输和网络的开销。例如,图中Image1和Image2的就实现了基础镜像层的复用。

四、容器的架构一览

  有了之前的基础知识,最后我们再来看看Docker的架构,如下图所示:

技术图片

   从上图可以看出,一个典型的Docker架构包含了三块内容:

  (1)Docker Registry:镜像仓库,主要负责存储镜像,官方的仓库是Docker Hub,你也可以基于开源项目Harbor或者使用阿里云等云服务厂商提供的镜像仓库服务来搭建私有镜像仓库,如果有兴趣可以参考我的这一篇《Docker常用流行镜像仓库搭建》。

  (2)Docker Host:Docker宿主,首先它会运行一个Docker daemon,会接收Docker Client发送的指令来执行拉取镜像、缓存、启动等操作;其次,Docker daemon执行完Docker Client发送过来的指令后,所有的容器都会在Docker Host上运行;

  (3)Docker Client:客户端操作,主要负责通过docker命令行对容器进行基本操作,如拉取镜像,构建镜像,运行容器等等;

  更多关于Docker架构的内容请参考:https://docs.docker.com/get-started/overview/

五、关于Docker Compose

  Docker主要用来运行单容器应用,而Docker Compose则是一个用来定义和应用多容器应用的工具,如下图所示:

技术图片

  使用Docker Compose,我们可以将多容器的定义和部署方式定义在一个yml文件中,这种方式特别是微服务这种架构风格,可以将多个微服务的定义及部署都规范在一个yml文件中,然后一键部署、启动或销毁整个微服务应用。所有的一切操作,只需要下面的一句话:

$docker-compose up

  很多人建议在测试环境,使用Docker Compose来快速的部署和测试微服务应用,在生产环境则建议使用Kubernetes这种生产级的容器云平台。

  如果对Docker Compose感兴趣,我之前也有写一篇使用Docker Compose来编排Spring Cloud微服务的示例文章,有兴趣可以看看。

六、小结

  本文从Docker容器要解决的几个问题入手,介绍了容器与集装箱的关联、容器的核心实现技术、容器的架构,最后简单介绍了一个Docker Compose这个多容器应用工具,相信能够从背景知识上帮你了解容器到底要帮助我们解决的问题。

参考资料

杨波,《Spring Boot与Kubernetes云原生应用实践》(强力推荐订阅学习)

EdisonZhou,《ASP.NET Core on Docker入门

EdisonZhou,《Docker资源限制学习与验证

godruoyi,《容器的工作原理和隔离机制

CloudMan,《每天5分钟玩转Docker容器技术

 

技术图片

 

纯纯的爬虫知识,pythonscrapy下载中间件知多少(代码片段)

这篇博客咱们聊聊scrapy中的DownloaderMiddleware,即下载中间件相关知识。DownloaderMiddlerware首先看一下中间件在scrapy数据流中的位置,下图黑色箭头即下载中间件。结合上图就能看出来,Requests和Response都会通过DownloaderMiddl... 查看详情

carson带你学java:泛型知识知多少(代码片段)

目录定义意义(即为什么要使用泛型)作用及特点原理额外说明:List能否转为List?定义可理解为适配广泛的类型,即参数化类型,可以把类型像方法的参数那样进行传递。//以ArrayList为示例//泛型T可以是... 查看详情

io模型知多少|代码篇(代码片段)

引言之前的一篇介绍IO模型的文章IO模型知多少|理论篇比较偏理论,很多同学反应不是很好理解。这一篇咱们换一个角度,从代码角度来分析一下。socket编程基础开始之前,我们先来梳理一下,需要提前了解的几个概念:socket:直... 查看详情

int类型知多少(代码片段)

前言:整型是MySQL中最常用的字段类型之一,通常用于存储整数,其中int是整型中最常用的,对于int类型你是否真正了解呢?本文会带你熟悉int类型相关知识,也会介绍其他整型字段的使用。1.整型分类及存储范围整数类型字节... 查看详情

温故知新——babylon.js基础·常用知识点总结(代码片段)

前言:复习BABYLON.js官网101基础文档之后,总结了一些在公司项目中常用的基础知识点。官网文档地址:http://doc.babylonjs.com/babylon101/ 一、创建场景的模板:varcreateScene=function()//创建场景空间varscene=newBABYLON.Scene(engine);//在场景... 查看详情

文件上传知多少,php面试学到老,虽然够用也挺好,知识体系也重要(代码片段)

日拱一卒无有尽,功不唐捐终入海💋目录前言经典面试题1.PHP如何获取上传的文件?2.哪些配置影响文件上传的大小数量?3.PHP除了POST还可以怎么接收上传文件?4.PHP上传文件的关键方法?文件上传处理完... 查看详情

文件上传知多少,php面试学到老,虽然够用也挺好,知识体系也重要(代码片段)

日拱一卒无有尽,功不唐捐终入海💋目录前言经典面试题1.PHP如何获取上传的文件?2.哪些配置影响文件上传的大小数量?3.PHP除了POST还可以怎么接收上传文件?4.PHP上传文件的关键方法?文件上传处理完... 查看详情

docker系列之基础实践篇(上)(代码片段)

 常用命令回顾帮助命令1.启动docker//启动$systemctlstartdocker2.查看docker版本$dockerversion3.查看安装的docker信息描述(容器多少,镜像多少等等)dockerinfo4.docker帮助命令(基本上docker的所有命令都有)docker--help此处比较长就不截图了,可... 查看详情

unitofwork知多少(代码片段)

原文链接:https://www.cnblogs.com/sheng-jie/p/7416302.html1.引言Maintainsalistofobjectsaffectedbyabusinesstransactionandcoordinatesthewritingoutofchangesandtheresolutionofconcurrencyproblems.UnitofWork  查看详情

大前端快闪:package.json文件知多少?(代码片段)

...构建完整的全栈技能体系。快闪一:package.json文件知多少如果你使用了nodejs、npm项目、Angular项目等&#x 查看详情

温故知新,.netcore遇见winforms客户端窗体框架,在dotnetcore大一统基础上老树发芽...(代码片段)

什么是WinFormhttps://docs.microsoft.com/zh-cn/dotnet/desktop/winformsWindows窗体(WindowsForm),简称WinForms,是一个可创建适用于Windows的丰富桌面客户端应用的UI框架。Windows窗体开发平台支持广泛的应用开发功能,包括控件、图形、数... 查看详情

玩转springboot原理篇(核心注解知多少)(代码片段)

type=FilterType.CUSTOM,classes=TypeExcludeFilter.classtype=FilterType.CUSTOM,classes=AutoConfigurationExcludeFilter.classSpringBootApplicationSpringBootConfigurationComponentScanEnableAutoConfiguratio 查看详情

__attribute__你知多少(代码片段)

__ATTRIBUTE__你知多少?GNUC 的一大特色就是__attribute__ 机制。__attribute__ 可以设置函数属性(FunctionAttribute )、变量属性(VariableAttribute )和类型属性(TypeAttribute )。__attribute__ 书写特征是:__attribu 查看详情

typescriptinterfacevstype知多少(代码片段)

接口和类型别名非常相似,在大多情况下二者可以互换。在写TS的时候,想必大家都问过自己这个问题,我到底应该用哪个呢?希望看完本文会给你一个答案。知道什么时候应该用哪个,首先应该了解二者之间的相同点和不同点... 查看详情

carson带你学android:常见的动画类型你知多少?(代码片段)

前言动画的使用是Android开发中常用的知识可是动画的种类繁多、使用复杂,每当需要采用自定义动画实现复杂的动画效果时,很多开发者就显得束手无策本文将献上一份Android动画简介,包括动画的种类、使用、原理... 查看详情

前端学习docker(代码片段)

文章参考知乎,花生博客。记录下docker的一些知识Docker没有使用docker前,我们经常遇到如下问题:手动部署成本太高,改错别字都很麻烦一台服务器由于时间累积导致环境变得“脏乱差”重装系统成本太高,难以迁移而Dock... 查看详情

温故而知新--javascript书摘

...的方式方法上有很大的提升。随着时间的增加,愈加发现基础知识的重要性,很多开发过程中遇到的问题都是由最基础的知识点遗忘造成,基础不牢,地动山摇。所以,就再次回归基础知识,重新学习JavaScript相关内容,加深对Ja... 查看详情

django学习日记-08回顾--温故知新(代码片段)

知识总结回顾:      -Ajax全部操作在一个html页面执行,对于之前的Ajax操作中事件的发生于其对于的联系方式相关,思路上首先都在思考编写模板内容部分,然后在是函数的执行    - 使用id=‘事件名’ ... 查看详情