Bootstrap

Docker简介

Docker最初是docCloud公司创始人Solomon Hykes在法国期间发起的一个公司内部项目,它是基于docCloud公司多年云服务技术的一次革新,并于2013年3月以Apache 2.0授权协议开源,主要项目代码在GitHub上进行维护。

Dokcer是一个开源的商业产品,Docker分为社区版(Community Edition, CE)和企业版(Enterprise Edition, EE)。其中Docker社区版是一个开放源代码软件,源代码位于https://github.com/docker/docker-ce,基于Go语言开发,基于Linux内核的cgroup、namespace,以及OverlayFS类的Union FS等技术,对进程进行封装隔离,属于操作系统层面的虚拟化技术。License为Apache-2.0,最新稳定版本为19.03.13,于2020年9月18日发布,支持Linux、Windows和Mac操作系统,是一个开放平台,用于开发应用、交付(shipping)应用、运行应用。由于隔离的进程独立于宿主和其它的隔离的进程,因此也称其为容器。最初实现是基于LXC,从0.7版本以后开始去除LXC,转而使用自行开发的libcontainer,从1.11开始,则进一步演进为使用runC和containerd。

Docker允许用户将基础设施(Infrastructure)中的应用单独分割出来,形成更小的颗粒(容器),从而提高交付软件的速度。Docker容器与虚拟机类似,但二者在原理上不同。容器是将操作系统层虚拟化,虚拟机则是虚拟化硬件,因此容器更具有便携性、高效地利用服务器。容器更多的用于表示软件的一个标准化单元。由于容器的标准化,因此它可以无视基础设施的差异,部署到任何一个地方。

Docker是一个用于开发、发布和运行应用程序的开放平台。Docker使你能够将应用程序与基础设施分开,从而可以快速交付软件。借助Docker,你可以以与管理应用程序相同的方式来管理基础设施。通过利用Docker的方法进行快速的交付、测试和部署,你可以大大减少编写代码和在生产环境中运行代码之间的延迟。

Docker利用Linux核心中的资源分离机制,例如cgroups,以及Linux核心命名空间(namespaces),来创建独立的容器(containers)。这可以在单一Linux实体下运作,避免引导一个虚拟机造成的额外负担。

Docker提供了在松散隔离的环境(loosely isolated environment)(称为容器)中打包和运行应用程序的功能。隔离和安全性使你可以在给定主机上同时运行多个容器。容器是轻量级的,因为它们不需要管理程序(hypervisor)的额外负担,而是直接在主机的内核中运行。这意味着与使用虚拟机相比,在给定的硬件组合上可以运行更多的容器。你甚至可以在实际上是虚拟机的主机中运行Docker容器。

Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个一个轻量级、可移植的容器中,然后发布到任何流行的Linux机器或Windows机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口,更重要的是容器性能开销极低。

和VMware虚拟机相比,Docker使用容器承载应用程序,而不使用操作系统,所以它的开销很少,性能很高。但是,Docker对应用程序的隔离不如虚拟机彻底,所以它并不能完全取代VMware。

Docker是基于容器的平台,允许高度可移植的工作负载。Docker容器可以在开发人员的本机上、数据中心的物理或虚拟机上、云服务上或混合环境中运行。Docker的可移植性和轻量级的特性,还可以使你轻松地完成动态管理的工作负担,并根据业务需求指示,实时扩展或拆除应用程序和服务。

Linux容器(Linux Containers,缩写为LXC):一种虚拟化技术,不是模拟一个完整的操作系统,而是对进程进行隔离。对于容器里面的进程来说,它接触到的各种资源都是虚拟的,从而实现与底层系统的隔离。由于容器是进程级别的,相比虚拟机有很多优势:

(1).启动快:容器里面的应用,直接就是底层系统的一个进程,而不是虚拟机内部的进程。所以,启动容器相当于启动本机的一个进程,而不是启动一个操作系统,速度就快很多。

(2).容器只占用需要的资源,不占用那些没有用到的资源;虚拟机由于是完整的操作系统,不可避免要占用所有资源。另外,多个容器可以共享资源,虚拟机都是独享资源。

(3).体积小:容器只要包含用到的组件即可,而虚拟机是整个操作系统的打包,所以容器文件比虚拟机文件要小很多。

传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;而容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便

Docker引擎(Docker Engine)是具有以下主要组件的客户端----服务器应用程序(client----server application):

(1).服务器:是一种长期运行的程序,称为守护进程(daemon process)(dockerd命令)。

