SoFunction
Updated on 2025-04-14

The entire process of Java project packaging Docker image

Environmental preparation

1. Development environment requirements

  • JDK 8+ (Recommended JDK 11/17 LTS version)
  • Maven 3.6+ or Gradle 7+
  • Docker Desktop (Mac/Windows) or Docker Engine (Linux)
  • Recommended IDE: IntelliJ IDEA (Community Edition)

2. Install Docker

Installation methods for different operating systems:

Linux (Ubuntu as an example):

# Uninstall the old versionsudo apt-get remove docker docker-engine  containerd runc

# Installation dependenciessudo apt-get update
sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg \
    lsb-release

# Add Docker official GPG keycurl -fsSL /linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/

# Set up a stable repositoryecho \
  "deb [arch=amd64 signed-by=/usr/share/keyrings/] /linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt// > /dev/null

# Install Docker Enginesudo apt-get update
sudo apt-get install docker-ce docker-ce-cli 

# Verify installationsudo docker run hello-world

Mac/Windows:Download the Docker Desktop installation package directly:
/products/docker-desktop

3. Verify the installation

docker --version
# The output is similar: Docker version 20.10.12, build e91ed57
docker-compose --version
# The output is similar: docker-compose version 1.29.2, build 5becea4c

Project structure description

Let's take a typical Spring Boot project as an example:

my-java-app/
├── src/
│   ├── main/
│   │   ├── java/com/example/demo/
│   │   │   ├── 
│   │   │   └── controllers/
│   │   └── resources/
│   │       ├── 
│   │       └── static/
│   └── test/
├── target/
│   ├── my-java-app-0.0.
│   └── ...
├── 
└── Dockerfile

Docker basic concepts

Before you begin, understand a few core concepts:

  • Image: Read-only template, containing all the content you need to run the application
  • Container: Running example of mirror
  • Dockerfile: Build the mirrored instruction file
  • Registry: Mirror repository (such as Docker Hub)

Docker's Advantages:

  • A consistent operating environment
  • Rapid deployment and scaling
  • Resource Isolation
  • Easy version management and rollback

Writing Dockerfile

Basic Dockerfile examples

# Phase 1: ConstructionFROM maven:3.8.4-openjdk-11 AS build
WORKDIR /app
COPY  .
#Use cache to download dependenciesRUN mvn dependency:go-offline
COPY src ./src
RUN mvn package -DskipTests

#Stage 2: RunFROM openjdk:11-jre-slim
WORKDIR /app
# Copy jar package from the build stageCOPY --from=build /app/target/my-java-app-*.jar 
# Expose portsEXPOSE 8080
# Start the commandENTRYPOINT ["java", "-jar", ""]

Line by line analysis

  1. FROM maven:3.8.4-openjdk-11 AS build
    Use Maven image as the basic image for the build phase and named "build"

  2. WORKDIR /app
    Set the working directory to /app

  3. COPY .
    Copy to working directory

  4. RUN mvn dependency:go-offline
    Download all dependencies (utilizing the Docker cache layer)

  5. COPY src ./src
    Copy the source code

  6. RUN mvn package -DskipTests
    Package the application (skip the test)

  7. FROM openjdk:11-jre-slim
    The second phase uses smaller JRE images

  8. COPY --from=build /app/target/my-java-app-*.jar
    Copy the generated jar package from the build stage

  9. EXPOSE 8080
    Declare the port exposed by the container

  10. ENTRYPOINT ["java", "-jar", ""]
    Commands executed when container starts

Multi-stage construction optimization

There are three major advantages for multi-stage construction:

  1. Reduce the mirror volume- The final image only contains the necessary content at runtime
  2. Improve safety- The build tool will not appear in the production image
  3. A clearer construction process- Separate the build and run environment

Advanced optimization skills

  1. Using .dockerignore file
    Avoid copying unnecessary files into the mirror:

.git
.idea
*.iml
target/
*.log
*.tmp
  1. Choose the right basic image

    • openjdk:11-jdk- Full JDK (larger)
    • openjdk:11-jre- Runtime only (small)
    • openjdk:11-jre-slim- A more streamlined version
    • openjdk:11-alpine- Based on Alpine Linux (minimum)
  2. Layer cache optimization
    Put infrequently changing instructions in front and make full use of cache:

# Copy and download the dependency firstCOPY  .
RUN mvn dependency:go-offline

# Then copy the source codeCOPY src ./src

Build and run the image

1. Build a mirror

# -t Specify the image name and label#. Indicates the use of the Dockerfile of the current directorydocker build -t my-java-app:1.0 .

Example of build process output:

[+] Building 45.3s (12/12) FINISHED
 => [internal] load build definition from Dockerfile                       0.0s
 => => transferring dockerfile: 37B                                        0.0s
 => [internal] load .dockerignore                                          0.0s
 => => transferring context: 35B                                           0.0s
 => [internal] load metadata for /library/openjdk:11-jre-slim    1.5s
 => [internal] load metadata for /library/maven:3.8.4-openjdk-11  1.5s
 => [build 1/5] FROM /library/maven:3.8.4-openjdk-11@sha256:9c... 0.0s
 => [internal] load build context                                          0.1s
 => => transferring context: 3.01kB                                        0.0s
 => CACHED [build 2/5] WORKDIR /app                                        0.0s
 => [build 3/5] COPY  .                                             0.0s
 => [build 4/5] RUN mvn dependency:go-offline                              20.1s
 => [build 5/5] COPY src ./src                                             0.0s
 => [build 6/5] RUN mvn package -DskipTests                               18.2s
 => [stage-1 1/2] FROM /library/openjdk:11-jre-slim@sha256:9c... 0.0s
 => [stage-1 2/2] COPY --from=build /app/target/my-java-app-*.jar   0.1s
 => exporting to image                                                     0.1s
 => => exporting layers                                                    0.1s
 => => writing image sha256:7e9b6e5ba...                                   0.0s
 => => naming to /library/my-java-app:1.0                         0.0s

2. View the mirror

docker images

# Output exampleREPOSITORY     TAG       IMAGE ID       CREATED         SIZE
my-java-app    1.0       7e9b6e5ba123   2 minutes ago   215MB

3. Run the container

# -d Backend Run# -p Port Mapping (Host Port: Container Port)# --name Container namedocker run -d -p 8080:8080 --name my-app my-java-app:1.0

4. Check the running status

docker ps

# Output exampleCONTAINER ID   IMAGE             COMMAND               CREATED         STATUS         PORTS                    NAMES
a3b8d7e6f5g4   my-java-app:1.0   "java -jar "   2 minutes ago   Up 2 minutes   0.0.0.0:8080->8080/tcp   my-app

5. View the log

docker logs -f my-app

# Output example  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.6.3)

6. Stop and delete containers

# Stop the containerdocker stop my-app

# Delete the containerdocker rm my-app

# Delete the mirrordocker rmi my-java-app:1.0

Push the mirror to the warehouse

1. Log in to Docker Hub

docker login -u your-username

2. Mark the mirror

# Format: docker tag local-image:tagname username/repository:tagnamedocker tag my-java-app:1.0 your-username/my-java-app:1.0

3. Push mirror

docker push your-username/my-java-app:1.0

4. Pull and run from the repository

docker run -d -p 8080:8080 your-username/my-java-app:1.0

Production environment deployment

1. Use docker-compose

createdocument:

version: '3.8'

services:
  app:
    image: your-username/my-java-app:1.0
    container_name: my-java-app
    ports:
      - "8080:8080"
    environment:
      - SPRING_PROFILES_ACTIVE=prod
    restart: unless-stopped
    volumes:
      - ./logs:/app/logs
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
      interval: 30s
      timeout: 10s
      retries: 3

Start the service:

docker-compose up -d

2. Kubernetes deployment example

create:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: java-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: java-app
  template:
    metadata:
      labels:
        app: java-app
    spec:
      containers:
      - name: java-app
        image: your-username/my-java-app:1.0
        ports:
        - containerPort: 8080
        resources:
          requests:
            cpu: "500m"
            memory: "512Mi"
          limits:
            cpu: "1000m"
            memory: "1024Mi"
        livenessProbe:
          httpGet:
            path: /actuator/health
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /actuator/health
            port: 8080
          initialDelaySeconds: 20
          periodSeconds: 5

Summary and best practices

Best Practice Summary

  1. Mirror optimization

    • Reduce image volume using multi-stage construction
    • Select the appropriate basic image (Alpine/slim version)
    • Regularly update the basic image to get security patches
  2. Build optimization

    • Reasonably utilize layer cache (.dockerignore + instruction order)
    • Fixed basic mirror version (avoid the use of the latest tag)
    • Implement automated construction in CI/CD
  3. Running optimization

    • Limit container resources (cpu/memory)
    • Configure health checks
    • Run with non-root users
    • Correctly process signals (such as SIGTERM)
  4. Safety advice

    • Do not hard-code sensitive information in the mirror (using environment variables/secret)
    • Scan the vulnerability in the image (using docker scan)
    • Minimize container permissions (avoid –privileged)

Frequently Asked Questions

Q: What should I do if the download dependency is very slow during construction?
A: Configure Maven image repository:

RUN mkdir -p /root/.m2 && \
    echo 'aliyunhttps:///repository/publiccentral' > /root/.m2/

Q: Exit immediately after the container is started?
A: Possible reasons:

  1. Application startup failed - View logdocker logs
  2. No foreground process - make sure the application is not running in daemon mode
  3. Port conflict - Check port mapping

Q: How to debug applications in containers?
A: Enter the running container:

docker exec -it  /bin/bash

Or directly attach to the process:

docker attach 

Next learning suggestions

  1. Learn Docker network and storage volume configuration
  2. Master Docker Compose orchestration of multi-container applications
  3. Understand Kubernetes container orchestration
  4. Explore the integration of CI/CD pipelines and Docker
  5. Learning service mesh (such as Istio) and containerized applications

Through the study of this article, you have mastered the core skills of containerization of Java projects. There are still many things worth exploring in the world of Docker. If you continue to practice, you will find more convenience and efficiency improvements brought by containerization!

The above is the detailed content of the entire process of Java project packaging Docker image. For more information about Java packaging Docker image, please pay attention to my other related articles!