Docker基础

一、 Docker 基础知识速览

1. 核心三要素
  • 镜像(Image):只读的模板,包含运行应用所需的代码、运行时、库和配置。相当于面向对象中的"类"。
  • 容器(Container):镜像的运行实例。容器被创建时,会在镜像层之上添加一个可写层。相当于面向对象中的"对象"。
  • 仓库(Registry):集中存储和分发镜像的服务。如 Docker Hub(公有)、Harbor(私有)。
2. 底层核心原理
  • Namespace(命名空间):实现"视图隔离"。让容器拥有独立的 PID(进程)、Network(网络)、Mount(挂载)、IPC(进程间通信)等,使容器看起来像一台独立的机器。
  • Cgroups(控制组):实现"资源限制"。限制容器能使用的 CPU、内存、磁盘 I/O 等物理资源上限,防止单个容器耗尽宿主机资源。
  • UnionFS(联合文件系统):实现"镜像分层"。将多个目录(层)挂载到同一个虚拟文件系统下。镜像层是只读的,容器层是可写的,通过写时复制(CoW)机制提高存储和启动效率。

二、 Docker 常见核心命令大全

1. 镜像管理命令
bash 复制代码
# 从仓库拉取镜像
docker pull nginx:latest

# 查看本地镜像列表
docker images
docker image ls

# 搜索仓库中的镜像
docker search redis

# 删除本地镜像(-f 强制删除)
docker rmi nginx:latest
docker rmi -f <image_id>

# 为镜像打标签(常用于推送到私有仓库)
docker tag myapp:1.0 registry.mycompany.com/myapp:1.0

# 将镜像推送到仓库
docker push registry.mycompany.com/myapp:1.0
2. 容器生命周期命令
bash 复制代码
# 启动容器(最常用组合:后台运行、端口映射、命名、自动重启)
docker run -d -p 8080:80 --name myweb --restart unless-stopped nginx

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

# 启动 / 停止 / 重启容器
docker start <container_name_or_id>
docker stop <container_name_or_id>
docker restart <container_name_or_id>

# 删除容器(-f 强制删除运行中的容器)
docker rm <container_name_or_id>
docker rm -f <container_name_or_id>
3. 容器运维与排查命令
bash 复制代码
# 查看容器日志(-f 实时跟踪,--tail 指定行数)
docker logs -f --tail 200 <container_name_or_id>

# 进入正在运行的容器内部(推荐方式,退出不会导致容器停止)
docker exec -it <container_name_or_id> /bin/bash
# 若基础镜像为 alpine,则使用 sh
docker exec -it <container_name_or_id> /bin/sh

# 查看容器详细信息(JSON格式,常用于排查网络、挂载、配置)
docker inspect <container_name_or_id>

# 查看容器实时资源占用(CPU、内存、网络I/O)
docker stats <container_name_or_id>

# 拷贝文件(宿主机与容器之间)
docker cp ./local_file.txt <container_name>:/app/
docker cp <container_name>:/app/remote_file.txt ./
4. 系统与清理命令
bash 复制代码
# 查看 Docker 磁盘占用情况
docker system df

# 一键清理无用资源(停止的容器、未被使用的网络、悬空镜像)
docker system prune

# 深度清理(包括所有未被任何容器使用的镜像和卷)
docker system prune -a --volumes

三、 Java 后端专属 Docker 实战指南

Java 后端在容器化时,有其特殊的关注点,如 JVM 内存识别、时区问题、多阶段构建等。

1. 标准的 Java 多阶段构建 Dockerfile

多阶段构建可以大幅减小最终镜像体积,是 Java 项目的最佳实践。

dockerfile 复制代码
# ================= 第一阶段:构建阶段 =================
# 使用包含 Maven 和 JDK 的镜像进行编译
FROM maven:3.8.4-openjdk-17-slim AS builder
WORKDIR /build

# 先拷贝 pom.xml 下载依赖,利用 Docker 缓存机制
COPY pom.xml .
RUN mvn dependency:go-offline -B

# 拷贝源码并打包
COPY src ./src
RUN mvn clean package -DskipTests

# ================= 第二阶段:运行阶段 =================
# 使用轻量级的 JRE 镜像运行(体积更小,更安全)
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app

# 设置时区为东八区(Alpine 镜像必须处理时区问题)
RUN apk add --no-cache tzdata && \
    cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
    echo "Asia/Shanghai" > /etc/timezone && \
    apk del tzdata

