Docker笔记(二):Docker原理

1、容器技术生态

围绕Docker有一个生态系统,Docker是这个生态系统的基石,完善的生态系统才是保障 Docker以及容器技术能够真正健康发展的决定因素,容器生态系统包含核心技术、平台技术和支持技术。

1.容器核心技术

容器核心技术是指能够让Container在主机上运行起来的那些技术,包括容器规范、容器runtime、容器管理工具、容器定义工具、Registry、容器OS等。

(1)容器规范

容器不止有Docker,还有其他容器,比如Cores的rkt。为了保证容器生态的健康发展,保证不同容器之间能够兼容,Docker、CoreOS、Google等若干公司成立了Open Container Initiative(OCI)组织,其目的是制定开放的容器规范。目前OCI发布了两个规范:runtime spec和image format spec,有了容器规范,不同组织和厂商开发的容器才能够在不同的 runtime上运行。这样就保证了容器的可移植性和互操作性。

(2)容器runtime

runtime是容器真正运行的地方。runtime需要跟操作系统kernel紧密协作,为容器提供运行环境。Java程序就好比是容器,JVM则好比是runtime,runtime为Docker提供运行环境。lxc、runc和rkt是目前主流的三种容器runtime。

  • lxc是Linux上老牌的容器runtime,Docker最初也是用lxc作为runtime。
  • runc是Docker自己开发的容器runtime,符合OCI规范,是现在Docker的默认runtime。
  • rkt是CoreOS开发的容器runtime,符合OCI规范,因而能够运行Docker的容器。

(3)容器管理工具

光有runtime还不够,还需要有工具来管理容器。容器管理工具对内与runtime交互,对外为用户提供接口,比如CLI。三种runtime各自的管理工具如下:

  • lxd是lxc对应的管理工具。
  • docker engine是runc的管理工具,包含后台deamon和cli两部分。我们通常提到 Docker,一般就是指的docker engine。
  • rkt cli是rkt的管理工具。

(4)容器定义工具

容器定义工具允许用户定义容器的内容和属性,这样容器就能够被保存、共享和重建。

  • docker image是Docker容器的模板,runtime依据docker image创建容器。
  • dockerfile是包含若干命令的文本文件,可以通过这些命令创建出docker image。
  • ACI(App Container Image)与docker image类似,是由CoreOS开发的rkt容器的image格式。

(5)Registry

统一存放Image的仓库叫做Registry,除了Docker Hub,企业可以自己搭建私有的仓库。

(6)容器OS

由于有容器 runtime,几乎所有的Linux、MAC OS和 Windows都可以运行容器,而容器OS是专门运行容器的操作系统。与常规OS相比,容器OS通常体积更小,启动更快。因为是为容器定制的OS,通常它们运行容器的效率会更高。目前已经存在不少容器OS,CoreOS、Atomic和Ubuntu Core是其中的杰出代表。

2.容器平台技术

容器核心技术使得容器能够在单个主机上运行,而容器平台技术能够让容器作为集群在分布式环境中运行。容器平台技术包括容器编排引擎、容器管理平台和基于容器的PaaS。

(1)容器编排引擎

基于容器的应用一般会采用微服务架构,在这种架构下,应用被划分为不同的组件,并以服务的形式运行在各自的容器中,通过API对外提供服务。为了保证应用的高可用,每个组件都可能会运行多个相同的容器,这些容器会组成集群,集群中的容器会根据业务需要被动态地创建、迁移和销毁。

这样一个基于微服务架构的应用系统实际上是一个动态的可伸缩的系统,对我们的部署环境提出了新的要求,需要有一种高效的方法来管理容器集群,这就是容器编排引擎要干的工作。

容器编排通常包括容器管理、调度、集群定义和服务发现等。通过容器编排引擎,容器被有机地组合成微服务应用,实现业务需求。当前主流的容器编排引擎包括:

  • Docker Swarm是Docker开发的容器编排引擎。
  • Kubernetes是Goge领导开发的开源容器编排引擎,同时支持Docker和CoreS容器。
  • mesos是一个通用的集群资源调度平台,mesos与 marathon一起提供容器编排引擎功能。

(2)容器管理平台

容器管理平台是架构在容器编排引擎之上的一个更为通用的平台。通常容器管理平台能够支持多种编排引擎,抽象了编排引擎的底层实现细节,为用户提供更方便的功能,比如一键应用部署等。Rancher和Container Ship是容器管理平台的典型代表。

(3)基于容器的PaaS

基于容器的PaaS为微服务应用开发人员和公司提供了开发、部署和管理应用的平台,使用户不必关心底层基础设施而专注于应用的开发。Deis,Flynn和Dokka都是开源容器PaaS的代表。

3.容器支持技术

(1)容器网络

容器的出现使网络拓扑变得更加动态和复杂。用户需要专门的解决方案来管理容器与容器、容器与其他实体之间的连通性和隔离性。docker network是Docker原生的网络解决方案。除此之外,我们还可以采用第三方开源解决方案,例如 flannel、weave和 calico。不同方案的设计和实现方式不同,各有优势和特点,应根据实际需要来选型。

(2)服务发现

动态变化是微服务应用的一大特点。当负载增加时,集群会自动创建新的容器;负载减小,多余的容器会被销毁。容器也会根据主机的资源使用情况在不同主机中迁移,容器的IP和端口也会随之发生变化。在这种动态的环境下,必须要有一种机制让客户端能够知道如何访问容器提供的服务,这就是服务发现技术要完成的工作。服务发现会保存容器集群中所有微服务最新的信息,比如IP和端口,并对外提供API,提供服务查询功能。etcd、consul和zookeeper是服务发现的典型解决方案。

