docker学习笔记

2026-05-21 13:42 技术

docker

docker


docker 概念

Docker 是一个用于开发、发布和运行应用程序的开放平台。 Docker 允许你将应用与基础设施分离,比如 能够快速交付软件。使用 Docker 可以管理基础设施 就像你管理申请的方式一样。 利用 Docker 的优势 快速发布、测试和部署代码的方法论,你可以 大幅减少编写代码到生产运行之间的延迟。

  • docker 容器
  • docker 镜像
  • docker registry

docker 引擎

Docker Engine 是一种开源的容器化技术,用于构建和 把你的应用容器化。 Docker 引擎作为客户端-服务器 应用方式:

  • 一个拥有长期运行的守护进程的服务器 docker。
  • 指定程序可用来通信和指令接口的 API。 Docker 守护进程。
  • 一个命令行界面(CLI)客户端 docker。 CLI 使用 Docker API 来控制或交互 Docker。 通过脚本或直接 CLI 命令来控制守护进程。 还有许多其他 Docker 应用 使用底层的 API 和 CLI。守护进程创建和管理 Docker 对象, 例如图像、容器、网络和卷。

使用 Dockerfile 定制镜像

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

所谓定制镜像,那一定是以一个镜像为基础,在其上进行定制。 就像我们之前运行了一个 nginx 镜像的容器,再进行修改一样,基础镜像是必须指定的。 而 FROM 就是指定 基础镜像,因此一个 Dockerfile 中 FROM 是必备的指令,并且必须是第一条指令。

除了选择现有镜像为基础镜像外,Docker 还存在一个特殊的镜像,名为 scratch。 这个镜像是虚拟的概念,并不实际存在,它表示一个空白的镜像。

如果你以 scratch 为基础镜像的话,意味着你不以任何镜像为基础, 接下来所写的指令将作为镜像第一层开始存在。

RUN 执行命令

RUN 指令是用来执行命令行命令的。由于命令行的强大能力,RUN 指令在定制镜像时是最常用的指令之一。其格式有两种:

  • shell 格式:RUN <命令>,就像直接在命令行中输入的命令一样。刚才写的 Dockerfile 中的 RUN 指令就是这种格式。
  • exec 格式:RUN ["可执行文件", "参数 1", "参数 2"],这更像是函数调用中的格式。

Dockerfile 指令

  • COPY 复制文件
    COPY 指令将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置。
  • ADD 更高级的复制文件
    另外需要注意的是,ADD 指令会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。
  • CMD 容器启动命令
  • ENTRYPOINT 入口点
  • ENV 设置环境变量
    这个指令很简单,就是设置环境变量而已,无论是后面的其它指令, 如 RUN,还是运行时的应用,都可以直接使用这里定义的环境变量。
  • ARG 构建参数
    构建参数和 ENV 的效果一样,都是设置环境变量。 所不同的是,ARG 所设置的构建环境的环境变量,在将来容器运行时是不会存在这些环境变量的。 但是不要因此就使用 ARG 保存密码之类的信息,因为 docker history 还是可以看到所有值的。
  • VOLUME 定义匿名卷
  • EXPOSE 声明端口
    EXPOSE 指令是声明容器运行时提供服务的端口, 这只是一个声明,在容器运行时并不会因为这个声明应用就会开启这个端口的服务。
  • WORKDIR 指定工作目录
  • USER 指定当前用户
  • HEALTHCHECK 健康检查
  • LABEL 指令
  • LABEL 指令用来给镜像以键值对的形式添加一些元数据(metadata)。
  • SHELL 指令
  • ONBUILD 指令
    ONBUILD 是一个特殊的指令,它后面跟的是其它指令,比如 RUN, COPY 等,而这些指令, 在当前镜像构建时并不会被执行。只有当以当前镜像为基础镜像,去构建下一级镜像的时候才会被执行。

操作 Docker 容器

  • 启动容器
    docker run
$ docker run ubuntu:18.04 /bin/echo 'Hello world'
Hello world

这跟在本地直接执行 /bin/echo 'hello world' 几乎感觉不出任何区别。

