玩转Docker(一):基本概念
容器技术是继大数据和云计算之后又一炙手可热的技术,而且未来相当一段时间内都会非常流行。
本文将对其基本概念和基本使用做出介绍。包括容器生态系统、容器的原理、怎样运行第一个容器、容器技术的概念与实践、Docker镜像等等
目录
一. 鸟瞰容器生态系统
1. 容器生态系统包含哪些不同层次的技术?
2. 先了解下Docker
3. 容器、镜像、镜像仓库
4. Docker容器与虚拟机技术的区别和联系
二. 运行第一个容器
三. 容器技术
1. What - 什么是容器?
2. Why - 为什么需要容器?
3. How - 容器是如何工作的
Docker架构
Docker服务器:Docker Daemon
Docker客户端:Docker CLI
Docker镜像:Image
Docker容器:Container
Registry:存放Docker镜像的仓库
4. 小结
四. Docker镜像
1. 镜像的内部结构
hello-world -- 最小的镜像
base镜像
支持运行多种LinuxOS
2. 镜像的分层结构
3. 构建镜像
docker commit
Dockerfile
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的服务在国外,下载镜像比较慢,最好配置成为免费的国内镜像服务。
环境就绪,马上运行第一个容器,执行命令:
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 run
、docker build
、docker 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镜像包含哪些内容。
下载镜像:
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 命令构建镜像并详细分析每个细节。
root@ubuntu:~# pwd ①/rootroot@ubuntu:~# ls ②Dockerfileroot@ubuntu:~# docker build -t ubuntu-with-vi-dockerfile . ③Sending build context to Docker daemon 32.26 kB ④Step 1 : FROM ubuntu ⑤---> f753707788c5Step 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会自动帮我们创建
2. WORKDIR中保存了我们希望的文件和目录
目录bunch:由ADD指令从build context复制的归档文件bunch.tar.gz,已经自动解压。 文件tmpfile1:由RUN指令创建。 文件tmpfile2:由COPY指令从build context复制。
3. 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日