Docker
基础知识
什么是Docker ?
Docker是基于Go语言实现的开源应用容器引擎,它可以让开发者打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或Windows 机器上,也可以实现虚拟化。Docker诞生于2013年。Docker的理念是实现应用组件的一次封装,到处运行。这里的应用组件,可以是web应用,可以是数据库服务,甚至是一个操作系统和集群。基于Linux平台上的多项开源技术,Docker提供了高效、敏捷和轻量级的容器方案,并支持部署到本地环境和多种主流云平台。
为什么要使用Docker ?
在云时代,开发者创建的应用必须能够很方便地在网络上传播,也就是说应用必须脱离底层物理硬件的限制,并且必须是任何时间任何地点都可以获取的。因此,开发者们需要一种新型的创建应用、快速分发和部署的方式,而这正是Docker最大的功能和优势。
举个简单的例子,之前开发者想要部署一个java web应用,首先需要安装Mysql、JDK、Tomcat等等应用所依赖的组件,然后进行配置,部署和功能测试,如果应用数目过多,这个过程将会付出很大的时间代价和不可控的风险。
并且当服务器需要迁移时,这个过程将会重复一次。这些繁琐的事情,极大的降低了工作效率。究其原因,是这些应用直接运行在了底层操作系统上,我们无法保证同一份应用在不同环境的行为一致。
而Docker,则使用了一种聪明的方式,通过容器来打包应用,解耦了应用和底层运行平台,这意味着迁移的时候,只需要在新的平台上启动容器即可,而不需要关注我们的应用是否会和平台冲突、会出现一些莫名的问题等等
这无疑帮助我们节约了大量的时间,并且降低了部署过程中出现的问题和风险。
真正实现了一次构建配置,然后可以在任意地方任意时间运行应用。
Docker的优点
- 更快速的交付和部署。使用Docker,开发人员可以使用镜像来快速构建一套标准的开发环境。测试和运维人员可以直接使用完全相同的环境来部署代码。只要是开发测试过的代码,就可以保证在测试生产环境中无缝运行,而不会因为环境变化而出现其他错误。
- 高效的资源利用。运行Docker容器不需要额外的虚拟化管理程序(比如VMware、Hyper-V等虚拟机管理工具)。Docker是内核级的虚拟化,可以实现更高的性能,并且对资源的额外需求很低,与传统虚拟机对比,性能要提高1-2个数量级。
- 轻松的迁移和扩展。Docker容器几乎可以在任意的平台上运行。物理机、虚拟机、公有云、私有云、个人电脑等等。
- …
Docker和虚拟机比较
- Docker容器很快,启动和停止可以在秒级实现。比传统的虚拟机(数分钟)要快得多.
- Docker容器对系统资源需求很少,一台主机上可以同时运行数千个Docker容器
- Docker通过类似Git设计理念的操作来方便用户获取、分发、更新镜像
- Docker通过Dockerfile支持灵活的自动化创建和部署机制,提高工作效率,标准化流程
- Docker除了运行其中的应用外,基本不消耗额外的系统资源,在保证应用性能同时尽量减少系统开销。传统虚拟机运行N个不同的应用就要启用N个虚拟机,需要分配单独的内存、磁盘等资源。Docker只需要启动N个容器,将应用放入容器即可,获得的是接近原生的运行性能。
Docker的核心概念
Docker镜像: Docker镜像类似于虚拟机镜像,为一个只读的模板。例如一个镜像可以包含一个基本的操作系统环境,里面仅安装了Apeche。就可以把他称为一个Apache镜像。镜像是创建Docker容器的基础。通过版本管理和增量的文件系统,Docker提供了一套十分简单的机制来创建和更新现有的镜像。
Docker容器: Docker容器类似于一个轻量级的沙箱,Docker利用容器来运行和隔离应用。容器是根据镜像创建的应用运行实例。镜像相当于是类,容器就是对象。它可以启动、开始、停止、删除,容器之间都是彼此隔离,互不可见的。可以把容器看作一个简易的linux系统以及运行在其中的应用打包而成的盒子。镜像自身是只读的。容器从镜像启动的时候,会在镜像最上层创建一个可写层。
Docker仓库: Docker仓库类似于代码仓库,是Docker集中存放镜像文件的场所。Docker仓库分为公开仓库和私有仓库两种形式。目前最大的公开仓库是官方提供的Docker Hub,其中存放着数量庞大的镜像供用户下载。国内如阿里云、腾讯云等也提供了仓库的本地源。Docker支持用户在本地网络创建只能自己访问的私有仓库。Docker利用仓库管理镜像的设计理念借鉴了Git
Docker镜像
Docker运行容器前需要本地存在对应的镜像。如果镜像不存在,Docker会尝试从默认镜像仓库下载。
- 获取镜像命令
docker [image] pull [OPTIONS] NAME[:TAG|@DIGEST]
option为指定一些操作,例如-a为下载所有带有该标签的镜像等等。
NAME是镜像仓库名称,TAG是镜像的标签,表示不同版本。
通常情况下,描述一个镜像需要包括"名称+标签"的信息。
如:docker pull ubantu:18.04 获取一个ubuntu 18.04版本的系统镜像
如果不显式指定TAG,则默认会选择latest标签,会下载仓库中最新版本的镜像。
我们下载mysql镜像时候发现有好多字符串分别在下载,这是什么呢?
镜像文件一般由若干层(layer)组成。5cb67864e624这样的字符串是层的唯一id。
使用docker pull命令下载中会获取并输出镜像的各层信息。
当不同的镜像包括相同的层时,本地仅存储一份层的内容,减小了存储空间。
- 列出本机所有镜像命令
docker images 或 docker image ls.
在列出的信息中,可以看到该镜像来自于哪个仓库,镜像的标签,镜像的ID(镜像唯一标识)
创建时间、镜像大小等。
如果两个镜像ID相同,他们实际上指向了同一个镜像,只是标签名称不同。
- 为镜像创建副本,添加自己的标签
docker tag 镜像名称:镜像标签 新镜像名称:新镜像标签
为了方便我们在工作中标记一些镜像供我们快速找到使用。
我们可以使用docker tag命令来为本地镜像添加标签。
我们创建了一个mysql的副本,并添加了自己的标签。
用docker images再次列出本地镜像信息,可以看到多了一个镜像,但是id和复制的一致
说明他们实际上指向一个镜像文件。
docker tag命令相当于是一个软链接的作用。
- 查看镜像详细信息
docker [image] inspect IMAGE
该命令可以获取该镜像的详细信息,包括制作者、适应架构等等。
- 搜寻镜像
docker search [OPTIONS] keyword
option参数
--filter , -f:添加过滤条件
--format::格式化输出内容
--limit:限制输出结果个数,默认25个
--no-trunc:不截断输出结果
搜索官方提供的nginx镜像
搜索收藏数超过4的mysql镜像
- 删除和清理镜像
使用docker rmi或docker image rm命令可以删除镜像
docker rmi [OPTIONS] IMAGE [IMAGE...]
image可以为标签或者id.
-f,-force:强制删除镜像,即使有容器依赖它
-no-prune:不要清理未带标签的父镜像.
例如删除我们的mysql,docker rmi mysql:myself
再次images查看,我们发现,当同一个镜像有多个标签时,rmi只是删除了该镜像的
指定标签而已,并不影响镜像文件.但是当镜像只剩下一个标签时,就会彻底删除镜像.
当我们使用id来删除镜像时,会删除所有指向该镜像的标签,然后删除镜像文件本身.
使用docker一段时间后,系统中可能会遗留一些临时的镜像文件
以及一些没有被使用的镜像.
可以通过docker image prune来进行清理.
docker image prune [OPTIONS]
options
-a,-all:删除所有无用镜像,不光是临时镜像
-filter:清理符合过滤条件的镜像
-f:强制删除镜像
- 创建镜像
创建镜像的方法主要有三种:
(1)基于已有镜像的容器创建
docker [container] commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
options:
-a,--author="":作者信息
-c,--change=[]:提交的时候执行Dockerfile指令
-m,--message="":提交信息
-p,--pause=true:提交时暂停容器运行
接下来演示一下,首先我们先启动一个ubantu容器,然后在容器中创建一个test文件.此时该容器与原镜像相比,已经发生了改变.我们的容器id是2c4717e97e2b。然后我们创建新镜像
(2)基于本地模板导入
不常用,可以自行了解
(3)基于Dockerfile创建.
这是最常见的形式.Dockerfile是一个文本文件,利用给定的指令描述基于某个父镜像创建新镜像的过程.后面会单独章节讲解.
其他的还有导出导入镜像,上传镜像等等都可以自行看官方文档,就不一一举例。
Docker容器
容器是镜像的一个运行实例.
- 创建容器
docker [container] create [OPTIONS] IMAGE [COMMAND] [ARG...]
该命令可以根据镜像新建一个容器。
使用该命令新建的容器处于停止状态,可以使用docker start启动。
由于容器是整个Docker技术的核心。
create和后续的run命令支持的OPTIONS都非常多,这里就不一一列举。
我们看到当我们启动容器时,如果本地没对应的镜像,会先去进行下载
- 启动容器
docker [container] start [OPTIONS] CONTAINER [CONTAINER...]
- 查看容器
docker ps [OPTIONS]
-a:查看所有容器,包括未运行的,默认不加参数只查看运行中的容器
- 新建并启动容器
docker container run [OPTIONS] IMAGE [COMMAND] [ARG...]
该命令包含的操作包括
-检查本地是否存在指定镜像,不存在从共有仓库下载
-利用镜像创建容器,启动该容器
-分配一个文件系统给容器,在只读的镜像层外面挂载一层可读写层
-从宿主机配置的网桥接口中桥接一个虚拟接口到容器中去
-从网桥的地址池配置一个ip给容器
-执行用户指定的应用程序
-执行完毕后容器被自动终止
这样可以与容器交互。
docker run -it 镜像 /bin/bash
-t选项让docker分配一个伪终端并绑定到容器的标准输入上,
-i则让容器的标准输入保持打开。
用户可以输入exit或者ctrl+D退出容器。
很多时候,需要让Docker容器在后台以守护态形式运行。
可以通过添加参数-d来实现。
我们在容器中执行exit退出bash进程时,容器也会自动结束。因为容器中的应用退出后,容器使命完成,也就没有存在的必要了。
- 停止容器
docker container pause CONTAINER [CONTAINER...]
- 恢复容器
docker container unpause CONTAINER [CONTAINER...]
- 终止容器
docker container stop [OPTIONS] CONTAINER [CONTAINER...]
options
--time , -t:等待时间,默认10s
该命令会首先向容器发送SIGTERM信号,等待一段超时时间后,再发送SIGKILL信号来终止容器。
执行docker container prune命令时,会自动清除掉所有处于停止状态的容器。
还可以通过docker [container] kill [OPTIONS] CONTAINER [CONTAINER...]
命令直接发送SIGKILL信号来强行终止容器。
当Docker容器中指定的应用终结时,容器也会自动停止。
处于终止状态的容器,可以通过docker start来重新启动。
- 进入容器
使用-d参数可以使我们的容器后台运行,在我们的容器在后台运行时,用户无法看到容器中的信息,也无法操作。这时候可以使用命令进入容器进行操作。
docker container attach [OPTIONS] CONTAINER
options
--detach-keys=[]:指定退出attach模式的快捷键。默认是ctrl+p ctrl+q
--no-stdin=true|false:是否关闭标准输入,默认是保持打开
--sig-proxy=true|false:是否代理收到的系统信号给应用进程,默认为true
使用attach命令有时候并不方便。当多个窗口同时attach到同一容器时
所有窗口都会同步显示;当某个窗口因命令阻塞时,其他窗口也无法执行操作了。所以docker提供了一个更为方便的命令exec
docker container exec [OPTIONS] CONTAINER COMMAND [ARG...]
options
- d, --detach 在容器中后台执行命令;
--detach-keys ="":指定将容器切回后台的按键;
- e, --env=[]:指定环境变量列表
-i, --interactive=true|false :打开标准输入接受用户输入命令, 默认值为false;
--privileged=true|false 是否给执行命令以高权限,默认值为 false;
-t, --tty=true|false 分配伪终端,默认值为 false;
-u, --user ="":执行命令的用户名或 ID
- 删除容器
docker [container] rm [OPTIONS] CONTAINER [CONTAINER...]
该命令用来删除处于终止或退出状态的容器。
options
--force , -f: 强制删除正在运行中的容器(使用SIGKILL信号)
--link , -l:删除容器的链接,但保留容器
--volumes , -v:删除容器挂载的数据卷
默认情况下, docker rm 命令只能删除已经处于终止或退出状态的容器,并不能删除还处于运行状态的容器。如果要直接删除运行中的容器,可以添加 -f参数。Docker 会先发送 SIGKILL信号给容器,终止其中的应用,之后强行删除。
- 导入和导出容器
导出容器是指,导出一个已经创建的容器到一个文件。不管此时这个容器是否处于运行状态。
docker [container] export [OPTIONS] CONTAINER
options
--output , -o:指定导出的tar文件名
之后,可将导出的 tar 文件传输到其他机器上,然后再通过导入命令导入到系统中,实现容器的迁移
导入容器
docker import [OPTIONS] file|URL|-- [REPOSITORY[:TAG]]
- 在容器和主机之间复制文件
docker [container] cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH
options
--archive , -a:打包模式,复制文件会带有原始的uid/gid信息
--follow-link , -L:当源路径为软连接时,默认只复制链接信息。
使用该选项会复制链接的目标内容
本地/opt目录下创建一个文件,然后复制到容器内。
Docker数据管理
使用Docker过程中,往往需要对数据进行持久化。或者需要在多个容器之间进行数据共享,这必然涉及容器的数据管理操作。容器中的管理数据主要有两种方式
- 数据卷:容器内数据直接映射到本地主机环境
- 数据卷容器:使用特定容器维护数据卷
数据卷
数据卷是一个可供容器使用的特殊目录,它将主机操作系统目录直接映射进容器。
数据卷有很多有用的特性
- 数据卷可以在容器之间共享和重用,容器间传递数据变得高效与方便
- 对数据卷内数据的修改会立马生效,无论是容器内操作还是本地操作
- 对数据卷的更新不会影响镜像,解耦开应用和数据
- 卷会一直存在,直到没有容器使用,可以安全地卸载它
创建数据卷
docker volume create [OPTIONS] [VOLUME]
绑定数据卷
除了使用volume来管理数据卷外。我们还可以在创建容器时将主机本地的任意路径挂载到容器内作为数据卷。
在使用docker run命令时,可以使用-mount选项来使用数据卷
-mount支持三种类型的数据卷
- volume:映射到主机/var/lib/docker/volumes路径下
- bind:绑定数据卷,映射到主机指定路径下
- tmpfs:临时数据卷,只存在于内存中
请看下面的例子。本地目录的路径必须为绝对路径,容器内可以为相对路径,如果路径不存在,容器会自动创建。Docker挂载数据卷默认权限为读写,可以通过指定参数改为只读。
数据卷容器
如果用户需要在多个容器之间共享一些持续更新的数据,最简单的方式是使用数据卷容器。数据卷容器也是一个容器,但是它的目的是专门提供数据卷给其他容器挂载。
(1)首先我们创建一个数据卷容器
(2)然后我们创建两个容器挂载到同一个数据卷容器
(3)接下来三个容器任一在该目录的写入,其他容器都能看到
可以多次使用–volumes-from参数来从多个容器挂载多个数据卷,还可以从其他已经挂载了容器卷的容器来挂载数据卷。
如果删除了挂载的容器(dbtest、test1、test2),数据卷并不会自动被删除。如果要删除数据卷,必须在删除最后一个还挂载着它的容器时显式使用docker rm -v命令来指定同时删除关联的数据卷。
有些时候不希望将数据保存在宿主机或容器中,还可以使用 tmpfs 类型的数据
卷,其中数据只存在于内存中,容器退出后自动删除。
端口映射
在我们日常开发中,经常需要多个服务组件容器共同协作的情况,这往往需要多个容器之间能够互相访问到对方的服务。
- Docker允许映射容器内应用的服务端口到本地宿主机
端口映射实现容器访问
在启动容器的时候,如果不指定对应参数,在容器外部是无法通过网络来访问容器内的网络应用和服务的。当容器中运行一些网络应用,要让外部访问这些应用时,可以通过-p或-P参数来指定端口映射。当使用-P参数时,Docker会随机映射一个49000-49900的端口到内部容器开放的网络端口。
运行容器
docker run -itd -P -e MYSQL_ROOT_PASSWORD=123456 mysql
-e为指定mysql默认密码
我们可以看到随机分配了一个49162端口映射到了容器mysql的3306端口,只要开启mysql访问权限等,就可以在外部访问到。
-p可以指定要映射的端口
#将本地的5000端口映射到容器的5000端口
docker run -d -p 5000:5000 mysql
#将指定地址的端口映射到容器的端口
docker run -d -p 127.0.0.1:5000:5000 mysql
#绑定指定地址的任意端口到容器5000端口,本地主机会自动分配端口
docker run -d -p 127.0.0.1::5000 mysql
Dockerfile
Dockerfile是一个文本格式的配置文件,用户可以使用Dockerfile来快速创建自定义的镜像。
基本结构
Dockerfile由一行行命令语句组成,并且支持以#开头的注释行。一般而言,Dockerfile主题内容分为四部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令。我们可以到DockerHub上找一些Dockerfile先大致熟悉一下结构。我们给出一个简单的例子
# 添加注释
FROM ubantu:18.04
LABEL maintainer docker_user<test@email.com>
RUN apt-get update && apt-get install -y nginx
RUN echo "\ndaernon off;" >> /etc/nginx/nginx.conf
# Commands when crea七ing a new container
CMD /usr/sbin/nginx
如上所示,首先需要使用FROM指令来指定一个基础镜像名称,一般使用LABEL指令来说明维护者信息。后面则是镜像操作指令,例如RUN指令将对镜像执行跟随的命令。 每运行一条RUN指令,镜像添加新的一层, 并提交。 最后是CMD指令, 来指定运行容器时的操作命令。
指令说明
- ARG
定义创建镜像过程中使用的变量。格式为
ARG name[=<default value>]
在执行docker build时,可以通过-build-arg来为变量赋值。
当镜像编译成功后,ARG指令的变量将不再存在。
Docker内置了一些镜像创建变量,用户可以直接使用而无需声明
例如HTTP_PROXY、HTTPS_PROXY等。
- FROM
指定所创建镜像的基础镜像,格式
FROM image:tag [AS name]
任何Dockerfile中第一条指令必须为FROM指令。
如果在一个Dockerfile中创建多个镜像,可以使用多个FROM。
- LABEL
LABEL指令可以为生成的镜像添加元数据标签信息。这些信息可以用来辅助过滤出特定镜像。
格式
LABEL <key>=<value>,<key>=<value>....
- EXPOSE
声明镜像内服务监听的端口,格式
EXPOSE <port>
该指令只是声明作用,并不会自动完成端口映射。
- ENV
指令环境变量,在镜像生成过程中会被后续RUN指令使用,在镜像启动的容器中也会存在。
格式
ENV <key> <value>或ENV <key>=<value>
指令指定的环境变量在运行时可以被覆盖掉
如 docker run --env <key>=<value> built_image。
注意当一条 ENV 指令中同时为多个环境变量赋值并且值也是从环境变量读取时, 会为
变量都赋值后再更新。
如下面的指令, 最终结果为 keyl=valuel key2=value2:
ENV keyl;value2
ENV keyl;valuel key2;${keyl)
- ENTRYPOINT
指定镜像的默认入口命令,该入口命令会在启动容器时作为根命令执行。
所有传入值作为该命令的参数。
支持两种格式:
(1)ENTRYPOINT ["executable", "paraml ", "param2"]: exec 调用执行;
(2) ENTRYPOINT command param 1 param2: shell 中执行。
此时, CMD指令指定值将作为根命令的参数。
每个 Dockerfile 中只能有一个 ENTRYPOINT, 当指定多个时, 只有最后一个起效。
在运行时, 可以被 --entrypoint 参数覆盖掉, 如 docker run --entrypoint。
- VOLUME
创建一个数据卷挂载点,格式
VOLUNE ["/data"]
运行容器时可以从本地主机或者其他容器挂载数据卷
- USER
指定运行容器时的用户名或UID,后续的RUN等指令也会使用指定的用户身份
- WORKDIR
为后续的RUN、CMD、ENTRYPOINT指令配置工作目录,格式
WORKDIR /path
- ONBUILD
指定当基于所生成镜像创建子镜像时,自动执行的操作指令。格式
ONBUILD [INSTRUCTION]
例如,使用如下的 Dockerfile 创建父镜像 ParentImag ,指定 ONBUILD
# Dockerfile for Parentimage
...
ONBUILD ADD . / app/src
ONBUILD RUN /usr / local/bin/python build --dir / app/src
...
使用 docker build 命令创建子镜像 ChildImage 时( FROM Parentimage ),会首
先执行 ParentImage 配置的 ONBUILD指令。
由于 ONBUILD 指令是隐式执行的,推荐在使用它的镜像标签中进行标注
例如 ruby:2.l-build
ONBUILD 指令在创建专门用于自动编译、检查等操作的基础镜像时,十分有用
- RUN
运行指定命令。格式
RUN <command> 或 RUN ["executable","param1","param2"]
后者指令会被解析成json数组,因此必须使用双引号。
前者默认在shell终端中运行命令,即/bin/sh.
后者不启动shell,使用exec执行。
指定使用其他终端类型可以通过第二种方式实现,例如 RUN ["/bin/bash" , "-C", "echo hello"]
每条 RUN 指令将在当前镜像基础上执行指定命令,并提交为新的镜像层 当命令较长时
可以使用\来换行 例如:
RUN apt-get update \
&& apt-get install -y libsnappy-dev zliblg-dev libbz2-dev \
&& rm -rf /var/cache/apt \
&& rm rf /var/lib/apt/lists/*
- CMD
用来指定启动容器时默认执行的命令。
支持三种格式:
(1)CMD ["executable","param1","param2"]:相当于执行 executable param 1
param2 ,推荐方式;
(2)CMD command param1 param2 :在默认的 Shell 中执行,提供给需要交互的应用;
(3)CMD ["param1","param2"] :提供给 ENTRYPOINT 的默认参数
每个 Dockerfile 只能有一条CMD 命令。如果指定了多条命令,只有最后一条会被执行。
如果用户启动容器时候手动指定了运行的命令(作为run命令的参数),则会覆盖掉
CMD 指定的命令
- ADD
添加内容到镜像。格式
ADD <src> <dest>
该命令将复制指定的<src>路径下内容到容器中的<dest>路径下。
其中<src>可以是Dockerfile所在目录的一个相对路径,也可以是一个url,还可以是一个tar 文件(自动解压为目录)。
<dest>可以是镜像内绝对路径,或者相对于工作目录(WORKDIR )的相对路径.
路径支持正则格式,例如:
ADD *.c /code/
- COPY
复制内容到镜像
格式为 COPY <src> <dest>
复制本地主机的<src> (为 Dockerfile 所在目录的相对路径,文件或目录)下内容到镜
像中的<dest>。目标路径不存在时,会自动创建.
路径同样支持正则格式
COPY与ADD 指令功能类似,当使用本地目录为源目录时,推荐使用 COPY
创建镜像
编写完成Dockerfile之后,可以通过docker [image] build去创建镜像
docker [image] build [OPTIONS] PATH|URL -
该命令将读取指定路径下的Dockerfile
并将该路径下所有数据作为上下文发送给Docker服务端。
Docker服务端在校验Dockerfile格式通过后,逐条执行其中定义的指令
碰到ADD、COPY和RUN指令会生成一层新的镜像。
最终如果创建镜像成功,会返回最终镜像的ID。
如果上下文过大,会导致发送大量数据给服务端,延缓创建过程。
因此除非是生成镜像所必需的文件,不然不要放到上下文路径 。
如果使用非上下文路径下的 Dockerfile,可以通过-f选项来指定其路径.
要指定生成镜像的标签信息,可以通过-t选项 该选项可以重复使用多次为镜像一次添
加多个名称.
例如,上下文路径为/tmp/docker_builder/,并且希望生成镜像标签为 builder/first image: 1.0.0,
可以使用下面的命令
$ docker build -t builder/first_image :1.0.0 /tmp/docker_builder/
选择父镜像
大部分情况下,生成新的镜像都需要通过FROM指令来指定父镜像。父镜像是生成镜像的基础,会直接影响到所生成镜像的大小和功能。
用户可以选择两种镜像作为父镜像,一种是所谓的基础镜像(baseimage ),另外一种是普通的镜像(往往由第三方创建,基于基础镜像。
基础镜像比较特殊,其Dockerfile中往往不存在FROM指令,或者基于 scratch 镜像
(FROM scratch),这意味着其在整个镜像树中处于根的位置.
下面的Dockerfile定义了个简单的基础镜像,将用户提前编译好的二进制执行文
binary复制到镜像中,运行容器时执行 binary 命令:
FROM scratch
ADD binary /
CMD ["binary"]
普通镜像也可以作为父镜像来使用,包括常见的 debian ubuntu等。
本文参考书籍《Docker技术入门与实战》