Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion complete/Dockerfile.dotnet
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,10 @@ EXPOSE 8080
# Set the environment variables
ENV ASPNETCORE_URLS=http://+:8080
ENV DOTNET_RUNNING_IN_CONTAINER=true
ENV ApiSettings__BaseUrl="${ApiSettings__BaseUrl}"

# Copy the published files from the build stage
COPY --from=publish /app/publish .

# Set the entry point for the container
ENTRYPOINT ["dotnet", "Contoso.BlazorApp.dll"]
ENTRYPOINT ["dotnet", "Contoso.BlazorApp.dll"]
85 changes: 60 additions & 25 deletions complete/Dockerfile.java
Original file line number Diff line number Diff line change
@@ -1,55 +1,90 @@
# Stage 1: Build the application
FROM mcr.microsoft.com/openjdk/jdk:21-ubuntu AS build
# Multi-stage build for Java Spring Boot application
# Stage 1: Build stage with Microsoft OpenJDK 21
FROM mcr.microsoft.com/openjdk/jdk:21-ubuntu AS builder

WORKDIR /app
# Set working directory for build
WORKDIR /workspace

# Copy gradle files for dependency resolution
COPY java/socialapp/gradle/ ./gradle/
COPY java/socialapp/gradlew java/socialapp/build.gradle java/socialapp/settings.gradle ./
# Copy Gradle configuration files
COPY java/socialapp/gradle ./gradle
COPY java/socialapp/gradlew .
COPY java/socialapp/gradlew.bat .
COPY java/socialapp/build.gradle .
COPY java/socialapp/settings.gradle .

# Give executable permissions to gradlew
# Make gradlew executable
RUN chmod +x ./gradlew

# Download dependencies to cache this layer
# Download dependencies (for better Docker layer caching)
RUN ./gradlew dependencies --no-daemon

# Copy source code
COPY java/socialapp/src ./src

# Build the application
RUN ./gradlew bootJar --no-daemon
RUN ./gradlew build --no-daemon -x test

# Stage 2: Extract JRE from JDK
FROM mcr.microsoft.com/openjdk/jdk:21-ubuntu AS jre-build
FROM mcr.microsoft.com/openjdk/jdk:21-ubuntu AS jre-builder

# Create a custom JRE using jlink that only includes modules needed for the application
# Create a custom JRE using jlink
RUN jlink \
--add-modules java.base,java.compiler,java.desktop,java.instrument,java.management,java.naming,java.prefs,java.rmi,java.security.jgss,java.security.sasl,java.sql,jdk.crypto.ec,jdk.unsupported,jdk.zipfs,jdk.management \
--add-modules java.base,java.desktop,java.instrument,java.management,java.naming,java.net.http,java.security.jgss,java.sql,jdk.unsupported \
--strip-debug \
--no-man-pages \
--no-header-files \
--compress=2 \
--output /jre-minimal
--output /custom-jre

# Stage 3: Create final image
# Stage 3: Runtime stage with custom JRE
FROM ubuntu:22.04

# Set environment variables
ENV JAVA_HOME=/opt/jre-minimal
# Install required packages and clean up
RUN apt-get update && \
apt-get install -y \
ca-certificates \
sqlite3 \
curl \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

# Copy custom JRE from jre-builder stage
COPY --from=jre-builder /custom-jre /opt/java/openjdk

# Set JAVA_HOME and update PATH
ENV JAVA_HOME=/opt/java/openjdk
ENV PATH="${JAVA_HOME}/bin:${PATH}"

# Copy the extracted JRE from the jre-build stage
COPY --from=jre-build /jre-minimal $JAVA_HOME
# Create application user for security
RUN groupadd -r appuser && useradd -r -g appuser appuser

