Docker镜像拉取、制作与上传的完整指南
作者:知远漫谈
在现代软件开发和部署中,容器化技术已经成为不可或缺的一部分。Docker 作为最流行的容器平台,其核心概念之一就是“镜像”。本文将带你深入理解 Docker 镜像的本质,掌握在 Linux 环境下如何拉取、制作并上传 Docker 镜像,并结合 Java 应用场景给出实用示例。
什么是 Docker 镜像?
Docker 镜像是一个轻量级、独立的、可执行的软件包,它包含了运行某个软件所需的一切:代码、运行时环境、系统工具、系统库和配置文件。镜像采用分层结构,每一层都是只读的,当容器启动时,会在镜像之上添加一个可写层(容器层)。
你可以把 Docker 镜像想象成一个“应用快照”,无论部署到哪台机器上,只要支持 Docker,就能保证一致的运行环境。
# 查看本地已有的镜像 docker images
输出示例:
REPOSITORY TAG IMAGE ID CREATED SIZE nginx latest abc123def456 2 weeks ago 142MB hello-world latest def789ghi012 3 months ago 13.3kB
第一部分:拉取 Docker 镜像
基础命令:docker pull
最简单的拉取方式是使用 docker pull 命令:
docker pull nginx:latest
这会从 Docker Hub(默认注册中心)拉取最新版的 Nginx 镜像。
你也可以指定特定版本:
docker pull openjdk:17-jdk-slim
这个命令会拉取 OpenJDK 17 的精简版镜像,非常适合运行 Java 应用。
拉取私有仓库或第三方镜像
如果你使用的是阿里云、腾讯云等国内镜像加速服务,或者公司内部私有仓库,可以这样拉取:
docker pull registry.cn-hangzhou.aliyuncs.com/library/nginx:1.21
或者登录后拉取私有镜像:
docker login myregistry.example.com docker pull myregistry.example.com/myapp:1.0.0
加速镜像拉取 —— 配置镜像加速器
在国内,直接访问 Docker Hub 可能较慢。推荐配置镜像加速器。
编辑 /etc/docker/daemon.json(若不存在则新建):
{
"registry-mirrors": [
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com",
"https://mirror.baidubce.com"
]
}
重启 Docker 服务:
sudo systemctl daemon-reload sudo systemctl restart docker
验证是否生效:
docker info | grep -A 3 "Registry Mirrors"
实战:拉取 Java 运行环境镜像
我们来拉取一个适合运行 Spring Boot 应用的镜像:
docker pull eclipse-temurin:17-jre-alpine
这个镜像是基于 Alpine Linux 的轻量级 JRE 17 镜像,体积小,安全补丁更新及时,是生产环境的理想选择。
第二部分:制作 Docker 镜像
制作镜像的核心是编写 Dockerfile —— 一个定义镜像构建步骤的文本文件。
编写你的第一个 Dockerfile
假设我们有一个简单的 Java 控制台程序:
// HelloWorld.java
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, Dockerized Java World! 🐳");
System.out.println("Current time: " + java.time.LocalDateTime.now());
}
}
编译它:
javac HelloWorld.java
现在创建 Dockerfile:
# 使用官方 OpenJDK 17 JRE 镜像作为基础镜像 FROM eclipse-temurin:17-jre-alpine # 设置工作目录 WORKDIR /app # 将编译好的 class 文件复制进镜像 COPY HelloWorld.class . # 设置容器启动时执行的命令 CMD ["java", "HelloWorld"]
构建镜像
在包含 Dockerfile 和 HelloWorld.class 的目录下执行:
docker build -t my-java-app:1.0 .
参数说明:
-t:指定镜像名称和标签.:表示当前目录为构建上下文(context)
构建成功后,查看镜像:
docker images | grep my-java-app
运行你的镜像
docker run --rm my-java-app:1.0
你应该看到输出:
Hello, Dockerized Java World! 🐳 Current time: 2025-04-05T10:30:45.123
成功!你已经制作并运行了第一个 Java Docker 镜像!
深入 Dockerfile —— 更复杂的 Java 应用
现实中的 Java 应用通常是打包成 .jar 文件的 Spring Boot 项目。我们来看看如何为这类应用构建镜像。
项目结构示例
my-spring-app/ ├── src/ │ └── main/ │ └── java/ │ └── com/example/DemoApplication.java ├── pom.xml └── Dockerfile
DemoApplication.java 示例:
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@GetMapping("/hello")
public String hello() {
return "Hello from Dockerized Spring Boot! 🐳";
}
}
使用 Maven 打包:
mvn clean package
生成 target/demo-app.jar
编写优化版 Dockerfile
# 第一阶段:构建阶段
FROM maven:3.8.6-eclipse-temurin-17 AS builder
WORKDIR /app
# 复制 pom.xml 并下载依赖(利用缓存)
COPY pom.xml .
RUN mvn dependency:go-offline -B
# 复制源码并打包
COPY src ./src
RUN mvn package -DskipTests
# 第二阶段:运行阶段
FROM eclipse-temurin:17-jre-alpine
# 安装时区数据(可选但推荐)
RUN apk add --no-cache tzdata
# 创建非 root 用户提高安全性
RUN addgroup -g 1001 -S appgroup && \
adduser -u 1001 -S appuser -G appgroup
WORKDIR /app
# 从构建阶段复制 jar 包
COPY --from=builder /app/target/demo-app*.jar app.jar
# 更改文件所有者
RUN chown appuser:appgroup app.jar
# 切换到非 root 用户
USER appuser
# 暴露端口
EXPOSE 8080
# 启动应用
ENTRYPOINT ["java", "-jar", "app.jar"]
多阶段构建的优势
上述 Dockerfile 使用了多阶段构建(multi-stage build),好处包括:
- 最终镜像不包含 Maven、源码等构建工具,体积更小
- 安全性更高(没有多余工具可被攻击者利用)
- 构建层缓存更高效(pom.xml 不变则跳过依赖下载)
镜像大小对比图表
渲染错误: Mermaid 渲染失败: Parsing failed: Lexer error on line 3, column 5: unexpected character: ->“<- at offset: 30, skipped 11 characters. Lexer error on line 3, column 17: unexpected character: ->:<- at offset: 42, skipped 1 characters. Lexer error on line 4, column 5: unexpected character: ->“<- at offset: 52, skipped 9 characters. Lexer error on line 4, column 15: unexpected character: ->:<- at offset: 62, skipped 1 characters. Lexer error on line 5, column 5: unexpected character: ->“<- at offset: 72, skipped 11 characters. Lexer error on line 5, column 17: unexpected character: ->:<- at offset: 84, skipped 1 characters. Parse error on line 3, column 19: Expecting token of type 'EOF' but found `580`. Parse error on line 4, column 17: Expecting token of type 'EOF' but found `190`. Parse error on line 5, column 19: Expecting token of type 'EOF' but found `165`.
可以看到,通过多阶段构建和使用 Alpine 基础镜像,体积减少了约 70%!
构建并测试 Spring Boot 镜像
# 构建镜像 docker build -t spring-demo:1.0 . # 运行容器,映射端口 docker run -d -p 8080:8080 --name myapp spring-demo:1.0 # 查看日志 docker logs -f myapp # 测试接口 curl http://localhost:8080/hello
预期输出:
Hello from Dockerized Spring Boot! 🐳
清理无用镜像和容器
构建过程中会产生中间镜像,定期清理很有必要:
# 删除停止的容器 docker container prune # 删除未被使用的镜像 docker image prune -a # 删除所有未使用的资源(谨慎!) docker system prune -a
第三部分:上传 Docker 镜像
制作好的镜像,通常需要推送到远程仓库,便于团队共享或部署到生产环境。
登录 Docker Hub 或私有仓库
docker login
输入你的用户名和密码(或访问令牌)。如果是私有仓库:
docker login myregistry.corp.com
标记镜像
推送前,必须给镜像打上符合目标仓库格式的标签:
# 格式:[仓库地址/]用户名/镜像名:标签 docker tag spring-demo:1.0 yourusername/spring-demo:1.0 # 如果是私有仓库: docker tag spring-demo:1.0 myregistry.corp.com/yourteam/spring-demo:1.0
推送镜像
docker push yourusername/spring-demo:1.0
推送成功后,其他人就可以通过 docker pull yourusername/spring-demo:1.0 拉取使用了!
安全最佳实践
使用非 root 用户
前面的 Dockerfile 中我们创建了 appuser,这是非常推荐的做法:
RUN adduser -u 1001 -S appuser USER appuser
避免容器内以 root 身份运行应用,降低安全风险。
固定基础镜像版本
不要使用 latest 标签:
# ❌ 不推荐 FROM eclipse-temurin:latest # ✅ 推荐 FROM eclipse-temurin:17.0.8_7-jre-alpine
这样可以确保构建的可重复性和稳定性。
扫描镜像漏洞
可以使用 docker scan(需安装 Docker Desktop 或 Snyk CLI):
docker scan yourusername/spring-demo:1.0
或者使用开源工具 Trivy:
trivy image yourusername/spring-demo:1.0
使用 BuildKit 提升构建体验
BuildKit 是 Docker 的新一代构建引擎,支持并行构建、更好的缓存、更清晰的输出等。
启用方式:
export DOCKER_BUILDKIT=1 docker build -t myapp .
或者在 /etc/docker/daemon.json 中全局启用:
{
"features": {
"buildkit": true
}
}实战案例:自动化构建脚本
创建一个 build.sh 脚本来自动化整个流程:
#!/bin/bash
set -e # 遇错即停
APP_NAME="spring-demo"
VERSION="1.0.0"
IMAGE_TAG="$APP_NAME:$VERSION"
REGISTRY_USER="your_dockerhub_username"
echo "📦 正在打包 Maven 项目..."
./mvnw clean package -DskipTests
echo "🏗️ 正在构建 Docker 镜像..."
DOCKER_BUILDKIT=1 docker build -t $IMAGE_TAG .
echo "🧪 正在本地测试镜像..."
CONTAINER_ID=$(docker run -d -p 8080:8080 $IMAGE_TAG)
sleep 10 # 等待应用启动
if curl -s http://localhost:8080/actuator/health | grep -q "UP"; then
echo "✅ 应用健康检查通过"
else
echo "❌ 应用启动失败"
docker logs $CONTAINER_ID
docker stop $CONTAINER_ID
exit 1
fi
docker stop $CONTAINER_ID
echo "🏷️ 正在标记镜像..."
docker tag $IMAGE_TAG $REGISTRY_USER/$IMAGE_TAG
echo "🔐 正在登录 Docker Hub..."
echo "$DOCKER_PASSWORD" | docker login -u "$REGISTRY_USER" --password-stdin
echo "📤 正在推送镜像..."
docker push $REGISTRY_USER/$IMAGE_TAG
echo "🎉 镜像发布完成!"
提示:敏感信息如密码应使用环境变量或密钥管理工具,不要硬编码在脚本中。
使用 .dockerignore 优化构建
类似 .gitignore,.dockerignore 用于排除不需要复制到构建上下文的文件:
.git .gitignore README.md *.md target/ !target/*.jar logs/ *.log .env .DS_Store
放在项目根目录,与 Dockerfile 同级。
调试技巧
查看镜像历史
docker history myimage:tag
可以了解每一层做了什么、大小多少。
进入容器调试
如果容器启动失败,可以这样进入调试:
# 启动临时容器并进入 shell docker run -it --rm myimage:tag sh # 或者针对已运行的容器 docker exec -it container_name sh
查看镜像详细信息
docker inspect myimage:tag
返回 JSON 格式的完整元数据,包括环境变量、挂载点、网络配置等。
高级技巧:使用 Build Args 和 ENV
可以在构建时传入参数:
ARG APP_PORT=8080 ENV PORT=$APP_PORT EXPOSE $APP_PORT
构建时指定:
docker build --build-arg APP_PORT=9000 -t myapp .
自动化 CI/CD 集成
虽然不能提供 GitHub Actions 示例,但在 Jenkins、GitLab CI、Drone 等平台都可以轻松集成 Docker 构建。
通用流程:
- 代码提交触发流水线
- 拉取代码
- 编译打包
- 构建 Docker 镜像
- 推送到仓库
- 通知部署系统
性能优化建议
合理安排 Dockerfile 指令顺序
经常变动的指令(如 COPY 源码)应放在后面,不变的指令(如安装系统包)放在前面,以便充分利用缓存。
# 👍 好的顺序 FROM ... RUN apt-get update && apt-get install -y some-package COPY pom.xml . RUN mvn dependency:go-offline COPY src ./src # ← 经常变动放最后
使用 .jar 分层(Spring Boot 2.3+)
Spring Boot 2.3 开始支持分层 jar,可以进一步优化 Docker 层缓存:
在 pom.xml 中启用:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<layers>
<enabled>true</enabled>
</layers>
</configuration>
</plugin>然后在 Dockerfile 中:
FROM eclipse-temurin:17-jre-alpine as builder WORKDIR application COPY target/demo-app.jar app.jar RUN java -Djarmode=layertools -jar app.jar extract FROM eclipse-temurin:17-jre-alpine WORKDIR application COPY --from=builder application/dependencies/ ./ COPY --from=builder application/snapshot-dependencies/ ./ COPY --from=builder application/resources/ ./ COPY --from=builder application/application/ ./ ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]
这样,只有业务代码变更时才会重建最后一层,大幅提升构建速度。
镜像管理策略
版本控制
推荐使用语义化版本:
myapp:1.0.0—— 生产稳定版myapp:1.0.0-beta—— 预发布版myapp:sha-abc123—— Git Commit 对应版myapp:latest—— 最新版(慎用于生产)
生命周期管理
制定镜像保留策略:
- 开发环境:保留最近 10 个版本
- 测试环境:保留带标签的所有版本
- 生产环境:保留所有上线过的版本
可以编写脚本定期清理:
# 删除 30 天前未使用的镜像 docker image prune -a --filter "until=720h"
私有镜像仓库搭建
虽然 Docker Hub 很方便,但企业通常需要私有仓库。
推荐使用 Harbor 或 Nexus Repository。
快速启动 Harbor(使用 docker-compose):
# docker-compose.yml 片段
version: '2.3'
services:
harbor-core:
image: goharbor/harbor-core:v2.7.0
# ... 其他配置访问 https://goharbor.io 获取完整安装指南。
测试你的镜像
健康检查
在 Dockerfile 中加入健康检查:
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \ CMD curl -f http://localhost:8080/actuator/health || exit 1
运行后查看状态:
docker ps --format "table {{.Names}}\t{{.Status}}"
集成测试
编写测试脚本验证镜像功能:
#!/bin/bash
IMAGE=$1
CONTAINER=test-container
docker run -d --name $CONTAINER -p 8080:8080 $IMAGE
sleep 15
if ! curl -s http://localhost:8080/hello | grep -q "Dockerized"; then
echo "❌ 测试失败"
docker logs $CONTAINER
exit 1
fi
echo "✅ 所有测试通过"
docker rm -f $CONTAINER
常见问题解答
如何减小 Java 镜像体积?
- 使用
jlink创建自定义 JRE(Java 9+) - 使用 Alpine 基础镜像
- 多阶段构建
- 分层 Jar
构建很慢怎么办?
- 使用国内镜像加速器
- 合理利用缓存(调整 Dockerfile 顺序)
- 使用 BuildKit
- 分层构建依赖
容器启动后立即退出?
- 检查
ENTRYPOINT或CMD是否正确 - 查看日志:
docker logs <container> - 交互式运行调试:
docker run -it yourimage sh
进阶:使用 Jib 工具(无需 Dockerfile)
Google 开发的 Jib 工具可以直接从 Maven/Gradle 构建 Docker 镜像,无需编写 Dockerfile。
在 pom.xml 中添加插件:
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>3.3.1</version>
<configuration>
<from>
<image>eclipse-temurin:17-jre-alpine</image>
</from>
<to>
<image>your-dockerhub-username/spring-app</image>
<tags>
<tag>latest</tag>
<tag>${project.version}</tag>
</tags>
</to>
<container>
<mainClass>com.example.DemoApplication</mainClass>
<ports>
<port>8080</port>
</ports>
</container>
</configuration>
</plugin>构建并推送:
./mvnw compile jib:build
Jib 会自动优化层结构、处理依赖缓存,是现代化 Java 项目的推荐方案。
镜像构建时间优化前后对比
渲染错误: Mermaid 渲染失败: Parse error on line 7: ...依赖 :a1, 0, 120 编译源码 :a2, -----------------------^ Expecting 'taskData', got 'NL'
通过缓存复用和分层构建,总构建时间从 300 秒降至 85 秒!
总结
掌握 Docker 镜像的拉取、制作与上传,是现代开发者必备技能。本文从基础命令讲起,逐步深入到 Java 应用的实战构建、安全加固、性能优化和自动化部署,希望能为你提供完整的知识体系。
记住几个关键点:
- ✅ 使用多阶段构建减小镜像体积
- ✅ 固定基础镜像版本确保一致性
- ✅ 使用非 root 用户提升安全性
- ✅ 合理利用缓存加速构建
- ✅ 自动化测试确保镜像质量
容器化不是终点,而是持续交付和云原生架构的起点。继续探索 Kubernetes、Helm、服务网格等技术,让你的应用真正“生于云、长于云”。
“Dockerize all the things!” —— 但请记得,工具是手段,不是目的。始终关注业务价值和系统稳定性。
以上就是Docker镜像拉取、制作与上传的完整指南的详细内容,更多关于Docker镜像拉取、制作与上传的资料请关注脚本之家其它相关文章!
