1
0
wiki/FormalSciences/ComputerScience/DevSecOps/5.Containerization/5.2-Docker详解.md

88 KiB
Raw Permalink Blame History

title description keywords tags author date
5.2-Docker详解.md 描述
关键字
标签
仲平 2024-10-17

概述

Docker 是一种开源的容器化技术,它允许开发者将应用及其运行环境打包在一个轻量级、可移植的容器中。这个容器可以在任何支持 Docker 的系统上运行,确保了应用在不同环境之间的一致性。可以把 Docker 容器看作是一个简化版的虚拟机,但与传统的虚拟机相比,它更为轻量和高效,因为容器直接运行在宿主机的操作系统内核上,而不需要额外的操作系统层。

想象一下如果你是一位厨师Docker 就像是你的食材和调料被一起打包在一个便携式的盒子里。无论你去到哪个厨房(服务器),只要那里有 Docker相当于一个标准的炉子你就能够使用那个盒子里的东西应用和环境来准备你的菜肴运行你的应用

我们还可以把 Docker 想象成一种创新的快递服务。它不仅提供了一个标准化的包裹盒(容器),而且还确保了无论包裹被送到哪里(无论是开发、测试还是生产环境),里面的物品(应用和环境)都能够完好无损地到达。

历史发展

2013 年Docker 的诞生

Docker 最初是由 Solomon Hykes 在 dotCloud 公司(后来改名为 Docker Inc.)开发的一个内部项目,旨在简化应用的部署过程。它基于 Linux 容器LXC技术并在 2013 年 3 月以开源项目的形式发布。

2014 年Docker 1.0 发布

Docker 迅速获得开发者社区的关注和支持。2014 年 6 月Docker 1.0 正式发布,标志着 Docker 成为生产环境准备就绪的技术。

2015 年Docker Compose 和 Docker Swarm 的推出

随着 Docker 的普及用户开始寻求更好的工具来管理多个容器。Docker Compose 作为定义和运行多容器 Docker 应用的工具在 2015 年初推出。同年Docker Swarm 也被引入作为 Docker 的原生集群管理工具。

2016 年Docker 成为 Moby 项目

2016 年Docker Inc.宣布将 Docker 核心分割为多个独立的组件,核心 Docker 平台被重命名为 Moby Project。这一变化旨在促进社区贡献并提高项目的模块化。

2017 年Docker 宣布支持 Kubernetes

随着 Kubernetes 成为容器编排领域的领导者Docker Inc.在 2017 年宣布原生支持 Kubernetes允许用户在 Docker 平台上直接使用 Kubernetes 进行容器编排。

2019 年Docker 企业业务被 Mirantis 收购

2019 年 11 月Docker Inc.宣布将其企业业务出售给云计算公司 Mirantis同时 Docker Inc.将专注于发展 Docker Desktop 和 Docker Hub。

2020 年及以后Docker 的持续发展

即使在企业业务被出售后Docker 仍然是开发和运行容器化应用最流行的平台之一。Docker 继续推出新版本,增加新特性,并优化用户体验。同时,社区和生态系统也在不断壮大,为 Docker 的未来发展提供了坚实的基础。

Docker 的发展历史体现了容器技术在软件开发和部署中的革命性变化。从一个小型内部项目到成为全球广泛采用的开源平台Docker 不仅改变了我们构建和部署应用的方式,也促进了 DevOps 文化和微服务架构的发展。

主要优势

Docker 提供了许多优势,包括但不限于:

  1. 一致性和可移植性无论开发者的本地机器使用什么操作系统Docker 容器都能确保应用可以在任何支持 Docker 的环境中以相同的方式运行。
  2. 快速部署:由于容器不需要启动一个完整的操作系统,它们可以在几秒钟内启动和停止,这大大加快了部署和扩展应用的速度。
  3. 资源高效:容器共享宿主机的核心,不需要额外的操作系统负担,这使得它们比虚拟机更加资源高效。
  4. 隔离:每个容器都在自己的环境中运行,与其他容器隔离。这提高了安全性,因为它防止了应用之间的干扰。

应用场景

Docker 可以用于多种场景,包括:

  • 开发环境的一致性:确保开发、测试和生产环境完全一致,减少了“在我这里运行得好好的”问题。
  • 微服务架构:每个微服务运行在自己的容器中,便于管理和扩展。
  • 持续集成/持续部署CI/CDDocker 容器可以用于自动化测试和生产部署,提高软件交付的速度和质量。
  • 应用的快速部署和扩展:在云平台和虚拟化环境中快速部署和扩展应用。

同类产品对比

特性/产品 Docker Podman Kubernetes
定义 开源容器化平台,允许开发者打包、分发和运行应用。 开源容器化工具,允许开发者构建、运行和管理容器和容器镜像。 开源的容器编排平台,用于自动化容器的部署、扩展和管理。
设计目标 简化应用的打包和部署流程。 提供一个与 Docker 兼容的命令行界面,但不依赖于守护进程,更加注重安全性。 在集群中自动化部署、扩展和操作容器化的应用程序。
运行环境 单机或 Swarm 模式下的多机环境。 单机,支持通过 Podman 或 Kubernetes 进行编排。 集群环境,可以跨多个主机运行容器。
安全性 通过 Docker 守护进程运行,需要考虑守护进程的安全性。 不需要守护进程,每个容器都是在用户空间中作为独立进程运行,提供更高的安全性。 设计用于多租户场景,提供严格的安全策略。
使用场景 开发、测试和生产环境中的应用容器化和微服务架构。 适用于希望避免使用守护进程或寻求更高安全性的开发者和系统管理员。 大规模容器管理和自动化部署、管理和扩展容器化应用。
社区和生态 庞大的社区支持和丰富的容器镜像库。 正在快速增长的社区,与 Docker 镜像和容器生态系统兼容。 强大的社区支持是云原生计算基金会CNCF的一部分拥有广泛的生态系统。
主要优势 用户友好的界面和命令行工具,广泛的采用和支持。 更适合安全敏感的环境,无需守护进程,支持 rootless 运行。 强大的容器编排和管理能力,适合大规模部署。

Docker 是一个开源的容器化平台,它允许开发者打包应用及其依赖到一个可移植的容器中,然后在任何支持 Docker 的系统上运行这个容器。容器化技术使得应用从环境配置中解脱出来,增强了应用的可移植性、效率和安全性。

Docker 架构

  • 容器Containers:容器是 Docker 的核心,可以被理解为一个轻量级、可执行的软件包,包含了运行某个应用所需的全部内容——代码、运行时环境、库、环境变量和配置文件等。你可以把容器想象成一个独立的小型计算机,它在一个隔离的环境中运行应用。
  • 镜像Images:镜像是创建 Docker 容器的模板。镜像是静态的包含了运行应用所需的代码、库、环境变量和配置文件。可以把镜像想象成容器的“蓝图”。创建容器时Docker 会从镜像中读取这些信息。
  • 仓库Repositories仓库是集中存放镜像的地方。Docker Hub 是最著名的公共仓库,但用户也可以创建私有仓库来存储和管理自己的镜像。
  • DockerfileDockerfile 是一个文本文件,包含了一系列的指令和参数,用于自动化构建 Docker 镜像的过程。通过编写 Dockerfile开发者可以定义如何构建镜像包括添加文件、运行命令和配置环境等。
  • Docker ComposeDocker Compose 是一个用于定义和运行多容器 Docker 应用的工具。通过一个 YAML 文件,你可以配置应用服务所需的所有容器,然后使用一个命令同时创建和启动所有这些容器。

Docker 工作原理

Docker 使用容器来运行应用,容器运行在 Docker 引擎之上。Docker 引擎负责管理容器的生命周期,包括容器的创建、启动、停止、移动和删除。容器与虚拟机相比,占用的资源更少,启动更快,因为容器共享宿主机的内核,而不需要模拟整个操作系统。

Docker 设计架构

Docker 的架构主要基于客户端 - 服务器Client-Server模型涉及几个关键组件Docker 客户端、Docker 服务器也称为守护进程、Docker 镜像、容器、仓库等。

  • Docker 客户端ClientDocker 客户端是用户与 Docker 交互的主要方式。用户通过运行 Docker 客户端命令来告诉 Docker 守护进程需要做什么。例如,构建镜像、运行容器、停止容器等操作都是通过客户端发起的。
  • Docker 服务器守护进程DaemonDocker 守护进程运行在宿主机上,处理客户端发来的请求,如创建、运行、监控容器,构建和存储镜像等。守护进程与其他 Docker 守护进程通信,管理 Docker 服务。

Docker 客户端和守护进程可以在同一系统上运行,也可以将 Docker 客户端连接到远程 Docker 守护进程。 Docker 客户端和守护进程使用 REST API 通过 UNIX 套接字或网络接口进行通信。

Docker 安装

安装脚本

# 正式版本
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh
# 测试版本
curl -fsSL https://test.docker.com -o test-docker.sh
sh test-docker.sh

启动测试

# 默认启动
sudo systemctl enable docker
sudo systemctl start docker

# 验证是否正确安装
docker run --rm hello-world

镜像加速

