Skip to content

Commit 84f9e03

Browse files
updates from review
1 parent 6d89554 commit 84f9e03

File tree

1 file changed

+108
-28
lines changed

1 file changed

+108
-28
lines changed

articles/container-apps/java-containers-intro.md

Lines changed: 108 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ services: container-apps
55
author: craigshoemaker
66
ms.service: azure-container-apps
77
ms.topic: conceptual
8-
ms.date: 04/09/2025
8+
ms.date: 04/10/2025
99
ms.author: cshoe
1010
ai-usage: ai-generated
1111
---
@@ -62,7 +62,7 @@ After installing Docker Desktop, you can verify your installation with the follo
6262

6363
```bash
6464
docker --version
65-
docker-compose --version
65+
docker compose version
6666
```
6767

6868
### Configure Visual Studio Code for container development
@@ -76,7 +76,7 @@ For instance, the following example configuration defines a Java build:
7676
```json
7777
{
7878
"name": "Java Development",
79-
"image": "mcr.microsoft.com/devcontainers/java:11",
79+
"image": "mcr.microsoft.com/devcontainers/java:21",
8080
"customizations": {
8181
"vscode": {
8282
"extensions": [
@@ -107,10 +107,10 @@ Choosing the right base image is crucial. Consider these options:
107107

108108
| Description | Name | Remarks |
109109
|---|---|---|
110-
| **Microsoft Java development Image** | `mcr.microsoft.com/java/jdk:11-zulu-ubuntu` | Full Java development kit (JDK) and optimized for Azure |
111-
| **Microsoft Java production Image** | `mcr.microsoft.com/java/jre:11-zulu-ubuntu` | Runtime only and optimized for Azure |
112-
| **Official OpenJDK development Image** | `openjdk:11-jdk` | Full JDK |
113-
| **Official OpenJDK production Image** | `openjdk:11-jre` | Runtime only |
110+
| **Microsoft Java development Image** | `mcr.microsoft.com/java/jdk:21-zulu-ubuntu` | Full Java development kit (JDK) and optimized for Azure |
111+
| **Microsoft Java production Image** | `mcr.microsoft.com/java/jre:21-zulu-ubuntu` | Runtime only and optimized for Azure |
112+
| **Official OpenJDK development Image** | `openjdk:21-jdk` | Full JDK |
113+
| **Official OpenJDK production Image** | `openjdk:21-jre` | Runtime only |
114114

115115
For development environments, use a full JDK image. For production, use JRE or distroless images to minimize size and attack surface of your application.
116116

@@ -121,7 +121,7 @@ The Microsoft Java images come with Azure-specific optimizations and are regular
121121
The following example shows a simple Dockerfile for a Java application:
122122

123123
```dockerfile
124-
FROM mcr.microsoft.com/java/jdk:11-zulu-ubuntu
124+
FROM mcr.microsoft.com/java/jdk:21-zulu-ubuntu
125125
WORKDIR /app
126126
COPY target/myapp.jar app.jar
127127
EXPOSE 8080
@@ -131,7 +131,7 @@ ENTRYPOINT ["java", "-jar", "app.jar"]
131131
For Spring Boot applications, you can setup your Dockerfile with the following base:
132132