# 从构建阶段拷贝产物
COPY --from=builder /build/target/*.jar app.jar

# 暴露端口(仅为声明,实际映射在 docker run 时指定)
EXPOSE 8080

# 使用 exec 格式,确保 Java 进程是 PID 1,能正确接收 SIGTERM 信号实现优雅停机
ENTRYPOINT ["java", "-jar", "app.jar"]
2. Java 容器启动高级命令(生产环境常用)

在启动 Java 容器时,通常需要传递 JVM 参数、挂载日志目录、设置环境变量。

bash 复制代码
docker run -d \
  --name my-spring-boot-app \
  -p 8080:8080 \
  -v /data/logs/myapp:/app/logs \
  -e SPRING_PROFILES_ACTIVE=prod \
  -e TZ=Asia/Shanghai \
  --restart unless-stopped \
  --memory="1g" \
  --cpus="2.0" \
  my-spring-boot-app:1.0.0 \
  java -XX:MaxRAMPercentage=75.0 -XX:+UseZGC -jar app.jar

参数解析(Java 后端重点关注):

  • -v /data/logs/myapp:/app/logs:将容器内的日志目录挂载到宿主机,防止容器删除后日志丢失,也方便 ELK/Filebeat 采集。
  • -e SPRING_PROFILES_ACTIVE=prod:通过环境变量指定 Spring Boot 的运行 Profile。
  • --memory="1g":限制容器最大内存为 1G。
  • java -XX:MaxRAMPercentage=75.0核心 JVM 参数。让 JVM 自动识别容器的内存限制,并将最大堆内存设置为容器限制内存的 75%(留出 25% 给堆外内存和操作系统)。避免在 Java 8 早期版本中 JVM 识别不到 Cgroups 限制而导致 OOM 被系统 Kill。
3. Java 后端常见 Docker 踩坑与排查
  • 问题一:容器内存 OOM 被 Kill(退出码 137)
    • 原因 :JVM 堆内存 + 堆外内存(Metaspace、直接内存、线程栈等)总和超过了 Docker 的 --memory 限制。
    • 解决 :不要将 -Xmx 设置得和容器限制内存一样大。推荐使用 -XX:MaxRAMPercentage=70.0 代替硬编码的 -Xmx
  • 问题二:docker stop 无法优雅停机,每次都要等 10 秒
    • 原因 :Dockerfile 中使用了 Shell 格式(如 CMD java -jar app.jar),导致 PID 1 是 /bin/sh,Java 进程是子进程,无法接收到 Docker 发送的 SIGTERM 信号。
    • 解决 :必须使用 Exec 格式(如 ENTRYPOINT ["java", "-jar", "app.jar"]),或者在 Shell 格式中使用 exec java -jar app.jar
  • 问题三:容器内日志时间与宿主机相差 8 小时
    • 原因:基础镜像(尤其是 Alpine)默认是 UTC 时区。
    • 解决 :在 Dockerfile 中配置时区(如上文 Dockerfile 所示),或在 docker run 时添加 -e TZ=Asia/Shanghai 并挂载 -v /etc/localtime:/etc/localtime:ro
相关推荐
极客先躯11 分钟前
高级java每日一道面试题-2026年02月02日-实战篇[Docker]-如何实现容器的持久化存储?
docker·容器·面试宝典·持久化·存储·韵味·java高级面试题
My is 李豆1 小时前
CentOS 7 安装 Docker 完整教程(含 docker-compose 插件)
docker·eureka·centos
极客先躯2 小时前
高级java每日一道面试题-2026年02月01日-实战篇[Docker]-Docker Volume 的生命周期管理是怎样的?
java·运维·docker·容器·持久化·架构图·容器卷
kong@react3 小时前
Rocky Linux 10.2 全面解析:企业级 CentOS 替代方案及保姆级docker安装
java·linux·运维·docker
某林2123 小时前
Isaac Sim 5.1.0 无头服务器部署与 RTX 显存段错误排障全记录
运维·服务器·docker·容器·isaac
m0_738120724 小时前
Docker 环境下 Vulfocus 靶场搭建全流程(附镜像源问题解决方案)
运维·服务器·网络·安全·docker·容器
simeple4 小时前
记一次 Docker Compose 项目迁移:从 Windows Docker Desktop 迁移到 CentOS 服务器
docker
哆啦A梦——4 小时前
Ubuntu 虚拟机 Docker 与 MySQL 8.0.42 部署指南
mysql·ubuntu·docker
Plastic garden5 小时前
K8s知识(3) Pod亲和性,调度
云原生·容器·kubernetes