Docker 教程(一):Docker 是什么
本文源自并发编程网的翻译邀请,翻译的是 Jakob Jenkov 的 《Docker 教程》 中的第一篇,本文大概介绍了 Docker 是什么和有什么用。可能在工作中,会有专业运维同学管理服务器镜像或其他内容,但是如果不了解这些概念,很多时候我们不会全面了解到系统的全貌。
Docker 是一种将应用程序和服务器配置打包成 Docker 镜像的方法,使用了一种称为 Dockerfile 的简单打包规范。Docker 镜像可以启动多个多个实例,这些运行的实例被称为 Docker 容器。这个系列的内容主要包括讲解什么是 Docker 镜像、什么是容器、什么是 Dockerfile,以及如何创建、运行和发布等。
Docker 的优势
使用 Dockerfile 打包应用和服务器配置最大的好处是:
不会忘记服务器是如何配置的,这些配置信息都记录在 Dockerfile 中。
很容易在一个全新啊的 Docker 主机上运行应用程序,只需要将应用程序的 Docker 镜像部署到这台 Docker 主机上,然后启动它即可。
可以使用 Kubernetes 和 Swarm 轻松管理集群中的 Docker 容器。
目前许多云服务器平台可以很轻松的部署 Docker 容器,Docker 已经成为让云更加独立的部署方案。
Docker 容器可以很简单的实现在客户自己的服务器上按照你的应用程序。
什么是 Docker 容器
Linux 操作系统有几个特性:运行在操作系统上运行容器化的应用程序,这些容器化的特性,运行将文件系统和网络在各个容器化应用程序之间彼此分离。换句话说,一个容器化应用程序,不能访问另一个容器化应用程序的文件系统或网络,除非增加特殊配置,允许这种操作。Docker 使用 Linux 的容器化特性,并通过一组易于使用的工具公开这些特性。
Docker 容器 vs. 虚拟机
Docker 容器在本质上类似于虚拟机,两者的不同之处在于,虚拟机在总栈上有一个额外的操作系统。也就是说,虚拟机有完整的操作系统,然后这个虚拟机运行在一个有操作系统的主机上。
Docker 容器与虚拟机的实现不同,它没有自己单独的操作系统,直接运行在所在主机的操作系统中。所以,Docker 容器足够小,因为它不包含虚拟机操作系统。Docker 容器运行的也很好,因为它不需要虚拟机的虚拟化。
Dockerfile
如前所述,我们可以通过一个按规则定义的 Dockerfile 文件,指定要包含在 Docker 容器中的内容。Dockerfile 文件包含了一组有 Docker 命令行工具执行的 Docker 指令,按照 Dockerfile 执行的结果是 Docker 镜像。我们可以从 Dockerfile 教程 中得到更详细的解释。【译者注:后续翻译完成后,将替换此处链接。】
Docker 镜像
Docker 命令行工具按照 Dockerfile 中定义的结构执行指令时,会生产一个可移植、可运行的 Docker 镜像。这个 Docker 镜像中包含了所有 Docker 容器需要的文件和指令,同一个 Docker 镜像可以启动多个 Docker 容器。
Docker 仓库
Docker 镜像可以存储在 Docker 仓库中,一个可以将 Docker 镜像上传、下载的存储仓库。Docker 仓库可以是私有的,只能你或者你的组织或者你指定的人管理其中的镜像,也可以是公有的,任何人都可以管理其中的镜像,或者是从中下载 Docker 镜像。
一个公有的 Docker 仓库,是运行潜在用户下载、安装和运行软件的很好的方式,只需要将应用程序打包为 Docker 镜像,上传到公有的 Docker 仓库中,你的用户就可以访问并使用它。
Docker 公司已将 Docker 仓库作为一项托管服务,提供了私有和公有两种服务。一些云服务商,比如 AWS、AZure 和 Google,也提供了 Docker 仓库服务器,可以上传自己的 Docker 镜像。很容易的就能在云基础设施上的虚拟机或 Kubernetes 中使用这些镜像。
Docker 命令行工具
当在操作系统中安装 Docker 的时候,会同时安装 Docker 命令行工具。Docker 命令行工具可以通过 Dockerfile 构建 Docker 镜像,可以将 Docker 镜像上传到 Docker 仓库中,可以从 Docker 仓库中下载 Docker 镜像,可以操作 Docker 镜像启动或停止 Docker 容器。
Docker Compose
Docker Compose 提供一种功能,可以将多个 Docker 容器链接成一个组合中,这个组合中的所有容器,可以一次性全部部署或停止。比如,一个 Docker 容器中运行应用,一个 Docker 容器中运行数据库,应用依赖于数据库,同时启动或停止,可以实现应用依赖的数据库没有正常运行。
Docker 教程(二):Dockerfile
Dockerfile包含一组关于如何构建Docker镜像的说明,通过docker build
命令执行Dockerfile文件,可以构建一个Docker镜像,本文介绍了如何编写Dockerfile文件以及构建一个Docker镜像。
Dockerfile的好处
Dockerfile文件以书面形式说明了如何构建一个Docker镜像,Docker镜像通常包含如下内容:
首先需要一个基本的Docker镜像,在这个基础Docker镜像上构建自己的Docker镜像。
一组需要安装在Docker镜像中的工具和应用。
一组需要复制到Docker镜像中的文件(比如配置文件)。
可能需要在防火墙中打开的网络(TPC/UDP)端口或其他。
等等。。。
首先,在Dockerfile文件中以书面形式说明这些,就意味着,我们不用特意记住应用程序如何安装,包括操作系统什么要求、需要安装的应用程序、需要赋值的文件、需要打开的网络端口等,这些内容都被记录在Dockerfile中。
另外,通过Dockerfile文件构建Docker镜像,我们不需要手动执行这些繁琐重复且容易出错的工作。Docker会自动做这些事情,简单、快速、且不容易出错。
第三,我们很容易和其他人分享Dockerfile文件,并且他们可以自己构建Docker镜像。
第四,Dockerfile很容易存储在Git这样的版本控制器中,这样就可以跟踪Dockerfile(服务器、应用配置)的变更记录。版本控制器也可以很容易的让人们协同合作,比如在Dockerfile上,以及分享Dockerfile。
Dockerfile的结构
Dockerfile包含一组指令,每个指令有一个命令和参数组成,类似于命令行可执行文件。下面是一个Dockerfile简单示例:
# 基础镜像 FROM ubuntu:latest
# 这里可以有更多安装软件和复制文件到镜像中的说明。 COPY /myapp/target/myapp.jar /myapp/myapp.jar
# 在Docker容器中执行的命令。 CMD echo Starting Docker Container
Docker基础镜像
Docker镜像是由层组成,每一层都会为最终的Docker镜像添加一些内容。每一个层实际上都是一个单独的Docker镜像,所以说,Docker镜像是由一个或多个层镜像组成,我们可以在其上添加自己的层。
当通过Dockerfile文件指定自己的Docker镜像时,通常是从一个Docker基础镜像开始。这是另一个Docker镜像,可以在其上构建自己的Docker镜像。这个Docker基础镜像本身可能也包含多个层,并且是基于另一个基础镜像构建的。
我们可以使用From
命令在Dockerfile文件中指定Docker镜像作为基础镜像,如下节所述。
MAINTAINER
MAINTAINER
命令用于说明谁在维护这个Dockerfile文件。比如:
MAINTAINER Joe Blocks <joe@blocks.com>
MAINTAINER
命令并不常用,因为这类信息在Git存储或其他地方有了。
FROM
FROM
命令用于指定Docker基础镜像,如果是从原始Linux镜像开始,可以使用如下命令:
# 基础镜像
FROM ubuntu:latest
CMD
CMD
命令用于指定启动Docker容器是需要执行的命令,该容器是基于此Dockerfile构建的Docker镜像,下面是一些Dockerfile的CMD
示例:
CMD echo Docker container started.
本例是打印“Docker container started”这行文本。
下一个CMD
示例是启动一个java应用:
CMD java -cp /myapp/myapp.jar com.jenkov.myapp.MainClass arg1 arg2 arg3
COPY
COPY
命令将一个或多个文件从主机(从Dockerfile文件构建Docker镜像的机器)复制到Docker镜像中,可以复制的内容包括文件或目录,下面是一个示例:
COPY /myapp/target/myapp.jar /myapp/myapp.jar
这个例子是把主机的/myapp/target/myapp.jar文件复制到Docker进行中的/myapp/myapp.jar文件。第一个参数是主机路径(从哪里来),第二个参数是Docker镜像的路径(到哪里去)。
我们还可以复制一个目录到Docker镜像中,比如:
COPY /myapp/config/prod /myapp/config
这个例子是把主机的/myapp/config/prod目录复制到Docker镜像中的/myapp/config目录。
我们还可以复制多个文件到Docker镜像中的一个目录中,比如:
COPY /myapp/config/prod/conf1.cfg /myapp/config/prod/conf2.cfg /myapp/config/
这个例子是将主机的/myapp/config/prod/conf1.cfg文件和/myapp/conig/prod/conf2.cfg文件复制到Docker镜像中的/myapp/config/目录中。注意,目标目录必须以/(斜杠)结束才能工作。
ADD
ADD
命令与COPY
命令工作方式相同,只有一些细微的差别:
ADD
命令可以复制并提取TAR文件到Docker镜像中。
ADD
命令可以通过HTTP下载文件,并复制到Docker镜像中。
下是一些示例:
这个例子是将指定的TAR文件解压缩并提取到Docker镜像的/myapp/目录中。
下面是另一个例子:
ADD http://jenkov.com/myapp.jar /myapp/
ENV
ENV
命令是在Docker镜像中设置环境变量,此环境变量可用于CMD
命令在Docker镜像内部启动应用程序。举个例子:
本例将环境变量MY_VAR
设置为值123。
RUN
RUN
可以在Docker镜像中执行命令行指令,执行时机是Docker镜像构建过程中,所以RUN
命令只会执行一次。RUN
命令可用于在Docker镜像中安装应用程序、提取文件或其他命令行功能,这些操作只需要执行一次,以供Docker镜像后续使用。
RUN apt-get install some-needed-app
ARG
ARG
命令允许定义一个参数,这个参数可以在通过Dockerfile文件构建Docker镜像时,通过命令参数传递给Docker。比如:
当执行docker build
命令执行Dockerfile构建Docker镜像时,可以指定tcpPort
参数,比如:
docker build --build-arg tcpPort=8080 .
注意,--build-arg
后面的tcpPort=8080
,是将tcpPort
参数的值设置为8080。
我们可以通过多个ARG
命令定义多个参数,举个例子:
当构建Docker镜像时,必须为所有构建参数提供值。【译者注,1.13版本之前,不提供值会直接报错,1.13版本之后,不提供值不会报错,但是会弹出警告】。举个例子:
docker build --build-arg tcpPort=8080 --build-arg useTls=true .
我们可以为ARG
设置默认值,当构建Docker镜像时,如果没有指定参数值,将使用默认值。举个例子:
ARG tcpPort=8080 ARG useTls=true
如果tcpPort
和useTls
在生成Docker镜像时,都没有设置参数,将使用默认值8080和true。
ARG
声明的参数通常在Dockerfile的其他地方引用,比如:
ARG tcpPort=8080 ARG useTls=true CMD start-my-server.sh -port ${tcpPort} -tls ${useTls}
注意:两个引用${tcpPort}
和${useTls}
,引用名是tcpPort
和useTls
这两个ARG
声明的参数。
docker build --build-arg tcpPort=8080
WORKDIR
WORKDIR
命令指明了Docker镜像中的工作目录,工作目录将对WORKDIR
指令之后的所有命令生效,举个例子:
EXPOSE
EXPOSE
命令将对外开放Docker容器中的网络端口,比如,如果Docker容器运行一个web服务器,那么,该web服务器可能需要打开端口80,以便客户端链接到它。举个例子:
我们还可以指明打开端口的通信协议,比如:UDP和TCP。下面是设置允许通信协议的示例:
如果没有指定协议,将默认认定为TCP协议。
VOLUME
VOLUME
命令会在Docker镜像中创建一个目录,这个目录可以挂载到Docker主机上。换句话说,可以在Docker镜像中创建目录,比如/data
,这个目录可以在稍后挂载到Docker主机的/container-data/container1
目录上。挂载成功后,容器会启动。下面是一个使用VOLUME
命令在Dockerfile中定义装载目录的示例:
ENTRYPOINT
ENTRYPOINT
命令为从该Docker镜像启动Docker容器提供入口点,入口点是Docker容器启动时执行的应用程序或命令。这样,ENTRYPOINT
和CMD
工作方式类似,不同之处在于,使用ENTRYPOINT
时,当ENTRYPOINT
执行的应用程序完成时,Docker容器将关闭。因此,ENTRYPOINT
使Docker镜像本身成为一个可执行命令,可以启动,完成后关闭。以下是ENTRYPOINT
示例:
ENTRYPOINT java -cp /apps/myapp/myapp.jar com.jenkov.myapp.Main
这个示例将在容器启动时执行Java应用程序的主类com.jenkov.myapp.Main
,当应用程序关闭时,Docker容器也会关闭。
HEALTHCHECK
HEALTHCHECK
命令可以定期执行健康检查,以监视Docker容器中运行的应用程序的运行状况。如果命令返回0,Docker将认为应用程序和容器正常,如果命令返回1,Docker会认为应用程序和容器不正常。示例如下:
HEALTHCHECK java -cp /apps/myapp/healthcheck.jar com.jenkov.myapp.HealthCheck https://localhost/healthcheck
这个示例中使用了java应用程序的com.jenkov.myapp.HealthCheck
作为健康检查的命令,我们可以使用任何有意义的健康检查命令。
健康检查间隔时间
默认情况下,Docker每30秒执行一次HEALTHCHECK
命令。如果想修改时间间隔,我们可以自定义时间,通过--interval
参数,可以指定健康检查的检查间隔时间。下面是一个将HEALTHCHECK
间隔设置为60秒的示例:
HEALTHCHECK --interval=60s java -cp /apps/myapp/healthcheck.jar com.jenkov.myapp.HealthCheck https://localhost/healthcheck
健康检查开始时间
默认情况下,Docker会立即检查Docker容器的监控状况。但是,有些应用程序可能需要一段时间启动,因此,只有经过某段时间后再进行健康检查才有意义。我们可以使用--start-period
参数设置健康检查开始时间。下面是一个将健康检查设置为5分钟的示例,在Docker开始健康检查之前,为容器和应用程序提供300秒(5分钟)的启动时间:
HEALTHCHECK --start-period=300s java -cp /apps/myapp/healthcheck.jar com.jenkov.myapp.HealthCheck https://localhost/healthcheck
健康检查超时时间
健康检查很有可能超时,如果HEALTCHECK
命令需要超过给定时间限制才完成,Docker将认为健康检查超时。可以使用--timeout
参数设置超时时间,如下是设置超时时间为5秒的示例:
HEALTHCHECK --timeout=5s java -cp /apps/myapp/healthcheck.jar com.jenkov.myapp.HealthCheck https://localhost/healthcheck
注意,如果健康检查超时,Docker也会认为容器不健康。
健康检查重复次数
如果HEALTHCHECK
命令执行失败,有可能是结果返回1,或者执行超时,Docker会在认定容器不健康前,重试3次HEALTHCHECK
命令,用于检查Docker容器是否返回健康状态。可以通过--retries
设置重试次数。下面是将重试次数设置为5的示例:
HEALTHCHECK --retries=5 java -cp /apps/myapp/healthcheck.jar com.jenkov.myapp.HealthCheck https://localhost/healthcheck
Docker 教程(三):Docker 命令
我们通过 Docker 命令与操作 Docker 服务,可以构建 Docker 镜像、运行 Docker 容器、将 Docker 镜像推送到远程等。本文主要介绍一些常用的 Docker 命令。
Docker 有很多命令,本文不会介绍所有的命令,如果需要完整的命令教程,可以参考 Docker command line reference 。
请注意,根据在 Linux 系统上安装 Docker 的方式,可能需要在所有命令前面加上sudo
,使用 root 权限运行他们。比如:
… 而不仅仅是:
Docker 命令行工具
在 Linux 系统中安装 Docker 时,会安装一个名为docker
的命令行工具,可以在 Linux 命令行执行。
docker
有很多的参数,不同的参数作用不同,可以指挥 Docker 做出不同的行为,可以认为是给 Docker 的命令。以下是docker
命令示例:
这个示例中包含三部分:docker
命令、参数build
、参数.
。
参数build
是一个 Docker 命令,换句话说,是一个给 docker 可执行命令行的命令。通常,docker 命令行的第一个参数都是 Docker 命令。
参数.
是build
命令的参数。
docker build
docker build
命令是调用 Docker 从 Dockerfile 文件构建 docker 镜像,要使用docker build
命令,必须告诉它从哪个 Dockerfile 文件生成镜像。关于 Dockerfile 的内容,可以查看 这里 。以下是docker build
命令示例:
参数.
表示从当前目录找到 Dockerfile 文件。
docker images
docker images
命令是列出本机的 Docker 镜像,以下是docker images
命令示例:
运行上述命令会输出类似下面的内容:
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest fce289e99eb9 9 months ago 1.84kB
docker run
docker run
命令用来基于给定的 Docker 镜像运行 Docker 容器,docker run
的参数,可以是 Docker 镜像的名称或 ID,以下是运行 Docker 容器的示例:
这个例子会基于hello-world
镜像运行 Docker 容器。
我们还可以通过 Docker 镜像 ID 运行 Docker 容器,命令如下:
docker ps
docker ps
命令用于显示当前系统中正在运行的 Docker 容器,示例如下:
注意,一些 Docker 容器会在完成任务后立即关闭,在docker ps
的结果列表中,这种 Docker 容器很有可能会很长时间都不可见。
【译者注:本文就 4 个命令,还有很多常用的命令没有提到,比如docker exec
之类的。其实,对于 Docker 命令行来说,我们可以先浏览一遍,知道个大概,等有需要的时候,重点看一下。个人感觉,命令的需要关键是要经常用。如果不用,转眼就忘,可以类比 Linux 命令。】
本文出自:https://ifeve.com/docker-%e6%95%99%e7%a8%8b%ef%bc%88%e4%b8%80%ef%bc%89%ef%bc%9adocker-%e6%98%af%e4%bb%80%e4%b9%88/
文章评论