Docker简介

Docker 是什么?

Docker

Docker 是一个开源的应用容器引擎,它允许开发者将应用及其所有依赖(比如库、框架、配置文件等)打包到一个轻量级、可移植的容器中。然后,这个容器可以在任何安装了 Docker 的机器上运行,无论是开发者的笔记本电脑、测试服务器还是生产环境的云主机,都能保证环境的一致性。

可以通过一个简单的比喻来描述 Docker。我们将 Docker 想象成一个“标准化的集装箱”,在没有集装箱之前,货物(应用)形状各异,运输(部署)起来非常麻烦。而集装箱(Docker 容器)把所有货物(应用和它的依赖)都打包成标准尺寸,这样就可以用同样的工具(Docker 引擎)在任何港口(服务器)之间轻松地搬运、装卸,而不用关心里面装的是什么。

核心概念:镜像、容器与仓库

  • 镜像(Image) 镜像就好比一个模板,我们可以通过这个模板来创建容器服务。Docker 镜像 是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像 不包含 任何动态数据,其内容在构建之后也不会被改变。

  • 容器(Container) 镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的 对象 一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。 容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的命名空间(了解过C++的小伙伴应该很熟悉,命名空间就是为了防止各种调用时不同“环境”之下出现冲突)。因此容器可以拥有自己的 root 文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。这种特性使得容器封装的应用比直接在宿主运行更加安全。也因为这种隔离的特性,很多人初学 Docker 时常常会混淆容器和虚拟机。

  • 仓库(Repository) 仓库就是存放镜像(image)的地方,仓库又可以分为公有和私有仓库。Docker 官方运营维护了一个官方仓库 Docker Hub ,很多需求都可以通过在 DockerHub 直接下载满足。

为什么需要 Docker?

相信很多人都曾遇到过一种非常棘手且令人恼火的问题,那就是 “为什么在我的电脑上跑不起来?” Docker的出现就是为了解决这个问题的!Docker 不仅确保了代码的可复现性,还提供了一个隔离的运行环境。在开发过程中,我们可以在容器内自由安装依赖、修改系统配置,而不会影响宿主机的环境。

Docker 和虚拟机技术的区别

其实乍一看 Docker 和虚拟机很像,都是在一台计算机中虚拟出了另一个计算机空间来运行需要环境以及程序。在容器技术出来之前,我们都是使用虚拟机技术,但是现在 Docker 的出现使得我们可以更加轻巧地使用这种技术。事实上,虚拟机是属于虚拟化技术,Docker容器技术,也是一种虚拟化技术

  • 虚拟机技术:通过软件模拟的具有完整硬件系统功能的、运行在一个完全隔离环境中的完整计算机系统 缺点:- 资源占用多、冗余步骤多、启动慢

  • 容器化技术:(容器化技术不是模拟的一个完整的操作系统) 容器内的应用可以直接运行在宿主 主机的内核中,容器没有自己的内核,也不用虚拟硬件; 每个容器是相互隔离的,每个容器内都有属于自己的文件系统,之间互不影响。

Docker 为什么比VM(虚拟机)快?

  1. Docker有着比虚拟机更少的抽象层。

  2. Docker利用的是宿主机的内核,VM需要是Guest OS,无需再加载一个操作系统。 可以这么想:当你用同一台手机打开一个应用软件的速度一定比这个手机开机的速度要快。

特性
容器
虚拟机

启动

秒级

分钟级

硬盘使用

一般为 MB

一般为 GB

性能

接近原生

系统支持量

单机支持上千个容器

一般几十个

二、安装 Docker

