Docker 完全指南:从镜像容器到生产部署

第一部分:为什么要用 Docker?

传统部署的痛点

在没有容器的年代,部署一个应用是件令人头疼的事:

  • 环境不一致:开发环境跑得好好的,一上测试服务器就各种报错------"缺少依赖库"、"Python版本不对"、"系统库版本冲突"

  • 环境冲突:同一台服务器上部署多个应用时,A应用需要Java 8,B应用需要Java 11,升级或降级JDK会互相影响

  • 资源浪费:为了隔离环境,不得不为每个应用单独租用一台物理机或虚拟机,资源利用率低

  • 部署繁琐:部署一套复杂的微服务架构可能需要配置十几个服务,手动操作极易出错

Docker 如何解决这些问题?

Docker通过容器(Container) 技术实现应用隔离。容器与虚拟机不同:

对比维度 虚拟机 Docker容器
启动速度 分钟级(需启动完整操作系统) 秒级(共享宿主机内核)
资源开销 GB级(每个VM包含完整OS) MB级(只包含应用和依赖)
隔离级别 硬件虚拟化,强隔离 进程级隔离(namespace + cgroups)
迁移能力 需要导出虚拟机镜像 通过Docker镜像轻松迁移

Docker在操作系统层面实现了应用及其运行环境的标准化封装,核心解决思路是:

应用 + 运行时环境 + 配置 = Docker镜像 → 在任何能运行Docker的机器上启动为容器


第二部分:Docker 核心概念

三大基石:镜像、容器、仓库

镜像(Image) 是Docker世界的"程序安装包"。它是一个只读的静态文件,包含了运行应用所需的一切:代码、运行时、系统工具、库和设置。类似于面向对象编程中的"类"------定义了应用所需的所有环境和依赖,但本身不运行。

容器(Container) 是镜像的"运行实例"。你从同一个镜像可以启动无数个容器,每个容器之间相互隔离。类似于面向对象编程中的"对象"------是镜像的具体运行实例,拥有独立的进程空间、网络和存储。

仓库(Repository) 是存储和分发镜像的地方。Docker Hub 是最著名的公共仓库,类似代码世界的GitHub。你可以从仓库拉取(pull)镜像,也可以把自己构建的镜像推送(push)到仓库供他人使用。

复制代码
镜像(静态定义)  ==docker run==>  容器(动态运行)
      ↑                              ↑
   docker pull                   docker start/stop
      ↑                              ↑
   仓库(分发中心)

第三部分:Docker 安装与环境配置

Linux 安装(以Ubuntu为例)

复制代码
# 更新软件源
sudo apt update

# 安装依赖包
sudo apt install apt-transport-https ca-certificates curl software-properties-common

# 添加Docker官方GPG密钥
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

# 添加Docker稳定版仓库
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

# 更新源并安装Docker引擎
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io

# 启动Docker服务
sudo systemctl start docker
sudo systemctl enable docker   # 设置开机自启

# 验证安装
docker --version   # 显示Docker版本信息

# 将当前用户加入docker组(避免每次使用sudo)
sudo usermod -aG docker $USER
# 然后重新登录使权限生效

第四部分:镜像管理 ------ Docker 的基石

镜像的基本操作

复制代码
# 搜索镜像(在Docker Hub上搜索)
docker search nginx

# 拉取镜像(从仓库下载到本地)
docker pull nginx:latest     # 拉取最新版
docker pull nginx:1.21       # 拉取指定版本
docker pull redis:alpine     # 拉取轻量级Alpine版本

# 列出本地所有镜像
docker images
# 或
docker image ls

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

# 删除镜像
docker rmi nginx:1.21        # 删除指定镜像
docker rmi -f nginx:1.21     # 强制删除(即使有容器依赖)
docker image prune           # 清理所有未被使用的镜像(悬空镜像)

# 给镜像打标签(用于推送到自己的仓库)
docker tag nginx:latest myhub/nginx:my-version

# 推送镜像到仓库
docker push myhub/nginx:my-version

# 导出镜像为tar文件
docker save -o nginx.tar nginx:latest

# 从tar文件加载镜像
docker load -i nginx.tar

镜像的分层结构

