Docker 基础入门:核心概念与架构原理

在云计算与容器化技术飞速发展的今天,Docker 已经成为开发者必备的工具之一。无论是本地开发环境的一致性保障、持续集成/持续部署(CI/CD)的自动化落地,还是服务器资源的高效利用,Docker 都发挥着不可替代的作用。对于刚接触容器技术的新手而言,想要快速上手 Docker,首先需要理清其核心概念与底层架构,这也是后续深入学习 Docker 进阶用法、解决实际问题的基础。本文将从 Docker 的起源与价值出发,详细拆解核心概念,剖析底层架构,并搭配实用代码示例,帮助大家从零入门 Docker,真正理解其工作原理与使用逻辑。

一、Docker 简介:什么是 Docker,为什么要用它?

1.1 Docker 的定义

Docker 是一个开源的应用容器引擎,基于 Go 语言开发,遵循 Apache 2.0 开源协议。它能够将应用程序及其依赖项打包到一个可移植的容器中,然后发布到任何支持 Docker 的操作系统上,实现"一次打包,到处运行"的效果。与传统的虚拟机技术不同,Docker 容器不依赖于底层操作系统的虚拟化,而是共享宿主机的内核,因此具有启动速度快、资源占用少、可移植性强等优势。

1.2 Docker 的核心价值

在 Docker 出现之前,开发者常常面临"开发环境能跑,生产环境跑不起来"的困境,核心原因在于开发环境、测试环境、生产环境的配置不一致,以及依赖项版本冲突等问题。Docker 的出现,正是为了解决这些痛点,其核心价值主要体现在以下几个方面:

  • 环境一致性:将应用及其依赖(如编程语言、库、配置文件等)打包成容器,容器在任何支持 Docker 的环境中运行时,都能保持一致的运行效果,彻底解决"环境不一致"问题。
  • 资源高效利用:Docker 容器共享宿主机内核,不需要像虚拟机那样占用独立的内存、CPU 和操作系统资源,启动时间通常在秒级,资源利用率远高于虚拟机。
  • 可移植性强:容器可以在本地、服务器、云平台之间自由迁移,只要目标环境支持 Docker,就能直接运行,无需修改任何配置。
  • 简化部署与运维:通过 Docker 可以快速部署应用,实现自动化运维,减少人工操作,降低部署失误的概率,同时便于应用的扩容与缩容。
  • 隔离性良好:每个容器都是独立的运行环境,容器之间相互隔离,不会相互影响,避免了应用之间的冲突,提高了系统的稳定性和安全性。

1.3 Docker 与虚拟机的区别

很多新手会将 Docker 与虚拟机混淆,但两者在底层实现、资源占用、启动速度等方面有本质区别,具体对比如下表所示:

对比维度 Docker 容器 虚拟机(VM)
底层实现 共享宿主机内核,基于容器化技术 虚拟化底层硬件,运行独立操作系统
资源占用 占用资源少,轻量级 占用资源多,重量级
启动速度 秒级启动 分钟级启动
隔离性 进程级隔离,隔离性较弱 系统级隔离,隔离性强
可移植性 强,可跨平台迁移 弱,依赖虚拟化软件和底层系统

简单来说,虚拟机是"模拟一个完整的操作系统",而 Docker 容器是"模拟一个应用的运行环境",两者的定位不同,适用场景也不同。在实际开发中,通常会结合两者的优势,比如用虚拟机提供底层环境,用 Docker 容器部署应用。

二、Docker 核心概念:吃透这5个概念,入门就成功了一半

Docker 有5个核心概念,分别是:镜像(Image)、容器(Container)、仓库(Repository)、Dockerfile、Docker Compose。这5个概念是理解 Docker 工作流程的关键,下面逐一详细讲解,并搭配代码示例,帮助大家快速掌握。

2.1 镜像(Image):容器的"模板"

2.1.1 镜像的定义