在安装过程中,每个人都可能有不同的情况,因此建议直接上网搜索相关教程并结合个人情况进行安装,详细教程推荐内容见[[#参考文章]],或参考安装DockerDocker安装

三、Docker 镜像使用

Docker镜像是用于创建Docker容器的模板。它是一个只读的文件,包含了运行容器所需的所有指令、文件和依赖项。可以把它想象成一个操作系统的“快照”,但它更轻量级,只包含运行特定应用程序所需的内容。

获取和管理镜像

1. 拉取镜像

从Docker Hub(默认的公共镜像仓库)或其他仓库拉取镜像,使用 docker pull 命令。

docker pull ubuntu:20.04 

2. 查看镜像列表

使用 docker imagesdocker image ls 命令查看本地已有的镜像。

docker images

3. 为镜像添加标签

使用 docker tag 命令为镜像添加一个新的标签,方便识别和管理。

docker tag ubuntu:20.04 my-ubuntu:latest

4. 查看镜像详情

使用 docker inspect 命令可以查看镜像的详细信息,包括镜像的层次结构、配置等。

docker inspect my-ubuntu:latest

5. 搜索镜像

在Docker Hub上搜索可用的镜像。

docker search mysql

6. 删除镜像

使用 docker rmidocker image rm 命令删除不再需要的本地镜像。

docker rmi my-ubuntu:latest

创建镜像

创建自己的镜像是Docker的核心功能之一。主要有两种方法:

1. 从容器创建镜像

这种方法适合快速创建一个临时的镜像,但不推荐用于生产环境,因为它不够透明和可重复。

  • 启动一个容器

    docker run -it ubuntu /bin/bash
  • 在容器中进行修改 (例如,安装一个软件)

    apt-get update && apt-get install -y vim
  • 退出容器

  • 使用 docker commit 创建新镜像

    docker commit [容器ID] my-custom-ubuntu:v1

2. 使用 Dockerfile 创建镜像 (推荐)

Dockerfile 是一个文本文件,包含了一系列指令,用于自动化地构建镜像。这是创建镜像的最佳实践,因为它保证了构建过程的透明、可重复和可追溯。

Dockerfile 基本指令

  • FROM: 指定基础镜像。

  • RUN: 在镜像构建过程中执行命令。

  • COPY: 将文件从主机复制到镜像中。

  • ADD: 功能与 COPY 类似,但更强大,可以解压压缩文件。

  • CMD: 指定容器启动时默认执行的命令。

  • ENTRYPOINT: 配置容器启动时执行的命令,更适合用于定义容器的主要功能。

  • WORKDIR: 设置工作目录。

  • ENV: 设置环境变量。

  • EXPOSE: 声明容器运行时监听的端口。

创建 Dockerfile 示例

创建一个名为 Dockerfile 的文件:

# 使用官方的 Ubuntu 20.04 作为基础镜像
FROM ubuntu:20.04

# 设置作者信息
LABEL author="Your Name"

# 更新软件包列表并安装 Nginx
RUN apt-get update && apt-get install -y nginx

# 将本地的 index.html 文件复制到 Nginx 的网站根目录
COPY index.html /var/www/html/

# 声明容器将监听 80 端口
EXPOSE 80

# 容器启动时,在前台运行 Nginx
CMD ["nginx", "-g", "daemon off;"]

构建镜像

在包含 Dockerfile 的目录下运行 docker build 命令。

docker build -t my-nginx:1.0 .

镜像的导入和导出

1. 保存镜像

将镜像保存为一个 tar 归档文件,方便在没有网络的环境下迁移。

docker save -o my-nginx.tar my-nginx:1.0

2. 加载镜像

docker load -i my-nginx.tar

3. 导出和导入镜像 (与 save/load 的区别)

  • docker export:导出的是一个容器的文件系统快照,会丢失镜像的历史记录和元数据。

  • docker import:导入一个容器快照作为镜像。 这种方式通常用于创建基础镜像,而不是迁移应用镜像。


创建 Dockerfile 的最佳实践

  • 使用 .dockerignore 文件:排除不需要包含在镜像中的文件,减小镜像体积。

  • 选择合适的基础镜像:尽量选择轻量级的基础镜像,如 alpine

  • 合并 RUN 指令:将多个 RUN 指令合并,减少镜像层数。

  • 清理临时文件:在 RUN 指令中清理软件包缓存等临时文件。

  • 充分利用构建缓存:将不经常变动的内容放在 Dockerfile 的前面。

  • 使用多阶段构建:对于编译型语言,可以使用多阶段构建来减小最终镜像的体积。

Tips:更多内容请参阅:Docker镜像使用 (利用commit理解镜像构成、构建多系统架构支持的Docker镜像、DockerFile多阶段构建、其他制作镜像的方法)


四、Docker 容器操作

容器是 Docker 又一核心概念。

简单的说,容器是独立运行的一个或一组应用,以及它们的运行态环境。对应的,虚拟机可以理解为模拟运行的一整套操作系统(提供了运行态环境和其他系统环境)和跑在上面的应用。

启动容器

启动Docker容器主要有两种方式,核心区别在于你是要创建新容器还是重启旧容器

新建并启动 (docker run)

此命令基于一个镜像来创建一个全新的容器并运行它。这可以理解为从“安装包”启动一个全新的程序。

docker run 的背后,Docker执行了一套标准操作,这也是其核心原理:

  • 检查/获取镜像:检查本地是否存在所需镜像,如果没有则从远程仓库下载。

  • 创建文件系统:在只读的镜像层之上,挂载一个可读写的容器层。

  • 网络配置:为容器连接到网络并分配IP地址。

  • 执行命令:运行你在命令中指定的应用程序(例如 /bin/bash)。

  • 终止:当指定的应用程序执行完毕后,容器会自动停止。

例如,使用 docker run -it [镜像名] /bin/bash 可以启动一个交互式终端,让你进入容器内部进行操作。其中 -i-t 参数是关键,它们共同为你分配了一个可以交互的伪终端(pseudo-tty)。

启动已终止容器 (docker start)

此命令用于将一个已经存在但处于终止状态的容器重新启动。它不会创建任何新东西,只是让旧的容器再次运行起来。

容器轻量级的核心原理

容器的本质就是其内部运行的应用程序进程

与虚拟机(VM)不同,容器内没有独立的操作系统内核和其他多余的服务。如果你在一个容器里用 ps 命令查看进程,你会发现只有你指定的那个应用(比如 bash)在运行。正因为这种极简的结构,Docker才能实现极高的资源利用率,成为名副其实的轻量级虚拟化技术。


守护态运行

通常,部署服务(如网站)时,我们需要让容器在后台持续运行,而不是让它占据当前的终端窗口。这就是守护态(Daemonized)模式。

核心参数 -d

实现后台运行的关键是在 docker run 命令中加入 -d 参数。

  • 不加 -d:容器在前台运行,所有输出会直接显示在你的终端上。

  • 加上 -d:Docker 会将容器放在后台运行,你的终端会立刻被释放,并返回一个唯一的容器ID。这个ID是后续管理该容器的重要凭证。

如何查看后台容器

容器在后台运行后,你需要用其他命令来与它交互:

  • 查看状态:使用 docker container ls 可以列出所有正在运行的容器,包括它们的ID、状态等信息。

  • 查看日志:使用 docker logs [容器ID] 可以获取该后台容器的输出日志,这是调试和监控后台应用的主要方式。

重要原理

容器能否持久运行,取决于其内部执行的命令,而与是否使用 -d 参数无关。

例如,一个执行 echo "hello" 的命令,无论是否加 -d,都会在输出 "hello" 后立即退出。而一个运行 web 服务器的命令,则会持续运行。-d 参数只决定容器是在前台还是后台运行,并不能决定其“生死”。


终止容器

当不再需要容器运行时,你需要正确地停止它。容器的生命周期会自然结束,也可以被我们主动终止。

两种终止方式

  1. 自动终止:这是最常见的方式。容器的核心是其内部运行的进程,当该主进程结束时,容器的生命周期也就随之结束,自动进入终止状态。例如,在一个交互式容器中执行 exit 命令,容器就会停止。

  2. 手动终止 (docker container stop):你可以使用此命令来主动停止一个正在前台或后台运行的容器。该命令会向容器发送一个停止信号,让其优雅退出。

终止后的状态

被终止的容器并不会被删除,而是进入终止状态(Exited)。你可以通过 docker container ls -a 命令看到所有容器,包括这些已经终止的容器。

相关的重启操作

  • docker container start:可以重新启动一个处于终止状态的容器。

  • docker container restart:这是一个便捷命令,它会先停止一个正在运行的容器,然后立即再重新启动它。


进入容器

当容器在后台运行时,我们有时需要进入其内部进行操作。有两个主要命令可以实现:docker attachdocker exec,但强烈推荐使用 docker exec

不推荐的方式:docker attach

  • 工作原理:此命令会将你的终端直接**“附加”到容器内正在运行的主进程(PID 1)**的标准输入输出上。

  • 致命缺点:因为你直接控制了容器的主进程,一旦你从这个终端中退出(例如使用 exit 命令),主进程就会结束,从而导致整个容器停止运行。这在生产环境中通常是灾难性的。

推荐的方式:docker exec

  • 工作原理docker exec 不会附加到主进程,而是在容器内启动一个全新的、独立的进程(例如,一个新的 bash 终端)。

  • 核心优势:你在这个新进程中的所有操作都与容器的主进程无关。当你退出时,只是结束了这个新创建的进程,容器本身的主应用会继续正常运行,不会受到任何影响

  • 常用方法:使用 docker exec -it [容器ID] bash 命令,通过 -i(交互式)和 -t(分配终端)参数,可以获得一个功能完整的、我们所熟悉的Linux命令行界面。

总而言之,始终推荐使用 docker exec,因为它提供了一种安全、隔离的方式进入容器进行操作,不会有误操作导致整个容器停止的风险。


导出与导入

1. 导出容器 (docker export)

此命令用于创建一个容器快照。它会将指定容器当前的文件系统打包成一个 .tar 文件,这个文件里只包含当时的文件,不包含其他任何信息。

# 将容器快照导出为 tar 文件
docker export [容器ID] > container_snapshot.tar

2. 导入快照 (docker import)

此命令会读取一个容器快照(.tar 文件),并将其转换为一个新的Docker镜像

# 从快照文件导入,并指定新镜像的名称和标签
cat container_snapshot.tar | docker import - new_image:v1.0

核心原理:importload 的关键区别

理解 docker import 的关键在于将其与 docker load 进行对比:

  • docker import

    • 操作对象:容器快照(由 export 创建)。

    • 结果丢弃所有的历史记录和元数据信息。它只关心容器在快照那一刻的文件系统状态,最终生成一个全新的、扁平化的、只有单层的镜像。

  • docker load

    • 操作对象:镜像存储文件(由 save 创建)。

    • 结果完整地保留镜像的所有分层历史、标签和元数据。它用于完美地还原一个镜像,体积通常比容器快照大得多。

简单来说,export/import 是创建和导入一个“干净”的文件系统快照,而 save/load 则是完整地备份和还原整个镜像本身。


删除容器

停止的容器并不会自动消失,它们依然会占用磁盘空间,因此需要手动删除。

删除单个容器 (docker container rm)

这是用于删除指定容器的命令。它遵循一个重要的安全原则:

  • 默认行为:仅能删除处于终止状态的容器。这可以防止你意外删除正在运行中的重要应用。

  • 强制删除:如果要删除一个运行中的容器,必须添加 -f 参数。此操作会强制停止并删除容器,应谨慎使用。

一键清理 (docker container prune)

当系统中存在大量已停止的容器时,逐个删除非常繁琐。docker container prune 命令提供了一个便捷的方式,可以一键清理掉所有处于终止状态的容器,是保持系统整洁的好帮手。

Tips: 更多内容参阅容器操作


五、访问仓库

仓库(Repository)是集中存放镜像的地方。 一个容易混淆的概念是注册服务器(Registry)。实际上注册服务器是管理仓库的具体服务器,每个服务器上可以有多个仓库,而每个仓库下面有多个镜像。

Docker Hub

Docker Hub 是 Docker 官方维护的公共镜像仓库,如同一个巨大的应用商店,包含了数百万个镜像,绝大多数需求都可以通过它来满足。

1. 账号与登录

要分享自己的镜像,你首先需要在 Docker Hub 网站上免费注册一个账号。之后,通过 docker login 命令在你的终端登录,或通过 docker logout 退出。

2. 查找与拉取镜像

  • 查找 (docker search):此命令可以根据关键词在 Docker Hub 上搜索镜像。

  • 拉取 (docker pull):此命令用于将远程仓库的镜像下载到你的本地。

搜索时,你需要了解两种不同类型的镜像:

  • 官方镜像:名称通常是单个单词(如 centos, ubuntu)。由 Docker官方维护,纯净、安全、可靠。

  • 用户镜像:名称格式为 用户名/镜像名(如 ansible/centos7-ansible)。由社区用户创建和维护。

3. 推送个人镜像

分享你自己创建的镜像,主要有两个步骤:

  1. 标记镜像 (docker tag):在推送前,必须先将你的镜像重命名为符合 Docker Hub 要求的 用户名/镜像名:标签 的格式。

    # 示例:将本地的 my-app:1.0 标记为你的用户名下的镜像
    docker tag my-app:1.0 your-username/my-app:1.0
  2. 推送镜像 (docker push):将标记好的镜像上传到 Docker Hub。

    docker push your-username/my-app:1.0

私有仓库:搭建自己的镜像库

有时,出于网络、安全或合规性的考虑,使用公共的 Docker Hub 并不方便。此时,你可以利用 Docker 官方提供的 registry 工具,轻松搭建一个完全由自己控制的私有镜像仓库。

1. 启动私有仓库服务

最简单的方式就是直接以容器方式运行官方的 registry 镜像。

docker run -d -p 5000:5000 --name registry registry

核心原理:数据持久化 上面的命令有一个问题:所有上传的镜像都保存在容器内部。一旦容器被删除,数据就会丢失。为了解决这个问题,我们必须通过 -v 参数将容器内的数据目录挂载到宿主机上,实现数据持久化

# 将镜像数据保存在宿主机的 /opt/data/registry 目录
docker run -d \
    -p 5000:5000 \
    -v /opt/data/registry:/var/lib/registry \
    --restart=always \
    --name registry \
    registry

2. 使用私有仓库

使用私有仓库的流程与 Docker Hub 完全一致,唯一的区别是在镜像名称前加上了私有仓库的地址作为前缀 (私有仓库地址/镜像名)。

  1. 标记 (tag):为本地镜像打上指向私有仓库的新标签。

    # 假设私有仓库地址为 192.168.1.10:5000
    docker tag my-app:latest 192.168.1.10:5000/my-app:latest
  2. 推送 (push):将标记好的镜像上传到私有仓库。

    docker push 192.168.1.10:5000/my-app:latest
  3. 拉取 (pull):从其他机器上下载镜像。

    docker pull 192.168.1.10:5000/my-app:latest

3. 核心问题:配置 HTTP 访问

当你使用 IP 地址(如 192.168.1.10:5000)作为仓库地址时,会发现推送失败。

  • 问题原因:出于安全考虑,Docker 客户端默认只信任 HTTPS 协议的仓库,并拒绝向不安全的 HTTP 仓库推送镜像

  • 解决方案:你必须在每一个需要访问该仓库的 Docker 客户端上,修改配置文件,明确将你的私有仓库地址加入“不安全的仓库”白名单,以信任该地址

对于主流的 Linux 系统或 Docker Desktop,你需要编辑(或创建)Docker 的配置文件 /etc/docker/daemon.json,并加入以下内容:

{
  "insecure-registries": ["192.168.1.10:5000"]
}

修改后,重启 Docker 服务即可生效。

Tips: 更多内容参考访问仓库 (Nexus 3、私有仓库高级配置)


六、数据管理

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

数据卷 (Volumes):容器的持久化存储

数据卷是 Docker 中用于数据持久化的核心机制。你可以将其理解为一个专为容器设计的、独立于容器生命周期的“虚拟硬盘”。

核心特性与原理

数据卷的设计初衷,就是为了将数据容器的生命周期解耦。它有以下关键特性:

  • 持久化:数据卷默认会一直存在,即使使用它的容器被删除,数据卷及其中的数据也不会丢失。

  • 独立性:对数据卷的任何修改,都直接发生在数据卷上,不会影响到镜像本身。

  • 共享性:同一个数据卷可以被多个不同的容器同时挂载,实现容器间的数据共享。

  • 性能:数据卷绕过了容器的写时复制(Copy-on-Write)文件系统,拥有更好的读写性能。

重要工作原理:当你将一个空的数据卷挂载到容器内一个非空的目录时,Docker 会自动将该目录下的文件复制到数据卷中。这个初始化过程只发生一次,确保了你的应用能以预期的文件状态启动。

管理与使用

管理和使用数据卷主要通过 docker volume 系列命令和 docker run--mount 参数。

  1. 创建与挂载: 你可以先用 docker volume create my-vol 创建一个“命名数据卷”,然后在启动容器时通过 --mount 参数将其挂载到指定路径。

    # 推荐使用 --mount 参数挂载数据卷
    docker run -d \
        --name my-nginx \
        --mount source=my-vol,target=/usr/share/nginx/html \
        nginx

source 是数据卷的名称,target 是容器内的挂载点。

  1. 查看与检查

    • docker volume ls:列出所有的数据卷。

    • docker volume inspect [卷名]:查看某个数据卷的详细信息,包括它在宿主机上的实际存储位置。

生命周期与清理

这是使用数据卷时必须理解的关键点:

  • Docker 不会自动删除数据卷:为了保护数据,当你用 docker rm 删除容器时,其挂载的命名数据卷不会被删除。

  • 清理无主数据卷:长期下来,系统中可能会积累大量不再被任何容器使用的“无主”数据卷。你可以使用以下命令安全地清理它们:

    docker volume prune
  • 删除指定数据卷:如果你确定某个数据卷不再需要,可以用 docker volume rm [卷名] 将其删除。

挂载主机目录 (Bind Mounts)

除了由 Docker 管理的“数据卷”外,Docker 还提供了另一种强大的数据共享方式:直接映射 (Bind Mount) 一个主机上的目录或文件到容器中。

这与上一节的“数据卷”是两种不同的机制。数据卷由 Docker 在特定目录中进行管理,而绑定挂载则是由用户指定主机上的任意路径。

核心用法与适用场景

绑定挂载最核心的应用场景是开发和测试。你可以将本地的项目代码目录直接映射到容器中运行服务的目录。这样,你在主机上用编辑器修改代码,无需重新构建镜像,容器内就能立刻看到变更,极大地提升了开发效率。

  • 推荐语法:使用 --mount 参数,并指定 type=bind

  # 将主机的 /path/to/my/code 目录挂载到容器的 /app 目录
  docker run -d \
      --name my-dev-container \
      --mount type=bind,source=/path/to/my/code,target=/app \
      my-app-image
  • 关键原则

    • source 必须是主机上的绝对路径

    • 与旧的 -v 参数不同,使用 --mount 时,如果 source 路径在主机上不存在,Docker 会报错而不是自动创建,这是一种更安全的行为。

控制读写权限

默认情况下,绑定挂载是可读写的。为了安全,你可以通过添加 readonly 选项,将其设置为只读,防止容器修改主机上的文件。

# 以只读方式挂载
--mount type=bind,source=/path/to/my/code,target=/app,readonly

挂载单个文件

绑定挂载的强大之处在于,它不仅能挂载整个目录,也可以挂载单个文件。一个常见的技巧是挂载主机的命令历史文件到容器中,这样你在容器中执行的命令就可以被保存下来。

# 将主机的 bash 历史文件挂载到容器中
--mount type=bind,source=$HOME/.bash_history,target=/root/.bash_history

Tips: 更多内容参考数据管理


七、网络使用

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

外部容器访问

默认情况下,容器内部的网络是与外界隔离的。为了让外部能够访问容器中运行的网络应用(如网站服务),我们必须通过端口映射(Port Mapping)技术,将主机的端口“连接”到容器的端口。

这就像是为一座大楼(主机)里的一个房间(容器)安装一部电话分机,让外线电话(外部请求)可以准确地找到它。

1. 随机端口映射 (-P)

这是最简单快捷的方式。

  • 工作原理:使用大写的 -P 参数,Docker 会自动将容器所有对外暴露的端口,一一映射到主机上的一个随机高位端口。

  • 适用场景:当你不在乎外部访问的具体端口号,只想快速启动一个服务进行测试时,此方法非常方便。

# -P 会为容器的 80 端口随机分配一个主机端口
docker run -d -P nginx

2. 指定端口映射 (-p)

这是最常用、最明确的方式,给予你完全的控制权。

  • 工作原理:使用小写的 -p 参数,你可以精确地指定**“哪个主机端口”映射到“哪个容器端口”**。

  • 适用场景:所有需要稳定、可预测访问地址的场景,例如正式部署网站或数据库服务。

核心语法-p 主机端口:容器端口

# 将主机的 80 端口映射到容器的 80 端口
docker run -d -p 80:80 nginx

高级用法

  • 指定IP:你还可以将端口绑定到主机的特定 IP 地址上,例如 -p 127.0.0.1:80:80,这样就只有本机可以访问。

  • 指定协议:默认为 TCP 协议,你可以通过 /udp 后缀来指定 UDP 端口,例如 -p 53:53/udp

  • 多次使用-p 参数可以在一条命令中多次使用,以映射多个不同的端口。

查看映射配置

如果你忘记了端口映射关系,可以使用 docker port [容器名或ID] 命令来快速查看。

容器互联

在 Docker 的早期,开发者使用 --link 参数来连接容器。然而,这种方式现已过时并被官方不推荐使用

现代 Docker 推荐通过**自定义网络(Custom Networks)**来实现容器间的通信,这是一种更灵活、更强大、更安全的方式。

工作原理与核心优势

其核心优势在于提供了自动的服务发现(Service Discovery)

当你创建一个自定义网络,并将多个容器连接到这个网络上时,Docker 会为这个网络内建一个 DNS 服务。这意味着,网络内的任何一个容器都可以通过容器名称作为主机名,直接访问到另一个容器。

例如,一个名为 webapp 的容器可以直接连接到名为 database 的容器,只需使用 database 这个地址,而无需关心其动态分配的 IP 地址。这极大地简化了多容器应用的配置。

实现步骤

整个过程非常简单,只需两步:

  1. 创建网络 (docker network create) 首先,为你的应用栈创建一个专属的、隔离的桥接网络。

    docker network create my-app-net
  2. 连接容器 (--network) 在启动容器时,使用 --network 参数将其连接到你刚刚创建的网络中。

    # 启动数据库容器并连接到网络
    docker run -d --name database --network my-app-net my-db-image
    
    # 启动应用容器并连接到同一网络
    docker run -d --name webapp --network my-app-net my-app-image

现在,webapp 容器内部就可以通过 ping database 或在代码中使用 database 作为主机名来直接访问数据库容器了。

更进一步:Docker Compose

对于需要多个容器协同工作的复杂应用,手动创建网络和逐个启动容器依然不够高效。在这种场景下,强烈推荐使用 Docker Compose。它允许你在一个 YAML 文件中定义整个多容器应用(包括服务、网络、数据卷等),然后用一条命令即可全部启动和连接,是现代 Docker 多容器编排的事实标准。

配置DNS

Docker 通过巧妙地利用虚拟文件系统,来管理容器的网络身份配置,主要涉及 /etc/hostname/etc/hosts/etc/resolv.conf 这三个文件。

1. Docker 的默认行为:继承主机配置

在默认情况下,Docker 会将宿主主机的 DNS 配置(即 /etc/resolv.conf 文件的内容)直接映射到容器内部。

  • 优点:这种方式非常智能。如果宿主主机的网络环境或 DNS 服务器发生变化,所有容器的 DNS 配置也会自动同步更新,通常情况下你无需任何手动配置。

2. 全局配置:为所有容器设置 DNS

如果你希望所有在本机上运行的容器都使用一组特定的 DNS 服务器(而不是继承自主机),你可以修改 Docker 守护进程的配置文件。

  • 方法:编辑(或创建)/etc/docker/daemon.json 文件,并添加 dns 键。

    {
      "dns": ["114.114.114.114", "8.8.8.8"]
    }

修改并重启 Docker 服务后,之后所有新启动的容器都会默认使用这里设置的 DNS 服务器。

3. 独立配置:为单个容器指定

你也可以在启动单个容器时,为其指定独立的网络配置,这将覆盖全局设置和默认行为。

  • 方法:在 docker run 命令中使用以下参数:

    • --hostname:设定容器内部的主机名。这个名字只在容器内部可见。

    • --dns:为该容器指定一个或多个 DNS 服务器。

    • --dns-search:为容器设定 DNS 搜索域。例如,设置为 .example.com 后,在容器内查找 service 时,DNS 会依次尝试解析 serviceservice.example.com

Tips: 更多内容参考网络使用


参考文章

最后更新于