可以利用 docker container start 命令,直接将一个已经终止(exited)的容器启动运行。

  • 后台运行
    更多的时候,需要让 Docker 在后台运行而不是直接把执行命令的结果输出在当前宿主机下。 此时,可以通过添加 -d 参数来实现。 使用 -d 参数启动后会返回一个唯一的 id,也可以通过 docker container ls 命令来查看容器信息。 要获取容器的输出信息,可以通过 docker container logs 命令。

  • 终止容器
    可以使用 docker container stop 来终止一个运行中的容器。 处于终止状态的容器,可以通过 docker container start 命令来重新启动。 此外,docker container restart 命令会将一个运行态的容器终止,然后再重新启动它。

  • 进入容器
    在使用 -d 参数时,容器启动后会进入后台。 某些时候需要进入容器进行操作,包括使用 docker attach 命令或 docker exec 命令, 推荐大家使用 docker exec 命令。 从 stdin 中 exit,不会导致容器的停止。这就是为什么推荐大家使用 docker exec 的原因。

  • 导出和导入容器
    导出容器 如果要导出本地某个容器,可以使用 docker export 命令。 导入容器快照 可以使用 docker import 从容器快照文件中再导入为镜像。 注:用户既可以使用 docker load 来导入镜像存储文件到本地镜像库, 也可以使用 docker import 来导入一个容器快照到本地镜像库。 这两者的区别在于容器快照文件将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态), 而镜像存储文件将保存完整记录,体积也要大。此外,从容器快照文件导入时可以重新指定标签等元数据信息。

  • 删除容器
    可以使用 docker container rm 来删除一个处于终止状态的容器。 如果要删除一个运行中的容器,可以添加 -f 参数。Docker 会发送 SIGKILL 信号给容器。 清理所有处于终止状态的容器 用 docker container ls -a 命令可以查看所有已经创建的包括终止状态的容器, 如果数量太多要一个个删除可能会很麻烦,用下面的命令可以清理掉所有处于终止状态的容器。 docker container prune

docker 仓库

  • 访问仓库
    仓库(Repository)是集中存放镜像的地方。

一个容易混淆的概念是注册服务器(Registry)。实际上注册服务器是管理仓库的具体服务器, 每个服务器上可以有多个仓库,而每个仓库下面有多个镜像。 从这方面来说,仓库可以被认为是一个具体的项目或目录。 例如对于仓库地址 docker.io/ubuntu 来说,docker.io 是注册服务器地址,ubuntu 是仓库名。

  • Docker Hub
    目前 Docker 官方维护了一个公共仓库 Docker Hub (opens new window), 其中已经包括了数量超过 2,650,000 (opens new window)的镜像。 大部分需求都可以通过在 Docker Hub 中直接下载镜像来实现。
  • 注册 你可以在 免费注册一个 Docker 账号。

  • 登录 可以通过执行 docker login 命令交互式的输入用户名及密码来完成在命令行界面登录 Docker Hub。 你可以通过 docker logout 退出登录。

  • 拉取镜像 你可以通过 docker search 命令来查找官方仓库中的镜像,并利用 docker pull 命令来将它下载到本地。

  • 推送镜像 用户也可以在登录后通过 docker push 命令来将自己的镜像推送到 Docker Hub。

  • 自动构建
    自动构建(Automated Builds)可以自动触发构建镜像,方便升级镜像。 有时候,用户构建了镜像,安装了某个软件,当软件发布新版本则需要手动更新镜像。 而自动构建允许用户通过 Docker Hub 指定跟踪一个目标网站 (支持 GitHub (opens new window)或 BitBucket (opens new window))上的项目, 一旦项目发生新的提交 (commit)或者创建了新的标签(tag),Docker Hub 会自动构建镜像并推送到 Docker Hub 中。

  • 私有仓库
    docker-registry (opens new window)是官方提供的工具, 可以用于构建私有的镜像仓库。本文内容基于 docker-registry (opens new window)v2.x 版本。
    Docker 默认不允许非 HTTPS 方式推送镜像。我们可以通过 Docker 的配置选项来取消这个限制。