镜像(Image)是 Docker 中最基础的概念,它是一个只读的模板,包含了运行应用程序所需的所有文件、依赖项、配置信息和操作系统内核。可以把镜像理解为"容器的模板",一个镜像可以创建多个容器,就像一个类可以实例化多个对象一样。
例如,一个 Nginx 镜像,就包含了 Nginx 服务器的安装文件、配置文件、依赖的库文件等,通过这个镜像,我们可以快速创建多个 Nginx 容器,每个容器都是独立运行的 Nginx 服务。

2.1.2 镜像的核心特性

  • 只读性:镜像一旦创建,就无法修改,只能通过创建新的镜像来实现更新。
  • 分层存储:Docker 镜像采用分层存储技术,每一层都是一个独立的文件系统,层与层之间相互依赖。这种分层结构可以实现镜像的复用,减少存储空间的占用。例如,多个镜像可能共享同一个基础层(如 Ubuntu 系统层),只需要存储一次基础层,就能被多个镜像复用。
  • 可继承性:可以基于一个已有的镜像,通过添加新的层,创建一个新的镜像。例如,基于 Ubuntu 镜像,安装 Python 环境,就能创建一个 Python 镜像。

2.1.3 镜像相关常用命令(代码示例)

下面是镜像操作的常用命令,所有命令均在 Linux 终端(或 Windows Docker Desktop 终端)中执行,大家可以直接复制执行,感受镜像的操作流程。

复制代码
# 1. 拉取镜像(从 Docker Hub 拉取官方镜像)
# 拉取最新版 Nginx 镜像
docker pull nginx:latest
# 拉取指定版本的 Nginx 镜像(如 1.24.0)
docker pull nginx:1.24.0

# 2. 查看本地所有镜像
docker images
# 输出示例:
# REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
# nginx        latest    605c77e624dd   2 weeks ago    142MB
# nginx        1.24.0    08393e824c32   2 months ago   141MB

# 3. 查看镜像详细信息
docker inspect nginx:latest

# 4. 给镜像打标签(便于区分镜像版本)
docker tag nginx:latest my-nginx:v1.0

# 5. 删除本地镜像
# 删除指定标签的镜像
docker rmi nginx:1.24.0
# 强制删除镜像(如果镜像已被容器使用)
docker rmi -f nginx:latest

# 6. 保存镜像为本地文件(便于迁移)
docker save -o nginx.tar nginx:latest

# 7. 加载本地镜像文件
docker load -i nginx.tar

说明:Docker Hub 是 Docker 官方的镜像仓库,包含了大量官方和第三方的镜像,我们可以通过 docker pull 命令直接拉取镜像,无需自己手动构建。

2.2 容器(Container):镜像的"实例"

2.2.1 容器的定义

容器(Container)是基于镜像创建的可运行实例,是 Docker 中用于运行应用程序的载体。如果说镜像是"模板",那么容器就是"模板实例化后的对象",它可以被启动、停止、重启、删除,并且容器之间相互隔离,拥有独立的运行环境。
容器与镜像的关系,就像进程与程序的关系:程序是静态的代码和资源,进程是程序的运行实例;镜像也是静态的模板,容器是镜像的运行实例。

2.2.2 容器的核心特性

  • 可运行性:容器是基于镜像创建的,包含了应用程序的运行环境,能够直接启动并运行应用。
  • 可写性:容器在运行过程中,会在镜像的只读层之上添加一个可写层,所有对容器的修改(如创建文件、修改配置)都会保存在这个可写层中,不会影响原始镜像。
  • 隔离性:每个容器都有自己独立的网络、进程、文件系统,与其他容器和宿主机隔离,避免相互干扰。
  • 轻量级:容器共享宿主机内核,不需要占用独立的操作系统资源,启动速度快,资源占用少。

2.2.3 容器相关常用命令(代码示例)

容器的操作是 Docker 日常使用中最频繁的,下面的命令涵盖了容器的创建、启动、停止、删除、进入等常用操作,建议大家实际操作一遍,加深理解。

