玩转Docker(一):基本概念

容器技术是继大数据和云计算之后又一炙手可热的技术,而且未来相当一段时间内都会非常流行。

本文将对其基本概念和基本使用做出介绍。包括容器生态系统、容器的原理、怎样运行第一个容器、容器技术的概念与实践、Docker镜像等等

目录

[一. 鸟瞰容器生态系统](#一. 鸟瞰容器生态系统)

[1. 容器生态系统包含哪些不同层次的技术?](#1. 容器生态系统包含哪些不同层次的技术?)

[2. 先了解下Docker](#2. 先了解下Docker)

[3. 容器、镜像、镜像仓库](#3. 容器、镜像、镜像仓库)

[4. Docker容器与虚拟机技术的区别和联系](#4. Docker容器与虚拟机技术的区别和联系)

[二. 运行第一个容器](#二. 运行第一个容器)

[三. 容器技术](#三. 容器技术)

[1. What - 什么是容器?](#1. What - 什么是容器?)

[2. Why - 为什么需要容器?](#2. Why - 为什么需要容器?)

[3. How - 容器是如何工作的](#3. How - 容器是如何工作的)

Docker架构

[Docker服务器:Docker Daemon](#Docker服务器:Docker Daemon)

[Docker客户端:Docker CLI](#Docker客户端:Docker CLI)

Docker镜像:Image

Docker容器:Container

Registry:存放Docker镜像的仓库

[4. 小结](#4. 小结)

[四. Docker镜像](#四. Docker镜像)

[1. 镜像的内部结构](#1. 镜像的内部结构)

[hello-world -- 最小的镜像](#hello-world -- 最小的镜像)

base镜像

支持运行多种LinuxOS

[2. 镜像的分层结构](#2. 镜像的分层结构)

[3. 构建镜像](#3. 构建镜像)

[docker commit](#docker commit)

Dockerfile

[RUN vs CMD vs ENTRYPOINT](#RUN vs CMD vs ENTRYPOINT)


一. 鸟瞰容器生态系统

1. 容器生态系统包含哪些不同层次的技术?

容器生态系统是基于Docker等各种容器的生态系统,包含的技术层次

容器生态系统包含核心技术、平台技术和支持技术。

简而言之:

  • 核心技术:能够让 Container 在 host 上运行的那些技术。解决的是容器自身怎样运行。
  • 平台技术:关注一组容器如何组织运行,管理这组容器的生命周期。
  • 容器支持技术:支持基于容器的基础设施。例如,容器网络、服务发现、监控、数据管理、日志管理、安全性等等

2. 先了解下Docker

Docker是一种开源的容器化平台,旨在简化应用程序的开发、部署和运行过程。提供了一种轻量级、可移植和自包含的容器化环境,使开发人员能够在不同计算机上以一致的方式构建、打包和分发应用程序

3. 容器、镜像、镜像仓库

  • 容器(Container):容器是Docker中运行应用程序的运行时实例。它是一个轻量级、可执行的软件包,包含了运行某个应用程序所需的所有内容,包括代码、运行时、系统工具、系统库和设置等。容器基于镜像创建,是镜像的运行实例。容器可以处于以下几种状态:

    • 运行中:容器正在运行应用程序
    • 已停止:容器已经停止运行,但仍然存在于系统中,可以随时重新启动。
    • 已删除:容器被删除后,其所有数据和状态都会被清除。
  • 镜像(Image):镜像是容器的模板,是只读的。它包含了容器运行所需的文件系统和应用程序的初始状态。镜像是由一系列的分层文件系统组成的,每一层都包含了特定的修改或更新。

  • 镜像仓库(Image Registry):镜像仓库是用于存储和分发 Docker 镜像的地方。最常用的公共镜像仓库是 Docker Hub,上面有大量的官方和社区共享的镜像。此外,还可以搭建私有的镜像仓库,用于存放自己的镜像。

  • Dockerfile:Dockerfile 是一种文本文件,用于定义 Docker 镜像的构建过程。它包含了一系列的指令,用于指定基础镜像、安装软件、拷贝文件、配置环境等。通过 Dockerfile,可以自动化地构建镜像,确保镜像的一致性和可重复性。

4. Docker容器与虚拟机技术的区别和联系

Docker容器和虚拟机都是用于隔离和运行应用程序的技术,但它们在实现方式、性能、资源占用、启动速度等方面存在显著差异。以下是它们的主要区别:

  • Docker容器:容器是一种轻量级的隔离运行环境,基于宿主机的操作系统内核,共享内核但拥有独立的文件系统、网络接口和进程空间。容器启动快(通常几秒内完成),资源占用低,性能接近物理机,适合快速部署和运行应用程序,尤其适用于微服务架构和开发测试环境。
  • 虚拟机:虚拟机通过虚拟化技术创建一个完整的虚拟计算机环境,运行独立的操作系统和应用程序。它提供强隔离性,适合运行多个不同操作系统或需要高度安全隔离的场景。虚拟机启动慢(通常几分钟),资源占用高,性能损耗较大,但可移植性强,适合长期运行且对隔离性要求高的应用。

5. 运行第一个容器

首先,请安装Docker并配置Docker的apt源。

  • 配置Docker的APT源主要是为了确保能够从官方或可信的源中安装和更新Docker软件包,同时也能解决一些常见的问题,比如版本兼容性、软件更新以及网络访问速度等。
  • 由于Docker Hub的服务在国外,下载镜像比较慢,最好配置成为免费的国内镜像服务。

环境就绪,马上运行第一个容器,执行命令:

bash 复制代码
docker run -d -p 80:80 httpd

结果如图所示:

其过程可以简单描述为:

  1. 从Docker Hub下载httpd镜像

  2. 启动httpd容器,并将容器的80端口映射到host的80端口

  3. 下面可以通过浏览器验证容器是否正常工作。在浏览器中输入:http://[your ubuntu host ip]/

结果如图所示:

二. 容器技术

容器技术,需要搞清楚 What、why 和 How三个方面:什么是容器、为什么使用容器、容器是如何工作的。其中容器是怎样工作的,是容器核心知识的最主要部分。

1. What - 什么是容器?

容器是一种轻量级、可移植、自包含的软件打包技术,使应用程序可以在几乎任何地方以相同的方式运行。

容器与虚拟机

谈到容器,就不得不将它与虚拟机进行对比,因为两者都是为应用提供封装和隔离。

  • 容器由两部分构成:应用程序本身、及其依赖(比如应用程序需要的库或者其他软件容器在Host操作系统的用户空间中运行,与操作系统的气压进程隔离,这一点显著区别于虚拟机)。
  • 传统的虚拟化技术:目标是创建完整的虚拟机。为了运行应用,除了部署应用本及其依赖,还得安装整个操作系统。

由于所有容器共享一个host os,这使得容器在体积上要比虚拟机小很多。另外,启动容器不需要启动整个操作系统,所以容器部署和启动更快、开销更小也更容易迁移。

2. Why - 为什么需要容器?

为什么需要容器,容器到底解决了什么问题?简要的答案是,容器使软件具备了超强的移植能力。

就像集装箱解决了货物运输过程中,不同种类的货物相互影响、干扰的难题。

任何货物,不论是钢琴和保时捷,都被放到各自的集装箱中。集装箱在整个运输过程中都是密封的,只有到达最终目的地才会被打开。集装箱被誉为运输界与世界贸易最重要的发明。(容器和集装箱的英文单词都是:Container)

Docker将集装箱思想用到软件打包上,为代码提供了一个基于容器的标准化运输系统。

Docker可以将任何应用以及依赖打包成一个轻量级、可移植、自包含的容器。容器可以运行在几乎所有的操作系统上。

3. How - 容器是如何工作的

Docker架构

Docker的核心组件包括:

  • Docker客户端:Client
  • Docker服务器:Docker daemon
  • Docker镜像:Image
  • Registry
  • Docker容器:Container

Docker架构如图所示

Docker采用的是Client / Server架构。客户端向服务器发送请求,服务器请求构建、运行和分发容器。客户端和服务器可以运行在同一个Host上,客户端也可以通过socket或REST API与远程服务器通信。

Docker服务器:Docker Daemon

Docker 服务器是容器管理的核心,负责实际的容器生命周期管理和资源分配。

Docker服务器是Docker的后台服务进程,通常定义为Docker守护进程。它负责管理Docker的生命周期,包括创建、运行、停止、删除容器等操作。

功能:

  • 容器管理:接收来自客户端的指令,执行容器的创建、启动、停止、删除等操作。
  • 镜像管理:管理Docker镜像的拉取、存储和推送
  • 网络管理:配置容器的网络环境,包括虚拟网络、端口映射等。
  • 存储管理:管理容器的存储卷,支持数据持久化。
  • 资源隔离:通过 Linux 内核的命名空间(Namespaces)和控制组(Cgroups)技术,为容器提供隔离的运行环境。

运行方式:Docker服务器通常在后台运行,监听来自客户端的请求,并执行相应的操作。

Docker客户端:Docker CLI

Docker 客户端是用户与 Docker 服务器之间的桥梁,提供用户友好的交互方式,方便用户发送命令和管理容器。最常用的Docker客户端是docker命令。通过docker我们可以方便地在Host上构建和运行容器。

  • Docker客户端是用户与Docker服务器交互的工具,通常是一个命令行界面(CLI),用户通过它发送命令来控制Docker服务器。

功能:

  • 命令执行:用户通过命令行输入指令,如 docker rundocker builddocker stop 等,将这些指令发送给 Docker 服务器。
  • 交互界面:提供用户友好的交互方式,方便用户管理容器和镜像。
  • 配置管理:允许用户配置 Docker 的运行参数,如网络设置、存储驱动等。

运行方式:Docker 客户端通常运行在用户的本地机器上,通过网络(默认是本地套接字)与 Docker 服务器通信。

Docker镜像:Image

可将Docker镜像看成只读模板,通过它可以创建Docker容器。

镜像有多种生成方法:

  • 从无到有开始创建镜像
  • 下载并使用别人创建好的现成的镜像
  • 在现有镜像上创建新的镜像

可以将镜像的内容和创建步骤描述在一个文本文件中,这个文件被称为Dockerfile,通过执行docker build <docker-file> 命令可以构建出Docker镜像。

Docker容器:Container

Docker容器就是Docker镜像的运行实例。

用户可以通过CLI(Docker)或是API启动、停止、移动或删除容器。可以这么认为:对于应用软件,镜像是软件生命周期的构建和打包阶段,而容器则是启动和运行阶段。

Registry:存放Docker镜像的仓库

Registry是存放Docker镜像的仓库,Registry分为私有和公有两种。

Docker Hub(https://hub.docker.com/)是默认的Registry,由Docker公司维护,上面有数以万计的镜像,用户可以自由下载和使用。

出于对速度或安全的考虑,用户也可以创建自己的私有Registry。

  • docker pull 命令可以从Registry下载镜像。
  • docker run 命令则是先下载镜像(如果本地没有),然后再启动容器。

还记得我们运行的第一个容器吗?现在通过它来体会一下Docker各个组件是如何协作的。容器启动过程如下:

  1. Docker客户端执行docker run命令

  2. Docker Daemon发现本地没有httpd镜像

  3. daemon从Docker Hub下载镜像

  4. 下载完成,镜像httpd被保存到本地

  5. Docker daemon启动容器。

docker images已经可以查看到httpd已经下载到本地

docker ps 或者 docker container ls显示容器正在运行。

4. 小结

Docker借鉴了集装箱的概念。标准集装箱将货物运往世界各地,Docker将这个模型运用到自己的设计哲学中。唯一不同的是:集装箱运输货物,Docker运输软件。

每个容器都有一个软件镜像,相当于集装箱中的货物。容器可以被创建、启动、关闭和销毁。和集装箱一样,Docker在执行这些操作时,并不关心容器里面到底装的什么,它不管里面是Web Server,还是Data-base。用户不需要关心容器最终在哪里运行,因为在哪里都可以运行

开发人员可以在笔记本上构建镜像并上传到Registry,然后QA人员将镜像下载到物理或虚拟机做测试,最终容器会部署到生产环境。

使用Docker以及容器技术,我们可以快速的构建一个应用服务器、一个消息中间件、一个数据库、一个持续集成的环境。因为Docker Hub上有我们能想到的几乎所有的镜像。

三. Docker镜像

镜像是Docker容器的基石,容器是镜像的运行实例,有了镜像才能启动容器。

本章内容安排如下:首先通过研究几个典型的镜像,分析镜像的内部结构;然后学习如何构建自己的镜像;最后介绍怎样管理和分发镜像。

1. 镜像的内部结构

为什么我们要讨论镜像的内部结构?如果只是使用镜像,当然不需要了解,直接通过Docker命令下载和运行就可以了。

但如果我们想构建自己的镜像,或者想理解Docker为什么是轻量级的,就非常有必要学习这部分知识了。

我们从一个最小的镜像开始学习。

hello-world -- 最小的镜像

hello-world是Docker官方提供的一个镜像,通常用来检验Docker是否安装成功。我们先通过docker pull 从Docker Hub下载它,如图所示:

用 docker images 查看镜像的信息,如图所示:

hello-world竟然还不到2kb,通过docker run运行,如图所示:

其实我们更关心 hello-world 镜像包含了哪些内容。

Dockerfile是镜像的描述文件,定义了如何构建Docker镜像。Dockerfile的语法简洁且可读性强,后面我们会讨论如何编写Dockerfile。

hello-world 的 Dockerfile内容如下图所示:

只有短短三条指令。

(1)From scratch镜像是白手起家,从0开始构建

(2)COPY hello/ 将文件 "hello"复制到镜像的根目录

(3)CMD ["/hello"] 容器启动时,执行 /hello

镜像hello-world中就只有一个可执行文件 "hello",其功能就是打印出 "Hello from Docker..."等信息。

/hello 就是文件系统的全部内容,连最基本的 /bin /usr /lib /dev 都没有

hello-world虽然是一个完整的镜像,但它并没有什么实际用途。通常来说,我们希望镜像能够提供一个基本的操作系统环境,用户可以根据需要安装和配置软件。

这样的镜像我们称作 base镜像。

base镜像

base镜像有两层含义:

  • 不依赖于其他镜像,从scratch构建
  • 其他镜像可以以之为基础进行扩展

所以,能称作base镜像的通常都是各种Linux发行版的Docker镜像,比如Ubuntu、Debian、CentOS等。

我们以CentOS为基础为例考察base镜像包含哪些内容。

下载镜像:

bash 复制代码
docker pull centos

查看镜像信息,如下图:

镜像大小不到200MB

等一下!

一个CentOS才200MB?

平时我们安装一个CentOS至少都有几个GB,怎么可能才200MB!

相信这是几乎所有 Docker 初学者都会有的疑问,包括我自己。下面我们来解释这个问题。

Linux操作系统由内核空间和用户空间组成,如下图:

1. rootfs

内核空间是kernel,Linux刚启动时会加载bootfs文件系统,之后bootfs会被卸载掉。

用户空间的文件系统是rootfs,包含我们熟悉的 /dev /proc /bin等目录

对于 base镜像 来说,底层直接用 Host 的 kernel,自己只需要提供rootfs就行了。

  • 而对于一个精简的OS,rootfs可以很小,只需要包括最基本的命令、工具和程序库就可以了。相比其他的Linux发行版,CentOS的rootfs已经算臃肿的了,alpine还不到10MB
  • 我们平时还会安装的CentOS除了rootfs之外,还会选装很多软件、服务、图形桌面等等,需要好几个GB就不足为奇了。

2. base镜像提供的是最小安装的Linux发行版

CentOS镜像的Dockerfile的内容如下图所示:

第二行ADD指令添加到镜像的 tar 包就是 CentOS 7 的rootfs,在制作镜像时,这个tar包会自动解压到 / 目录下,生成 /dev、/proc、/bin等目录。

支持运行多种LinuxOS

不同Linux发行版的区别主要就是rootfs,所以Docker可以同时支持多种Linux镜像,模拟出多种操作系统环境。

上图Debian和BusyBox(一种嵌入式Linux)上层提供各自的rootfs,底层共用Docker Host的kernel

2. 镜像的分层结构

Docker支持通过扩展现有镜像,创建新的镜像。

实际上,Docker Hub中99%的镜像都是通过在base镜像中安装和配置需要的软件构建出来的。比如我们构建一个新的镜像,Dockerfile 如下图所示:

(1)新镜像不再是从scratch开始,而是直接在Debian base镜像上创建

(2)安装 emacs 编辑器

(3)安装 Apache2

(4)容器启动时运行 bash

构建过程中如下图:

可以看到,新镜像是从base镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层。

为什么Docker镜像要采用这种分层结构呢?

最大的一个好处就是:共享资源。

3. 构建镜像

对于Docker用户来说,最好的情况是不需要自己创建镜像。几乎所有常用的数据库、中间件、应用软件等都有现成Docker官方镜像或其他人和组织创建的镜像,我们只需要稍作配置就可以直接使用。

使用现成镜像的好处除了省去自己做镜像的工作量外,更重要的是可以利用前人的经验。特别是使用官方的镜像,因为Docker工程师更知道如何更好地在容器中运行软件。

当然,某些情况下我们也不得不自己构建镜像,比如:

(1)找不到现成的镜像,比如自己开发的应用程序。

(2)需要在镜像中加入特定的功能,比如官方镜像几乎都不提供ssh

所以本节我们将介绍构建镜像的方法。同时分析构建的过程也能够加深我们对前面镜像分层结构的理解。

Docker提供了两种构建镜像的方法:docker commit命令与Dockerfile构建文件。

docker commit

docker commit 命令是创建新镜像最直观的方法,其过程包含三个步骤:

  • 运行容器
  • 修改容器
  • 将容器保存为新的镜像

举个例子:在Ubuntu base镜像中安装vi并保存为新镜像。

(1)运行容器

如图所示:

-it的作用是以交互模式进入容器,并打开终端。

(2)安装vi

确认vi没有安装,如下图所示:

安装vi,如下图所示:

(3)保存为新镜像

在新窗口中查看当前运行的容器,如图所示:

silly_goldberg是Docker为我们容器随机分配的名字。

执行 docker commit 命令将容器保存为镜像,如图所示:

新镜像命名为ubuntu-with-vi

查看新镜像的属性,如图所示:

从size上看到镜像因为安装了软件而变大了。

从新镜像启动容器,验证 vi 已经可以使用,如图所示:

以上演示了如何用 docker commit创建新镜像。然而,Docker并不建议用户通过这种方式构建镜像。原因如下:

(1)这是一种手动创建镜像的方式,容易出错,效率低且可重复性若。比如要在 debian base镜像中也加入vi,还得重复前面所有的步骤。

(2)更重要的:使用者并不知道镜像是如何创建出来的,里面是否有恶意程序。也就是说无法对镜像进行审计,存在安全隐患。

既然 docker commit不是推荐的方法,我们为什么还要花时间学习呢?原因是,即便是用Dockerfile(推荐方法)构建镜像,底层也是docker commit一层一层构建新镜像的。学习docker commit 能够帮助我们更加深入地理解构建过程和镜像的分层结构。

Dockerfile

Dockerfile是一个文本文件,记录了镜像够简单的所有步骤。

1. 第一个Dockerfile

用 Dockerfile 创建上节的 ubuntu-with-vi,其内容如图所示:

下面我们运行 docker build 命令构建镜像并详细分析每个细节。

bash 复制代码
root@ubuntu:~# pwd ①
    /root
    root@ubuntu:~# ls ②
    Dockerfile
    root@ubuntu:~# docker build -t ubuntu-with-vi-dockerfile . ③
    Sending build context to Docker daemon 32.26 kB ④
    Step 1 : FROM ubuntu ⑤
    ---> f753707788c5
    Step 2 : RUN apt-get update && apt-get install -y vim ⑥
    ---> Running in 9f4d4166f7e3 ⑦
    ......
    Setting up vim (2:7.4.1689-3ubuntu1.1) ...
    ---> 35ca89798937 ⑧
    Removing intermediate container 9f4d4166f7e3 ⑨
    Successfully built 35ca89798937 ⑩
    root@ubuntu:~#

① 当前目录为 /root。

② Dockerfile准备就绪。

③ 运行docker build命令,-t将新镜像命名为ubuntu-with-vi-dockerfile,命令末尾的.指明build context为当前目录。Docker默认会从build context中查找Dockerfile文件,我们也可以通过-f参数指定Dockerfile的位置。

④ 从这步开始就是镜像真正的构建过程。

首先Docker将build context中的所有文件发送给Docker daemon。build context为镜像构建提供所需要的文件或目录。 Dockerfile中的ADD、COPY等命令可以将build context中的文件添加到镜像。此例中,build context为当前目录 /root,该目录下的所有文件和子目录都会被发送给Docker daemon。 所以,使用build context就得小心了,不要将多余文件放到build context,特别不要把 /、/usr作为build context,否则构建过程会相当缓慢甚至失败。

⑤ Step 1:执行FROM,将Ubuntu作为base镜像。 Ubuntu镜像ID为f753707788c5。

⑥ Step 2:执行RUN,安装vim,具体步骤为 ⑦ ⑧ ⑨。

⑦ 启动ID为9f4d4166f7e3的临时容器,在容器中通过apt-get安装vim。

⑧ 安装成功后,将容器保存为镜像,其ID为35ca89798937。 这一步底层使用的是类似docker commit的命令。

⑨ 删除临时容器9f4d4166f7e3。

⑩ 镜像构建成功。

通过docker images查看镜像信息,如图3-21所示。 [插图] 图3-21 镜像ID为35ca89798937,与构建时的输出一致。 在上面的构建过程中,我们要特别注意指令RUN的执行过程 ⑦ ⑧ ⑨。Docker会在启动的临时容器中执行操作,并通过commit保存为新的镜像。

2. 查看镜像的分层结构

ubuntu-with-vi-dockerfile 是通过在base镜像的顶部增加一个新的镜像层而得到的,如图所示:

这个新镜像层的内容由 RUN apt-get update && apt-get in stall -y vim 生成。这一点我们可以通过docker history命令验证,如图所示:

docker history会显示镜像的构建历史,也就是Dockerfile的执行过程。

ubuntu-with-vi-dockerfile 与 Ubuntu 镜像相比,确实只是多了顶部的一层35ca89798937,由apt-get命令创建,大小为97.07MB。docker history向我们展示了镜像的分层结构,每一层由上至下排列。

注:missing表示无法获取IM-AGE ID,通常从 Docker Hub 下载的镜像会有这个问题。

3. 镜像的缓存特征

我们接下来看Docker镜像的缓存特征。

Docker会缓存已有镜像的镜像层,构建新镜像时,如果某镜像直接存在,就直接使用,无需重新创建。

例如,如果在Dockerfile中添加一点新内容,往镜像中复制一个文件:

(1)确保 testfile 已存在

(2)由于之前已经运行过相同的 RUN 命令,这次直接使用缓存中的镜像层 35ca89798937

(3)执行 COPY 命令

其过程是启动临时容器,复制 testfile,提交新的镜像层 8d02784a78f4,删除临时容器。

在ubuntu-with-vi-dockerfile 镜像上直接添加一层就得到了新的镜像 ubuntu-with-vi-docker-file-2,如图所示:

如果我们希望在构建镜像时不使用缓存,可以在 docker build 命令中加上 no-cache 参数。

Dockerfile每一个指令就会创建一个镜像层,上层是依赖于下层的。无论什么时候,只要某一层发生变化,其上面所有层的缓存都会失效。

也就是说,如果我们改变 Dockerfile 的执行顺序,或者修改或者添加指令,都会使缓存失效。举例说明:

  • 如果交换前面 RUN 和 COPY 的顺序,如图所示:
  • 虽然在逻辑上这种改动对镜像的内容没有影响,但由于分层的结构特征,Docker必须重建受影响的镜像层。
  • 从执行过程可以看到,生成了新的镜像层,缓存已经失效。

除了构建时使用缓存,Docker在下载镜像时也会使用。

4. 调试Dockerfile

总结一下通过 Dockerfile 构建镜像的过程:

(1)从base镜像运行一个容器

(2)执行一条指令,对容器做修改

(3)执行类似docker commit的操作,生成一个新的镜像

(4)Docker再基于刚刚提交的镜像运行一个新容器

(5)重复2~~4步,直到Dockerfile中的所有指令执行完毕

5. Dockerfile 常用指令

是时候系统学习Dockerfile了

  • FROM:指定base镜像

  • MAINTAINER:设置镜像作者,可以是任意字符串

  • COPY:

    • 将文件从build context复制到镜像
    • COPY支持两种形式:COPY src dest 与 COPY ["src", "dest"]
    • 注意,src只能指定 build context 中的文件或目录
  • ADD:

    • 与COPY类似,从 build context 复制文件到镜像。不同的是,如果 src 是归档文件(tar、zip、tgz、xz等),文件会被自动解压到dest
  • ENV:

    • 设置环境变量,环境变量可以被后面的指令使用。例如:
    • ENV MY_VERSION 1.3 RUN apt-get install -y mypackage=$MY_VERSION
  • EXPOSE:

    • 指定容器中的进程会监听某一个端口,Docker可以将该端口暴露出来。
  • VOLUMN:

    • 将文件或者目录声明为volume
  • WORKDIR:

    • 为后面的RUN、CMD、ENTRY-POINT、ADD或COPY指令设置镜像中的当前工作目录
  • RUN

    • 在容器中执行指定的命令
  • CMD

    • 容器启动时运行指定的命令

    • Dockerfile可以有多个CMD指令,但只有最后一个生效。CMD可以被 docker run 之后的参数替换。

  • ENTRYPOINT

    • 设置容器启动时运行的命令。

    • Dockerfile中可以有多个ENTRYPOINT指令,但只有最后一个生效。CMD 或 docker run之后的参数会被当做参数传递给 ENRTYPOINT。

这是一个比较全面的Dockerfile(注:Dockerfile支持以 "#" 开头的注释)

构建镜像,如下图:

(1)构建前确保build context中存在需要的文件

(2)依次执行Dockerfile指令,完成构建

(3)运行容器,验证镜像内容,如下图

  1. 进入容器,当前目录即为WORKDIR

如果WORKDIR不存在,Docker会自动帮我们创建

  1. WORKDIR中保存了我们希望的文件和目录

目录bunch:由ADD指令从build context复制的归档文件bunch.tar.gz,已经自动解压。 文件tmpfile1:由RUN指令创建。 文件tmpfile2:由COPY指令从build context复制。

  1. ENV指令定义的环境变量已经生效。
RUN vs CMD vs ENTRYPOINT

RUN、CMD和ENTRYPONIT这三个Dockerfile指令看上去很类似,很容易混淆。

简单地说:

(1)RUN:执行命令并创建新的镜像层,RUN经常用于安装软件包

(2)CMD:设置容器启动后默认执行的命令及其参数,但CMD能够被 docker run 后面接的命令行替换

(3)ENTRYPOINT:配置容器启动时运行的命令

最佳实践:

  1. 使用RUN命令安装应用和软件包,构建镜像

  2. 如果docker镜像的用途是运行应用程序或服务,比如运行一个MySQL,应该使用Exec格式的ENTRYPOINT指令。CMD可为ENTRYPONIT提供额外的默认参数,同时可以利用 docker run 命令行替换默认参数,同时可以利用 docker run 命令行替换默认参数。

  3. 如果想为容器设置默认的启动命令,可使用CMD指令,用户可在 docker run 命令中替换此默认命令。

4. 小结

本章我们学习了Docker镜像。首先讨论了镜像的分层结构,然后学习了如何构建镜像,最后实践使用Docker Hub和本地registry。

下面是镜像的常用操作子命令:

  • images:显示镜像列表。
  • history:显示镜像构建历史。
  • commit:从容器创建新镜像。
  • build:从Dockerfile构建镜像。
  • tag:给镜像打tag。
  • pull:从registry下载镜像。
  • push:将镜像上传到registry。
  • rmi:删除Docker host中的镜像。
  • search:搜索Docker Hub中的镜像。

以上是 docker 技术的基本概念,其余知识明日继续连载

Good night~~

-- 2025年5月2日

相关推荐
你好,帅哥2 小时前
openssl ,msys2 ,交叉编译
linux·运维·服务器
计算机安禾2 小时前
【Linux从入门到精通】第36篇:DNS服务探秘——自己搭建一个内网DNS
linux·运维·servlet
Web极客码3 小时前
2026年Linux VPS安全加固清单:SSH、防火墙与审计就绪配置
运维·服务器·数据库
星恒讯工业路由器4 小时前
配网自动化多网融合应用解决方案
运维·自动化
智慧物业老杨4 小时前
智慧物业收费系统的数智化落地实践:从人工硬扛到自动化闭环
运维·自动化
techdashen4 小时前
Cloudflare 为何抛弃 NGINX,用 Rust 自研了一个代理
运维·nginx·rust
南城猿4 小时前
保姆级 Ubuntu 部署 禅道
linux·运维·ubuntu
珠海西格电力5 小时前
零碳园区产业园管理系统的全场景源网荷储氢协同调度功能是如何实现的
大数据·运维·人工智能·物联网·能源
木雷坞5 小时前
K8s GPU 推理服务 ImagePullBackOff 排查与预热
云原生·容器·kubernetes·gpu算力
wj3055853785 小时前
CC-Switch 在 WSL Ubuntu 中安装记录
linux·运维·ubuntu