国内从 Docker Hub 拉取镜像有时会遇到困难,此时可以配置镜像加速器。国内各大云服务商(腾讯云、阿里云、百度云)均提供了 Docker 镜像加速服务,建议根据运行 Docker 的云平台选择对应的镜像加速服务。

请首先执行以下命令,查看是否在 docker.service 文件中配置过镜像地址。

$ systemctl cat docker | grep '\-\-registry\-mirror'

如果该命令有输出,那么请执行 $ systemctl cat docker 查看 ExecStart= 出现的位置,修改对应的文件内容去掉 --registry-mirror 参数及其值,并按接下来的步骤进行配置。

如果以上命令没有任何输出,那么就可以在 /etc/docker/daemon.json 中写入如下内容(如果文件不存在请新建该文件):

{
  "registry-mirrors": [
    "https://hub-mirror.c.163.com",
    "https://mirror.baidubce.com"
  ]
}

注意,一定要保证该文件符合 json 规范,否则 Docker 将不能启动。

最后重新启动服务。

sudo systemctl daemon-reload

sudo systemctl restart docker

Docker 使用

Docker 是一个开源平台用于自动化开发、部署和运行应用程序的过程通过使用容器化技术Docker 允许开发者将应用及其依赖打包成一个轻量级、可移植的容器,然后这个容器可以在任何地方运行。这样,它解决了在我的机器上可以运行的问题,提高了软件交付的效率和可靠性。

容器

容器化是一种虚拟化技术,它允许你在隔离的环境中运行和部署应用。每个容器独立运行一个或多个应用程序,包括它们所需的所有依赖。这就像将你的应用及其所有依赖打包在一个集装箱中,无论在什么环境下运输(运行),都能确保其内容不受影响。

生命周期

容器的生命周期管理是 Docker 使用的核心概念之一,涉及容器从创建到销毁的全过程。容器的生命周期可以通过一系列的 Docker 命令来管理,这些命令包括创建、启动、停止、重启、删除等操作。

生命周期

创建容器

创建容器是容器生命周期的第一步,这一过程依赖于 Docker 镜像。Docker 镜像是一个包含了应用及其依赖的轻量级、可执行的软件包,确保了应用在任何环境下的一致性和可移植性。

docker run hello-world

容器管理

容器一旦创建,就可以通过各种命令进行管理。这些命令允许用户控制容器的生命周期,包括启动、停止、重启和删除等操作。

  • 启动容器docker start my_container,此命令用于启动一个或多个已经创建但停止运行的容器。
  • 停止容器docker stop my_container,该命令用于停止一个或多个正在运行的容器。停止容器会向容器内的主进程发送 SIGTERM 信号,之后发送 SIGKILL 信号,以确保容器停止运行。
  • 查看运行中的容器docker ps,此命令展示了所有当前正在运行的容器。使用 -a 选项可以查看包括停止的在内的所有容器。
  • 进入运行中的容器docker exec -it my_container /bin/bash,该命令允许用户进入一个正在运行的容器内部,并以交互模式启动一个新的终端会话。这对于调试应用或管理容器内的服务非常有用。
  • 删除容器docker rm my_container,使用这个命令可以删除一个或多个已停止的容器。如果要删除运行中的容器,需要加上 -f--force 参数来强制删除。

高级容器管理

除了基本的生命周期管理命令Docker 还提供了一系列高级功能,以支持更复杂的容器操作和管理需求。

  • 查看容器日志docker logs my_container,这个命令允许用户检查和跟踪容器内的标准输出和错误输出。对于调试应用和监控容器运行状态非常有用。
  • 查看容器内部进程docker top my_container,此命令显示运行在容器内部的进程列表,有助于了解容器内部的活动。
  • 暂停容器docker pause my_container,该命令用于暂停运行中的容器,所有进程都会被挂起。这可以用于资源管理或在特定时刻“冻结”容器的状态。
  • 恢复容器docker unpause my_container,与 docker pause 相对,此命令用于恢复被暂停的容器的执行。
  • 容器资源限制:在创建或运行容器时,可以通过 --memory--cpu-shares 等参数来限制容器可以使用的资源,从而避免单个容器占用过多的系统资源。

数据卷

数据卷是 Docker 实现数据持久化和共享的关键机制之一。通过使用数据卷,用户可以在不同容器之间共享数据,同时保证数据的持久化存储,即使容器被删除,卷中的数据也不会丢失。

  • 数据持久化:数据卷提供了一种机制,可以将数据存储在容器之外,确保重要数据不会因容器的删除而丢失。
  • 数据共享与重用:数据卷可以被多个容器挂载和访问,实现数据的共享。
  • 容器解耦:通过数据卷,应用程序的运行状态可以与数据保持独立,便于应用的迁移和备份。

使用数据卷

创建和使用数据卷的基本命令如下:

# 创建一个新的数据卷
docker volume create my_volume

# 将数据卷挂载到容器
docker run -d -v my_volume:/path/in/container --name my_container my_image

此命令会启动一个新的容器,将之前创建的数据卷 my_volume 挂载到容器的指定路径 /path/in/container 下。容器内应用对该路径的任何写操作都会直接反映到数据卷上,同样,对数据卷的任何更改也会立即在挂载它的所有容器中可见。

数据卷容器

数据卷容器是一种使用数据卷共享数据的模式。通过创建一个专门的容器来持有数据卷,其他容器可以通过 --volumes-from 标志来挂载这个容器中的数据卷。

# 创建一个带数据卷的容器
docker run -d --name data_container -v my_volume:/path/in/container my_image

# 使用 --volumes-from 从其他容器挂载数据卷
docker run -d --name app_container --volumes-from data_container my_app_image

这种方法使得数据的管理和共享变得更加集中和高效。

Docker 网络

Docker 网络功能允许容器相互通信并与外部世界交互。Docker 提供了多种网络模式,以支持不同的使用场景。

网络模式

  • bridge默认网络模式。当容器运行在桥接网络中时Docker 会自动使用私有子网内的 IP 地址来分配给每个容器,并通过 NAT 实现与外部网络的通信。
  • host:在这种模式下,容器共享宿主机的网络命名空间,不进行网络隔离。容器的网络性能更好,但是安全性降低。
  • none:在这种模式下,容器具有自己的网络命名空间,但不配置任何网络接口,通常用于需要手动管理网络的高级场景。

自定义网络

创建自定义网络可以提供更灵活的网络配置,使得容器间的通信更加方便和安全。

# 创建自定义桥接网络
docker network create --driver bridge my_custom_bridge

# 运行容器时指定网络
docker run -d --name my_container --network my_custom_bridge my_image

在自定义网络中,容器可以通过容器名相互访问,而不需要使用 IP 地址,简化了容器间通信的配置。

网络连接和断开

Docker 允许在运行时将容器连接到网络或从网络断开。

# 将运行中的容器连接到网络
docker network connect my_custom_bridge my_container

# 将容器从网络断开
docker network disconnect my_custom_bridge my_container

这提供了动态管理容器网络连接的灵活性,允许根据需要调整容器的网络配置。

Docker 存储

Docker 提供了三种主要的数据存储机制:数据卷、目录绑定和临时数据。 这些机制可以根据不同的需求和场景来实现数据的持久化存储和共享。

数据卷

数据卷是一种用于持久化存储容器数据的机制。它可以将主机上的目录或文件挂载到容器中,从而实现数据在容器和主机之间的共享和持久化。数据卷的主要优势是容器与数据的解耦,使得容器可以在不同的主机上迁移和共享数据。

数据卷的主要特点包括:

  • 数据卷是独立于容器的实体。即使容器被删除,数据卷仍然存在。
  • 数据卷可以被多个容器共享。这意味着多个容器可以访问和修改同一个数据卷中的数据。
  • 数据卷可以在容器之间进行传递。例如,可以将一个数据卷从一个容器挂载到另一个容器中,从而实现数据的共享和传递。
  • 数据卷可以在容器运行时进行挂载和卸载。这意味着可以在容器运行时动态地修改数据卷的挂载点。

使用数据卷的步骤如下:

  1. 创建一个数据卷:

    docker volume create my-volume
    

    这将创建一个名为 my-volume 的数据卷。

  2. 将数据卷挂载到容器中:

    docker run -v my-volume:/path/in/container my-image
    

    这将把名为 my-volume 的数据卷挂载到容器中的 /path/in/container 目录。

  3. 可以在多个容器中使用相同的数据卷:

    docker run -v my-volume:/path/in/container another-image
    

    这将把同一个名为 my-volume 的数据卷挂载到另一个容器中。

数据卷的生命周期管理包括创建、使用和删除。可以使用以下命令和操作来管理数据卷:

  • 创建一个数据卷:

    docker volume create my-volume
    

    这将创建一个名为 my-volume 的数据卷。

  • 将数据卷挂载到容器中:

    docker run -v my-volume:/path/in/container my-image
    

    这将把名为 my-volume 的数据卷挂载到容器中的 /path/in/container 目录。

  • 查看数据卷的详细信息:

    docker volume inspect my-volume
    

    这将显示关于数据卷的详细信息,包括挂载点、创建时间等。

  • 删除一个数据卷:

    docker volume rm my-volume
    

    这将删除名为 my-volume 的数据卷。请注意,只有在没有容器使用该数据卷时才能删除。