复制代码
# 1. 基于镜像创建并启动容器
# 格式:docker run [选项] 镜像名:标签 [容器内执行的命令]
# 示例1:启动 Nginx 容器,后台运行,映射宿主机80端口到容器80端口
docker run -d -p 80:80 --name my-nginx nginx:latest
# 选项说明:
# -d:后台运行容器(守护进程模式)
# -p 80:80:将宿主机的80端口映射到容器的80端口(宿主机端口:容器端口)
# --name my-nginx:给容器命名为 my-nginx,便于后续操作

# 示例2:启动 Ubuntu 容器,进入交互模式(可以在容器内执行命令)
docker run -it --name my-ubuntu ubuntu:latest /bin/bash
# 选项说明:
# -it:交互模式(-i 保持标准输入打开,-t 分配伪终端)
# /bin/bash:容器启动后执行的命令,进入 bash 终端

# 2. 查看正在运行的容器
docker ps
# 查看所有容器(包括已停止的)
docker ps -a

# 3. 启动、停止、重启容器
# 启动已停止的容器
docker start my-nginx
# 停止正在运行的容器
docker stop my-nginx
# 重启容器
docker restart my-nginx

# 4. 进入正在运行的容器(交互模式)
# 方法1:exec 命令(推荐,不会影响容器的运行状态)
docker exec -it my-nginx /bin/bash
# 方法2:attach 命令(进入容器后,退出会导致容器停止)
docker attach my-nginx

# 5. 查看容器日志(用于排查问题)
docker logs my-nginx
# 实时查看日志(类似 tail -f)
docker logs -f my-nginx

# 6. 查看容器详细信息
docker inspect my-nginx

# 7. 删除容器(需先停止容器,或强制删除)
# 删除已停止的容器
docker rm my-nginx
# 强制删除正在运行的容器
docker rm -f my-nginx

# 8. 容器与宿主机之间复制文件
# 宿主机文件复制到容器内:docker cp 宿主机路径 容器名:容器内路径
docker cp /home/test.txt my-nginx:/usr/share/nginx/html
# 容器内文件复制到宿主机:docker cp 容器名:容器内路径 宿主机路径
docker cp my-nginx:/usr/share/nginx/html/index.html /home
实操验证:执行 docker run -d -p 80:80 --name my-nginx nginx:latest 命令后,打开浏览器,访问 http://localhost,如果能看到 Nginx 的默认欢迎页面,说明容器启动成功,端口映射生效。

2.3 仓库(Repository):镜像的"仓库"

2.3.1 仓库的定义

仓库(Repository)是用于存储和管理 Docker 镜像的地方,类似于代码仓库(如 GitHub),我们可以将自己构建的镜像推送到仓库,也可以从仓库拉取别人上传的镜像。
仓库分为公有仓库和私有仓库:

2.3.2 仓库相关常用命令(代码示例)

复制代码
# 1. 登录 Docker Hub(需先注册 Docker Hub 账号)
docker login
# 输入用户名和密码,登录成功后,即可推送镜像到 Docker Hub

# 2. 推送镜像到 Docker Hub(需先给镜像打标签,标签格式:用户名/镜像名:标签)
# 示例:给本地 Nginx 镜像打标签,推送至自己的 Docker Hub 仓库
docker tag nginx:latest your-username/my-nginx:v1.0
docker push your-username/my-nginx:v1.0

# 3. 从 Docker Hub 拉取自己推送的镜像
docker pull your-username/my-nginx:v1.0

# 4. 退出 Docker Hub 登录
docker logout

# 5. 私有仓库相关操作(以 Docker Registry 为例)
# 拉取私有仓库镜像(需先登录私有仓库)
docker login private-registry-url:port
docker pull private-registry-url:port/my-nginx:v1.0
# 推送镜像到私有仓库
docker tag nginx:latest private-registry-url:port/my-nginx:v1.0
docker push private-registry-url:port/my-nginx:v1.0

2.4 Dockerfile:构建镜像的"脚本"

2.4.1 Dockerfile 的定义

