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
FROM maven:3.8.4-openjdk-11 AS build
Use Maven image as the basic image for the build phase and named "build"WORKDIR /app
Set the working directory to /appCOPY .
Copy to working directoryRUN mvn dependency:go-offline
Download all dependencies (utilizing the Docker cache layer)COPY src ./src
Copy the source codeRUN mvn package -DskipTests
Package the application (skip the test)FROM openjdk:11-jre-slim
The second phase uses smaller JRE imagesCOPY --from=build /app/target/my-java-app-*.jar
Copy the generated jar package from the build stageEXPOSE 8080
Declare the port exposed by the containerENTRYPOINT ["java", "-jar", ""]
Commands executed when container starts
Multi-stage construction optimization
There are three major advantages for multi-stage construction:
- Reduce the mirror volume- The final image only contains the necessary content at runtime
- Improve safety- The build tool will not appear in the production image
- A clearer construction process- Separate the build and run environment
Advanced optimization skills
Using .dockerignore file
Avoid copying unnecessary files into the mirror:
.git .idea *.iml target/ *.log *.tmp
-
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)
-
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
-
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
-
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
-
Running optimization:
- Limit container resources (cpu/memory)
- Configure health checks
- Run with non-root users
- Correctly process signals (such as SIGTERM)
-
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:
- Application startup failed - View log
docker logs
- No foreground process - make sure the application is not running in daemon mode
- 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
- Learn Docker network and storage volume configuration
- Master Docker Compose orchestration of multi-container applications
- Understand Kubernetes container orchestration
- Explore the integration of CI/CD pipelines and Docker
- 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!