数据卷的备份和还原可以使用以下方法:

  • 备份数据卷:

    docker run --rm -v my-volume:/data -v $(pwd):/backup busybox tar cvf /backup/my-volume.tar /data
    

    这将创建一个名为 my-volume.tar 的备份文件,其中包含了 my-volume 数据卷中的所有数据。

  • 还原数据卷:

    docker run --rm -v my-volume:/data -v $(pwd):/backup busybox tar xvf /backup/my-volume.tar -C /
    

    这将从备份文件 my-volume.tar 中还原数据到 my-volume 数据卷中。

目录绑定

目录绑定是将主机上的目录直接映射到容器中的一种机制。通过目录绑定,容器可以直接访问和修改主机上的文件和目录。

目录绑定的主要特点包括:

  • 目录绑定是容器和主机之间的直接映射关系。容器中的操作会直接影响主机上的文件和目录。
  • 目录绑定是一种静态的映射关系。一旦映射建立,容器运行期间无法修改映射关系。
  • 目录绑定是一对一的关系。每个容器只能与一个主机目录进行映射。
  • 目录绑定可以在容器创建时进行设置,也可以在容器运行时进行修改。但无论何时修改映射关系,都需要重新启动容器。

使用目录绑定的步骤如下:

  1. 将主机上的目录映射到容器中:

    docker run -v /path/on/host:/path/in/container my-image
    

    这将把主机上的 /path/on/host 目录映射到容器中的 /path/in/container 目录。

  2. 容器中对映射的目录进行操作,将直接影响主机上的目录。

临时数据

在某些情况下容器可能需要临时性的数据存储这些数据不需要持久化保存。Docker 提供了几种方式来实现临时数据存储。

临时数据的存储方式包括:

  • 临时文件系统tmpfs可以将一个临时文件系统挂载到容器中的某个目录用于存储临时数据。这些数据在容器停止时会被删除。

    docker run --rm -it --mount type=tmpfs,destination=/data my-image
    
  • 临时性数据卷:可以创建一个临时性的数据卷,用于存储临时数据。这些数据卷在容器停止时会被删除。

    docker run --rm -it -v /data my-image
    

临时数据的清理与管理方法包括:

  • 定期清理任务:可以编写一个定期运行的清理任务,删除不再需要的临时数据。
  • 使用临时性数据卷:如果使用临时性数据卷存储临时数据,可以在容器停止时自动删除数据卷。

数据卷插件

除了默认的本地数据卷驱动程序Docker 还支持使用数据卷插件进行数据存储。数据卷插件可以提供更高级的存储功能,例如远程存储、分布式存储等。

数据卷插件分为存储驱动程序插件和第三方数据卷插件。

存储驱动程序插件

存储驱动程序插件是 Docker 的一种官方插件类型,用于扩展 Docker 引擎的存储功能。存储驱动程序插件可以实现不同的存储后端,例如 Amazon EBS、GlusterFS、Ceph 等。

使用存储驱动程序插件时,需要先安装插件并将其配置为 Docker 引擎的默认存储驱动程序。然后,可以使用标准的 Docker 命令和操作来创建和管理存储卷。

第三方数据卷插件

除了官方的存储驱动程序插件,还有很多第三方数据卷插件可供选择。这些插件提供了各种不同的存储后端和功能,可以根据具体需求选择合适的插件。

使用第三方数据卷插件时,需要先安装插件并配置其相关参数。然后,可以使用插件特定的命令和操作来创建和管理存储卷。

数据备份与迁移

在 Docker 中,数据备份和迁移是常见的需求。下面介绍一些备份和迁移容器中数据的方法。

备份容器中的数据

备份容器中的数据可以使用以下方法:

  • 使用 docker cp 命令将容器中的数据复制到主机上:

    docker cp <container_id>:/path/in/container /path/on/host
    

    这将把容器中的 /path/in/container 目录或文件复制到主机上的 /path/on/host 目录。

  • 使用数据卷进行备份:如果容器使用了数据卷,可以直接备份数据卷,或者将数据卷挂载到另一个容器中进行备份。

迁移容器中的数据到其他环境

迁移容器中的数据到其他环境可以使用以下方法:

  • 使用数据卷进行迁移:如果容器使用了数据卷,可以将数据卷挂载到另一个容器中,然后在新环境中运行该容器,从而迁移数据。

  • 使用容器快照进行迁移Docker 提供了容器快照功能,可以将容器的状态和数据保存为一个快照文件,然后在其他环境中加载该快照文件,从而迁移数据。

Docker 网络

Docker 网络是容器间通信的基础,它提供了不同容器之间的网络连接和通信能力。**Docker 默认的网络是 bridge 网络,它是一种虚拟的以太网桥,用于连接未指定网络配置的容器。**除了 bridge 网络之外Docker 还提供了其他网络驱动类型,如 hostipvlanmacvlanoverlay 等,用于满足不同的网络需求。

  • 自动连接:当启动容器时,如果没有明确指定网络,容器会自动加入到 bridge 网络。这种默认行为简化了容器间通信的设置。
  • 隔离与通信bridge 网络允许容器之间相互通信,但默认情况下对外部网络是不可见的。要从外部访问容器内的应用,需要设置端口映射。
  • 内部 DNS 解析Docker 为 bridge 网络提供了内部 DNS 解析,容器可以使用其他容器的名字进行相互通信,而不是依赖于 IP 地址,提高了配置的灵活性和容器间互联的便利性。

网络管理

Docker 网络的管理涉及以下几个方面:

步骤 1: 创建自定义网络

首先,我们可以创建一个自定义的网络,以实现更好的网络隔离和通信管理。

docker network create --driver bridge my-custom-network

这个命令创建了一个名为 my-custom-network 的新网络,使用的是 bridge 驱动。

步骤 2: 在自定义网络中启动容器

现在,我们可以在这个新创建的网络中启动容器了。例如,我们可以运行一个简单的 web 应用容器:

docker run -d --name my-web-app --network my-custom-network -p 8080:80 nginx

这个命令做了几件事情:

  • -d:以 detached 模式运行容器,即在后台运行。
  • --name my-web-app:给容器指定一个名称,这里是 my-web-app
  • --network my-custom-network:指定容器加入 my-custom-network 网络。
  • -p 8080:80:将容器内部使用的端口 80 映射到宿主机的端口 8080 上。这意味着,你可以通过访问宿主机的 8080 端口来访问容器内部运行的 Nginx 服务。

步骤 3: 验证网络和端口映射

在容器启动后,你可以使用以下命令来检查网络设置和端口映射是否按预期工作:

docker container inspect my-web-app

这个命令会输出很多信息,包括容器的网络配置。你可以查找到 Networks 部分,确保容器已经加入到 my-custom-network 网络。同时,查看 Ports 部分,确认端口映射设置正确。

步骤 4: 访问你的 Web 应用

既然我们已经将容器的 80 端口映射到了宿主机的 8080 端口,你可以通过浏览器访问 http://<宿主机IP>:8080 来查看 Nginx 的欢迎页面。这表明你的容器已经成功运行,并且端口映射工作正常。

网络类型

Docker 提供了多种网络类型,可以根据需求选择合适的网络驱动和配置。下面是一个关于 Docker 网络驱动的表格整理:

网络驱动 介绍 优点 缺点 配置方式 适用场景
Bridge 默认网络驱动,创建桥接网络 简单易用,容器之间可以互相通信 容器与宿主机之间的网络性能有一定损耗 docker network create --driver bridge my-bridge-network 多个容器需要在同一网络中进行通信
Host 容器直接使用宿主机网络栈 最大化网络性能,容器与宿主机共享网络资源 容器与宿主机之间的网络隔离性较弱 在运行容器时使用 --network host 参数 需要容器与宿主机共享网络资源的场景
IPvlan 容器直接使用宿主机物理网络接口 容器与外部网络直接通信,性能较好 需要满足宿主机网络接口的限制,配置较为复杂 docker network create --driver ipvlan my-ipvlan-network 需要容器具有独立的 IP 地址的场景
Macvlan 容器直接使用宿主机物理网络接口 容器与外部网络直接通信,性能较好 需要满足宿主机网络接口的限制,配置较为复杂 docker network create --driver macvlan my-macvlan-network 需要容器具有独立的 MAC 和 IP 地址的场景
Overlay 多主机网络,用于跨主机容器通信 容器可以在多个主机之间进行通信,支持跨主机容器编排和服务发现 需要配置额外的网络管理工具和服务 使用 Docker Swarm 模式创建 Overlay 网络 多主机环境下需要容器之间进行通信的场景
None 容器不连接到任何网络 提供完全的网络隔离,适用于一些特殊的使用场景 容器无法与其他容器或外部网络进行通信 在运行容器时使用 --network none 参数 需要在容器中运行一些网络隔离的工具或测试环境

桥接网络Bridge Network