Dockerfile 是一个文本文件,包含了一系列的指令(Instruction),用于描述如何构建一个 Docker 镜像。通过 Dockerfile,我们可以自定义镜像的内容,比如安装特定的软件、配置环境变量、复制文件等,实现镜像的自动化构建。
Dockerfile 的核心作用是"标准化镜像构建流程",只要有 Dockerfile,任何人都可以按照相同的步骤构建出相同的镜像,避免了手动构建镜像的繁琐和误差。

2.4.2 Dockerfile 常用指令

Dockerfile 中的指令有固定的格式,通常以大写字母开头,后面跟随具体的参数,常用指令如下:

  • FROM :指定基础镜像,是 Dockerfile 的第一个指令,用于指定构建镜像的基础模板。例如 FROM ubuntu:latest,表示基于最新版的 Ubuntu 镜像构建新镜像。
  • WORKDIR :指定容器运行时的工作目录,后续的指令(如 RUN、COPY)都会在这个目录下执行。例如 WORKDIR /app,表示工作目录为 /app。
  • COPY :将宿主机的文件或目录复制到镜像中。例如 COPY ./app.py /app,表示将宿主机当前目录下的 app.py 文件复制到镜像的 /app 目录下。
  • ADD :与 COPY 类似,也用于复制文件,但支持解压压缩文件和从 URL 下载文件。例如 ADD ./app.tar.gz /app,表示将宿主机的 app.tar.gz 压缩文件复制到镜像的 /app 目录,并自动解压。
  • RUN :在构建镜像时执行命令,用于安装软件、配置环境等。例如 RUN apt update && apt install -y python3,表示更新软件源并安装 Python3。
  • ENV :设置环境变量,在镜像构建和容器运行时都生效。例如 ENV PYTHONPATH=/app,表示设置 Python 的环境变量。
  • EXPOSE :声明容器运行时监听的端口,只是一个声明,不会自动映射端口,需要在 docker run 时使用 -p 选项进行端口映射。例如 EXPOSE 8080,表示容器监听 8080 端口。
  • CMD :指定容器启动时执行的命令,一个 Dockerfile 中只能有一个 CMD 指令,若有多个,只有最后一个生效。例如 CMD ["python3", "app.py"],表示容器启动时执行 python3 app.py 命令。
  • ENTRYPOINT :与 CMD 类似,也用于指定容器启动时执行的命令,但 ENTRYPOINT 的命令不会被 docker run 后面的命令覆盖,而 CMD 会被覆盖。例如 ENTRYPOINT ["python3"],如果执行docker run -it my-image app.py,则容器启动时执行 python3 app.py

2.4.3 Dockerfile 构建镜像示例(代码示例)

下面我们通过一个实际案例,使用 Dockerfile 构建一个 Python 应用镜像,步骤如下:

  1. 创建一个工作目录,新建 Dockerfile 文件和 Python 应用文件(app.py)。
  2. 编写 Dockerfile 指令,定义镜像的构建流程。
  3. 使用 docker build 命令构建镜像。
  4. 基于构建好的镜像启动容器,验证应用是否能正常运行。
复制代码
# 1. 创建工作目录并进入
mkdir python-app && cd python-app

# 2. 新建 app.py 文件(简单的 Python Web 应用,使用 Flask 框架)
cat > app.py << EOF
from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello():
    return "Hello Docker! This is a Python App."

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080)
EOF

# 3. 新建 Dockerfile 文件,编写构建指令
cat > Dockerfile << EOF
# 指定基础镜像(Python 3.10 官方镜像)
FROM python:3.10-slim

# 设置工作目录
WORKDIR /app

# 复制宿主机的 app.py 文件到镜像的 /app 目录
COPY app.py /app

# 安装 Flask 依赖
RUN pip install flask -i https://pypi.tuna.tsinghua.edu.cn/simple

# 声明容器监听的端口
EXPOSE 8080

# 指定容器启动时执行的命令
CMD ["python3", "app.py"]
EOF

# 4. 构建镜像(-t 选项指定镜像标签,格式:镜像名:标签)
docker build -t my-python-app:v1.0 .
# 说明:最后的 "." 表示 Dockerfile 所在的当前目录

# 5. 基于构建好的镜像启动容器,映射 8080 端口
docker run -d -p 8080:8080 --name my-python-app my-python-app:v1.0

