docker

关注公众号 jb51net

关闭
首页 > 网站技巧 > 服务器 > 云和虚拟化 > docker > Docker镜像拉取、制作与上传

Docker镜像拉取、制作与上传的完整指南

作者:知远漫谈

本文文章主要介绍了Docker镜像的核心概念、实用示例以及最佳实践,从基础的镜像拉取、制作到高级ocker安全加固、性能优化和自动化部署,全方位讲解了Java应用在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"]

构建镜像

在包含 DockerfileHelloWorld.class 的目录下执行:

docker build -t my-java-app:1.0 .

参数说明:

构建成功后,查看镜像:

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),好处包括:

镜像大小对比图表

渲染错误: 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 构建。

通用流程:

  1. 代码提交触发流水线
  2. 拉取代码
  3. 编译打包
  4. 构建 Docker 镜像
  5. 推送到仓库
  6. 通知部署系统

性能优化建议

合理安排 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"]

这样,只有业务代码变更时才会重建最后一层,大幅提升构建速度。

镜像管理策略

版本控制

推荐使用语义化版本:

生命周期管理

制定镜像保留策略:

可以编写脚本定期清理:

# 删除 30 天前未使用的镜像
docker image prune -a --filter "until=720h"

私有镜像仓库搭建

虽然 Docker Hub 很方便,但企业通常需要私有仓库。

推荐使用 HarborNexus 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 镜像体积?

构建很慢怎么办?

容器启动后立即退出?

进阶:使用 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 应用的实战构建、安全加固、性能优化和自动化部署,希望能为你提供完整的知识体系。

记住几个关键点:

容器化不是终点,而是持续交付和云原生架构的起点。继续探索 Kubernetes、Helm、服务网格等技术,让你的应用真正“生于云、长于云”。

“Dockerize all the things!” —— 但请记得,工具是手段,不是目的。始终关注业务价值和系统稳定性。

以上就是Docker镜像拉取、制作与上传的完整指南的详细内容,更多关于Docker镜像拉取、制作与上传的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文