(2).REST API:它指定程序可以用来与守护进程进行通信并指示其操作的接口。

(3).客户端:命令行界面(command line interface, CLI)(docker命令)。

我们通过客户端写命令,然后客户端将命令发送给守护进程,守护进程再将命令执行的结果返回给客户端,这就使我们能通过命令查看执行结果,镜像就是容器的源代码,容器通过镜像启动,使用仓库来保存用户构建的镜像守护进程创建和管理Docker对象,例如镜像、容器、网络和卷。

Docker引擎是用来运行和管理容器的核心软件,通常人们会简单地将其代指为Docker或Docker平台。

CLI使用Docker REST API通过脚本或直接CLI命令控制或与Docker守护进程交互。许多其他Docker应用程序都使用基础API和CLI。

Docker架构:Docker使用客户端----服务器架构,如下图所示。Docker客户端与Docker守护进程(daemon)进行对话,该守护进程完成了构建、运行和分发Docker容器的繁重工作。Docker客户端和守护进程可以在同一系统上运行,或者你可以将Docker客户端连接到远程Docker守护进程。Docker客户端和守护进程在UNIX套接字或网络接口上使用REST API进行通信。

(1).Docker守护进程(Docker daemon):侦听Docker API请求并管理Docker对象,例如镜像、容器、网络和卷。守护进程还可以与其他守护进程通信以管理Docker服务。

Docker守护进程作为服务端接受来自客户端的请求,并处理这些请求(创建、运行、分发容器)。客户端和服务端既可以运行在一个机器上,也可通过socket或者REST API来进行通信。Docker守护进程一般在宿主主机后台运行,等待接收来自客户端的消息。Docker客户端则为用户提供一系列可执行命令,用户用这些命令实现跟Docker守护进程交互。

(2). Docker客户端(Docker client):是许多Docker用户与Docker交互的主要方式。 当你使用诸如docker run之类的命令时,客户端会将这些命令发送到dockerd,然后执行它们。 docker命令使用Docker API。Docker客户端可以与多个守护进程通信。客户端和服务端既可以运行在一个机器上,也可通过socket或者RESTful API来进行通信。Docker daemon一般在宿主主机后台运行,等待接收来自客户端的消息。Docker客户端则为用户提供一系列可执行命令,用户用这些命令实现跟Docker daemon交互。

(3).Docker注册中心(Docker registry):存储Docker镜像。Docker Hub是任何人都可以使用的公共注册中心,并且默认情况下,Docker已配置为在Docker Hub上查找镜像。你甚至可以运行自己的私人注册中心。使用docker pull或docker run命令时,所需的镜像将从配置的注册中心中提取。使用docker push命令时,会将镜像推送到配置的注册中心。

镜像构建完成后,可以很容易的在当前宿主机上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,Docker Registry就是这样的服务。

一个Docker Registry中可以包含多个仓库(Repository);每个仓库可以包含多个标签(Tag);每个标签对应一个镜像。通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过<仓库名>:<标签>的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以latest作为默认标签

以Ubuntu镜像为例,ubuntu是仓库的名字,其内包含有不同的版本标签,如16.04、18.04。我们可以通过ubuntu:16.04,或者ubuntu:18.04来具体指定所需哪个版本的镜像。如果忽略了标签,比如ubuntu,那将视为ubuntu:latest。

仓库名经常以两段式路径形式出现,比如jwilder/nginx-proxy,前者往往意味着Docker Registry多用户环境下的用户名,后者则往往是对应的软件名。但这并非绝对,取决于所使用的具体Docker Registry的软件或服务。

Docker Registry公开服务:是开放给用户使用、允许用户管理镜像的Registry服务。一般这类公开服务允许用户免费上传、下载公开的镜像,并可能提供收费服务供用户管理私有镜像。最常使用的Registry公开服务是官方的Docker Hub,这也是默认的Registry,并拥有大量的高质量的官方镜像。除此以外,还有Red Hat的Quay.io;Google的Google Container Registry, Kubernetes的镜像使用的就是这个服务。

由于某些原因,在国内访问这些服务可能会比较慢。国内的一些云服务商提供了针对Docker Hub的镜像服务(Registry Mirror),这些镜像服务被称为加速器。常见的有阿里云加速器、DaoCloud加速器等。国内也有一些云服务商提供类似于Docker Hub的公开服务。比如网易云镜像服务、阿里云镜像库等。

私有Docker Registry:除了使用公开服务外,用户还可以在本地搭建私有Docker Registry。Docker官方提供了Docker Registry镜像,可以直接使用做为私有Registry服务。