# 6. 验证应用是否正常运行(访问 http://localhost:8080,查看是否返回指定内容)
curl http://localhost:8080
验证结果:执行 curl http://localhost:8080 后,如果输出 Hello Docker! This is a Python App.,说明镜像构建成功,容器运行正常。

2.5 Docker Compose:多容器管理工具

2.5.1 Docker Compose 的定义

在实际开发中,一个应用往往需要多个容器协同工作,比如一个 Web 应用需要 Web 容器、数据库容器、缓存容器等。如果手动一个个启动、配置这些容器,会非常繁琐,且容易出错。Docker Compose 就是为了解决多容器管理问题而出现的工具。
Docker Compose 是 Docker 官方提供的多容器编排工具,基于 YAML 文件定义多个容器的配置(如镜像、端口映射、环境变量、依赖关系等),通过一条命令就能启动、停止、重启所有相关容器,实现多容器的自动化管理。

2.5.2 Docker Compose 常用命令与示例(代码示例)

首先需要安装 Docker Compose(Docker Desktop 已内置 Docker Compose,Linux 系统需手动安装),然后通过编写 docker-compose.yml 文件定义多容器配置,最后使用 docker compose 命令进行操作。
下面以"Web 应用 + MySQL 数据库"为例,演示 Docker Compose 的使用:

复制代码
# 1. 创建工作目录并进入
mkdir web-mysql && cd web-mysql

# 2. 新建 docker-compose.yml 文件(核心配置文件)
cat > docker-compose.yml << EOF
version: '3.8'  # 指定 Docker Compose 的版本

# 定义所有服务(容器)
services:
  # 定义 Web 服务(基于之前构建的 my-python-app 镜像)
  web:
    image: my-python-app:v1.0  # 指定镜像
    ports:
      - "8080:8080"  # 端口映射
    depends_on:
      - mysql  # 依赖 mysql 服务,mysql 启动后再启动 web
    environment:  # 设置环境变量(用于连接 MySQL)
      - MYSQL_HOST=mysql
      - MYSQL_USER=root
      - MYSQL_PASSWORD=123456
      - MYSQL_DB=test_db
    restart: always  # 容器异常退出时自动重启

  # 定义 MySQL 服务(使用官方 MySQL 镜像)
  mysql:
    image: mysql:8.0  # 指定 MySQL 镜像版本
    ports:
      - "3306:3306"  # 端口映射,宿主机 3306 端口映射到容器 3306 端口
    environment:  # 设置 MySQL 环境变量
      - MYSQL_ROOT_PASSWORD=123456  # 根密码
      - MYSQL_DATABASE=test_db  # 初始化数据库
    volumes:
      - mysql-data:/var/lib/mysql  # 数据卷挂载,持久化 MySQL 数据
    restart: always

# 定义数据卷(用于持久化数据,避免容器删除后数据丢失)
volumes:
  mysql-data:
EOF

# 3. 启动所有服务(容器)
docker compose up -d
# 说明:-d 表示后台运行,会自动创建并启动 web 和 mysql 两个容器

# 4. 查看所有服务状态
docker compose ps

# 5. 查看服务日志(可指定服务名,如查看 web 服务日志)
docker compose logs web
# 查看所有服务日志
docker compose logs -f

# 6. 停止所有服务(容器不会删除)
docker compose stop

# 7. 启动已停止的服务
docker compose start

# 8. 停止并删除所有服务(包括容器、网络、数据卷)
docker compose down
# 保留数据卷(只删除容器和网络)
docker compose down -v

说明:数据卷(volumes)的作用是持久化数据,MySQL 容器中的数据会存储在宿主机的指定目录下,即使容器被删除,数据也不会丢失。depends_on 选项用于定义服务之间的依赖关系,确保 MySQL 服务先启动,Web 服务再启动,避免 Web 服务因无法连接 MySQL 而报错。

三、Docker 架构原理:理解 Docker 是如何工作的

