Docker

文章目录

  • Docker
    • [一、Docker 到底是什么?](#一、Docker 到底是什么?)
    • [二、为什么要学 Docker?](#二、为什么要学 Docker?)
    • [三、Docker 的核心概念](#三、Docker 的核心概念)
      • [1. 镜像(Image)](#1. 镜像(Image))
      • [2. 容器(Container)](#2. 容器(Container))
      • [3. 仓库 / 注册表(Registry)](#3. 仓库 / 注册表(Registry))
      • [4. 数据卷(Volume)](#4. 数据卷(Volume))
      • [5. 网络(Network)](#5. 网络(Network))
    • [五、Docker 安装怎么理解?](#五、Docker 安装怎么理解?)
    • [六、先记住这几个最核心的 Docker 命令](#六、先记住这几个最核心的 Docker 命令)
      • [1. 镜像相关](#1. 镜像相关)
      • [2. 容器相关](#2. 容器相关)
      • [3. 进入容器、查看日志、检查信息](#3. 进入容器、查看日志、检查信息)
      • [4. 端口映射、环境变量、命名与重启策略](#4. 端口映射、环境变量、命名与重启策略)
    • [七、从 0 到 1:跑起你的第一个 Nginx 容器](#七、从 0 到 1:跑起你的第一个 Nginx 容器)
    • 八、Dockerfile:把项目做成镜像
    • 九、数据持久化:为什么删了容器数据就没了?
      • [1. Bind Mount(绑定挂载)](#1. Bind Mount(绑定挂载))
      • [2. Volume(数据卷)](#2. Volume(数据卷))
    • [十、Docker 网络:容器之间如何通信?](#十、Docker 网络:容器之间如何通信?)
      • [1. bridge 模式](#1. bridge 模式)
      • [2. host 模式](#2. host 模式)
      • [3. none 模式](#3. none 模式)
    • [十一、Docker Compose:管理多个容器](#十一、Docker Compose:管理多个容器)
      • [1. Compose 文件名](#1. Compose 文件名)
      • [2. 一个简单的 Compose 示例](#2. 一个简单的 Compose 示例)
      • [3. 常用 Compose 命令](#3. 常用 Compose 命令)
    • [十二、写 Dockerfile 和用 Docker 时的几个实用建议](#十二、写 Dockerfile 和用 Docker 时的几个实用建议)
      • [1. 不要把所有东西都塞进一个巨大镜像里](#1. 不要把所有东西都塞进一个巨大镜像里)
      • [2. 不要把重要数据只放在容器里](#2. 不要把重要数据只放在容器里)
      • [3. 不要把 `EXPOSE` 当成端口映射](#3. 不要把 EXPOSE 当成端口映射)
      • [4. 不要把容器当成虚拟机](#4. 不要把容器当成虚拟机)

Docker

在后端开发、运维部署、微服务架构,甚至前端工程化里,Docker 几乎已经成了绕不开的基础工具。很多人第一次接触 Docker,都会觉得它像"轻量版虚拟机";但真正用起来之后你会发现,它的价值远不止隔离环境这么简单。Docker 解决的核心问题,是把"应用"和"运行应用所需的环境"一起打包,让程序在开发、测试、上线时都尽可能保持一致。Docker 把应用运行在相对隔离的 container 中,这些 container 轻量、启动快,并且包含运行应用所需的一切。

一、Docker 到底是什么?

Docker 是一个用于开发、交付和运行应用的平台。它允许我们把应用打包到容器中运行,从而把"代码能跑"这件事,从依赖宿主机环境,变成依赖镜像本身。对开发者来说,这意味着"我本地能跑,服务器也能跑";对团队来说,这意味着环境更加统一;对运维来说,这意味着部署更快、迁移更方便。Docker 官方也明确把它定位为开发、交付和运行应用的开放平台。

你可以把 Docker 理解成一套完整体系,而不只是一个命令行工具。它背后有 Docker Client、Docker Daemon、镜像仓库、镜像、容器、网络、数据卷等对象共同协作。日常我们输入的 docker rundocker pulldocker build,本质上都是 Docker Client 在向 Docker Daemon 发请求,由 Daemon 去完成真正的构建、运行和分发工作。

二、为什么要学 Docker?

Docker 之所以流行,原因非常直接:它能让软件交付更稳定、更高效。

第一,环境一致性更强 。开发机、测试机、生产机经常因为系统版本、依赖版本、配置差异导致"同一套代码表现不一致"。Docker 通过镜像把这些依赖打包起来,显著减少环境差异。第二,部署更快 。容器本质上是宿主机上的隔离进程,而不是完整虚拟机,因此启动通常更轻量。第三,可移植性强 。只要目标环境支持 Docker,同一个镜像就可以在本地、物理机、虚拟机、云服务器甚至混合环境中运行。第四,非常适合 CI/CD 和微服务。容器可以作为交付单元进入测试、灰度、上线流程,也适合把大系统拆成多个独立服务。

三、Docker 的核心概念

1. 镜像(Image)

镜像是一个只读模板,里面包含了运行应用所需的基础环境、依赖、文件和启动指令。我们可以基于现成镜像继续扩展,也可以通过 Dockerfile 自己构建镜像。镜像由多层组成,Dockerfile 里的每条构建指令通常都会形成一层,这也是镜像构建高效、可缓存的重要原因。

2. 容器(Container)

容器是镜像的运行实例。换句话说,镜像像模板,容器像运行起来的实体。你可以创建、启动、停止、删除容器,也可以给容器连接网络、挂载存储。Docker 官方对容器的定义非常明确:它是镜像的 runnable instance,本质上仍然是运行在宿主机上的一个进程,只不过拥有自己的文件系统、网络和进程树视图。

3. 仓库 / 注册表(Registry)

注册表用于存储和分发镜像。最常见的公共仓库是 Docker Hub。执行 docker pull 时,Docker 会从配置的注册表拉取镜像;执行 docker push 时,则会把镜像推送到注册表。

4. 数据卷(Volume)

容器默认的数据写在可写层里,容器删除后,这些数据通常也会消失。为了实现持久化,Docker 提供了 Volume。官方文档把 Volume 视为持久化容器数据的首选机制,因为它由 Docker 管理,独立于容器生命周期。

5. 网络(Network)

Docker 提供网络机制,让容器既能对外暴露服务,也能在容器之间通信。Bridge、Host、None 是初学者最常接触的三种模式,其中 bridge 是默认驱动。## 四、Docker 的底层原理:容器到底是怎么隔离出来的?

Docker 并不是自己发明了一套全新的操作系统虚拟化技术,它大量利用了 Linux 内核已有能力。最核心的两个关键词是:

Namespaces:负责"看见什么"。它给容器提供隔离的工作空间,让容器拥有自己独立的进程视图、网络视图等。Docker 官方说明中提到,容器运行时会创建一组 namespaces,从而形成隔离环境。

Cgroups :负责"能用多少"。它控制容器可以使用多少 CPU、内存等资源。官方文档也明确说明,Docker 可以通过 docker run 的运行参数来限制容器的内存和 CPU 使用。

所以,从技术本质上说,容器不是一台完整虚拟机,而是宿主机上的一个被隔离、被限制资源的进程。这也是 Docker 比传统虚拟机更轻量、启动更快的重要原因。

五、Docker 安装怎么理解?

如果你使用的是 Windows 或 macOS,最常见的安装方式是 Docker Desktop ;如果你使用的是 Linux,常见做法是安装 Docker Engine,也可以根据场景使用 Docker Desktop。Docker Desktop 本身已经集成了 Docker Daemon、Docker Client 和 Docker Compose 等组件。

有些 Linux 环境里,执行 Docker 命令可能需要加 sudo。Docker 官方也提到,这取决于系统配置;如果不想每次都写 sudo,可以把当前用户加入 docker 用户组。所以下面文章中的命令,我默认省略 sudo,你在自己的机器上按实际情况决定是否添加。

六、先记住这几个最核心的 Docker 命令

下面这些命令足够支撑初学者完成"拉镜像、起容器、进容器、看日志、删容器、管数据卷"的日常操作。命令写法我统一成更标准、更新的形式。

1. 镜像相关

bash 复制代码
docker pull nginx
docker image ls
docker rmi nginx
  • docker pull nginx:拉取镜像

  • docker image ls:查看本地镜像

  • docker rmi nginx:删除镜像

2. 容器相关

bash 复制代码
docker run nginx
docker run -d nginx
docker ps
docker ps -a
docker stop 容器名
docker start 容器名
docker rm -f 容器名
  • docker run:基于镜像创建并启动容器

  • -d:后台运行

  • docker ps:默认只看正在运行的容器

  • docker ps -a:查看所有容器,包括已停止的容器

  • docker stop / docker start:停止与启动容器

  • docker rm -f:强制删除容器

docker run 的通用形式是 docker run [OPTIONS] IMAGE [COMMAND] [ARG...]。如果没有手动指定名称,Docker 会自动给容器分配一个随机名字。(Docker Documentation)

3. 进入容器、查看日志、检查信息

bash 复制代码
docker logs 容器名
docker logs -f 容器名
docker inspect 容器名
docker exec 容器名 ps -ef
docker exec -it 容器名 /bin/sh
  • docker logs:查看容器日志

  • docker logs -f:持续跟踪日志输出

  • docker inspect:查看容器详细信息,默认是 JSON

  • docker exec在一个已经运行中的容器里执行新命令

  • docker exec -it 容器名 /bin/sh:进入容器交互式命令行

这里要特别纠正一个初学者常见误区:docker exec 不是"让你进入容器的唯一方式",它的本质是在运行中的容器里执行命令 ;只不过当你执行 /bin/sh/bin/bash 时,看起来像"进入了容器"。

4. 端口映射、环境变量、命名与重启策略

bash 复制代码
docker run -d --name mynginx -p 8080:80 nginx
docker run -d --name myapp -e APP_ENV=prod myimage
docker run -d --restart unless-stopped myimage
  • --name:给容器自定义名称

  • -p 8080:80:把宿主机 8080 端口映射到容器 80 端口

  • -e:注入环境变量

  • --restart unless-stopped:配置自动重启策略

要注意,-p 的格式是 宿主机端口:容器端口。而且如果你没有指定绑定 IP,Docker 默认会把端口发布到所有网络接口。Docker 也提供重启策略来控制容器异常退出或 Docker 重启后的行为。

七、从 0 到 1:跑起你的第一个 Nginx 容器

学 Docker,最好的方式不是背概念,而是先把一个现成服务跑起来。

bash 复制代码
docker pull nginx
docker run -d --name mynginx -p 8080:80 nginx
docker ps

这三步做了什么?

第一步,拉取 nginx 镜像。

第二步,基于镜像启动一个后台运行的容器,并把宿主机 8080 端口映射到容器的 80 端口。

第三步,查看容器是否正常运行。

如果一切顺利,你在浏览器访问 http://localhost:8080,就能看到 Nginx 默认欢迎页。Docker 官方也明确说明,容器端口默认不会自动暴露给宿主机,必须通过 -p-P 发布端口。

接着你还可以继续执行:

bash 复制代码
docker logs -f mynginx
docker exec -it mynginx /bin/sh
docker stop mynginx
docker rm mynginx

这就是最基础的一条 Docker 使用链路:拉镜像 → 起容器 → 看状态 → 看日志 → 进容器 → 停容器 → 删容器

八、Dockerfile:把项目做成镜像

如果说镜像是成品,那 Dockerfile 就是生产成品的"配方"。

Docker 官方把 Dockerfile 定义为一个文本文件,里面写满了构建镜像所需的指令。最常见的指令包括 FROMRUNWORKDIRCOPYCMD。其中,WORKDIR 用来设置后续指令的工作目录,COPY 用来复制文件到镜像内,CMD 用来定义容器启动时默认运行的程序。

下面是一个更规范的示例:

dockerfile 复制代码
FROM python:3.12-slim

WORKDIR /app

COPY . .

RUN pip install -r requirements.txt

EXPOSE 8000

CMD ["python", "main.py"]

上面这段 Dockerfile 的含义是:

  • FROM python:3.12-slim:以 Python 官方精简镜像为基础

  • WORKDIR /app:设置工作目录为 /app

  • COPY . .:把当前目录内容复制进镜像工作目录

  • RUN pip install -r requirements.txt:安装依赖

  • EXPOSE 8000:声明容器应用使用的端口

  • CMD ["python", "main.py"]:容器启动时默认执行的命令

这里也顺手纠正你原文里的一个小笔误:应当是 COPY ,不是 CPOY。另外,EXPOSE 更像是对镜像使用者的说明,它本身不会自动把端口暴露到宿主机;真正发布端口仍然要在运行容器时用 -p

构建和运行镜像的命令如下:

bash 复制代码
docker build -t my-python-app .
docker run -d --name myapp -p 8000:8000 my-python-app

如果你要把镜像推送到远程仓库:

bash 复制代码
docker push 用户名/镜像名:标签

九、数据持久化:为什么删了容器数据就没了?

最容易踩的坑之一,就是把数据直接写进容器内部,然后删除容器时发现数据没了。

这是因为容器默认数据写在容器的可写层中,而这个可写层随着容器的删除而消失。官方文档明确写到:如果数据没有存入持久化存储,容器删除后,状态变化也会一起消失。

Docker 里常见的两种持久化方式是:

1. Bind Mount(绑定挂载)

把宿主机的某个目录直接挂到容器里。

bash 复制代码
docker run -d -v /data/html:/usr/share/nginx/html nginx

这种方式适合开发环境,比如把本地代码目录挂到容器里,修改代码后容器能直接看到变化。Bind mount 的特点是:挂载的是宿主机真实路径。

2. Volume(数据卷)

由 Docker 自己管理的数据存储区域。

bash 复制代码
docker volume create mydata
docker run -d -v mydata:/data redis
docker volume inspect mydata
docker volume ls
docker volume rm mydata
docker volume prune

Volume 更适合数据库、缓存、中间件等需要持久化的数据场景。官方文档把 Volume 视为持久化容器数据的首选方式,因为它完全由 Docker 管理,更容易备份、迁移,也更适合在多个容器之间共享。

一句话总结:

  • 开发时共享代码,常用 bind mount

  • 生产时做数据持久化,更推荐 volume

十、Docker 网络:容器之间如何通信?

Docker 的网络系统是可插拔的,最常用的是下面三种模式:

1. bridge 模式

这是默认网络驱动。如果你创建网络时不指定驱动,通常就是 bridge。它适合运行在同一台宿主机上的多个容器互相通信。

bash 复制代码
docker network create app-net
docker run -d --name web --network app-net nginx:alpine
docker run --rm -it --network app-net busybox ping web

当多个容器连到同一个自定义网络时,它们可以直接通过容器名进行通信,这也是 Docker 内置 DNS 机制带来的便利。

2. host 模式

Host 模式会移除容器与宿主机之间的网络隔离,容器直接使用宿主机网络。性能和网络可见性更直接,但隔离性更弱。

bash 复制代码
docker run -d --network host myimage

3. none 模式

None 模式会让容器与宿主机及其他容器完全隔离,不提供网络连接。适合一些不需要联网的特殊场景。

十一、Docker Compose:管理多个容器

当你的项目不止一个容器时,比如"Web 服务 + Redis + MySQL",如果还靠一个个 docker run 去启动,就会很快变得混乱。这时候就轮到 Docker Compose 出场了。

Docker Compose 是 Docker 官方提供的多容器编排工具,用一个 YAML 文件定义应用里的服务、网络、数据卷等对象,然后用一条命令统一启动和管理。官方文档对它的描述也非常直接:Compose 用于定义和运行多容器应用,并能通过单个 YAML 文件统一管理整个应用栈。

1. Compose 文件名

现在更推荐使用:

bash 复制代码
compose.yaml

同时也兼容:

bash 复制代码
compose.yml
docker-compose.yaml
docker-compose.yml

如果不显式指定 -f,Compose 会在当前目录及父目录查找默认文件;推荐优先使用标准名称 compose.yaml。Compose v2 的命令形式是 docker compose,而不是旧版的 docker-compose

2. 一个简单的 Compose 示例

yaml 复制代码
services:
  app:
    build: .
    container_name: demo-app
    ports:
      - "8000:8000"
    environment:
      - REDIS_HOST=redis
    depends_on:
      - redis

  redis:
    image: redis:alpine
    container_name: demo-redis
    volumes:
      - redis-data:/data

volumes:
  redis-data:

这个文件表达了三层意思:

  • app 服务从当前目录构建镜像

  • redis 服务直接使用官方镜像

  • redis-data 是命名卷,用于持久化 Redis 数据

默认情况下,Compose 会为应用创建一个默认网络,每个服务都会加入该网络,并且可以通过服务名 互相访问。所以这里 app 可以直接通过 redis 这个名字访问 Redis,而不需要手写 IP。

3. 常用 Compose 命令

bash 复制代码
docker compose up -d
docker compose down
docker compose stop
docker compose start
docker compose -f 文件名 up -d

这些命令的含义分别是:

  • docker compose up -d:创建并启动服务,后台运行

  • docker compose down:停止并移除由 Compose 创建的容器和默认网络

  • docker compose stop:只停止,不删除

  • docker compose start:启动已存在但已停止的服务

  • docker compose -f 文件名 up -d:指定 Compose 文件启动

其中,docker compose up 会构建、创建并启动服务;加 -d 后会在后台运行。docker compose down 默认会删除 Compose 创建的容器和网络,但不会删除外部卷和外部网络。

十二、写 Dockerfile 和用 Docker 时的几个实用建议

1. 不要把所有东西都塞进一个巨大镜像里

镜像不是越大越稳,恰恰相反,镜像越大,传输越慢,启动越慢,维护越麻烦。优先选择精简基础镜像,比如 slim 版本;项目复杂时可以进一步使用多阶段构建减小最终镜像体积。Docker 官方也把 multi-stage build 作为构建最佳实践之一。

2. 不要把重要数据只放在容器里

容器删了,没持久化的数据也可能跟着没了。数据库、上传文件、缓存目录这类数据,一开始就应该考虑挂卷。

3. 不要把 EXPOSE 当成端口映射

EXPOSE 8000 只是声明容器使用了这个端口,不等于宿主机能访问它。真正需要访问时,仍然要:

bash 复制代码
docker run -p 8000:8000 your-image

4. 不要把容器当成虚拟机

容器不是一台完整系统,它更像是一个被隔离的进程运行环境。理解这一点之后,很多 Docker 命令就会更容易明白,比如为什么容器启动时实际上是在运行一个主进程,为什么 docker exec 是"执行命令"而不是"开另一台机器"。

相关推荐
rockmelodies3 小时前
用 Python 实现 Docker 镜像批量推送(带进度条)
python·docker·eureka
实名上网宋凯宣3 小时前
dockerfile镜像-python文件
docker
PH = 73 小时前
Docker将jar包装为Image并运行
运维·docker·容器
敲上瘾3 小时前
Docker核心要点和指令速通
linux·运维·docker·容器
cypking3 小时前
docker基础使用
docker
色空大师3 小时前
【阿里云部署服务问题指南】
java·mysql·阿里云·docker
晨旭缘3 小时前
GitLab CICD 中 K8s 部署:BOM 头与 YAML 格式全解
容器·kubernetes·gitlab
HelloWorld_SDK13 小时前
Docker安装OpenClaw
运维·docker·容器·openclaw
刘~浪地球17 小时前
云原生与容器--Kubernetes 生产环境部署实战
云原生·容器·kubernetes