Docker 基础实战完整指南
🐳 Docker 基础实战完整指南
定位:零基础 → 能独立构建/部署/调试容器化应用
环境:华为云 ECS ecs-fce0-0001 (2vCPU/4GiB/ac9.large.2/Ubuntu 24.04)
工具:Docker CE 29.5.3 + Compose v5.1.4
风格:「原理简述 + 代码实操 + 常见坑点 + 企业小技巧」
Part 1: 为什么需要 Docker?——从痛点出发
1.1 传统部署的噩梦
没有 Docker 的年代,你的部署流程可能是这样的:
开发环境(Win/Mac) → 测试环境(Linux) → 生产环境(CentOS) "在我机器上能跑!" "缺依赖/版本不对" "JDK版本冲突!"| 痛点 | 描述 | Docker 解决方案 |
|---|---|---|
| 环境不一致 | Win vs Linux vs Mac 差异 | 容器统一环境,一次构建到处运行 |
| 依赖冲突 | 项目A用 JDK8,项目B用 JDK17 | 每个容器独立环境 |
| 部署慢 | 手动装依赖 → 1~2 小时 | 镜像秒级启动 |
| 资源浪费 | 每个应用一台虚拟机 | 容器共享内核,一台机器跑几十个 |
1.2 容器 vs 虚拟机
┌─────────────────────────────────────────────────────────────┐ │ Virtual Machine (虚拟机) │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ App A │ │ App B │ │ App C │ │ │ │ Bin/Libs │ │ Bin/Libs │ │ Bin/Libs │ ← 各自完整的 OS │ │ │ Guest OS │ │ Guest OS │ │ Guest OS │ │ │ └──────────┘ └──────────┘ └──────────┘ │ │ Hypervisor (虚拟化层) │ │ Host OS (宿主机 OS) │ │ Physical Hardware │ └─────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────┐ │ Docker Container (容器) │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ App A │ │ App B │ │ App C │ │ │ │ Bin/Libs │ │ Bin/Libs │ │ Bin/Libs │ ← 仅含应用依赖 │ │ └──────────┘ └──────────┘ └──────────┘ │ │ Docker Engine (容器引擎) │ │ Host OS (共享内核!) │ │ Physical Hardware │ └─────────────────────────────────────────────────────────────┘| 维度 | 虚拟机 (VM) | 容器 (Container) |
|---|---|---|
| 启动速度 | 分钟级 | 秒级 |
| 磁盘占用 | GB 级 | MB 级 |
| 内存开销 | 每个额外 ~512MB | 几乎无额外开销 |
| 隔离性 | 完整隔离 | 进程级隔离 |
| 内核 | 每个 VM 独立内核 | 共享宿主机内核← 关键差异 |
1.3 镜像 vs 容器:类 vs 实例
Image (镜像) Container (容器) ┌──────┐ ┌──────────────┐ │ JDK │ │ JDK (layer 3)│ ├──────┤ -run-> ├──────────────┤ │ Tomcat│ │Tomcat(layer2)│ ← 镜像的"运行时" ├──────┤ ├──────────────┤ │ War │ │ War (layer 1)│ 实例 + 可写层 └──────┘ └──────────────┘ 只读 读写(R/W layer) 类比: Class → new → Object Image → run → Container1.4 Hello-World 拆解执行流程
在docker-01 (121.36.42.55)上实际执行:
$dockerpull hello-world:latest Digest: sha256:0e760fdfbc48ba8041e7c6db999bb40bfca508b4be580ac75d32c4e29d202ce1 Status: Downloaded newer imageforhello-world:latest $dockerrun--namehw-demo hello-world Hello from Docker!This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps:1. The Docker client contacted the Docker daemon.2. The Docker daemon pulled the"hello-world"image from the Docker Hub.(amd64)3. The Docker daemon created a new container from that imagewhichruns the executable that produces the output you are currently reading.4. The Docker daemon streamed that output to the Docker client,whichsent it to your terminal.执行流程拆解:
① docker run hello-world Docker CLI ──────────────────────────► Docker Daemon │ ② 本地有没有镜像? │ ├─ 没有 → 去 Registry 拉取 ──────┤ │ ③ 下载 hello-world:latest └─ 有 → 直接用 │ │ ④ 基于镜像创建容器 │ ├─ 分配文件系统 (可写层) │ ├─ 分配网络 (默认 bridge) │ └─ 启动进程 │ │ ⑤ 执行容器内程序,stdout 流回 Client │ └─ 程序结束 → 容器退出 (Exited)# 验证容器生命周期$dockerps-a--filtername=hw-demo NAMES IMAGE STATUS PORTS hw-demo hello-world Exited(0)Less than a second ago# 镜像大小仅 9.49KB!$dockerimages hello-world IMAGE ID DISK USAGE CONTENT SIZE hello-world:latest 0e760fdfbc4825.9kB9.49kB企业真题:“docker run 背后的完整流程是什么?”
答:CLI → Daemon → 检查本地镜像 → (无)拉取 Registry → 创建容器(分配网络/存储/Cgroup) → 启动进程 → 输出流回客户端
Part 2: 环境搭建与核心命令速成(1小时上手)
2.1 三平台安装(以 Ubuntu 24.04 为例)
# Step1: 卸载旧版本apt-getremove-ydocker.io docker-doc podman-docker containerd runc# Step2: 安装依赖apt-getupdate&&apt-getinstall-yca-certificatescurl# Step3: 添加 Docker GPG 密钥(阿里云镜像)install-m0755-d/etc/apt/keyringscurl-fsSLhttps://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg\-o/etc/apt/keyrings/docker.ascchmoda+r /etc/apt/keyrings/docker.asc# Step4: 添加仓库(注意 CODENAME 变量)echo"deb [arch=$(dpkg --print-architecture)signed-by=/etc/apt/keyrings/docker.asc] \ https://mirrors.aliyun.com/docker-ce/linux/ubuntu noble stable"\>/etc/apt/sources.list.d/docker.list# Step5: 安装apt-getupdate&&apt-getinstall-y\docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin# Step6: 配置镜像加速 + log 限制mkdir-p/etc/dockercat>/etc/docker/daemon.json<<'EOF' { "registry-mirrors": [ "https://docker.1ms.run", "https://docker.xuanyuan.me" ], "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" } } EOFsystemctl daemon-reload&&systemctl restartdockersystemctlenabledocker# Step7: 验证$docker--versionDocker version29.5.3, build d1c06ef $dockercompose version Docker Compose version v5.1.42.2 高频命令实战清单
在docker-01上的真实操作:
# ──────────── 1. docker run ────────────$dockerrun-d--namenginx-demo-p8088:80 nginx:alpine# -d: 后台运行 (detached)# --name: 给容器命名# -p 8088:80: 端口映射 宿主机:容器# ──────────── 2. docker ps (查看运行中) ────────────$dockerps--format"table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}"NAMES IMAGE STATUS PORTS nginx-demo nginx:alpine Up5minutes0.0.0.0:8088->80/tcp# ──────────── 3. docker logs (实时看日志) ────────────$dockerlogs nginx-demo--tail3# 关键参数: -f (follow实时) --tail N (最后N行) --since (时间范围)# ──────────── 4. docker exec (进入容器) ────────────$dockerexecnginx-demosh-c"nginx -v 2>&1"Nginx version:1.27.4# exec 让你"穿透"容器边界,在容器内执行命令# 常用: docker exec -it <name> /bin/bash 进入交互式 shell# ──────────── 5. docker cp (传文件) ────────────$echo"host_content">/tmp/host-file.txt $dockercp/tmp/host-file.txt nginx-demo:/tmp/ $dockerexecnginx-democat/tmp/host-file.txt host_content# 双向传输: 宿主机→容器 和 容器→宿主机# ──────────── 6. docker stats (资源监控) ────────────$dockerstats --no-stream nginx-demo# 实时显示 CPU/MEM/NET/DISK 使用情况命令速查表:
| 命令 | 作用 | 常用参数 |
|---|---|---|
docker run -d --name X -p H:C IMG | 后台启动容器 | --restart-v-e--network |
docker ps -a | 查看所有容器 | --filter--format-q |
docker logs -f <id> | 实时看日志 | --tail N--since |
docker exec -it <id> sh | 进入容器 | -u root(以root执行) |
docker cp HOST_PATH ID:CONT_PATH | 传文件 | -a(保留权限) |
docker inspect <id> | 查看详细配置 | --format(Go模板) |
docker stop/start/restart <id> | 启停控制 | -t(等待超时秒数) |
docker rm <id> | 删除容器 | -f(强制)-v(同时删volume) |
docker rmi <image> | 删除镜像 | -f(强制) |
docker compose up -d | Compose 启动 | --build-f |
2.3 镜像管理
$dockerimages--format"table {{.Repository}}\t{{.Tag}}\t{{.Size}}"REPOSITORY TAG SIZE my-nginx v192.7MB nginx alpine93.6MB redis7-alpine57.8MB mysql8.01.1GB alpine latest13.1MB小技巧:Alpine Linux 基础镜像仅 13.1MB,是制作精简镜像的首选,但注意它用
musl libc而非glibc。
Part 3: 镜像构建——从 Dockerfile 开始
3.1 Dockerfile 核心指令精讲
FROM ← 基础镜像(必须第一行) WORKDIR ← 设置工作目录 COPY/ADD ← 复制文件(COPY 简单复制, ADD 支持URL/tar解压) RUN ← 构建时执行命令(每RUN一层layer) ENV ← 环境变量 EXPOSE ← 声明端口(仅是文档, 不实际映射) CMD ← 容器启动默认命令(可被 docker run 覆盖) ENTRYPOINT ← 容器入口(docker run 参数作为其参数) VOLUME ← 声明数据卷 USER ← 切换用户 HEALTHCHECK ← 健康检查| 指令 | 执行时机 | 是否可被覆盖 | 多层影响 |
|---|---|---|---|
RUN | 构建时 (build) | 否 | 每 RUN 一层 |
CMD | 运行时 (run) | docker run IMG cmd完全覆盖 | 只有最后一层 |
ENTRYPOINT | 运行时 (run) | 需--entrypoint强覆盖 | 只有最后一层 |
COPY vs ADD:
| 指令 | 功能 | 建议 |
|---|---|---|
COPY | 从构建上下文复制文件 | 优先使用 |
ADD | 复制 + URL下载 + 自动解压tar | 仅在需要tar自动解压时用 |
3.2 实战:构建一个 Nginx 静态网站
在docker-01上实操:
$mkdir/tmp/docker-nginx $cat>/tmp/docker-nginx/Dockerfile<<'DEOF' FROM nginx:alpine LABEL maintainer="admin@example.com" LABEL description="Nginx 静态网站实战" COPY index.html /usr/share/nginx/html/ EXPOSE 80 CMD ["nginx", "-g", "daemon off;"] DEOF$echo"<h1>Hello from Docker Nginx!</h1>">/tmp/docker-nginx/index.html $dockerbuild-tmy-nginx:v1 /tmp/docker-nginx# Step 1/6 : FROM nginx:alpine# Step 2/6 : LABEL maintainer=...# Step 3/6 : COPY index.html /usr/share/nginx/html/# Step 4/6 : EXPOSE 80# Step 5/6 : CMD ["nginx", "-g", "daemon off;"]# Successfully built my-nginx:v1$dockerrun-d--namenginx-build-demo-p8090:80 my-nginx:v1 $curl-shttp://localhost:8090/<h1>Hello from Docker Nginx!</h1>$dockerimages my-nginx--format"table {{.Repository}}\t{{.Tag}}\t{{.Size}}"REPOSITORY TAG SIZE my-nginx v192.7MB3.3 进阶:多阶段构建优化镜像大小
┌────────────────────────────────────────────────────────┐ │ 传统构建 (1个镜像) │ │ ┌──────────────────────┐ │ │ │ FROM JDK │ │ │ │ COPY src . │ │ │ │ RUN mvn package │ ← 构建工具 + 代码都留在镜像 │ │ │ CMD java -jar ... │ 体积: 500MB+ │ │ └──────────────────────┘ │ └────────────────────────────────────────────────────────┘ ┌────────────────────────────────────────────────────────┐ │ 多阶段构建 (Multi-stage) │ │ ┌──────────────────────┐ ┌──────────────────┐ │ │ │ Stage 1: build │ │ Stage 2: runtime │ │ │ │ FROM maven:3.9 AS b │ │ FROM jre:17 │ │ │ │ COPY src . │ │ COPY --from=b /app│ │ │ │ RUN mvn package │──▶│ CMD java -jar ... │ │ │ └────────┬─────────────┘ └──────────────────┘ │ │ │ 体积: 120MB ↓↓↓ │ │ 构建产物 (.jar) 仅复制到运行阶段 │ └────────────────────────────────────────────────────────┘多阶段构建 Dockerfile 模板:
# === 阶段1: 编译 === FROM maven:3.9-eclipse-temurin-17 AS build WORKDIR /app COPY pom.xml . RUN mvn dependency:go-offline # 缓存依赖(加速后续构建) COPY src ./src RUN mvn package -DskipTests # === 阶段2: 运行 === FROM eclipse-temurin:17-jre WORKDIR /app COPY --from=build /app/target/*.jar app.jar EXPOSE 8080 CMD ["java", "-jar", "app.jar"]企业级技巧:
.dockerignore:避免node_modules/,.git/,*.md进入构建上下文- 层优化:把不变的层放前面(依赖 > 代码),变动层放后面
- 非 root 用户:
USER 1000避免容器内 root 权限 - 健康检查:
HEALTHCHECK CMD curl -f http://localhost/ || exit 1
Part 4: 容器网络与数据持久化
4.1 网络模式实战
Docker 三大网络模式:
| 模式 | 特点 | 适用场景 |
|---|---|---|
| bridge(默认) | 独立网络栈,NAT 通信 | 一般容器,需端口映射 |
| host | 共享宿主机网络栈 | 高性能场景(如监控 agent) |
| none | 无网络,完全隔离 | 安全敏感(如密钥生成) |
# 查看网络模式$dockernetworklsNETWORK ID NAME DRIVER SCOPE 683234b9fb40 bridge bridgelocal← 默认 bridge 02635a047886hosthostlocal0cf4b1c9abef none nulllocal4.2 自定义网络:容器间 DNS 互通
# 创建自定义网络(内置 DNS 解析!)$dockernetwork create app-net $dockernetwork inspect app-net--format'Subnet: {{range .IPAM.Config}}{{.Subnet}}{{end}}'Subnet:172.18.0.0/16# 在同一网络中启动容器$dockerrun-d--nameweb--networkapp-net nginx:alpine $dockerrun-d--nameapp--networkapp-net alpinesleep300# DNS 解析测试(容器名 → IP,自动!)$dockerexecappping-c2web PING web(172.18.0.2):56data bytes64bytes from172.18.0.2:seq=0ttl=64time=0.120ms64bytes from172.18.0.2:seq=1ttl=64time=0.115ms关键:自定义 bridge 网络提供自动 DNS 解析,容器间用名称即可通信,不用
--link(已废弃)!
4.3 Volume vs Bind Mount
┌──────────────────────────────────────────────────┐ │ Volume (Docker 管理) │ │ Container ───► /var/lib/mysql │ │ │ │ │ ┌──────▼─────────┐ │ │ │ /var/lib/docker│ │ │ │ /volumes/... │ ← Docker 管理 │ │ └────────────────┘ │ └──────────────────────────────────────────────────┘ ┌──────────────────────────────────────────────────┐ │ Bind Mount (宿主机直连) │ │ Container ───► /app/config │ │ │ │ │ ┌──────▼──────┐ │ │ │ /home/user/ │ ← 用户管理 │ │ │ config/ │ │ │ └─────────────┘ │ └──────────────────────────────────────────────────┘| 类型 | 管理方 | 路径 | 跨容器 | 适用场景 |
|---|---|---|---|---|
| Volume | Docker | /var/lib/docker/volumes/ | ✅ | 数据库、Redis |
| Bind Mount | 用户 | 任意宿主机路径 | ❌ | 开发调试、配置热更新 |
实战:Volume 持久化数据(在 docker-01 上已执行):
$dockervolume create mysql-data $dockerrun-d--namemysql-persist\-eMYSQL_ROOT_PASSWORD=root123\-vmysql-data:/var/lib/mysql\mysql:8.0# 写入测试数据$dockerexecmysql-persist mysql-uroot-proot123\-e"CREATE TABLE testdb.demo(id INT); INSERT INTO testdb.demo VALUES(42);"# 重启容器$dockerrestart mysql-persist# 数据仍在!$dockerexecmysql-persist mysql-uroot-proot123\-e"SELECT * FROM testdb.demo;"+------+|id|+------+|42|+------+Bind Mount 演示:
$echo"host file content">/tmp/bind-demo.txt $dockerrun--rm-v/tmp/bind-demo.txt:/data/file.txt:ro alpinecat/data/file.txthostfilecontent# :ro = read-only,防止容器修改宿主机文件Part 5: Compose 编排——告别单容器时代
5.1 docker-compose.yml 语法精要
核心三要素:services,networks,volumes
# docker-compose.yml# 三要素: services, networks, volumesservices:# 定义服务(容器)web:# 服务名(即 DNS 名)image:nginx:alpineports:-"9090:80"volumes:-./html:/usr/share/nginx/html:rorestart:unless-stopped# 生产必备!redis:image:redis:7-alpineports:-"6379:6379"restart:unless-stoppedcommand:redis-server--save 60 1--loglevel warning5.2 实战:一键部署 Nginx + Redis
真实执行(docker-01):
$mkdir-p/tmp/compose-demo/html $echo"<h1>Compose Demo - Nginx + Redis</h1>">/tmp/compose-demo/html/index.html $dockercompose up-d# [+] Running 4/4# Network compose-demo_default Created# Container compose-demo-web-1 Started# Container compose-demo-redis-1 Started$dockerps--format"table {{.Names}}\t{{.Image}}\t{{.Status}}"NAMES IMAGE STATUS compose-demo-web-1 nginx:alpine Up5seconds compose-demo-redis-1 redis:7-alpine Up5seconds# 测试 Web$curl-shttp://localhost:9090/<h1>Compose Demo - Nginx + Redis</h1># 测试 Redis$dockerexeccompose-demo-redis-1 redis-clipingPONG5.3 环境变量管理
# .env 文件(自动加载)$cat.envREDIS_PASSWORD=secret123DB_HOST=mysql-db# docker-compose.yml 中使用services: app: environment: -REDIS_PASSWORD=${REDIS_PASSWORD:-default}# 有默认值-DB_HOST=${DB_HOST:?DB_HOST is required}# 必须设置关键注意:
depends_on只等容器启动,不等待服务就绪!MySQL 可能需要 30s 初始化。- 解决方案:健康检查 +
wait-for-it.sh脚本 restart: unless-stopped生产必备(手动 stop 不会重启,其他退出都重启)
| restart 值 | 行为 |
|---|---|
no(默认) | 不自动重启 |
always | 无论退出码都重启 |
on-failure:N | 仅非0退出码重启,最多 N 次 |
unless-stopped | 推荐:手动 stop 不重启,其他都重启 |
5.4 常用 Compose 命令
dockercompose up-d# 后台启动dockercompose down# 停止并删除容器/网络dockercompose down-v# 同时删除 Volume!dockercomposeps# 查看服务状态dockercompose logs-fweb# 实时日志dockercompose restart# 重启所有服务dockercompose up-d--build# 重新构建并启动Part 6: 调试与故障排查实战
6.1 容器启动失败?5 步诊断法
Container 启动失败! │ ┌─────▼──────┐ ① │ docker logs │ → 看错误输出 └─────┬──────┘ │ ┌─────▼──────────────┐ ② │ docker inspect │ → 查 CMD/Entrypoint/Env └─────┬──────────────┘ │ ┌─────▼────────────────────┐ ③ │ docker exec -it <id> sh │ → 进容器检查文件/权限 └─────┬────────────────────┘ │ ┌─────▼────────────────────┐ ④ │ netstat -tulnp | grep :XX│ → 检查端口冲突 └─────┬────────────────────┘ │ ┌─────▼────────────────────┐ ⑤ │ /var/log/syslog/audit.log│ → 宿主机日志 └──────────────────────────┘ │ [ 定位根因! ]实际诊断演示:
# 故意创建一个会退出的容器$dockerrun-d--namebad-cmd alpine /bin/nonexistent $dockerps-a--format"table {{.Names}}\t{{.Status}}"NAMES STATUS bad-cmd Exited(127)1second ago ← 启动即退出, 退出码127$dockerlogs bad-cmdexec/bin/nonexistent: no suchfileor directory ← 定位到问题!$dockerinspect bad-cmd--format'CMD: {{.Config.Cmd}}'CMD:[/bin/nonexistent]← 确认 CMD 错误6.2 经典问题合集
| 错误 | 原因 | 解决 |
|---|---|---|
port is already allocated | 端口冲突 | lsof -i :8080找出占用进程 + 换端口 |
standard_init_linux.go:228: exec user process caused: no such file or directory | CRLF 换行符 | dos2unix或git config core.autocrlf=false |
Permission denied挂载目录 | SELinux/AppArmor | 加:z标签或改用非 root 用户 |
bind: address already in use | 端口已被占用 | 检查docker ps已存在的容器 |
429 Too Many Requests | 镜像仓库限流 | 换镜像源或等待 |
COPY failed: file not found | 构建上下文路径不对 | 检查.dockerignore和 Dockerfile 中的相对路径 |
6.3 端口冲突实战(真实踩坑)
# docker-01 上的真实错误$dockerrun-d--nameweb-demo-p8088:80 nginx:alpine Error response from daemon: Bindfor0.0.0.0:8088 failed: port is already allocated# 诊断$dockerps--format"table {{.Names}}\t{{.Ports}}"NAMES PORTS nginx-demo0.0.0.0:8088->80/tcp ←8088已被占用!# 解决:先停掉占用的或换端口$dockerstop nginx-demo&&dockerrmnginx-demo# 或$dockerrun-d--nameweb-demo-p9090:80 nginx:alpinePart 7: 企业级入门实践
7.1 CI/CD 中的 Docker
┌──────────────────────────────────────────────────────┐ │ Jenkins / GitHub Actions │ │ │ │ git push ──► Build ──► Test ──► Push Image ──► Deploy│ │ │ │ │ │ docker build docker push │ │ │ │ │ │ ┌────▼────┐ ┌───────▼────────┐ │ │ │ 本地镜像 │ │ Harbor/ECR/ACR │ │ │ └─────────┘ │ (私有仓库) │ │ │ └───────┬────────┘ │ │ │ │ │ docker pull │ │ │ │ │ ┌─────▼─────┐ │ │ │ K8s / ECS │ │ │ └───────────┘ │ └──────────────────────────────────────────────────────┘# GitHub Actions 示例name:Docker Build & Pushon:[push]jobs:build:runs-on:ubuntu-lateststeps:-uses:actions/checkout@v3-name:Build Imagerun:docker build-t myapp:${{github.sha}}.-name:Push to Registryrun:|docker tag myapp:${{ github.sha }} registry.example.com/myapp:${{ github.sha }} docker push registry.example.com/myapp:${{ github.sha }}7.2 Docker 最佳实践 Checklist
☑ 使用 .dockerignore 避免打包无用文件 ☑ 镜像分层合理(不变层在上,变化层在下) ☑ 非 root 用户运行容器 (USER 1000) ☑ 启用健康检查 (HEALTHCHECK) ☑ 标签规范 v1.2.3-{BUILD_NUMBER} ☑ 多阶段构建减小镜像体积 ☑ 日志输出到 stdout/stderr (不要写文件) ☑ 避免在 Dockerfile 中写密码 (用 --build-arg + secrets) ☑ 生产环境 restart: unless-stopped ☑ 资源限制 --memory --cpus 防止容器耗尽宿主机 ☑ 定期清理无用镜像/容器 (docker system prune -f)7.3 安全提醒
# ❌ 危险做法 FROM ubuntu:latest ENV DB_PASSWORD=mysecret123 # 密码明文写在镜像层! USER root # root 运行! # ✅ 安全做法 FROM ubuntu:24.04 # 固定版本,不用 :latest RUN groupadd -r appgroup && useradd -r -g appgroup appuser USER appuser # 非 root 运行 # 密码通过 docker run -e 或 secrets 传入附录 & 资源包
A. 镜像大小优化对比
| 方案 | 基础镜像 | 大小 | 说明 |
|---|---|---|---|
| 传统 JDK | openjdk:17 | ~470MB | 含完整 JDK |
| JRE 精简 | eclipse-temurin:17-jre | ~210MB | 仅运行时 |
| Alpine JRE | eclipse-temurin:17-jre-alpine | ~185MB | 最小 JRE |
| 多阶段 | 自定义 | ~120MB | 编译+运行分离 |
| Distroless | gcr.io/distroless/java17 | ~120MB | Google 最小化 |
| 方案 | 基础镜像 | 大小 | 说明 |
|---|---|---|---|
| Nginx 官方 | nginx:latest | ~187MB | Debian 基础 |
| Nginx Alpine | nginx:alpine | ~93MB | 实测 93.6MB |
| Nginx Distroless | nginx:alpine+精简 | ~60MB | 去掉 shell |
B. Docker 命令速查卡
镜像管理: docker pull <img>:<tag> 拉取镜像 docker build -t <name> . 构建镜像 docker push <img>:<tag> 推送镜像 docker rmi <img> 删除镜像 docker tag <src> <dst> 打标签 docker save/load 导入导出 容器管理: docker run -d --name X -p H:C IMG 启动 docker exec -it X /bin/bash 进入 docker logs -f X 看日志 docker cp HOST_PATH X:CONT_PATH 传文件 docker commit X new:tag 保存为镜像 系统管理: docker system df 磁盘占用 docker system prune -f 清理无用资源 docker stats --no-stream 资源监控 docker info 系统信息 Compose: docker compose up -d 启动 docker compose down -v 停止+清理 docker compose ps 状态 docker compose logs -f svc 日志C. 常见问题 FAQ
Q1: 容器退出后数据还在吗?
A: 容器删除后可写层数据丢失。Volume/Bind Mount 的数据保留。
Q2: 如何让容器开机自启?
A:docker run --restart unless-stopped或 Compose 中设restart: unless-stopped
Q3: 容器之间如何通信?
A: 创建自定义 bridge 网络,容器间用服务名(容器名)做 DNS 解析。
Q4: 镜像太大怎么办?
A: 多阶段构建 + Alpine 基础镜像 +.dockerignore+ 清理apt-get clean
Q5: docker compose 和 docker-compose 区别?
A:docker compose是 Docker CLI 插件(v2),docker-compose是独立 Python 脚本(v1 已废弃)。
Q6: 如何限制容器资源?
A:docker run --memory 512m --cpus 1.5
Q7: 生产环境需要哪些镜像?
A: 应用镜像 + 监控 (Prometheus) + 日志 (ELK) + 反向代理 (Nginx/Traefik) + 数据库 (建议用云服务而非容器)
Q8: 容器内时间不对?
A:docker run -v /etc/localtime:/etc/localtime:ro或设置 TZ 环境变量
今日挑战
尝试用 Alpine 构建一个 Python Flask 应用容器,要求:
- 基于
python:3-alpine- 安装 Flask (
pip install flask)- 编写一个返回
{"status": "ok"}的/health接口- 最终镜像 < 100MB
提示:
cd /tmp && docker build -t flask-app:alpine .
本系列博客基于华为云 ecs-fce0 集群实战操作编写,Docker CE 29.5.3,所有输出均为真实服务器执行结果。