桥接网络是 Docker 默认网络的一种模式它允许容器通过一个虚拟网桥接口连接到宿主机的物理网络。这种网络模式下Docker 会为每个容器分配一个唯一的 IP 地址,并使用 NAT网络地址转换技术将容器内部的 IP 地址映射到宿主机的 IP 地址上,从而实现容器与外部网络的通信。

要创建一个桥接网络,可以使用以下命令:

docker network create my-bridge-network

主机网络Host Network

主机网络模式允许容器直接使用宿主机的网络栈,与宿主机共享网络命名空间。这意味着容器将使用宿主机的 IP 地址和端口,与宿主机一样具有与外部网络通信的能力。这种模式适用于需要容器与宿主机共享网络资源的场景,但也带来了安全性和隔离性的考虑。

要在容器中使用主机网络模式,可以在运行容器时使用 --network host 参数:

docker run --network host my-container

当涉及到 Docker 网络连接时,除了桥接网络、主机网络和 None 网络之外还有两种重要的网络连接方式ipvlan 和 macvlan。这两种连接方式可以提供更高级的网络功能和更好的性能。下面我们将深入了解这两种网络连接方式的概念、用法和适用场景。

IPvlan Network

IPvlan 是一种网络连接方式,允许容器直接使用宿主机的网络接口,并为每个容器分配独立的 MAC 和 IP 地址。与桥接网络不同IPvlan 不需要进行 NAT 转换,从而提供了更好的性能和更低的延迟。

在 IPvlan 中,有两种模式可供选择:

  • L2 模式Layer 2 mode容器可以直接使用宿主机的网络接口每个容器分配一个独立的 MAC 地址。这种模式适用于需要容器与外部网络直接通信的场景,如虚拟机迁移和容器之间的高性能通信。
  • L3 模式Layer 3 mode容器使用宿主机的网络接口并为每个容器分配一个独立的 IP 地址。这种模式适用于需要容器与外部网络进行通信,但不需要直接与其他容器通信的场景。

使用 IPvlan 连接容器

要在 Docker 中使用 IPvlan 连接容器,需要满足以下要求:

  • 宿主机的内核版本必须支持 IPvlan。
  • 宿主机的网络接口必须支持多播multicast

以下是使用 IPvlan 连接容器的示例命令:

docker network create -d ipvlan --subnet=192.168.0.0/24 --gateway=192.168.0.1 -o parent=eth0 my-ipvlan-network

docker run --network=my-ipvlan-network --ip=192.168.0.2 my-container

在上面的示例中,我们创建了一个名为 my-ipvlan-network 的 IPvlan 网络,并将容器连接到该网络。容器被分配了一个 IP 地址192.168.0.2),并使用了宿主机的 eth0 接口。

Macvlan Network

Macvlan 是另一种网络连接方式,允许容器直接使用宿主机的网络接口,并为每个容器分配独立的 MAC 地址。与 IPvlan 类似Macvlan 也提供了更好的性能和更低的延迟。

在 Macvlan 中,有三种模式可供选择:

  • 桥接模式Bridge mode容器使用宿主机的网络接口并分配一个独立的 MAC 地址。这种模式适用于需要容器与外部网络直接通信的场景。
  • VEPA 模式Virtual Ethernet Port Aggregator mode容器使用宿主机的网络接口并分配一个独立的 MAC 地址。这种模式适用于需要容器与外部网络通信,并且需要在物理网络上进行流量分析的场景。
  • Private 模式:容器使用宿主机的网络接口,并分配一个独立的 MAC 地址。这种模式适用于需要容器与外部网络通信,但不需要与其他容器直接通信的场景。
使用 Macvlan 连接容器

要在 Docker 中使用 Macvlan 连接容器,需要满足以下要求:

  • 宿主机的内核版本必须支持 Macvlan。
  • 宿主机的网络接口必须支持 promiscuous 模式。

以下是使用 Macvlan 连接容器的示例命令:

docker network create -d macvlan --subnet=192.168.0.0/24 --gateway=192.168.0.1 -o parent=eth0 my-macvlan-network

docker run --network=my-macvlan-network --ip=192.168.0.2 my-container

在上面的示例中,我们创建了一个名为 my-macvlan-network 的 Macvlan 网络,并将容器连接到该网络。容器被分配了一个 IP 地址192.168.0.2),并使用了宿主机的 eth0 接口。

None 网络

None 网络模式是一种特殊的网络模式,它表示容器不连接到任何网络。在这种模式下,容器只能与它自己隔离,并且无法与其他容器或外部网络进行通信。这种模式适用于一些特殊的使用场景,例如需要在容器中运行一些网络隔离的工具或测试环境。

要在容器中使用 None 网络模式,可以在运行容器时使用 --network none 参数:

docker run --network none my-container

自定义网络

Docker 允许用户创建自定义网络,以满足特定的网络需求。自定义网络可以提供更好的隔离性、灵活性和可管理性。

1. 创建自定义网络

首先,确定你需要的网络类型。Docker 支持多种网络类型(例如,bridgeoverlaymacvlan),但对于大多数单宿主场景,bridge 类型是最常用的。

可以使用以下命令创建具有自定义子网和网关的 bridge 类型网络:

docker network create --driver bridge --subnet=192.168.1.0/24 --gateway=192.168.1.1 my-custom-network
选项 描述
--driver 指定网络的驱动类型。常用的驱动有 bridgeoverlaymacvlan 等。
--subnet 定义网络的 IP 地址范围。例如,--subnet=192.168.1.0/24 指定了一个包含 256 个可能 IP 地址的网络。
--ip-range 指定允许分配给容器的 IP 地址范围。它必须在 --subnet 指定的范围内。
--gateway 定义网络的网关地址。容器将使用这个地址作为出口网关。
--aux-address 为网络上的特定用途保留 IP 地址。例如,可以为网络服务保留地址。
--ipam-driver 指定 IP 地址管理IPAM驱动默认是 default
--ipam-opt 传递给 IPAM 驱动的选项。
--opt-o 设置驱动特定的选项和参数。例如,-o com.docker.network.bridge.name=docker1 可以设置桥接网络的名称。
--label 为网络添加元数据标签。

2. 指定容器的网络设置

在你的自定义网络中启动容器时,可以使用 --ip 选项为容器指定一个固定的 IP 地址:

docker run -d --name my-container --network my-custom-network --ip=192.168.1.5 nginx

确保指定的 IP 地址在 --subnet 指定的范围内。

如果需要,可以在启动容器时通过 --dns 选项指定一个或多个 DNS 服务器:

docker run -d --name my-container --network my-custom-network --dns=8.8.8.8 nginx
选项 描述
--dns 设置容器使用的 DNS 服务器的 IP 地址。
--dns-search 设置容器 DNS 搜索域名用于解析未完全限定的域名FQDN
--dns-option 设置容器 DNS 解析器的内部选项。

3. 管理和验证网络配置

创建网络和容器后,可以使用以下命令查看网络的详细信息,验证配置是否正确:

docker network inspect my-custom-network

这将显示网络的配置详情,包括分配给网络中容器的 IP 地址。

为了测试容器间的网络通信,可以在两个或更多容器之间进行 ping 测试,确保它们能够相互通信。

Docker Swarm 模式下的网络

Docker Swarm 是 Docker 的集群管理和编排工具,用于在多个 Docker 守护进程上运行和管理容器。在 Docker Swarm 模式下,网络的管理和配置与单个 Docker 守护进程的方式有所不同。Docker Swarm 提供了一种名为 Overlay 网络的特殊网络类型,用于实现跨主机容器的通信。

Overlay 网络

Overlay 网络是一种多主机网络,它允许在 Docker Swarm 集群中的多个节点上创建和管理网络。Overlay 网络使用 VXLANVirtual Extensible LAN技术来实现容器之间的通信提供了跨主机的网络隔离和连接。

要创建一个 Overlay 网络,需要先初始化一个 Docker Swarm 集群,然后使用以下命令创建网络:

docker network create --driver overlay my-overlay-network

这将创建一个名为 my-overlay-network 的 Overlay 网络。

在 Overlay 网络中启动服务

在 Overlay 网络中启动服务与在普通网络中启动服务类似,只需将服务加入到 Overlay 网络即可。以下是一个示例命令:

docker service create --name my-service --network my-overlay-network nginx

这将在 Swarm 集群中启动一个名为 my-service 的服务,并将其加入到 my-overlay-network 网络中。服务将在 Swarm 集群中的多个节点上运行,并通过 Overlay 网络进行通信。

跨主机通信

在 Overlay 网络中容器可以跨主机进行通信无需显式配置。Docker Swarm 使用内置的路由和负载均衡机制来处理跨主机通信。

例如,如果在 Swarm 集群中有两个节点,分别是 Node1 和 Swarm 节点上的网络管理有一些特殊考虑。

Overlay 网络

Overlay 网络是 Docker Swarm 模式下的一种网络类型,它允许在多个 Swarm 节点之间创建跨主机的容器网络。Overlay 网络提供了容器之间的透明通信,并支持容器的动态伸缩和服务发现。

要创建一个 Overlay 网络,可以使用以下命令:

docker network create --driver overlay my-overlay-network

在创建 Overlay 网络时Docker 会自动配置网络的路由和负载均衡,使得容器可以在不同的 Swarm 节点上进行通信。

跨主机通信

在 Docker Swarm 模式下,容器可以在不同的 Swarm 节点上运行。为了实现跨主机的容器通信,需要使用 Overlay 网络。

以下是在 Swarm 模式下实现跨主机通信的一般步骤:

  1. 创建一个 Overlay 网络:

    docker network create --driver overlay my-overlay-network
    
  2. 在 Swarm 中创建服务:

    docker service create --name my-service --network my-overlay-network my-image
    

    这将在 Swarm 中创建一个名为 my-service 的服务,并将其连接到 my-overlay-network 网络。

  3. 根据需要进行扩展:

    docker service scale my-service=3
    

    这将将 my-service 服务的副本数扩展到 3 个。

  4. 验证容器间的通信:

    docker exec -it <container_id> ping <container_name>
    

    使用上述命令在一个容器中执行 ping 命令,以验证与另一个容器的通信。

负载均衡

在 Docker Swarm 模式下Overlay 网络提供了内置的负载均衡功能。当多个副本的服务容器运行在不同的 Swarm 节点上时Docker 会自动将流量分发到这些容器上,实现负载均衡。

负载均衡是通过 Swarm 内部的 DNS 解析和代理实现的。当一个服务容器被创建时Docker 会自动为该容器分配一个虚拟 IP 地址,并将其注册到内部 DNS 服务中。当其他容器或外部客户端访问该服务时DNS 解析会将请求路由到可用的服务副本上。

下面是一个在 Docker Swarm 模式下创建 Overlay 网络和服务的操作示例:

  1. 创建一个 Overlay 网络:

    docker network create --driver overlay my-overlay-network
    
  2. 构建一个包含 Web 应用的镜像:

    docker build -t my-web-app .
    
  3. 将镜像推送到 Docker 镜像仓库:

    docker push my-web-app:latest
    
  4. 在 Swarm 中创建一个服务:

    docker service create --name my-service --network my-overlay-network -p 8080:80 my-web-app
    

    这将在 Swarm 中创建一个名为 my-service 的服务,并将其连接到 my-overlay-network 网络。同时,将容器内部的 80 端口映射到宿主机的 8080 端口上,以便从外部访问该服务。

  5. 验证服务是否正常运行:

    curl http://localhost:8080
    

    如果一切正常,你应该能够看到 Web 应用返回的内容。

Docker 镜像

Dockerfile 是一个文本文件,包含了一系列指令和参数,用于自动化构建 Docker 镜像。每条指令都会在镜像中创建一个新的层,涵盖了从基础镜像开始、复制文件、运行命令、设置环境变量等多种操作。通过 Dockerfile可以确保镜像的构建过程是可重复且无差异的这对于持续集成和持续部署CI/CD的实施至关重要。

Dockerfile

Dockerfile 的开发是一个循环的过程,涉及编写、构建、测试、优化和维护,旨在创建高效、可维护且可重复使用的 Dockerfile以生成高质量的 Docker 镜像。

以下是 Dockerfile 开发的常规工作流程:

graph TD
    A[需求分析] --> B[编写 Dockerfile]
    B --> C[构建镜像]
    C --> D[测试镜像]
    D --> E{满足需求?}
    E -->|是| F[优化和迭代]
    E -->|否| G[维护和更新]
    F --> H[分享和部署]
    G --> B
    H --> I[结束]

关键步骤:

  1. 定义基础镜像:从一个已有的镜像开始,这是所有后续操作的基础。
  2. 执行构建命令:安装软件包、修改配置文件等。
  3. 添加文件和目录:将所需文件和目录添加到镜像中。
  4. 设置工作目录:为 Dockerfile 中的指令指定工作目录。
  5. 配置环境变量:设定必要的环境变量。
  6. 暴露端口:声明容器监听的端口。
  7. 配置启动命令:设置容器启动时执行的命令。

指令