掌握了 Docker 的核心概念后,我们需要深入了解 Docker 的底层架构,理解 Docker 各个组件之间的交互流程,这样才能更好地排查问题、优化容器配置。Docker 采用的是客户端-服务器(C/S)架构,主要由客户端(Docker Client)、服务器端(Docker Daemon)、容器运行时(Container Runtime)、镜像仓库(Registry)和网络、存储等组件组成。

3.1 Docker 整体架构图

Docker 的整体架构可以分为以下几个核心组件,各组件之间相互协作,完成镜像的拉取、容器的创建与运行等操作:

  • Docker 客户端(Docker Client):用户与 Docker 交互的入口,通过命令行或图形界面(如 Docker Desktop)向 Docker 服务器发送指令(如 docker run、docker build 等),客户端不直接执行操作,而是将指令发送给 Docker 守护进程,由守护进程完成具体操作。
  • Docker 守护进程(Docker Daemon):运行在宿主机上的后台进程(daemon 进程),负责监听客户端发送的指令,执行镜像拉取、镜像构建、容器创建、容器启动等核心操作,是 Docker 架构的核心。
  • 容器运行时(Container Runtime):负责容器的实际运行,Docker 最初使用的是 LXC(Linux Containers)作为容器运行时,后来推出了自研的 runc,目前 Docker 默认使用 runc 作为容器运行时。容器运行时的核心作用是创建和管理容器的进程、文件系统、网络等,实现容器的隔离与运行。
  • 镜像仓库(Registry):用于存储和管理 Docker 镜像,客户端通过 Docker 守护进程与仓库交互,完成镜像的拉取和推送。
  • 网络(Network):Docker 提供了多种网络模式,用于实现容器之间、容器与宿主机之间、容器与外部网络之间的通信,确保容器的网络隔离与连通性。
  • 存储(Storage):Docker 提供了多种存储驱动和数据卷机制,用于实现容器数据的持久化存储,避免容器删除后数据丢失。

3.2 Docker 核心组件详解

3.2.1 Docker 客户端(Docker Client)

Docker 客户端是用户操作 Docker 的主要工具,支持命令行(docker 命令)、API 接口和图形界面三种交互方式。用户输入的每一条 docker 命令,本质上都是通过客户端向 Docker 守护进程发送一个 HTTP 请求,请求守护进程执行相应的操作。
例如,当用户执行 docker run nginx:latest 命令时,客户端会将该指令转换为 HTTP 请求,发送给 Docker 守护进程,守护进程收到请求后,会先检查本地是否有 nginx:latest 镜像,如果没有,则从 Docker Hub 拉取镜像,然后基于镜像创建并启动容器,最后将执行结果返回给客户端。

3.2.2 Docker 守护进程(Docker Daemon)

Docker 守护进程(dockerd)是运行在宿主机上的后台进程,负责管理 Docker 的所有资源(镜像、容器、网络、存储等),其核心功能包括:

  • 监听客户端的请求(通过 Unix 套接字、TCP 端口等方式)。
  • 管理镜像:拉取、构建、删除、标签等操作。
  • 管理容器:创建、启动、停止、重启、删除、监控等操作。
  • 管理网络:创建、删除、配置 Docker 网络,实现容器之间的通信。
  • 管理存储:配置存储驱动,管理数据卷,实现容器数据的持久化。

Docker 守护进程可以通过配置文件(如 /etc/docker/daemon.json)进行自定义配置,例如设置镜像加速器、指定私有仓库地址、配置存储驱动等。

3.2.3 容器运行时(Container Runtime)

容器运行时是 Docker 实现容器隔离与运行的核心组件,负责创建容器的运行环境,包括进程隔离、文件系统隔离、网络隔离等。Docker 遵循 OCI(Open Container Initiative,开放容器倡议)标准,OCI 标准定义了容器镜像格式和容器运行时规范,确保不同容器引擎(如 Docker、containerd、Podman)之间的兼容性。
Docker 最初使用 LXC 作为容器运行时,后来为了更好地遵循 OCI 标准,推出了自研的 runc,runc 是一个轻量级的容器运行时,实现了 OCI 运行时规范,目前 Docker 默认使用 runc 作为容器运行时。此外,Docker 还支持 containerd 作为容器运行时,containerd 是一个更强大的容器运行时,负责镜像管理、容器生命周期管理等功能,是 Docker 架构的重要组成部分。

