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
37 changes: 37 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# ---- Stage 1: Build ----
# Uses the full JDK image to compile the application with Maven
FROM eclipse-temurin:25-jdk AS build
WORKDIR /app

# Copy Maven wrapper and pom.xml first to leverage Docker layer caching
# Dependencies are downloaded only when pom.xml changes
COPY mvnw pom.xml ./
COPY .mvn .mvn
RUN chmod +x mvnw && ./mvnw dependency:go-offline -B
Comment thread
MayuriXx marked this conversation as resolved.

# Copy source code and build the JAR (tests are skipped as they run in CI)
COPY src src
RUN ./mvnw package -DskipTests -B
Comment thread
MayuriXx marked this conversation as resolved.

# ---- Stage 2: Run ----
# Uses a lightweight JRE-only image for a smaller and more secure final image
FROM eclipse-temurin:25-jre
WORKDIR /app

# Create a non-root user and group for running the application securely
RUN groupadd --system appgroup && useradd --system --gid appgroup appuser

# Copy the built JAR from the build stage using a stable pattern so version changes do not break the image build
COPY --from=build /app/target/*.jar app.jar

# Ensure the non-root user owns the application files
RUN chown -R appuser:appgroup /app

# Switch to the non-root user
USER appuser

# Document the port the application listens on
EXPOSE 8080

# Start the Spring Boot application
ENTRYPOINT ["java", "-jar", "app.jar"]
Comment thread
MayuriXx marked this conversation as resolved.
68 changes: 68 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,69 @@ docker-compose up -d

---

## 🐳 Docker

### Architecture

The application can be fully containerized using a **multi-stage Dockerfile** and **Docker Compose**.

Comment thread
MayuriXx marked this conversation as resolved.
Comment thread
MayuriXx marked this conversation as resolved.
The `app` container connects to the `postgres` container over the `xpeho_network` bridge network using the PostgreSQL service name as the hostname.
```
┌─────────────────── xpeho_network (bridge) ───────────────────┐
│ │
│ ┌──────────┐ jdbc:postgresql:// ┌──────────┐ │
│ │ app │ ──────── postgres:5432 ────────▶ │ postgres │ │
│ │ :8080 │ (service name) │ :5432 │ │
│ └──────────┘ └──────────┘ │
│ │
└───────────────────────────────────────────────────────────────┘
```

| Service | Image / Build | Role | Exposed Port |
|------------|------------------------------|----------------------------|---------------------------|
| `postgres` | `postgres:17-alpine` | PostgreSQL database | `${POSTGRES_PORT}` → 5432 |
| `app` | Built from `Dockerfile` | Spring Boot application | 8080 → 8080 |
Comment thread
MayuriXx marked this conversation as resolved.

### Dockerfile — Multi-stage Build

The Dockerfile uses two stages to produce a lightweight, secure final image:

| Stage | Image | Role |
|-------|-------|------|
| **Build** | `eclipse-temurin:25-jdk` | Compiles the JAR with Maven (full JDK) |
| **Run** | `eclipse-temurin:25-jre` | Runs the application (lightweight JRE, non-root user) |

> **Why Eclipse Temurin?** Reference OpenJDK distribution: free, open-source, maintained by the Eclipse Foundation (Adoptium).

> **Security:** The final image runs as a non-root user (`appuser`), without source code or build tools.

### Compose Profiles

The `app` service is behind a **Compose profile** to avoid interfering with the dev/CI workflow:

```bash
# Start PostgreSQL only (dev, tests, CI)
docker compose up -d

# Start PostgreSQL + Application (full deployment)
docker compose --profile app up -d --build
```
Comment thread
MayuriXx marked this conversation as resolved.
Comment thread
MayuriXx marked this conversation as resolved.
Comment thread
MayuriXx marked this conversation as resolved.

### Useful Commands

```bash
# View application logs
docker compose logs -f app

# Stop and remove containers
docker compose down

# Stop and remove containers + volumes (reset DB)
docker compose down -v
```

---

## ⚙️ Configuration

### Environment Variables (.env)
Expand All @@ -56,6 +119,11 @@ POSTGRES_USER=your_user
POSTGRES_PASSWORD=your_password
POSTGRES_DB=your_database
POSTGRES_PORT=5432

# Liquibase (optional, defaults provided)
LB_CHANGELOG=db/changelog/db.changelog-master.yaml
LB_SCHEMA=public
SPRING_LIQUIBASE_ENABLED=true
```

### External API Configuration
Expand Down
24 changes: 24 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,30 @@ services:
networks:
- xpeho_network

app:
profiles:
- app
build:
context: .
dockerfile: Dockerfile
Comment thread
MayuriXx marked this conversation as resolved.
container_name: xpeho_app
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_PORT: 5432
SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/${POSTGRES_DB}
SPRING_LIQUIBASE_ENABLED: ${SPRING_LIQUIBASE_ENABLED:-true}
LB_CHANGELOG: ${LB_CHANGELOG:-db/changelog/db.changelog-master.yaml}
LB_SCHEMA: ${LB_SCHEMA:-public}
ports:
- "8080:8080"
Comment thread
MayuriXx marked this conversation as resolved.
depends_on:
postgres:
condition: service_healthy
networks:
- xpeho_network

volumes:
postgres_data:
driver: local
Expand Down
Loading