指令 描述 示例
FROM 指定基础镜像,是构建新镜像的起点。 FROM ubuntu:18.04
RUN 在镜像构建过程中运行命令。 RUN apt-get update && apt-get install -y nginx
CMD 提供容器启动时的默认执行命令。 CMD ["nginx", "-g", "daemon off;"]
ENTRYPOINT 配置容器启动时运行的命令,可以与 CMD 指令配合使用。 ENTRYPOINT ["./app"]
COPY 将文件从构建上下文复制到镜像中。 COPY . /app
ADD 将文件从构建上下文或 URL 复制到镜像中,可自动解压压缩包。 ADD http://example.com/big.tar.xz /usr/src/things/
ENV 设置环境变量。 ENV MY_VAR=value
EXPOSE 声明容器运行时监听的端口。 EXPOSE 80
VOLUME 创建一个挂载点来持久化数据。 VOLUME /data
WORKDIR 为 Dockerfile 中的指令设置工作目录。 WORKDIR /app
ARG 定义构建时的变量,可以在构建命令中用 --build-arg 来覆盖。 ARG VERSION=latest
USER 指定运行容器时的用户名或 UID以及可选的用户组或 GID。 USER www-data
LABEL 为镜像添加元数据。 LABEL version="1.0"
ONBUILD 为镜像指定触发器指令,当镜像作为基础镜像时,触发器将在派生镜像中执行。 ONBUILD RUN echo 'Doing something...'
HEALTHCHECK 指定一个命令,用于检查容器是否健康运行。 `HEALTHCHECK CMD curl --fail http://localhost:80/
SHELL 用于覆盖默认的 shell 命令。 SHELL ["/bin/bash", "-c"]
STOPSIGNAL 设置停止容器时发送的系统调用信号。 STOPSIGNAL SIGTERM

示例

# 指定基础镜像
FROM python:3.8

# 设置工作目录
WORKDIR /app

# 复制依赖文件到容器中
COPY requirements.txt ./

# 安装依赖
RUN pip install --no-cache-dir -r requirements.txt

# 将当前目录下的所有文件复制到容器的工作目录中
COPY . .

# 暴露端口
EXPOSE 5000

# 定义容器启动时执行的命令
CMD ["flask", "run", "--host=0.0.0.0"]

镜像构建

镜像构建是 Docker 使用中的核心概念,它允许用户从一个基础镜像开始,通过一系列步骤添加自定义的层次,最终创建出一个新的镜像。深入了解镜像构建,包括二次构建(多阶段构建)等高级特性,可以帮助你更高效地使用 Docker优化你的开发和部署流程。

  • DockerfileDockerfile 是构建 Docker 镜像的蓝图,它包含了一系列的指令,每个指令都会在镜像中创建一个新的层。
  • 镜像层Docker 镜像是由多个只读层组成的。当你更改镜像并提交这些更改时,你实际上是在基础镜像上添加了一个新层。
  • 构建上下文:构建上下文是指向 Docker 守护进程的一组文件和目录,这些文件和目录用于构建 Docker 镜像。构建上下文的路径可以在 docker build 命令中指定。

基本构建

使用 docker build 命令和 Dockerfile 来构建镜像。在构建过程中Docker 逐条处理 Dockerfile 中的指令,每条指令都会创建镜像的一个新层。构建完成后,你将获得一个可用于创建容器的镜像。

docker build -t my_image_name:my_tag .

这个命令将使用当前目录中的 Dockerfile 来构建镜像,并将其标记为 my_image_name:my_tag

多阶段构建

多阶段构建是 Docker 17.05 版本引入的一个特性,它允许在一个 Dockerfile 中定义多个构建阶段,每个阶段都可以使用不同的基础镜像。多阶段构建的主要优点是减小最终镜像的大小,提高构建效率,避免在最终镜像中包含不必要的文件。

  • 定义多个阶段:可以通过在 Dockerfile 中多次使用 FROM 指令来定义多个构建阶段。
  • 复制阶段间的文件:使用 COPY --from=<stage> 指令可以从一个阶段复制文件到另一个阶段。
# 第一阶段:构建阶段
# 使用官方 Python 镜像作为构建镜像的基础
FROM python:3.8-slim as builder

# 设置工作目录
WORKDIR /app

# 将应用依赖复制到容器中
COPY requirements.txt .

# 安装应用依赖
RUN pip install --user -r requirements.txt

# 复制应用代码到容器中
COPY . .

# 第二阶段:运行阶段
# 再次从一个干净的 Python 镜像开始
FROM python:3.8-slim

# 创建一个非 root 用户
RUN useradd -m myuser
USER myuser

# 从构建阶段复制已安装的依赖
COPY --from=builder /root/.local /home/myuser/.local
COPY --from=builder /app /app

# 设置工作目录
WORKDIR /app

# 设置环境变量
ENV PATH=/home/myuser/.local/bin:$PATH

# 暴露应用端口
EXPOSE 5000

# 设置容器启动时执行的命令
CMD ["python", "app.py"]

优化构建

  • 减少层的数量:合并多个 RUN 指令可以减少镜像层的数量,减小镜像大小。
  • 使用 .dockerignore 文件:通过定义 .dockerignore 文件排除不必要的文件和目录,减少构建上下文的大小,加快构建速度。
  • 利用构建缓存Docker 会缓存每一层的结果,如果 Dockerfile 中的某一层没有变化,则在构建时会重用这一层的缓存。合理利用构建缓存可以显著提高构建效率。

镜像管理

Docker 提供了多种命令来管理本地存储的镜像:

命令 描述 示例
docker imagesdocker image ls 列出本地所有镜像 docker images
docker rmi <image> 删除指定的镜像 docker rmi nginx:latest
docker inspect <image> 显示镜像的详细信息 docker inspect ubuntu:18.04
docker pull <image> 从远程仓库拉取指定的镜像 docker pull python:3.8-slim
docker push <image> 将本地镜像推送到远程仓库 docker push myusername/myimage:tag
docker build -t <tag> . 根据当前目录的 Dockerfile 构建镜像 docker build -t myapp:v1 .
docker history <image> 查看镜像的构建历史 docker history nginx:latest
docker tag <image> <tag> 为镜像添加一个新标签 docker tag myimage:latest myimage:v2
docker save -o <path> <image> 将镜像保存为 tar 归档文件 docker save -o myimage.tar myimage:latest
docker load -i <path> 从 tar 归档文件中加载镜像 docker load -i myimage.tar
docker image prune 删除未被任何容器使用的悬挂镜像 docker image prune
docker image rm <image> 删除一个或多个镜像 docker image rm myimage1 myimage2

镜像仓库

Docker 镜像仓库扮演着在 Docker 生态系统中极为关键的角色,它们不仅存储和分发容器镜像,还促进了开发和运维工作的协同。这些仓库可以是公开的,也可以是私有的,以满足不同的安全和隐私需求。

Docker Hub 是最广为人知的 Docker 镜像仓库,提供了大量的公共镜像供下载和使用。它支持个人和组织管理镜像,并能与自动化构建和测试流程无缝集成。

对于需要控制镜像访问权限的场景,私有 Docker 仓库是理想的选择。私有仓库可以部署在内部网络中确保敏感镜像的安全。Docker Registry 是官方提供的开源仓库解决方案,支持本地部署和管理私有镜像。

使用 Docker Hub 拉取镜像

从 Docker Hub 或私有仓库拉取镜像是常见操作。使用 docker pull 命令可以轻松完成这一任务:

docker pull my_username/my_image_name:my_tag

推送镜像到 Docker Hub

1. 创建 Docker Hub 账号

如果你还没有 Docker Hub 的账号,你需要先在 Docker Hub 上注册一个。

2. 登录到 Docker Hub

在终端或命令行界面,使用 docker login 命令登录到你的 Docker Hub 账号。输入你的用户名和密码进行认证。

docker login

成功登录后,你的认证信息将被保存,以便后续操作无需重复登录。

3. 标记你的镜像

在推送镜像之前你需要为你的镜像设置一个标签Tag这个标签应该包含你的 Docker Hub 用户名、镜像的名字,以及(可选的)标签。

docker tag local-image-name:tag your-dockerhub-username/repository-name:tag
  • local-image-name:tag 是你本地镜像的名称和标签。
  • your-dockerhub-username 是你在 Docker Hub 上的用户名。
  • repository-name 是你希望在 Docker Hub 上创建的仓库名。
  • tag 是你给镜像指定的标签,如果不指定,默认为 latest

例如,如果你的 Docker Hub 用户名是 johndoe,并且你想要推送一个名为 myapp 的镜像,标签为 v1.0,你可以执行:

docker tag myapp:latest johndoe/myapp:v1.0
4. 推送镜像到 Docker Hub

使用 docker push 命令将镜像推送到你的 Docker Hub 仓库:

docker push your-dockerhub-username/repository-name:tag

继续之前的例子:

docker push johndoe/myapp:v1.0

这个命令会将 myapp 镜像的 v1.0 标签版本推送到 Docker Hub 上的 johndoe/myapp 仓库中。

5. 验证

推送完成后,你可以在 Docker Hub 的网站上登录你的账号,查看你的仓库列表,确认新推送的镜像已经出现在列表中。

推送镜像到私人仓库

推送镜像到私人仓库的过程与推送到 Docker Hub 类似,但需要确保你有权限访问该私人仓库,并且可能需要配置额外的认证信息。以下是推送镜像到私人仓库的一般步骤:

1. 登录私人仓库

私有仓库通常需要认证,以保证仓库的安全性。使用 docker login 命令进行登录,确保你拥有足够的权限来推送镜像。

docker login myregistry.example.com
2.标记你的镜像

在推送镜像之前,需要将其标记为私人仓库的地址。这是通过 docker tag 命令完成的,标记格式通常为 仓库地址/用户名/镜像名称:标签

docker tag my_image_name:my_tag myregistry.example.com/my_username/my_image_name:my_tag

这里:

  • my_image_name:my_tag 是你本地镜像的名称和标签。
  • myregistry.example.com 是你的私人仓库地址。
  • my_username 是你在该仓库的用户名或命名空间。
3. 推送镜像

完成镜像标记后,使用 docker push 命令将其推送到私人仓库。

标记完成后,使用 docker push 命令将镜像推送到私人仓库:

docker push myregistry.example.com/my_username/my_image_name:my_tag
4. 管理私人仓库中的镜像

私人仓库可能提供了一个用户界面或者 API供你管理仓库中的镜像包括查看、删除和设置访问权限等。

5. 使用私人仓库中的镜像

从私人仓库拉取镜像时,同样需要先进行认证。一旦认证通过,你可以使用 docker pull 命令拉取所需的镜像。

docker pull myregistry.example.com/my_username/my_image_name:my_tag

Docker Compose

Docker Compose 是一种工具,用于定义和运行多容器 Docker 应用程序。通过使用 Compose你可以使用 YAML 文件来配置你的应用服务。然后,只需一个简单的命令,就能创建并启动你配置中的所有服务。

Docker Compose 允许你使用 YAML 文件来定义多个容器的应用服务,包括网络、卷等其他资源。这种方法可以让你将整个应用的配置集中管理,极大地简化了容器管理过程。

  • 简化配置:使用 YAML 文件定义服务,使得配置过程更加简单明了。
  • 一键部署:多容器应用可以通过一个命令同时启动,无需分别操作每个容器。
  • 易于维护和扩展:服务的更新和扩展可以通过修改配置文件实现,易于管理。

安装

Docker Compose 的安装过程取决于你的操作系统。在大多数情况下,它可以作为 Docker Desktop 的一部分自动安装,或者可以单独安装。

在 Linux 上安装

curl -L "https://github.com/docker/compose/releases/download/v2.24.6/docker-compose-linux-x86_64" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

基本命令

命令 描述
docker-compose up 构建、(重新)创建、启动和连接到服务的容器。使用 -d 参数以后台模式运行。
docker-compose down 停止并移除容器、网络、卷和镜像。
docker-compose build 构建或重新构建服务中定义的镜像。
docker-compose logs 查看服务的日志输出。
docker-compose pull 拉取服务依赖的镜像。
docker-compose push 将服务镜像推送到 Docker Hub 或其他镜像仓库。
docker-compose restart 重启服务。
docker-compose start 启动已经存在的服务容器。
docker-compose stop 停止运行中的容器,不移除它们。
docker-compose pause 暂停服务中的容器。
docker-compose unpause 恢复服务中已暂停的容器。
docker-compose rm 删除所有(停止状态的)服务容器。
docker-compose run 在一个服务上运行一次性命令。
docker-compose exec 在服务的容器中执行命令。
docker-compose scale 设置服务的容器数量。(注:在 3.x 版本中已被 docker-compose up --scale 代替)
docker-compose config 验证并查看 Compose 文件的配置。
docker-compose top 显示运行中的容器的进程。
docker-compose port 打印绑定的公开端口。
docker-compose ps 列出项目中目前的所有容器。
docker-compose version 显示 Docker Compose 的版本信息。

如果你想操作特定的一个 Docker Compose 编排,你应该在该编排文件所在的目录下执行相应的 docker-compose 命令,并使用 -f 参数指定你的编排文件(如果不是使用默认的 docker-compose.yml 文件名)。

管理应用

让我们通过一个简单的示例来展示如何使用 Docker Compose 管理多容器应用。

示例应用

下面创建一个 docker-compose.yml 文件,定义一个简单的 web 应用服务。

app.py
from flask import Flask
from redis import Redis

app = Flask(__name__)
redis = Redis(host='redis', port=6379)

@app.route('/')
def hello():
    count = redis.incr('hits')
    return 'Hello World! 该页面已被访问 {} 次。\n'.format(count)

if __name__ == "__main__":
    app.run(host="0.0.0.0", debug=True)
Dockerfile
FROM python:3.6-alpine
ADD . /code
WORKDIR /code
RUN pip install redis flask
CMD ["python", "app.py"]
docker-compose.yml
version: '3'
services:

  web:
    build: .
    ports:
     - "5000:5000"

  redis:
    image: "redis:alpine"

启动应用

使用 docker-compose up 命令来启动应用Docker Compose 会自动启动定义的所有服务。

docker-compose up -d

停止应用

当你完成工作后,可以使用 docker-compose down 命令来停止并清理应用服务。

docker-compose down

Compose 文件

Docker Compose 文件是 Docker Compose 的核心,它使用 YAML 文件格式定义了多容器 Docker 应用的所有服务、网络和卷。

文件结构

一个基本的 docker-compose.yml 文件包含三个主要部分services服务、networks网络和 volumes

下面是一个简单的示例,展示了这些组件如何被定义和关联:

version: '3'
services:
  web:
    image: nginx
    ports:
      - "80:80"
    depends_on:
      - db
    networks:
      - backend
  db:
    image: postgres
    environment:
      POSTGRES_PASSWORD: mysecretpassword
    volumes:
      - db-data:/var/lib/postgresql/data
    networks:
      - backend

networks:
  backend:

volumes:
  db-data:
服务Services

services 部分,你定义了应用中的各个服务,每个服务可以是一个容器,在上面的例子中,有两个服务:webdb

  • image: 指定服务使用的镜像。
  • ports: 映射端口到宿主机。
  • depends_on: 表示服务之间的依赖关系。
  • networks: 指定服务连接的网络。
  • environment: 设置环境变量。
网络Networks

networks 部分,你可以定义一个或多个网络,服务可以连接到这些网络。在上例中,定义了一个名为 backend 的网络,webdb 服务都连接到了这个网络,使得它们可以相互通信。

Volumes

volumes 部分,你定义了数据卷用于数据持久化。在上例中,db-data 卷被挂载到了 db 服务的容器中,用于存储数据库数据。

语法

graph LR
    A[Docker Compose] --> B[Services]
    A --> C[Volumes]
    A --> D[Networks]
    A --> E[Configs]
    A --> F[Secrets]

    B --> G[Service 1]
    B --> H[Service 2]
    B --> I[Service N]
    
    G --> J[Image/Build]
    G --> K[Environment]
    G --> L[Ports]
    G --> M[Depends On]
    G --> N[Volumes]
    G --> O[Networks]

    C --> P[Volume 1]
    C --> Q[Volume 2]
    C --> R[Volume N]

    D --> S[Network 1]
    D --> T[Network 2]
    D --> U[Network N]

    E --> V[Config 1]
    E --> W[Config 2]

    F --> X[Secret 1]
    F --> Y[Secret 2]

    J --> J1[Type: Image or Build Path]
    K --> K1[Variables]
    L --> L1[Container:Host]
    M --> M1[Service Dependencies]
    N --> N1[Service:Volume Mapping]
    O --> O1[Service Networks]

    P --> P1[Driver]
    Q --> Q1[Driver Options]

    S --> S1[Driver]
    T --> T1[Driver Options]

    V --> V1[File or External]
    W --> W1[File or External]

    X --> X1[File or External]
    Y --> Y1[File or External]

关键字

配置项 描述
build 定义了构建服务的配置,可以是一个构建上下文的路径,或者一个包含 contextdockerfileargs 的对象。
cap_add, cap_drop 添加或删除容器的能力。
cgroup_parent 指定容器的父 cgroup。
command 覆盖容器的默认命令。
configs 为服务提供对配置的访问。
container_name 指定自定义容器名称。
credential_spec 配置管理服务帐户的凭据规范。
depends_on 表达服务之间的依赖关系。
deploy 指定与服务部署和运行相关的配置。
devices 设备映射列表。
dns, dns_search 自定义 DNS 服务器和搜索域。
entrypoint 覆盖容器的默认入口点。
env_file 从文件中加载环境变量。
environment 设置环境变量。
expose 暴露端口而不发布到宿主机。
external_links 链接到 Docker Compose 外部的容器。
extra_hosts 添加主机名映射。
healthcheck 配置容器的健康检查。
image 指定服务使用的镜像。
init 使用 Docker 的 init 进程。
labels 添加标签到容器。
links 链接到其他服务的容器。
logging 配置日志记录。
network_mode 网络模式。
networks 配置网络。
pid PID 模式。
ports 发布端口。
secrets 配置访问秘密。
security_opt 安全选项。
stop_grace_period 设置停止前的等待时间。
stop_signal 设置停止容器的信号。
sysctls 内核参数设置。
tmpfs 挂载临时文件系统。
ulimits 用户限制。
user 指定运行用户。
userns_mode 用户命名空间模式。
volumes, volume_driver 配置卷。
volumes_from 从其他服务或容器挂载卷。
working_dir 工作目录。

服务配置详解

构建选项

如果你不是使用现有的镜像,而是需要构建自定义镜像,可以使用 build 选项:

version: '3'
services:
  webapp:
    build: ./dir

环境变量

你可以直接在 docker-compose.yml 文件中为服务设置环境变量,或者使用 .env 文件来管理:

version: '3'
services:
  web:
    image: nginx
    environment:
      - NGINX_PORT=80

依赖关系

使用 depends_on 选项可以定义服务启动的先后顺序:

version: '3'
services:
  web:
    image: nginx
    depends_on:
      - db
  db:
    image: postgres

端口映射

通过 ports 选项,可以将容器内的端口映射到宿主机的端口:

version: '3'
services:
  web:
    image: nginx
    ports:
      - "80:80"

环境变量与 .env 文件的使用

管理配置和敏感信息时,推荐使用 .env 文件来外部定义环境变量,然后在 docker-compose.yml 文件中引用这些变量:

.env 文件:

DB_PASSWORD=mysecretpassword

docker-compose.yml 文件:

version: '3'
services:
  db:
    image: postgres
    environment:
      POSTGRES_PASSWORD: ${DB_PASSWORD}

通过这种方式,你可以避免将敏感信息直接硬编码在 docker-compose.yml 文件中,而是将其存储在外部的 .env 文件中,这有助于保持你的配置的安全性和灵活性。

多容器应用管理

在 Docker Compose 的使用中,管理多容器应用是核心任务之一。这包括了如何定义和运行多容器应用、如何管理容器间的网络连接以及如何实现数据的持久化和共享。

定义与运行多容器应用

利用 docker-compose.yml 文件,开发者可以定义涵盖多个服务(容器)的完整应用架构,实现一键部署和管理。

考虑到一个典型的三层应用架构,包含前端、后端及数据库层:

version: '3.8'
services:
  frontend:
    image: nginx:latest
    ports:
      - "80:80"
    depends_on:
      - backend
    networks:
      - app-network

  backend:
    image: node:14
    environment:
      DB_HOST: db
    ports:
      - "3000:3000"
    depends_on:
      - db
    networks:
      - app-network

  db:
    image: postgres:13
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
    volumes:
      - db-data:/var/lib/postgresql/data
    networks:
      - app-network

volumes:
  db-data:

networks:
  app-network:

在这个例子中,我们指定了使用的镜像、环境变量、端口映射、依赖关系、网络和数据卷。通过这样的配置,可以确保应用的各个部分能够正确连接和交互,同时数据也得到了持久化。

网络管理

Docker Compose 默认创建一个网络,使得同一 docker-compose.yml 文件中定义的所有服务都能够在这个网络中相互通信。然而,复杂应用可能需要更精细的网络配置来满足不同的安全和隔离需求。

自定义网络配置允许服务根据实际需求分配到不同的网络中,实现更细致的网络隔离和通信策略。

networks:
  app-network:
    driver: bridge
  internal-network:
    driver: bridge
    internal: true

在上述配置中,app-network 用于暴露外部可访问的服务(如前端),而 internal-network 则用于内部服务间的通信,不对外部暴露,增强了安全性。

数据卷与持久化

数据持久化对于任何生产级应用都至关重要Docker Compose 通过卷volumes提供了数据持久化的能力。

volumes:
  db-data:
    driver: local

这里定义了一个名为 db-data 的卷,用于 PostgreSQL 数据库的数据持久化存储。通过指定卷,即使容器重新创建,数据也不会丢失。

Docker Compose 也支持定义卷来实现服务之间的数据共享:

services:
  service1:
    volumes:
      - shared-data:/path/to/data
  service2:
    volumes:
      - shared-data:/path/to/data

volumes:
  shared-data:

在此配置中,service1service2 共享了同一个卷 shared-data,允许它们访问和修改相同的数据集,这在需要数据共享的应用场景中非常有用。

高级功能

Docker Compose 不仅仅是一个多容器部署工具,它还提供了一系列高级功能和最佳实践,帮助开发者和运维人员优化应用配置和管理。本章节将深入探讨服务的健康检查、如何使用 extends 特性以及如何通过覆盖文件分离环境配置。

服务的健康检查

健康检查是监控服务状态和健康状况的重要手段。通过配置健康检查Docker 可以自动检测服务是否正常运行。

docker-compose.yml 文件中,可以为服务配置 healthcheck 指令:

services:
  web:
    image: my-web-app
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

这个配置定义了一个健康检查,每 30 秒执行一次 curl -f http://localhost 命令来检查 web 服务的健康状态,如果命令在 10 秒内没有成功执行(即返回状态码非 0则认为是一次失败。如果连续 3 次检查失败,则服务被认为是不健康的。

扩展与重写服务

extends 特性允许在一个服务中重用另一个服务的配置。这对于不同环境下的配置共享非常有用。

假设有一个基础服务配置 base-service.yml

version: '3.8'
services:
  app_base:
    image: my-app
    environment:
      - DEBUG=false

可以在 docker-compose.yml 中扩展这个服务:

version: '3.8'
services:
  app:
    extends:
      file: base-service.yml
      service: app_base
    ports:
      - "80:80"

通过这种方式,app 服务继承了 app_base 的所有配置,并添加了端口映射。

使用覆盖文件来分离环境配置

Docker Compose 允许使用多个文件来定义项目配置,这使得可以针对不同环境(如开发、测试、生产)使用不同的配置。

基础 docker-compose.yml 文件定义了所有环境共有的配置:

version: '3.8'
services:
  web:
    image: my-web-app
    environment:
      - LOG_LEVEL=info

针对开发环境的 docker-compose.override.yml

version: '3.8'
services:
  web:
    environment:
      - DEBUG=true
    volumes:
      - .:/code

在生产环境的 docker-compose.prod.yml

version: '3.8'
services:
  web:
    ports:
      - "80:80"
    environment:
      - LOG_LEVEL=warning

通过指定 -f 参数来使用不同的配置文件:

docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d

这种方法使得基础配置与环境特定配置分离,便于管理和维护。

Docker 实战项目

本实战项目将引导你构建一个简单的 Web 应用,该应用包含三个主要组件:前端(使用 Nginx 静态文件服务),后端(一个简单的 Node.js API以及数据库PostgreSQL。此外我们还将探讨如何调试这些服务并进行基本的性能优化。

Web 实战项目

项目概述

  • 前端:使用 Nginx 服务静态文件。
  • 后端Node.js 应用提供 RESTful API。
  • 数据库PostgreSQL 存储数据。

docker-compose.yml

version: '3.8'
services:
  frontend:
    image: nginx:alpine
    volumes:
      - ./frontend:/usr/share/nginx/html
    ports:
      - "80:80"
    depends_on:
      - backend
    networks:
      - app-network

  backend:
    build:
      context: ./backend
      dockerfile: Dockerfile
    environment:
      DATABASE_URL: postgres://user:password@db:5432/mydb
    ports:
      - "3000:3000"
    depends_on:
      - db
    networks:
      - app-network

  db:
    image: postgres:13
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
      POSTGRES_DB: mydb
    volumes:
      - db-data:/var/lib/postgresql/data
    networks:
      - app-network

volumes:
  db-data:

networks:
  app-network:

前端

前端使用 Nginx 静态文件服务。你需要在 ./frontend 目录下放置你的静态文件HTML、CSS、JavaScript 文件等)。

后端

后端是一个简单的 Node.js 应用,提供 RESTful API。你需要在 ./backend 目录下创建一个 Dockerfile 和你的 Node.js 应用代码。

./backend/Dockerfile

FROM node:14-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]

Node.js 服务器

// server.js
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;

app.get('/api', (req, res) => {
  res.json({ message: "Hello from the backend!" });
});

app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});

数据库

使用 PostgreSQL 作为数据库服务。docker-compose.yml 文件中已经配置了必要的环境变量。

调试与优化

容器日志查看

使用 Docker Compose 查看服务日志的命令:

docker-compose logs -f backend

这将跟踪并显示后端服务的实时日志输出。

资源监控与性能优化

Docker Desktop 和其他第三方工具如 Portainer 或 cAdvisor 可用于监控容器的资源使用情况。基于监控数据,你可以对服务进行必要的调整,比如调整容器的 CPU 和内存限制:

services:
  backend:
    build: ./backend
    mem_limit: 500m
    cpus: '0.5'

docker-compose.yml 文件中,为后端服务设置了内存限制为 500MBCPU 使用限制为 50%。

Docker 命令手册

容器生命周期管理

命令 说明
docker run [OPTIONS] IMAGE [COMMAND] [ARG...] 创建一个新容器并运行一个命令
docker start CONTAINER 启动一个或多个已经停止的容器
docker stop CONTAINER 停止一个或多个正在运行的容器
docker restart CONTAINER 重启一个或多个容器
docker kill CONTAINER 强制停止一个或多个正在运行的容器
docker rm CONTAINER 删除一个或多个容器
docker pause CONTAINER 暂停一个或多个容器的所有进程
docker unpause CONTAINER 恢复一个或多个容器的所有进程
docker create [OPTIONS] IMAGE [COMMAND] [ARG...] 创建一个新的容器但不启动它
docker exec [OPTIONS] CONTAINER COMMAND [ARG...] 在运行的容器中执行一个命令

容器操作

命令 说明
docker ps [OPTIONS] 列出容器
docker inspect [OPTIONS] TARGET 返回 Docker 对象的底层信息
docker top CONTAINER [ps OPTIONS] 显示容器的运行进程
docker attach CONTAINER 连接到正在运行的容器
docker events [OPTIONS] 从服务器获取实时事件
docker logs [OPTIONS] CONTAINER 获取容器的日志
docker wait CONTAINER 阻塞到容器停止,然后打印退出代码
docker export CONTAINER 将文件系统作为一个 tar 归档文件导出到 STDOUT
docker port CONTAINER [PRIVATE_PORT[/PROTO]] 列出容器的端口映射,或打印指定端口的映射
docker stats [OPTIONS] [CONTAINER...] 实时显示容器的资源使用统计信息

网络管理

命令 说明
docker network ls 列出所有网络
docker network inspect NETWORK 显示指定网络的详细信息
docker network create [OPTIONS] NETWORK 创建一个新的网络
docker network connect NETWORK CONTAINER 将一个容器连接到指定网络
docker network disconnect NETWORK CONTAINER 从网络中断开容器
docker network rm NETWORK 删除一个或多个网络

卷管理

命令 说明
docker volume ls 列出所有卷
docker volume inspect VOLUME 显示指定卷的详细信息
docker volume create [OPTIONS] [VOLUME] 创建一个新的卷
docker volume rm VOLUME 删除一个或多个卷
docker volume prune 删除所有未使用的卷

Docker Compose

命令 说明
docker-compose up [OPTIONS] 启动并运行服务
docker-compose down [OPTIONS] 停止并删除容器、网络等资源
docker-compose ps 列出服务状态
docker-compose logs [OPTIONS] 查看服务的日志
docker-compose build [OPTIONS] 构建或重新构建服务
docker-compose exec SERVICE COMMAND 在指定服务的容器中执行命令

安全与权限管理

命令 说明
docker update [OPTIONS] CONTAINER 更新一个或多个容器的资源限制
docker rename CONTAINER NEW_NAME 重命名容器
docker checkpoint create CONTAINER CHECKPOINT 创建容器的检查点
docker checkpoint ls CONTAINER 列出容器的所有检查点
docker checkpoint rm CONTAINER CHECKPOINT 删除容器的检查点

配置管理

命令 说明
docker config create CONFIG_NAME FILE 从文件创建新的配置
docker config ls 列出所有配置
docker config inspect CONFIG 显示指定配置的详细信息
docker config rm CONFIG 删除指定配置

多主机集群管理 (Swarm 模式)

命令 说明
docker swarm init 初始化一个新的 Swarm 集群
docker swarm join [OPTIONS] 将节点加入到 Swarm 集群
docker swarm leave [OPTIONS] 让当前节点离开 Swarm 集群
docker node ls 列出所有集群节点
docker service create [OPTIONS] IMAGE [COMMAND] [ARG...] 创建一个新服务
docker service ls 列出所有服务
docker service rm SERVICE 删除一个服务
docker stack deploy [OPTIONS] STACK 部署一个新的应用堆栈
docker stack rm STACK 删除一个应用堆栈

容器 Rootfs 命令

命令 说明
docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]] 从容器创建一个新的镜像
`docker cp [OPTIONS] CONTAINERDEST_PATH -`
docker diff CONTAINER 检查在容器文件系统上所做的更改

镜像仓库

命令 说明
docker login [OPTIONS] [SERVER] 登录 Docker 的镜像仓库
`docker pull [OPTIONS] NAME[ @DIGEST]`
docker push [OPTIONS] NAME[:TAG] 将镜像或仓库推送到镜像仓库
docker search [OPTIONS] TERM 在 Docker Hub 中搜索镜像

本地镜像管理

命令 说明
docker images [OPTIONS] [REPOSITORY[:TAG]] 列出镜像
docker rmi [OPTIONS] IMAGE [IMAGE...] 删除一个或多个镜像
docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG] 为源镜像创建一个新的别名标签
`docker build [OPTIONS] PATH URL
docker history [OPTIONS] IMAGE 显示镜像的历史
docker save [OPTIONS] IMAGE [IMAGE...] 将一个或多个镜像保存为 tar 归档文件
docker load [OPTIONS] 从 tar 归档文件加载一个或多个镜像
`docker import [OPTIONS] file URL

系统信息

命令 说明
docker info [OPTIONS] 显示系统级信息
docker version [OPTIONS] 显示 Docker 版本信息