3.2.4 网络(Network)

Docker 提供了多种网络模式,用于满足不同场景下的容器通信需求,默认的网络模式有以下4种:

  • bridge 模式(默认):这是 Docker 默认的网络模式,每个容器都会被分配一个独立的 IP 地址,容器之间通过 bridge 网络相互通信,容器与宿主机之间通过端口映射实现通信。
  • host 模式:容器不使用独立的网络,而是共享宿主机的网络,容器的 IP 地址与宿主机的 IP 地址相同,容器监听的端口直接占用宿主机的端口,无需进行端口映射。这种模式的优势是网络性能好,劣势是容器与宿主机之间没有网络隔离。
  • none 模式:容器没有网络配置,无法与外界通信,通常用于不需要网络的场景。
  • container 模式:一个容器共享另一个容器的网络,两个容器拥有相同的 IP 地址和网络配置,通常用于需要两个容器紧密协作的场景。

此外,Docker 还支持自定义网络(如 bridge 网络、overlay 网络等),用于实现跨主机容器之间的通信,满足分布式应用的需求。

3.2.5 存储(Storage)

Docker 的存储机制主要分为两种:镜像存储和容器存储,核心目标是实现镜像的分层存储和容器数据的持久化。

  • 镜像存储:Docker 镜像采用分层存储技术,每一层都是一个只读的文件系统,层与层之间相互依赖,这种分层结构可以实现镜像的复用和增量更新。例如,基于 Ubuntu 镜像构建 Python 镜像时,只需要在 Ubuntu 镜像的基础上添加 Python 相关的层,无需重新存储整个 Ubuntu 镜像,节省存储空间。
  • 容器存储:容器在运行过程中,会在镜像的只读层之上添加一个可写层,所有对容器的修改都会保存在这个可写层中。当容器被删除时,这个可写层也会被删除,容器内的数据会丢失。为了实现数据持久化,Docker 提供了数据卷(Volumes)和绑定挂载(Bind Mounts)两种方式,将容器内的目录与宿主机的目录关联起来,容器内的数据会同步到宿主机,即使容器被删除,数据也不会丢失。

Docker 支持多种存储驱动(如 overlay2、devicemapper、aufs 等),不同的存储驱动在性能、稳定性等方面有不同的特点,其中 overlay2 是目前 Docker 默认的存储驱动,适用于大多数场景。

3.3 Docker 工作流程详解(以容器启动为例)

为了更好地理解 Docker 的架构原理,我们以"启动一个 Nginx 容器"为例,详细拆解 Docker 的工作流程,看看各个组件之间是如何协同工作的:

  1. 用户在 Docker 客户端执行 docker run -d -p 80:80 nginx:latest 命令,客户端将该指令转换为 HTTP 请求,发送给 Docker 守护进程。
  2. Docker 守护进程收到请求后,首先检查本地镜像仓库中是否存在 nginx:latest 镜像。
  3. 如果本地没有该镜像,Docker 守护进程会向 Docker Hub(默认仓库)发送请求,拉取 nginx:latest 镜像到本地。
  4. 镜像拉取完成后,Docker 守护进程调用容器运行时(runc),基于 nginx 镜像创建一个容器,分配容器 ID、网络地址、文件系统等资源,并在镜像的只读层之上添加一个可写层。
  5. Docker 守护进程配置容器的网络,将宿主机的 80 端口映射到容器的 80 端口,确保外部能够访问容器内的 Nginx 服务。
  6. 容器创建完成后,Docker 守护进程启动容器,执行镜像中定义的启动命令(CMD 指令),Nginx 服务开始运行。
  7. Docker 守护进程将容器的运行状态(如容器 ID、启动时间、端口映射等)返回给 Docker 客户端,用户可以通过 docker ps 命令查看容器状态。