切勿在没有配置Docker APT源的情况下直接使用apt命令安装Docker。

(4).Docker对象(Docker objects):是指Images、Containers、Networks、Volumes、Plugins等等。

A.镜像(Images):是一个只读模板,其中包含创建Docker容器的说明。通常,一个镜像基于另一个镜像,并进行一些其他自定义。例如,你可以构建基于ubuntu镜像的镜像,但安装Apache Web服务器和你的应用程序,以及运行应用程序所需的配置详细信息。你可以创建自己的镜像,也可以仅使用其他人创建并在注册中心中发布的镜像。要构建自己的镜像,你可以使用简单的语法创建一个Dockerfile,以定义创建镜像并运行它所需的步骤。 Dockerfile中的每条指令都会在镜像中创建一个层。当你更改Dockerfile并重建镜像时,仅重建那些已更改的层。与其他虚拟化技术相比,这是使镜像如此轻巧、小型和快速的部分原因。镜像分层(layers)构建的,而定义这些层次的文件叫Dockerfile。

操作系统分为内核和用户空间。对于Linux而言,内核启动后,会挂载root文件系统为其提供用户空间支持。而Docker镜像,就相当于是一个root文件系统。比如官方镜像ubuntu:18.04就包含了完整的一套Ubuntu 18.04最小系统的root文件系统。

Docker镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变

因为镜像包含操作系统完整的root文件系统,其体积往往是庞大的,因此在Docker设计时,就充分利用Union FS的技术,将其设计为分层存储的架构。所以严格来说,镜像并非是像一个ISO那样的打包文件,镜像只是一个虚拟的概念,其实际体现并非由一个文件组成,而是由一组文件系统组成,或者说,由多层文件系统联合组成。镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。在构建镜像的时候,需要额外小心,每一层尽量只包含该层需要添加的东西,任何额外的东西应该在该层构建结束前清理掉。分层存储的特征还使得镜像的复用、定制变得更为容易。甚至可以用之前构建好的镜像作为基础层,然后进一步添加新的层,以定制自己所需的内容,构建新的镜像。

Docker把应用程序及其依赖,打包在镜像文件里面。只有通过这个文件,才能生成Docker容器。镜像文件可以看作是容器的模板。Docker根据镜像文件生成容器的实例。同一个镜像文件,可以生成多个同时运行的容器实例。镜像是二进制文件。实际开发中,一个镜像文件往往通过继承另一个镜像文件,加上一些个性化设置而生成。

镜像文件是通用的,一台机器的镜像文件拷贝到另一台机器,照样可以使用。一般来说,为了节省时间,我们应该尽量使用别人制作好的镜像文件,而不是自己制作。即使要定制,也应该基于别人的镜像文件进行加工,而不是从零开始制作。为了方便共享,镜像文件制作完成后,可以上传到网上的仓库。Docker的官方仓库Docker Hub是最常用的镜像仓库。

使用镜像创建一个容器,该镜像必须与Docker宿主机系统架构一致,例如Linux x86_64架构的系统中只能使用Linux x86_64的镜像创建容器。Windows、Mac除外,其使用了binfmt_misc提供了多种架构支持,Windows、Mac系统上(x86_64)可以运行arm等其它架构的镜像

当用户获取一个镜像时,Docker引擎会首先查找该镜像是否有manifest列表,如果有的话Docker引擎会按照Docker运行环境(系统及架构)查找出对应镜像。如果没有的话会直接获取镜像。

每个镜像都由很多层次构成,Docker使用Union FS将这些不同的层结合到一个镜像中去。通常Union FS有两个用途,一方面可以实现不借助LVM、RAID将多个disk挂到同一个目录下,另一个更常用的就是将一个只读的分支和一个可写的分支联合在一起。

B.容器(Containers)是独立运行的一个或一组应用,是镜像运行时的实体。你可以使用Docker API或CLI创建、启动、停止、移动或删除容器。你可以将容器连接到一个或多个网络,将存储连接到它,甚至根据其当前状态创建一个新镜像。默认情况下,容器与其他容器及其主机之间的隔离度相对较高。 你可以控制容器的网络、存储或其他基础子系统与其他容器或与主机的隔离程度。容器由其镜像以及在创建或启动时为其提供的任何配置选项定义。删除容器后,未存储在永久性存储中的状态更改将消失。Docker容器通过Docker镜像来创建。

镜像和容器的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。关闭容器并不会删除容器文件,只是容器停止运行而已。终止运行的容器文件,依然会占据硬盘空间。