Docker镜像由多个只读层(Layer) 叠加而成。每一层对应Dockerfile中的一条指令。这种分层结构带来两个巨大优势:

  1. 共享与复用:多个镜像可以共享相同的基础层(如Ubuntu基础层),节省磁盘空间

  2. 增量更新:构建新版本时只需重新构建变更的层,其余层使用缓存,大幅加速构建

    复制代码
    # 查看镜像的构建历史(展示分层)
    docker history nginx:latest

第五部分:容器管理 ------ 镜像的生命周期

容器的完整生命周期

复制代码
# 运行容器(从镜像创建并启动)
docker run nginx:latest

# 带参数运行
docker run -d --name mynginx -p 8080:80 nginx:latest
# -d:后台运行(detach模式)
# --name:为容器指定名称
# -p 8080:80:端口映射,宿主机8080端口映射到容器的80端口

# 查看正在运行的容器
docker ps

# 查看所有容器(包括已停止的)
docker ps -a

# 停止容器
docker stop mynginx

# 启动已停止的容器
docker start mynginx

# 重启容器
docker restart mynginx

# 暂停容器(冻结所有进程)
docker pause mynginx

# 恢复暂停的容器
docker unpause mynginx

# 删除容器(需先停止)
docker rm mynginx
docker rm -f mynginx        # 强制删除(运行中的容器也会被删除)

# 批量删除所有停止的容器
docker container prune

# 进入运行中的容器(交互式)
docker exec -it mynginx /bin/bash
# -i:交互模式,-t:分配伪终端
# /bin/bash:在容器中执行的命令

# 查看容器日志
docker logs mynginx
docker logs -f mynginx      # 实时追踪日志(类似tail -f)

# 查看容器进程
docker top mynginx

# 查看容器资源占用(CPU、内存等)
docker stats mynginx

docker run 的常用参数

参数 说明 示例
-d 后台运行(detach) docker run -d nginx
--name 指定容器名称 --name mynginx
-p 端口映射:宿主机:容器 -p 8080:80
-P 随机映射端口(自动分配) -P
-v 挂载卷(数据持久化) -v /host/data:/container/data
-e 设置环境变量 -e MYSQL_ROOT_PASSWORD=123456
--env-file 从文件加载环境变量 --env-file .env
--restart 重启策略 --restart=always
--network 指定网络 --network bridge
-it 交互式终端(组合) -it /bin/bash

第六部分:Dockerfile ------ 构建专属镜像

Dockerfile 基础指令

Dockerfile 是一个文本文件,包含构建镜像所需的所有命令。每个命令都会创建一个新的镜像层。

复制代码
# 指定基础镜像(所有镜像必须从基础镜像开始)
FROM ubuntu:20.04

# 设置维护者信息
LABEL maintainer="jack@example.com"

# 设置环境变量
ENV APP_HOME /app
ENV APP_VERSION 1.0