docker 数据管理

介绍如何在 Docker 内部以及容器之间管理数据,在容器中管理数据主要有两种方式:

  • 数据卷(Volumes) 数据卷 是一个可供一个或多个容器使用的特殊目录,它绕过 UFS,可以提供很多有用的特性:
  • 数据卷 可以在容器之间共享和重用。
  • 对 数据卷 的修改会立马生效。
  • 对 数据卷 的更新,不会影响镜像。
  • 数据卷 默认会一直存在,即使容器被删除。

  • 挂载主机目录 (Bind mounts) 挂载一个主机目录作为数据卷 使用 --mount 标记可以指定挂载一个本地主机的目录到容器中去。

Docker 中的网络功能

Docker 允许通过外部访问容器或容器互联的方式来提供网络服务。

  • 外部访问容器 容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过 -P 或 -p 参数来指定端口映射。 当使用 -P 标记时,Docker 会随机映射一个端口到内部容器开放的网络端口。 -p 则可以指定要映射的端口,并且,在一个指定端口上只可以绑定一个容器。 支持的格式有 ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort。

  • 容器互联
    如果你之前有 Docker 使用经验,你可能已经习惯了使用 --link 参数来使容器互联。 随着 Docker 网络的完善,强烈建议大家将容器加入自定义的 Docker 网络来连接多个容器,而不是使用 --link 参数。

Docker Compose 如果你有多个容器之间需要互相连接,推荐使用 Docker Compose。

  • 配置 DNS
    如果用户想要手动指定容器的配置,可以在使用 docker run 命令启动容器时加入如下参数: -h HOSTNAME 或者 --hostname=HOSTNAME 设定容器的主机名, 它会被写到容器内的 /etc/hostname 和 /etc/hosts。但它在容器外部看不到, 既不会在 docker container ls 中显示,也不会在其他的容器的 /etc/hosts 看到。 --dns=IP_ADDRESS 添加 DNS 服务器到容器的 /etc/resolv.conf 中, 让容器用这个服务器来解析所有不在 /etc/hosts 中的主机名。 --dns-search=DOMAIN 设定容器的搜索域,当设定搜索域为 .example.com 时, 在搜索一个名为 host 的主机时,DNS 不仅搜索 host,还会搜索 host.example.com。

注意:如果在容器启动时没有指定最后两个参数,Docker 会默认用主机上的 /etc/resolv.conf 来配置容器。

高级网络配置

容器访问控制 容器的访问控制,主要通过 Linux 上的 iptables 防火墙来进行管理和实现。 iptables 是 Linux 上默认的防火墙软件,在大部分发行版中都自带。

docker 底层实现

Docker 底层的核心技术包括 Linux 上的命名空间(Namespaces)、 控制组(Control groups)、Union 文件系统(Union file systems)和容器格式(Container format)。

Docker 采用了 C/S 架构,包括客户端和服务端。 Docker 守护进程 (Daemon)作为服务端接受来自客户端的请求,并处理这些请求(创建、运行、分发容器)。 客户端和服务端既可以运行在一个机器上,也可通过 socket 或者 RESTful API 来进行通信。

命名空间是 Linux 内核一个强大的特性。每个容器都有自己单独的命名空间, 运行在其中的应用都像是在独立的操作系统中运行一样。命名空间保证了容器之间彼此互不影响。

控制组(cgroups (opens new window))是 Linux 内核的一个特性, 主要用来对共享资源进行隔离、限制、审计等。只有能控制分配到容器的资源,才能避免当多个容器同时运行时的对系统资源的竞争。 控制组技术最早是由 Google 的程序员在 2006 年提出,Linux 内核自 2.6.24 开始支持。 控制组可以提供对容器的内存、CPU、磁盘 IO 等资源的限制和审计管理。

联合文件系统(UnionFS (opens new window))是一种分层、轻量级并且高性能的文件系统, 它支持对文件系统的修改作为一次提交来一层层的叠加, 同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。 联合文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。