容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的命名空间。因此容器可以拥有自己的root文件系统、自己的网络配置、自己的进程空间、甚至自己的用户ID空间。容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。

镜像使用的是分层存储,容器也是如此。每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,我们可以称这个为容器运行时读写而准备的存储层为容器存储层。容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。因此,任何保存于容器存储层的信息都会随容器删除而丢失。

按照Docker最佳实践的要求,容器不应该向其存储层内写入任何数据,容器存储层要保持无状态化。所有的文件写入操作,都应该使用数据卷(Volume)、或者绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。因此,使用数据卷后,容器删除或者重新运行之后,数据却不会丢失。

Docker运行容器前需要本地存在对应的镜像,如果本地不存在该镜像,Docker会从镜像仓库下载该镜像。容器是以镜像为基础,再加一层容器存储层,组成这样的多层存储结构去运行的。因此该镜像如果被这个容器所依赖的,那么删除必须会导致故障。如果这些容器是不需要的,应该先将它们删除,然后再来删除镜像。

当我们运行一个容器的时候(如果不使用卷的话),我们做的任何文件修改都会被记录于容器存储层里。而Docker提供了一个”docker commit”命令,可以将容器的存储层保存下来成为镜像。换句话说,就是在原有镜像的基础上,再叠加上容器的存储层,并构成新的镜像。以后我们运行这个新镜像的时候,就会拥有原有容器最后的文件变化。

启动容器有两种方式,一种是基于镜像新建一个容器并启动,另外一个是将在终止状态(stopped)的容器重新启动。因为Docker的容器实在太轻量级了,很多时候用户都是随时删除和新创建容器。

Docker容器和LXC容器很相似,所提供的安全特性也差不多。当用docker run启动一个容器时,在后台Docker为容器创建了一个独立的命名空间和控制组集合。命名空间提供了最基础也是最直接的隔离,在容器中运行的进程不会被运行在主机上的进程和其它容器发现和作用。每个容器都有自己独有的网络栈,意味着它们不能访问其它容器的sockets或接口。不过,如果主机系统上做了相应的设置,容器可以像跟主机交互一样的和其它容器交互。当指定公共端口或使用links来连接2个容器时,容器就可以相互通信了(可以根据配置来限制通信的策略)。

镜像可以理解为一种构建时(build-time)结构,而容器可以理解为一种运行时(run-time)结构。可以从单个镜像上启动一个或多个容器。

C.服务(Services):使你可以在多个Docker守护进程之间扩展容器,这些守护进程都可以与多个管理者和工作人员一起工作。集群(swarm)的每个成员都是Docker守护进程,所有守护进程都使用Docker API进行通信。服务允许你定义所需的状态,例如在任何给定时间必须可用的服务副本的数量。默认情况下,该服务在所有工作节点之间是负载平衡(load-balanced)的。对于消费者而言,Docker服务似乎是一个单独的应用程序。Docker Engine在Docker 1.12及更高版本中支持集群模式(swarm mode)。

Docker主机(Host):一个物理或者虚拟的机器用于执行Docker守护进程和容器。

Docker底层技术:Docker是用Go编程语言编写的,利用Linux内核的几个特性来交付其功能。

(1).命名空间(Namespaces):Docker使用一种称为命名空间的技术来提供称为容器的隔离工作区。运行容器时,Docker会为该容器创建一组命名空间。这些命名空间提供了一层隔离。容器的每个方面都在单独的命名空间中运行,并且对其的访问仅限于该命名空间。命名空间是Linux内核一个强大的特性。每个容器都有自己单独的命名空间,运行在其中的应用都像是在独立的操作系统中运行一样。命名空间保证了容器之间彼此互不影响。Docker Engine在Linux上使用以下命名空间:

A.pid命名空间:进程隔离(PID:进程ID)。

B.net命名空间:管理网络接口(NET:网络)。

Docker允许通过外部访问容器或容器互联的方式来提供网络服务。容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过-P或-p参数来指定端口映射。

默认情况下,容器可以主动访问到外部网络的连接,但是外部网络无法访问到容器。容器所有到外部网络的连接,源地址都会被NAT成本地系统的IP地址。这是使用iptables的源地址伪装操作实现的。

C.ipc命名空间:管理对IPC资源的访问(IPC:进程间通信)。

D.mnt命名空间:管理文件系统挂载点(MNT:mount)。

E.uts命名空间:隔离内核和版本标识符(UTS:Unix时间共享系统)。