# 在构建时执行命令(安装软件、创建目录等)
RUN apt-get update && apt-get install -y \
    python3 \
    python3-pip \
    && rm -rf /var/lib/apt/lists/*   # 清理缓存减小镜像体积

# 创建工作目录
WORKDIR $APP_HOME

# 复制文件到镜像中(从构建上下文复制到镜像内)
COPY requirements.txt .
COPY app.py .

# 更灵活的复制(支持通配符,保留元数据)
ADD https://example.com/file.tar.gz /tmp/   # ADD支持远程URL和解压

# 安装Python依赖
RUN pip3 install -r requirements.txt

# 声明容器运行时监听的端口(仅是文档说明,不会自动映射)
EXPOSE 5000

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

# 或使用ENTRYPOINT(结合CMD使用)
ENTRYPOINT ["python3"]
CMD ["app.py"]

FROM、RUN、CMD、ENTRYPOINT 的区别

这几个指令初学者容易混淆,必须彻底搞清楚:

指令 执行时机 作用 特点
FROM 构建时 指定基础镜像 必须作为第一条指令
RUN 构建时 安装软件、修改配置、创建文件 会创建新的镜像层,影响镜像体积
CMD 容器启动时 指定默认启动命令 可以被 docker run 命令行参数覆盖;一个Dockerfile中只能有一条CMD
ENTRYPOINT 容器启动时 指定容器的主程序 不会被 docker run 命令行参数覆盖(参数会追加);更适合配置"固定执行程序"的容器

最佳实践组合

复制代码
# 固定ENTRYPOINT为可执行程序,CMD提供默认参数
ENTRYPOINT ["python3"]
CMD ["app.py"]

# 运行时可以覆盖CMD:
docker run myimage main.py   # 实际执行:python3 main.py

构建镜像

复制代码
# 构建镜像(.表示使用当前目录作为构建上下文)
docker build -t myapp:1.0 .

# 构建时指定Dockerfile路径
docker build -f /path/to/Dockerfile -t myapp:1.0 .

# 构建时不使用缓存(强制重新构建所有层)
docker build --no-cache -t myapp:1.0 .

构建上下文(Build Context)

构建时,Docker会将指定的目录(上例中的 .打包上传给Docker守护进程。这意味着构建目录中的文件都会被发送到Docker引擎。因此:

  • 不要把整个 node_modulestarget 目录作为构建上下文

  • 使用 .dockerignore 文件排除不需要的文件

.dockerignore

类似 .gitignore,放在构建目录根目录,用于排除文件:

复制代码
node_modules/
*.log
.git/
.DS_Store
*.tmp

第七部分:数据管理 ------ 让容器有"记忆"

容器是临时的,删除容器后其中的数据也会丢失。要持久化数据,有三种方式:

1. 绑定挂载(Bind Mount)------开发最常用

将宿主机目录挂载到容器内,双向同步,适合开发环境的热更新。

复制代码
# 将宿主机的 ./app 目录挂载到容器的 /app
docker run -v $(pwd)/app:/app myapp:1.0

# 现代写法(--mount更明确)
docker run --mount type=bind,source=$(pwd)/app,target=/app myapp:1.0

2. 数据卷(Volume)------生产环境推荐

由Docker管理的独立存储区域,与宿主机目录分离,更安全更易迁移。

复制代码
# 创建数据卷
docker volume create mydata

# 查看所有数据卷
docker volume ls

# 挂载数据卷到容器
docker run -v mydata:/app/data myapp:1.0

# 查看数据卷详情
docker volume inspect mydata

# 删除数据卷
docker volume rm mydata

# 清理未使用的数据卷
docker volume prune

总结:

Docker 的核心思想是标准化交付。它把应用和它的依赖一起打包成一个可移植的单元,从此运维不再需要关心应用内部的具体实现,开发也不再需要担心环境差异。

Docker 的学习路径建议

1.先会用 :掌握 docker rundocker psdocker exec 等基础命令

2.再会造:学会写 Dockerfile,把自己的应用打包成镜像

3.再会管:掌握数据卷、网络、Compose,管理多容器应用

4.再会优:理解层缓存、多阶段构建、安全配置等高级技巧

5.再往上走:进入 Kubernetes 的世界------那是容器编排的下一站

容器化是云计算时代的核心技能,掌握了 Docker,你就拿到了通往现代化开发与运维世界的入场券。

相关推荐
JavaPub-rodert2 小时前
Docker 容器启动了,不代表服务真的能用:Healthcheck 实战
运维·docker·容器
先吃饱再说3 小时前
别再手动敲三遍 docker run 了:学会使用 Docker Compose 多容器编排
docker·容器
xixiaoyunya4 小时前
Docker 容器化部署实战:从零搭建一套完整的 Nginx + Node.js + MySQL + Redis 项目环境
nginx·docker·node.js
全栈攻略16 小时前
Docker 中 ROS2 工作流 Topic 验证与常用命令指南
运维·docker·容器
名字还没想好☜18 小时前
Docker 数据卷实战:volume、bind mount、tmpfs 到底怎么选,数据持久化与权限坑
运维·docker·容器·kubernetes
唐青枫19 小时前
Docker diff 详解:看清容器里到底改了什么
docker
lpfasd12320 小时前
Docker存储清理与防膨胀实践
运维·docker·容器
weixin_444579301 天前
Docker(下):镜像仓库管理
运维·docker·容器
DreamLife☼1 天前
Agent开发环境搭建完全指南
python·docker·typescript·node·工业知识点