(3)监控

监控对于基础架构非常重要,而容器的动态特征对监控提岀更多挑战。针对容器环境,已经涌现出很多监控工具和方案。docker ps/top/stats是Docker原生的命令行监控工具,除了命令行,Docker也提供Stats API,用户可以通过HTTP请求获取容器的状态信息。

(4)数据管理

容器经常会在不同的主机之间迁移,如何保证持久化数据也能够动态迁移,是Rex-Ray这类数据管理工具提供的能力。

(5)日志管理

日志为问题排查和事件管理提供了重要依据。日志工具有两类:

  • docker logs是Docker原生的日志工具。
  • logspout对日志提供了路由功能,可以收集不同容器的日志并转发给其他工具进处理。

2、Docker底层依赖的核心技术

1. 基础架构

Docker采用了标准的C/S架构,包括客户端和服务端两大部分,同时通过镜像仓库来存储镜像,架构如下图。客户端和服务端既可以运行在一个机器上,也可通过 socket或者 RESTful API来进行通信。

img

(1)服务端

Docker服务端一般在宿主机后台运行,dockerd组件作为服务端接受来自客户的请求,并通过 containerd组件处理这些请求(创建、运行、分发容器)。服务端主要包括四个组件:

  • dockerd:为客户端提供RESTful API ,响应来自客户端的请求,采用模块化的架构,通过专门的Engine模块来分发管理各个来自客户端的任务,可以单独升级。
  • docker-proxy:dockerd 的子进程,负责配置容器的端口映射规则,只有当启动容器并且使用端口映射时候才会执行。
  • containerd:dockerd 的子进程,提供gRPC接口响应来自dockerd 的请求,管理 runC镜像和容器环境,可以单独升级。
  • containerd-shim:containerd的子进程,为runC容器提供支持,同时作为容器内进程的根进程 。

Docker服务端默认监听本地的unix: ///var/run/docker.sock套接字,默认只允许本地的root用户访问。可以通过-H选项来修改监听的方式。Ubuntu系统中,Docker服务端的默认启动配置文件在/etc/default/docker。

(2)客户端

Docker客户端则为用户提供一系列可执行命令,用户用这些命令实现与Docker服务端的交互。用户使用的Docker可执行命令即为客户端程序。与Docker服务端不同的是,客户端发送命令后,等待服务端返回,一旦收到返回后,客户端立刻执行结束并退出。用户执行新的命令,需要再次调用客户端命令。同样,客户端默认通过本地的unix: ///var/run/docker.sock套接字向服务端发送命令。如果服务端没有监听到默认套接字,则需要客户端在执行命令的时候显式指定。

(3)镜像仓库

镜像是使用容器的基础,Docker使用镜像仓库( Registry)在大规模场景下存储和分发镜像 。

2.命名空间

命名空间(Namespace)是Linux内核针对实现容器虚拟化而引入的一个强大特性。每个容器都可以拥有自己单独的命名空间,运行在其中的应用都像是在独立的操作系统中运行一样。命名空间保证了容器之间彼此互不影响。

在操作系统中,内核、文件系统、网络、PID、UID、IPC、内存、硬盘、CPU等资源,所有的资源都是应用进程直接共享的。要想实现虚拟化,除了要实现对内存、CPU、网络IO、硬盘IO、存储空间等的限制外,还要实现文件系统、网络、PID、UID、IPC等等的相互隔离。前者相对容易实现一些,后者则需要宿主主机系统的深入支持。

随着 Linux系统对于命名空间功能的逐步完善,Linux软件工程师已经可以实现上文所述的所有需求,让某些进程在彼此隔离的命名空间中运行。虽然,这些进程都共用一个内核和某些运行时环境(runtime,例如一些系统命令和系统库),但是彼此是不可见的,它们都认为自己是独占系统的。Docker容器每次启动时候,通过调用setNamespaces()方法来完成对各个命名空间的配置。

(1)进程命名空间

Linux通过进程命名空间管理进程号,对于同一进程(同一个task struct ),在不同的命名空间中,看到的进程号不相同 。每个进程命名空间有一套自己的进程号管理方法。进程命名空间是一个父子关系的结构,子空间中的进程对于父空间是可见的 。新fork出的一个进程,在父命名空间和子命名空间将分别对应不同的进程号。

例如,查看docker相关进程:

ps -ef |grep docker

img

进程号1553对应docker主进程,它作为父进程启动了 docker-containerd 进程,进程号为1654。启动一个ubuntu1604容器,执行如下命令,此时 , docker-containerd 进程作为父进程, 会为新建的容器启动一个 docker-containerd-shim 进程,作为该容器内所有进程的根进程。

img

进入容器内部查看容器内部的进程:

docker exec -it ubuntu1604 bash -c 'ps -ef'

img

在容器内的进程空 间中 则把 docker-containerd-shim 进程作为 0 号根进程,bash命令为1号进程,容器内只能看到 docker- containerd』iim 进程往下的子进程空 间,而无法获知宿主机上的进程信息。启动多个容器时,宿主机与容器内进程空间的关系如图。

img

(2) IPC 命名空间

容器中的进程交互采用了Linux常见

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值