整个流程中,Docker 客户端负责接收用户指令,Docker 守护进程负责协调各个组件完成具体操作,容器运行时负责容器的实际运行,镜像仓库负责提供镜像,网络和存储组件负责保障容器的通信和数据持久化,各个组件协同工作,实现了容器的快速创建和运行。

四、Docker 实战:常见问题与解决方案

在实际使用 Docker 的过程中,新手常常会遇到一些问题,下面整理了几个常见问题及解决方案,帮助大家快速排查问题,顺利上手 Docker。

4.1 问题1:拉取镜像速度慢

原因:默认的 Docker Hub 仓库位于国外,国内访问速度较慢。
解决方案:配置国内镜像加速器(如阿里云、网易云等),步骤如下:

复制代码
# 1. 编辑 Docker 守护进程配置文件
sudo vi /etc/docker/daemon.json

# 2. 添加镜像加速器配置(以阿里云为例,需替换为自己的加速器地址)
{
  "registry-mirrors": ["https://xxxx.mirror.aliyuncs.com"]
}

# 3. 重启 Docker 服务,使配置生效
sudo systemctl daemon-reload
sudo systemctl restart docker

# 4. 验证配置是否生效
docker info
# 查看输出中是否有 "Registry Mirrors" 字段,显示配置的加速器地址即生效

4.2 问题2:容器启动失败,提示端口被占用

原因:容器要映射的宿主机端口已经被其他进程(或其他容器)占用。
解决方案:

  • 方法1:更换宿主机端口,例如将 80 端口改为 8080,命令:docker run -d -p 8080:80 nginx:latest
  • 方法2:停止占用该端口的进程或容器,例如查看 80 端口占用情况:netstat -tuln | grep 80,然后停止对应的进程或容器。

4.3 问题3:容器内无法访问外部网络

原因:Docker 网络配置异常,或宿主机防火墙阻止了容器的网络访问。
解决方案:

  • 检查 Docker 网络是否正常:docker network ls,确保 bridge 网络正常。
  • 重启 Docker 服务:sudo systemctl restart docker
  • 关闭宿主机防火墙(临时测试):sudo systemctl stop firewalld(CentOS 系统),或 sudo ufw disable(Ubuntu 系统)。

4.4 问题4:容器删除后,数据丢失

原因:容器内的数据存储在可写层中,容器删除后,可写层被删除,数据丢失。
解决方案:使用数据卷(Volumes)或绑定挂载(Bind Mounts)实现数据持久化,参考 2.5 节 Docker Compose 示例中的数据卷配置。

五、总结与进阶学习建议

5.1 总结

本文围绕 Docker 基础入门,详细讲解了 Docker 的核心概念(镜像、容器、仓库、Dockerfile、Docker Compose)、底层架构(客户端、守护进程、容器运行时等组件),并搭配了大量实用的代码示例,帮助大家从零掌握 Docker 的基本使用和工作原理。
核心要点回顾:

5.2 进阶学习建议

如果想要进一步深入学习 Docker,可以从以下几个方向入手:

  • Docker 进阶特性:学习 Docker 网络高级配置(如 overlay 网络、macvlan 网络)、存储驱动原理、容器编排高级技巧等。
  • 容器编排工具:学习 Kubernetes(K8s),K8s 是目前最流行的容器编排平台,能够实现容器的大规模部署、自动扩缩容、故障自愈等功能,是 Docker 进阶的核心方向。
  • CI/CD 集成:学习如何将 Docker 与 CI/CD 工具(如 Jenkins、GitLab CI)集成,实现应用的自动化构建、测试、部署。
  • 生产环境部署:学习 Docker 在生产环境中的最佳实践,如容器监控(Prometheus + Grafana)、日志收集(ELK 栈)、安全配置等。

Docker 作为容器化技术的代表,已经成为云计算、微服务、DevOps 领域的核心工具,掌握 Docker 不仅能提高开发和部署效率,还能为后续学习更高级的容器技术打下坚实的基础。希望本文能帮助大家顺利入门 Docker,在实际实践中不断提升自己的技术能力。