(2).控制组(Control groups, cgroups):Linux上的Docker引擎还依赖于另一种称为控制组的技术。cgroup将应用程序限制为一组特定的资源。控制组允许Docker Engine将可用的硬件资源共享给容器,并有选择地实施限制和约束。例如,你可以限制特定容器可用的内存。

控制组是Linux容器机制的另外一个关键组件,负责实现资源的审计和限制。它提供了很多有用的特性,以及确保各个容器可以公平地分享主机的内存、CPU、磁盘IO等资源,当然,更重要的是,控制组确保了当容器内的资源使用产生压力时不会连累主机系统。

(3).联合文件系统(Union file systems, or UnionFS):通过创建层(layers)进行操作的文件系统,使其非常轻便且快速。Docker Engine使用UnionFS为容器提供构建模块。Docker Engine可以使用多个UnionFS变体,包括AUFS、btrfs、vfs和DeviceMapper。

UnionFS是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。联合文件系统是Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。另外,不同Docker容器可以共享一些基础的文件系统层,同时再加上自己独有的改动层,大大提高了存储的效率。

(4).容器格式(Container format):Docker Engine将命名空间、控制组和UnionFS组合到一个称为容器格式的包装器中。默认容器格式为libcontainer。将来,Docker可以通过与BSD Jails或Solaris Zones等技术集成来支持其他容器格式。

Docker Compose:是用于定义和运行多个容器Docker应用程序的工具。通过Compose,你可以使用YAML文件来配置应用程序需要的所有服务,然后通过使用一个命令,就可以创建并启动所有服务。Compose使用的三个步骤:

(1).使用Dockerfile定义应用程序的环境;

(2).使用docker-compose.yml定义构成应用程序的服务,这样它们可以在隔离环境中一起运行;

(3).最后,执行docker-compose up命令来启动并运行整个应用程序。

Docker Compose是Docker官方编排(Orchestration)项目之一,负责快速的部署分布式应用。Compose定位是”定义和运行多个Docker容器的应用(Defining and running multi-container Docker applications)”,其前身是开源项目Fig。Compose允许用户通过一个单独的docker-compose.yml模板文件(YAML格式)来定义一组相关联的应用容器为一个项目(project)。Compose支持Linux、Mac、Windows10三大平台。Compose可以通过Python的包管理工具pip进行安装,也可以直接下载编译好的二进制文件使用,甚至能够直接在Docker容器中运行。

Docker Swarm:是Docker集群管理工具,其主要作用是把若干台Docker主机抽象为一个整体,并且通过一个入口统一管理这些Docker主机上的各种Docker资源。它将Docker主机池转变为单个虚拟Docker主机。Docker Swarm提供了标准的Docker API,所有任何已经与Docker守护进程通信的工具都可以使用Swarm轻松地扩展到多个主机。Swarm集群由管理节点(manager)和工作节点(work node)构成:

(1).swarm manager:负责整个集群的管理工作包括集群配置、服务管理等所有跟集群有关的工作。

(2).work node:主要负责运行相应的服务来执行任务(task)。

Swarm Mode:是指Docker引擎内嵌的集群管理和编排功能。当你初始化了一个swarm(cluster)或者将节点加入一个swarm时,其Docker引擎就会以swarm mode的形式运行。Swarm Mode内置kv存储功能,提供了众多的新特性,比如:具有容错能力的去中心化设计、内置服务发现、负载均衡、路由网格、动态伸缩、滚动更新、安全传输等。

Docker Machine:是Docker官方编排(Orchestration)项目之一,负责在多种平台上快速安装Docker环境,是一个简化Docker安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker,并可以使用docker-machine命令来管理主机。Docker Machine也可以集中管理所有的docker主机,比如快速的给100台服务器安装上docker。Docker Machine管理的虚拟主机可以是机上的,也可以是云供应商,如阿里云、腾讯云。使用docker-machine命令,你可以启动、检查、停止和重新启动托管主机,也可以升级Docker客户端和守护进程,以及配置Docker客户端与你的主机进行通信。

安装Docker Machine之前需要先安装Docker,可按照https://github.com/docker/machine/releases 中的说明进行安装。

Docker Hub:仓库(Repository)是集中存放镜像的地方。目前Docker官方维护了一个公共仓库Docker Hub。不止Docker Hub,只是远程的服务商不一样,操作都是一样的。大部分需求都可以通过在Docker Hub中直接下载镜像来实现。步骤:

(1).注册:在https://hub.docker.com 免费注册一个Docker账号;

