# PicTv.Api — Dockerfile Build Optimization Changes ## Summary The `api/PicTv.Api/Dockerfile` was updated to fix Docker layer caching issues that caused slow builds. Most rebuilds were re-downloading NuGet packages and re-copying the entire repository even when only source code changed. ## What Changed ### Before ```dockerfile COPY ["api/PicTv.Api/PicTv.Api.csproj", "api/PicTv.Api/"] RUN dotnet restore "api/PicTv.Api/PicTv.Api.csproj" COPY . . ``` - Only `PicTv.Api.csproj` was copied before restore, but the project depends on 3 other projects (`PicTv.Application`, `PicTv.Infrastructure`, `PicTv.Domain`). The restore could not resolve ProjectReferences from the `.csproj` files alone, so the layer cache was effectively useless. - `COPY . .` copied the entire repository (workers, tests, migrations, etc.) into the build stage. Any file change anywhere in the repo invalidated the build cache. ### After ```dockerfile # 1. Copy all .csproj files in the dependency chain COPY ["api/PicTv.Api/PicTv.Api.csproj", "api/PicTv.Api/"] COPY ["core/PicTv.Application/PicTv.Application.csproj", "core/PicTv.Application/"] COPY ["core/PicTv.Infrastructure/PicTv.Infrastructure.csproj", "core/PicTv.Infrastructure/"] COPY ["core/PicTv.Domain/PicTv.Domain.csproj", "core/PicTv.Domain/"] # 2. Restore with NuGet cache mount RUN --mount=type=cache,target=/root/.nuget/packages \ dotnet restore "api/PicTv.Api/PicTv.Api.csproj" # 3. Copy only the source directories needed for this build COPY ["api/PicTv.Api/", "api/PicTv.Api/"] COPY ["core/", "core/"] ``` ## Changes Explained | # | Change | Why | |---|--------|-----| | 1 | Copy all 4 `.csproj` files before restore | `dotnet restore` needs the full ProjectReference chain to resolve dependencies. Without them the restore layer is invalidated on every build. | | 2 | `--mount=type=cache,target=/root/.nuget/packages` on restore, build, and publish steps | Persists the NuGet package cache across builds. Even when the restore layer is invalidated (e.g., a new package is added), already-downloaded packages are reused from the cache mount instead of re-downloaded. | | 3 | Replace `COPY . .` with selective `COPY` of `api/PicTv.Api/` and `core/` | Changes to `workers/`, `tests/`, or other unrelated directories no longer invalidate the build cache. | | 4 | `--no-install-recommends` on `apt-get install` in the final stage | Skips optional apt packages, reducing final image size. | ## Requirements - **BuildKit must be enabled.** The `--mount=type=cache` syntax requires BuildKit. Docker Desktop has it enabled by default. For CI/CD pipelines or older Docker daemons, ensure `DOCKER_BUILDKIT=1` is set or the daemon config has `"features": {"buildkit": true}`. - **Build context must be the repository root.** The Dockerfile uses paths relative to the repo root (e.g., `core/PicTv.Application/`), so the build command must run from the root: ```bash docker build -f api/PicTv.Api/Dockerfile . ``` ## Project Dependency Chain ``` PicTv.Api ├── PicTv.Application │ └── PicTv.Domain └── PicTv.Infrastructure ``` If a new ProjectReference is added to any of these projects, the corresponding `.csproj` must also be copied in the Dockerfile before the restore step. ## Risk - No functional changes. The build output is identical. - If BuildKit is not available in the CI/CD environment, the `--mount=type=cache` lines will cause a build error. In that case, remove the `--mount` flags — the other optimizations (granular .csproj copy and selective source copy) still work without BuildKit. --- **Please review these changes and confirm they are compatible with our CI/CD environment. Specifically:** 1. Is BuildKit enabled in our pipeline? 2. Are there any concerns with the cache mount approach? 3. Any other feedback before we merge?