# Copy the built application from the build stage
# Set working directory
WORKDIR /app
COPY --from=build /app/build/libs/*.jar app.jar

# Create a directory for persistent data
RUN mkdir -p /app/data
# Copy the built JAR from builder stage
COPY --from=builder /workspace/build/libs/*.jar app.jar

# Create SQLite database file with proper permissions
RUN touch sns_api.db && \
chown appuser:appuser sns_api.db && \
chmod 664 sns_api.db

# Expose the application port
# Change ownership of the app directory
RUN chown -R appuser:appuser /app

# Switch to non-root user
USER appuser

# Set environment variables for GitHub Codespaces
ENV CODESPACE_NAME="${CODESPACE_NAME}"
ENV GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN="${GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN}"

# Expose port 8080
EXPOSE 8080

# Set the entrypoint command to run the application
ENTRYPOINT ["java", "-jar", "/app/app.jar"]
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=60s --retries=3 \
CMD curl -f http://localhost:8080/actuator/health || exit 1

# Run the application
ENTRYPOINT ["java", "-jar", "app.jar"]
24 changes: 15 additions & 9 deletions complete/compose.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
version: '3.8'

networks:
contoso:
driver: bridge

services:
contoso-backend:
build:
Expand All @@ -9,10 +15,14 @@ services:
environment:
- CODESPACE_NAME=${CODESPACE_NAME}
- GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN=${GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN}
volumes:
- ./java/socialapp/sns_api.db:/app/sns_api.db
networks:
- contoso
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
interval: 30s
timeout: 3s
start_period: 60s
retries: 3

contoso-frontend:
build:
Expand All @@ -21,13 +31,9 @@ services:
container_name: contoso-frontend
ports:
- "3030:8080"
depends_on:
- contoso-backend
environment:
- ApiSettings__BaseUrl=http://contoso-backend:8080/api/
- ApiSettings__BaseUrl=http://contoso-backend:8080/api
networks:
- contoso

networks:
contoso:
name: contoso
depends_on:
- contoso-backend
19 changes: 13 additions & 6 deletions docs/05-containerization.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,16 @@ Refer to the [README](../README.md) doc for preparation.
```text
I'd like to build a container image of a Java app. Follow the instructions below.

- The Java app is located at `java`.
- Your working directory is the repository root.
- Identify all the steps first, which you're going to do.
- The Java app is located at `java/socialapp`.
- Your working directory is the repository root.
- Create a Dockerfile, `Dockerfile.java`.
- Use Microsoft OpenJDK 21.
- Use multi-stage build approach.
- Extract JRE from JDK.
- Use the target port number of `8080` for the container image.
- Add both environment variables, `CODESPACE_NAME` and `GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN` from the host to the container image.
- Create an SQLite database file, `sns_api.db`, in the container image. DO NOT Copy the file from the host.
```

1. Click the ![the keep button image](https://img.shields.io/badge/keep-blue) button of GitHub Copilot to take the changes.
Expand All @@ -101,6 +103,7 @@ Refer to the [README](../README.md) doc for preparation.
Use the container image just built, run a container and verify if the app is running properly.

- Use the host port of `8080`.
- Both `CODESPACE_NAME` and `GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN` values should be the ones from GitHub Codespaces.
```

### Containerize .NET Application
Expand All @@ -111,13 +114,14 @@ Refer to the [README](../README.md) doc for preparation.
```text
I'd like to build a container image of a .NET app. Follow the instructions below.

- Identify all the steps first, which you're going to do.
- The .NET app is located at `dotnet`.
- Your working directory is the repository root.
- Identify all the steps first, which you're going to do.
- Create a Dockerfile, `Dockerfile.dotnet`.
- Use .NET 9.
- Use multi-stage build approach.
- Use the target port number of `8080` for the container image.
- Add the environment variable, `ApiSettings__BaseUrl` to the container. It should point to the Java app, `http://localhost:8080/api`.
```

1. Click the ![the keep button image](https://img.shields.io/badge/keep-blue) button of GitHub Copilot to take the changes.
Expand All @@ -141,12 +145,13 @@ Refer to the [README](../README.md) doc for preparation.
Use the container image just built, run a container and verify if the app is running properly.

- Use the host port of `3030`.
- Pass the environment variable `ApiSettings__BaseUrl` the value of `http://localhost:8080/api`.
```

1. Make sure that both frontend and backend apps are NOT communicating with each other because they don't know each other yet. Run the prompt like below.

```text
Regardless or not, remove both containers currently running.
Remove both Java and .NET containers and their respective container images.
```

### Orchestrate Containers
Expand All @@ -157,22 +162,24 @@ Refer to the [README](../README.md) doc for preparation.
```text
I'd like to create a Docker Compose file. Follow the instructions below.

- Identify all the steps first, which you're going to do.
- Your working directory is the repository root.
- Use `Dockerfile.java` as a backend app.
- Use `Dockerfile.dotnet` as a frontend app.
- Create `compose.yaml` as the Docker Compose file.
- Use `contoso` as the network name.
- Use `contoso-backend` as the container name of the Java app. Its target port is 8080, and host port is 8080.
- Use `contoso-frontend` as the container name of the .NET app. Its target port is 8080, and host port is 3030.
- Mount the volume for the database that the Java app uses, `java/socialapp/sns_api.db`.
- Add both environment variables, `CODESPACE_NAME` and `GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN` from the host to the Java container.
- Add the environment variable, `ApiSettings__BaseUrl` to the .NET container. It should point to the Java app's `/api`.
```

1. Click the ![the keep button image](https://img.shields.io/badge/keep-blue) button of GitHub Copilot to take the changes.

1. Once the `compose.yaml` file is created, run it and verify if both apps are running properly.

```text
Now, run the Docker compose file and verify if the apps are running properly.
Run the Docker compose file and verify if all the apps are running properly.
```

1. Open a web browser and navigate to `http://localhost:3030`, and verify if the apps are up and running properly.
Expand Down