(2).登录和退出:登录需要输入用户名和密码,登录成功后,我们就可以从Docker Hub上拉取自己账号下的全部镜像:

登录:$ docker login

退出:$ docker logout

可以通过docker search命令来查找官方仓库中的镜像,如以ubuntu为关键词进行搜索:$ docker search ubuntu

利用docker pull命令将它下载到本地:$ docker pull ubuntu

登录后,可通过docker push命令将自己的镜像推送到Docker Hub,其中username为自己的Docker账号用户名:$ docker push username/ubuntu:18.04

Docker有两种文件格式:Dockerfile和Compose file。Dockerfile定义了单个容器的内容和启动时候的行为。Compose file定义了一个多容器应用。

(1).Dockerfile:Docker可以依照Dockerfile的内容,自动化地构建镜像。Dockerfile是包含着用户想要如何构建镜像的所有命令的文本

Dockerfile是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建

(2).Compose文件:是一个YAML文件,定义了服务(service)、网络、卷(volume)。

Docker默认下,所有文件将会存储在容器里的可写的容器层(container layer)。容器有两种永久化存储方式:卷(volumes)和绑定挂载(bind mounts)。另外,Linux用户还可使用tmpfs进行挂载;Windows用户还可以使用命令管道(named pipe)。在容器中,不管是哪种永久化存储,表现形式都是一样的。

(1).卷(volumes):是宿主机器的文件系统的一部分,由Docker进行管理(在Linux,存储于/var/lib/docker/volumes/)。非Docker程序不应该去修改这些文件。Docker推荐使用卷进行持久化数据。卷可支持卷驱动(volume drivers),该驱动允许用户将数据存储到远程主机或云服务商(cloud provider)或其它。没有名字的卷叫匿名卷(anonymous volume),有名字的卷叫命名卷(named volume)。匿名卷没有明确的名字,当被初始化时,会被赋予一个随机名字。

卷是一个可供一个或多个容器使用的特殊目录,它绕过UFS,可以提供很多有用的特性:A.卷可以在容器之间共享和重用;B.对卷的修改会立马生效;C.对卷的更新,不会影响镜像;D.卷默认会一直存在,即使容器被删除。

卷的使用,类似于Linux下对目录或文件进行mount,镜像中的被指定为挂载点的目录中的文件会复制到卷中(仅卷为空时会复制)。卷是被设计用来持久化数据的,它的生命周期独立于容器,Docker不会在容器被删除后自动删除卷,并且也不存在垃圾回收这样的机制来处理没有任何容器引用的卷。

(2).绑定挂载(bind mounts):通过将宿主机器的路径挂载到容器里的这种方式,从而数据持久化,因此绑定挂载可将数据存储在宿主机器的文件系统的任何地方。非Docker程序可修改这些文件。绑定挂载是Docker早期就存在的,相比起卷,绑定挂载十分简单明了。在开发Docker应用时,应使用命名卷(named volume)代替绑定挂载,因为用户不能对绑定挂载进行Docker CLI命令操作。

绑定挂载常用于:A.同步配置文件,如:将宿主主机的DNS配置文件(/etc/resolv.conf)同步至容器中;B.在开发程序时,将源代码或Artifact同步至容器中。这种用法与Vagrant类似。

(3).tmpfs挂载(tmpfs mouts):仅仅存储于内存中,并不操作宿主机器的文件系统(不持久化于磁盘)。它可用于存储一些非持久化状态、敏感数据。

(4).命名管道(named pipes):通过npipe挂载的形式,使Docker主机和容器之间能互相通讯。常见用例是在容器内运行第三方工具,并使用命名管道连接到Docker Engine API。

(5).覆盖问题:当挂载空的卷至一个目录中,目录中的内容会被复制于卷中(不会覆盖)。如果挂载非空的卷或绑定挂载至一个目录中,那么该目录的内容将会被隐藏(obscured),当卸载后内容将会恢复显示。

日志:默认配置下,Docker的日志(如:docker logs、docker service log)所记载的是命令行的输出结果(STDOUT和STDERR)。而STDOUT和STDERR对应的文件路径分别是/dev/stderr和/dev/stdout。另外,也可以在宿主主机上查看容器的日志。

以上内容全部来自于网络整理,主要参考:

1. https://yeasy.gitbook.io/docker_practice/

2. https://www.runoob.com/docker/docker-tutorial.html

3. https://zh.wikipedia.org/wiki/Docker

4. https://docs.docker.com/get-started/overview/

;