133133
```dockerfile
134-
FROM mcr.microsoft.com/java/jdk:11-zulu-ubuntu
134+
FROM mcr.microsoft.com/java/jdk:21-zulu-ubuntu
135135
WORKDIR /app
136136
COPY target/*.jar app.jar
137137
EXPOSE 8080
@@ -141,7 +141,7 @@ ENTRYPOINT ["java", "-Dspring.profiles.active=docker", "-jar", "app.jar"]
141141
For production deployments, use the JRE image to reduce the size and minimize the attack surface of your application:
142142

143143
```dockerfile
144-
FROM mcr.microsoft.com/java/jre:11-zulu-ubuntu
144+
FROM mcr.microsoft.com/java/jre:21-zulu-ubuntu
145145
WORKDIR /app
146146
COPY target/*.jar app.jar
147147
EXPOSE 8080
@@ -155,27 +155,39 @@ Containers are meant to execute in various contexts. In this section, you learn
155155

156156
### Use Docker Compose for multi-container applications
157157

158-
Most Java applications interact with databases, caches, or other services.
158+
Most Java applications interact with databases, caches, or other services. Docker Compose helps you define and orchestrate multi-container applications using a simple YAML configuration file.
159159

160-
Docker Compose helps you define and manage multi-container Docker applications. It allows you to configure your application's services, networks, and volumes using a simple YAML file named `docker-compose.yml`. With Docker Compose, you can start, stop, and manage all the containers in your application as a single unit.
160+
#### What is Docker Compose?
161161

162-
The following example demonstrates how to configure Docker Compose to prepare a database connection to your application.
162+
Docker Compose is a tool that:
163+
- Defines multi-container applications in a single file
164+
- Manages application lifecycle (start, stop, rebuild)
165+
- Maintains isolated environments
166+
- Creates networks for service communication
167+
- Persists data using volumes
168+
169+
> [!NOTE]
170+
> Docker Compose is now integrated as a plugin to the Docker command itself (using `docker compose`) rather than as a separate utility. The preferred configuration filename is `compose.yml` instead of the legacy `docker-compose.yml`.
171+
172+
#### Example: Java application with database
173+
174+
Here's an example `compose.yml` that configures a Java application with a PostgreSQL database:
163175

164176
```yaml
165177
version: '3.8'
166178
services:
167179
app:
168-
build: .
180+
build: . # Build from Dockerfile in current directory
169181
ports:
170-
- "8080:8080"
171-
- "5005:5005"
182+
- "8080:8080" # Map HTTP port
183+
- "5005:5005" # Map debug port
172184
environment:
173185
- SPRING_PROFILES_ACTIVE=dev
174186
- SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/myapp
175187
volumes:
176-
- ./target:/app/target
188+
- ./target:/app/target # Mount target directory for hot reloads
177189
depends_on:
178-
- db
190+
- db # Ensure database starts first
179191

180192
db:
181193
image: postgres:13
@@ -184,15 +196,84 @@ services:
184196
- POSTGRES_PASSWORD=postgres
185197
- POSTGRES_DB=myapp
186198
ports:
187-
- "5432:5432"
199+
- "5432:5432" # Expose PostgreSQL port
188200
volumes:
189-
- postgres-data:/var/lib/postgresql/data
201+
- postgres-data:/var/lib/postgresql/data # Persist database data
190202

191203
volumes:
192-
postgres-data:
204+
postgres-data: # Named volume for database persistence
193205
```
194206
195-
This configuration creates two containers: one for the Java application and one for a PostgreSQL database. It also sets up networking between them, mounts volumes for persistence, and exposes necessary ports.
207+
In this example:
208+
209+
- Services can reference each other by name (like `db` in the JDBC URL)
210+
- Docker Compose automatically creates a network for the services
211+
- The Java application waits for the database to start due to `depends_on`
212+
- The database data persists across restarts using a named volume
213+
214+
#### Common Docker Compose commands
215+
216+
Once you've created your `compose.yml` file, manage your application with these commands:
217+
218+
```bash
219+
# Build images without starting containers
220+
docker compose build
221+
222+
# Start all services defined in compose.yml
223+
docker compose up
224+
225+
# Start in detached mode (run in background)
226+
docker compose up -d
227+
228+
# View running containers managed by compose
229+
docker compose ps
230+
231+
# View logs from all containers
232+
docker compose logs
233+
234+
# View logs from a specific service
235+
docker compose logs app
236+
237+
# Stop all services
238+
docker compose down
239+
240+
# Stop and remove volumes (useful for database resets)
241+
docker compose down -v
242+
```
243+
244+
#### Development workflow
245+
246+
A typical Java development workflow with Docker Compose looks like:
247+
248+
1. Create `compose.yml` and `Dockerfile`
249+
2. Run `docker compose up` to start all services
250+
3. Make changes to your Java code
251+
4. Rebuild your application (depending on configuration, you might need to restart containers)
252+
5. Test the changes in the containerized environment
253+
6. When finished, run `docker compose down`
254+
255+
### Running single containers with Docker
256+
257+
For simpler scenarios when you don't need multiple interconnected services, you can use the `docker run` command to start individual containers.
258+
259+
Here are some common examples for Java applications:
260+
261+
```bash
262+
# Run a Java application JAR directly
263+
docker run -p 8080:8080 myapp:latest
264+
265+
# Run with environment variables
266+
docker run -p 8080:8080 -e "SPRING_PROFILES_ACTIVE=prod" myapp:latest
267+
268+
# Run in detached mode (background)
269+
docker run -d -p 8080:8080 myapp:latest
270+
271+
# Run with a name for easy reference
272+
docker run -d -p 8080:8080 --name my-java-app myapp:latest
273+
274+
# Run with volume mount for persistent data
275+
docker run -p 8080:8080 -v ./data:/app/data myapp:latest
276+
```
196277

197278
## Debugging containerized applications
198279

@@ -207,7 +288,7 @@ Debugging containerized Java applications requires exposing a debug port and con
207288
1. To enable debugging, modify your Dockerfile or container startup command:
208289

209290
```dockerfile
210-
FROM mcr.microsoft.com/java/jdk:11-zulu-ubuntu
291+
FROM mcr.microsoft.com/java/jdk:21-zulu-ubuntu
211292
WORKDIR /app
212293
COPY target/*.jar app.jar
213294
EXPOSE 8080 5005
@@ -283,16 +364,15 @@ The JVM doesn't automatically detect container memory limits in Java 8. For Java
283364
Configure your JVM to respect container limits:
284365

285366
```dockerfile
286-
FROM mcr.microsoft.com/java/jre:11-zulu-ubuntu
367+
FROM mcr.microsoft.com/java/jre:21-zulu-ubuntu
287368
WORKDIR /app
288369
COPY target/*.jar app.jar
289370
EXPOSE 8080
290-
ENTRYPOINT ["java", "-XX:+UseContainerSupport", "-XX:MaxRAMPercentage=75.0", "-jar", "app.jar"]
371+
ENTRYPOINT ["java", "-XX:MaxRAMPercentage=75.0", "-jar", "app.jar"]
291372
```
292373

293374
Key JVM flags for containerized applications:
294375

295-
- `-XX:+UseContainerSupport`: Makes JVM container-aware (default in Java 10+)
296376
- `-XX:MaxRAMPercentage=75.0`: Sets maximum heap as a percentage of available memory
297377
- `-XX:InitialRAMPercentage=50.0`: Sets initial heap size
298378
- `-Xmx` and `-Xms`: Are also available, but requires fixed values
@@ -312,7 +392,7 @@ Secure your containerized Java applications with these practices:
312392
- **Default security context**: Run your application as a non-root user:
313393

314394
```dockerfile
315-
FROM mcr.microsoft.com/java/jre:11-zulu-ubuntu
395+
FROM mcr.microsoft.com/java/jre:21-zulu-ubuntu
316396
WORKDIR /app
317397
COPY target/*.jar app.jar
318398
RUN addgroup --system javauser && adduser --system --ingroup javauser javauser
@@ -358,7 +438,7 @@ This section guides you through preparing your Java containers for Azure Contain
358438
- **Port configuration**: Ensure your container listens on the port provided by Azure:
359439

360440
```dockerfile
361-
FROM mcr.microsoft.com/java/jre:11-zulu-ubuntu
441+
FROM mcr.microsoft.com/java/jre:21-zulu-ubuntu
362442
WORKDIR /app
363443
COPY target/*.jar app.jar
364444
ENV PORT=8080

0 commit comments

Comments
 (0)