Docker

Run the app and its database as containers — one profile per DatabaseProvider, no local .NET SDK or database install required.

Quick Start

docker-compose.yml (repo root) defines a db-<provider> / app-<provider> service pair for each supported database, selected with a Compose profile:

cp .env.example .env   # set real passwords/secrets first
docker compose --profile sqlserver up --build   # or: postgres / mysql / sqlite

The app is then at http://localhost:8080. Program.cs runs its usual startup sequence inside the container exactly as it does locally — migrations apply and seed data loads automatically (see Database Setup) — so there’s no separate migration step to run.

Only run one profile at a time

Every app-* service publishes the same host port (APP_PORT, default 8080). Stop one profile (docker compose --profile <name> down) before starting another.

Profiles

ProfileContainers startedNotes
sqlserverdb-sqlserver + app-sqlservermcr.microsoft.com/mssql/server:2022-latest. Matches the project default.
postgresdb-postgres + app-postgrespostgres:16-alpine.
mysqldb-mysql + app-mysqlmysql:8.4. On a first-ever boot the official MySQL image runs a temporary initialization server before the real one; the healthcheck pings over TCP (-h 127.0.0.1) so it only reports healthy once the real server is accepting connections, and the app starts cleanly on its first attempt.
sqliteapp-sqlite onlyNo database container — the .sqlite3 file lives in the sqlite_data named volume at /app/data.

Each database container has a real healthcheck (sqlcmd/pg_isready/mysqladmin ping), and the app service waits for it (depends_on: condition: service_healthy) before its first migration attempt.

On a brand-new PostgreSQL database, the first startup logs one fail: Microsoft.EntityFrameworkCore.Database.Command entry for a SELECT ... FROM "__EFMigrationsHistory" query. That is EF Core checking for its migrations table before creating it; the migration is applied immediately afterwards and the message does not appear on later startups.

Persisted Data

Named volumes keep data across container recreation:

  • sqlserver_data / postgres_data / mysql_data / sqlite_data — whichever provider’s data directory / database file.
  • uploads_data — mounted at /app/wwwroot/content/images, shared by every app-* service. This is where the image-upload actions (SharedController) write product/category/slider pictures and user avatars at runtime, so they survive rebuilding or recreating the app container. Only image files (.jpg, .jpeg, .png, .gif, .webp) are accepted, from signed-in users only (Administrators for slider images).

Configuration

Copy .env.example to .env and set real values before running anything beyond a quick local try — .env is gitignored.

VariableUsed byPurpose
APP_PORTall app-*Host port the app is published on (container always listens on 8080).
ASPNETCORE_ENVIRONMENTall app-*Standard ASP.NET Core environment (Development shows detailed error pages).
APP_ENVIRONMENTall app-*Maps to the app’s own Environment config key (LIVE/other) — see Go-Live Checklist. Separate from ASPNETCORE_ENVIRONMENT.
JWT_KEYall app-*Signing key for the API area’s JWTs (Jwt:Key). Generate a real secret for anything beyond local testing.
SA_PASSWORD, SQLSERVER_PORTsqlserver profileSQL Server sa password and published port.
POSTGRES_DB, POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_PORTpostgres profileStandard Postgres image variables.
MYSQL_DATABASE, MYSQL_USER, MYSQL_PASSWORD, MYSQL_ROOT_PASSWORD, MYSQL_PORTmysql profileStandard MySQL image variables.

Reference: Files

FilePurpose
docker-compose.ymlRepo root. All eight services (four db-* + four app-*) and their profiles, volumes, and env vars.
eCommerceMVCCore/DockerfileMulti-stage build (SDK → publish → aspnet runtime). One image (ecommercemvc-web:latest) is shared by all four app-* services — only the runtime env vars differ per provider.
eCommerceMVCCore/docker-entrypoint.shThe image’s entrypoint. With docker-compose it simply starts the app. Optional: on a host that can’t mount a volume onto wwwroot/content/images but keeps some other folder (e.g. Azure App Service’s /home), set PERSISTENT_IMAGES_PATH to that folder and uploaded pictures are kept there across restarts.
eCommerceMVCCore/.dockerignoreExcludes bin/, obj/, .vs/, etc. from the build context.
.env.exampleRepo root. Template for .env — every variable above, with placeholder values.