Docker 入门须知

前言:

之前大概了解了一下 Docker 的一些皮毛,知道 Docker 是基于 Go 语言开发的容器技术,可以在同一台服务器上构建多个互不干扰的干净的隔离环境。

Docker 的优点:

相比于传统的虚拟技术,容器可以以更低的成本为应用提供一个干净的隔离环境,原因大致如下:

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

除了资源消耗低外, 使用 Docker 的在一次创建或配置在任何地方地方运行也是优势之一:

  • 开发人员用 Dockerfile 来进行镜像构建,并结合 持续继承(Continuous Integration)系统 进行集成测试;
  • 运维人员可以直接在生产环境中快速部署该镜像,甚至结合 持续部署(Continuous Delivery/Deployment)系统 进行自动部署。

Docker 基础:

在使用Docker 前,需要弄清楚三个概念:

  • 镜像(Image):

    一个特殊的文件系统,提供容器运行时所需的程序、库、资源、配置等文件,还有运行时的一些配置参数(环境变量等),不包含任何动态数据,内容在构建之后不会被改变。(使用时充分利用 Union Fs 技术,将其设计为分层存储的架构)

  • 容器(Container):

    镜像与容器的关系,就像 实例 一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。使用容器时,存储数据应该使用 数据卷(Volume) 或 绑定宿主目录,不要写在容器存储层中,这样数据在容器被删除后不会丢失。

  • 仓库(Repository):

    为了使镜像可以在其他服务器上使用,需要用到一个集中的存储、分发镜像的服务 Docker Registry ,一个 Docker Registry 中可以包含多个 仓库(Repository) ;每个仓库中可以包含多个 标签(Tag) ; 每个标签对应一个镜像。(通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。)

从 Docker Registry 中获取镜像的指令:

docker pull [选项] [Docker Registry地址]<仓库名>:<标签>
  • Docker Registry 地址:一般格式是 <域名/IP>[:端口号],默认地址是 Docker Hub;

  • 仓库名:两段式名称,即 <用户名>/<软件名> ,在 Docker Hub 中,不给用户名的,则默认为 library ,即官方镜像。

Docker 中的镜像是分层的,这样可以提高层的复用性,即两个不同的镜像可能使用了同一个基础层,那么下载这两个镜像后,docker 中其实只存在一份两者共有的层,提高资源利用率并节省空间,分层也是 Docker 容器技术的核心之一。

常用指令:

docker image

docker image 和 docker images 是用来管理镜像的接口:

docker image ls

docker container

这是用于操作基于 image 启动出来的容器,例如:

docker container stop [containerName]   # 停止一个正在运行的容器
docker container rm [containerName]     # 移除一个已停止运行的容器

containerName 是使用 docker run 启动一个容器时 --name 字段所指定的容器名称。

docker commit

docker commit 用于将当前运行的容器对所基于的镜像的修改内容保存起来,生成新的镜像,但这种方式一般不用于定制镜像,应使用 Dockerfile 来实现自定义镜像。可以把容器当作是基于镜像加一层数据层的运行结果,数据层可变,变化内容可以通过 docker commit 保存下来。指令格式:

docker commit --author "" --message "" <容器 id 或容器名> [<仓库名>[:<标签>]]

可以通过 docker diff <容器名> 查看修改内容。

慎用 docker commit ,原因如下:

  • 对单个文件的简单的操作可能导致多个文件的修改和添加,不及时清理便会导致镜像臃肿;
  • 操作不透明,这种黑箱操作生成的黑箱镜像,只有制作镜像的人才能知道镜像生成过程执行过的操做,其他人即使借助 docker diff 也无法确保能生成一致的镜像;
  • 修改操作仅对当前层有效,即使对上一层的东西执行了删除操作,上层的东西也还存在,即使无法再被访问,但会一致跟随此镜像。

Dockerfile

关于镜像的定制,实际上就是定制每一层所添加的配置和文件。把每一层修改、安装、构建和操作的命令都写入一个脚本,用这个脚本来构建和定制镜像,这个脚本就是 Dockerfile

可以解决 docker commit 中存在的无法重复、景象构建透明性、体积臃肿等问题。

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

1. 创建简单的 Dockerfile:

创建一个目录,然后在该目录下创建 Dockerfile 文件:

$ mkdir TestDockerfile
$ cd TestDockerfile
$ touch Dockerfile

然后编辑 Dockerfile 的内容:

vi Dockerfile

输入以下内容:

FROM scratch
RUN apt-get update
  • FROM 指令用于指定当前镜像的基础镜像,是 Dockerfile 中必备的指令也是第一条指令,假如不需要基于任何基础镜像,可以基于 Docker 的一个特殊的镜像 scratch ,这是一个虚拟的概念,并不实际存在,它表示一个空白镜像。

  • RUN 指令用来执行命令行命令,使用格式有两种:

    • shell 格式: RUN <命令行>
    • exec 格式:RUN ["可执行文件","参数1","参数2"] ,更像函数调用的格式。

    之前说过 Dockerfile 中一条指令会构建当前镜像的一层,那么假如一层中需要执行多个 shell 命令来完成构建,则需要使用 && 连接符来连接多个命令,为了提高可读性,RUN 指令也支持在行尾使用 \ 的命令换行方式,例如:

    RUN apt-get update \
    && apt-get install -y go \
    && ...

    合理地规划好镜像构建的分层非常重要,而且每一层构建完成后,需要将无用的下载和展开文件内容清理掉,否则到了下一层就无法删除了,会不断累积跟随镜像。

2. 执行 Dockerfile 构建镜像:

上面我们已将创建了一个 Dockerfile 文件,接下来我们就要是使用该文件来构建镜像,执行方式就是在 Dockerfile 所在的目录(一个目录下只能存在一个 Dockerfile 文件)下执行如下指令:

docker build [选项] <上下文路径/URL/->

例如:docker build -t testDockerfile:v1 . ,即构建出来的镜像名称为 -t testDockerfile:v1 ,最后指定上下文路径为 . ,即表示当前目录。

docker 的各种功能其实是使用远程调用的形式在服务端(Docker 引擎)完成的,客户端通过 Dcoker Remote API 来与 Docker 引擎交互,完成各种功能。

上下文目录在执行 docker build 时会将该目录下的所有内容打包,上传给 Docker 引擎,提供引擎构建镜像所需的所有文件。这个过程在 docker build 的输出日志可以看到:

Sending build context to Docker daemon ...

切记不可在上下文目录下放置过多构建镜像时无用的文件,不然这些文件也会全部被打包上传,导致镜像构建缓慢甚至容易失败。所以,通常将 Dockerfile 放置在一个空目录下。

也可以通过 .dockerignore 剔除上下文目录中无需传递给 Docker 引擎的文件,该文件的功能类似与 git 操作中的 .gitignore

构建镜像的 Dockerfile 文件并非必须使用 Dockerfile 来命名,也并非必须放在上下文目录下,可以通过 -f ../Dockerfile.php 参数的形式来指定当前镜像构建脚本,只是一般都习惯直接命名为 Dockerfile 并直接放在上下文目录下而已。

更多 Dockerfile 的指令可以参考:Dockerfile 指令详解

参考文章:

猜你喜欢

转载自blog.csdn.net/linshuhe1/article/details/79056357