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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ This project uses famous football stadiums (A-Z) that hosted FIFA World Cup matc

### Changed

- Switch runtime base image from `mcr.microsoft.com/dotnet/aspnet:10.0` (Debian)
to `mcr.microsoft.com/dotnet/aspnet:10.0-alpine` (before: 113.4 MB →
after: 73.9 MB compressed; measured via `docker manifest inspect` and
`docker save | wc -c`); replace `apt-get` with `apk` and
`useradd`/`groupadd` with `adduser`/`addgroup` accordingly (#456)
- Refactor `scripts/entrypoint.sh`: add `log()` helper with timestamp prefix,
replace raw `echo` calls, and print API base URL on startup (#456)
- Rename `ValidateAsync_SquadNumber_BelongsToPlayerBeingUpdated_ReturnsNoErrors` to `ValidateAsync_SquadNumberBelongsToPlayerBeingUpdated_ReturnsNoErrors` to align with the 3-segment naming convention for service/validator tests (#427)
- Make CSharpier step in `/pre-commit` conditional (skip with a note if not installed), consistent with the Docker and CodeRabbit steps (#427)
- Add "Verify tag commit is reachable from master" step to CD workflow using `git merge-base --is-ancestor` before any build or publish steps (#439)
Expand Down
11 changes: 7 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,12 @@ RUN dotnet publish -c Release -o /app/publish
# Stage 2: Runtime
# This stage creates the final, minimal image to run the application.
# ------------------------------------------------------------------------------
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime
FROM mcr.microsoft.com/dotnet/aspnet:10.0-alpine AS runtime

WORKDIR /app

# Install curl for health check
RUN apt-get update && apt-get install -y --no-install-recommends curl && \
rm -rf /var/lib/apt/lists/*
RUN apk add --no-cache curl

# Metadata labels for the image. These are useful for registries and inspection.
LABEL org.opencontainers.image.title="🧪 Web API made with .NET 10 (LTS) and ASP.NET Core"
Expand All @@ -39,6 +38,9 @@ LABEL org.opencontainers.image.source="https://github.com/nanotaboada/Dotnet.Sam
# Set environment variables
ENV ASPNETCORE_URLS=http://+:9000
ENV ASPNETCORE_ENVIRONMENT=Production
# Alpine images default to invariant globalization mode. Explicitly opt in since
# this API uses ISO-8601 dates and ASCII data — ICU is not required.
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=true

# Copy published app from builder
COPY --from=builder /app/publish/ .
Expand All @@ -57,7 +59,8 @@ COPY --chmod=555 scripts/healthcheck.sh ./healthcheck.sh
COPY --from=builder /src/Dotnet.Samples.AspNetCore.WebApi/storage/players-sqlite3.db ./hold/players-sqlite3.db

# Add non-root user and make volume mount point writable
RUN groupadd -r aspnetcore && useradd -r -g aspnetcore aspnetcore && \
RUN addgroup -S aspnetcore && \
adduser -S -G aspnetcore aspnetcore && \
mkdir -p /storage && \
chown aspnetcore:aspnetcore /storage

Expand Down
28 changes: 20 additions & 8 deletions scripts/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,25 +1,37 @@
#!/bin/sh
set -e

# Helper function for formatted logging
log() {
local message="$1"
echo "[ENTRYPOINT] $(date '+%Y/%m/%d - %H:%M:%S') | $message"
return 0
}

IMAGE_STORAGE_PATH="/app/hold/players-sqlite3.db"
VOLUME_STORAGE_PATH="/storage/players-sqlite3.db"

echo "✔ Starting container..."
log "✔ Starting container..."

if [ ! -f "$VOLUME_STORAGE_PATH" ]; then
echo "⚠️ No existing database file found in volume."
log "⚠️ No existing database file found in volume."
if [ -f "$IMAGE_STORAGE_PATH" ]; then
echo "🔄 Copying database file to writable volume..."
log "🔄 Copying database file to writable volume..."
cp "$IMAGE_STORAGE_PATH" "$VOLUME_STORAGE_PATH"
echo "✔ Database initialized at $VOLUME_STORAGE_PATH"
log "✔ Database initialized at $VOLUME_STORAGE_PATH"
else
echo "⚠️ Database file missing at $IMAGE_STORAGE_PATH"
log "⚠️ Database file missing at $IMAGE_STORAGE_PATH"
exit 1
fi
else
echo "✔ Existing database file found. Skipping seed copy."
log "✔ Existing database file found. Skipping seed copy."
fi

echo "✔ Ready!"
echo "🚀 Launching app..."
log "✔ Ready!"
log "🚀 Launching app..."
# Derive the API URL from ASPNETCORE_URLS (first entry if semicolon-separated),
# replacing the wildcard host (+, 0.0.0.0) with localhost for display purposes.
_raw_url=$(printf '%s' "${ASPNETCORE_URLS:-http://+:9000}" | cut -d';' -f1)
API_URL=$(printf '%s' "$_raw_url" | sed 's|+|localhost|g; s|0\.0\.0\.0|localhost|g')
log "🔌 API endpoints | $API_URL"
exec "$@"
Loading