Your First "Aha" Moment: Docker image = Your app + .NET runtime + OS. One zip file that runs anywhere.
1. The Problem Docker Solves
Without Docker: "It works on my laptop." Prod server: missing .NET 8, wrong OS, different paths. Crash.
With Docker: Ship your app + .NET 8 + Ubuntu in one container. Server just needs Docker. Runs identical everywhere.
2. Dockerfile - 4 Lines That Matter
Create Dockerfile in project root:
# 1. Build stage: SDK has compiler
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY *.csproj .
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /app
# 2. Runtime stage: Only runtime, 100MB not 1GB
FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY --from=build /app .
ENTRYPOINT ["dotnet", "MyApp.dll"]
Key: Multi-stage. Build with SDK. Run with ASPNET runtime. Final image ~200MB not 1.2GB.
3. Run It Locally - 3 Commands
docker build -t myapp .
docker run -d -p 8080:8080 --name myapp myapp
curl http://localhost:8080/weatherforecast
-p 8080:8080 = Map host port 8080 β container port 8080. Set in launchSettings.json: "ASPNETCORE_URLS": "http://+:8080"
Career-Killer Mistake #1: Using SDK image for runtime.
FROM mcr.microsoft.com/dotnet/sdk:8.0 in final stage.
What happens: Image is 1.2GB vs 200MB. Pull takes 5 min. 10 pods = 12GB RAM wasted. AWS bill +$300/month.
Fix: Always multi-stage. Final stage = aspnet:8.0 or runtime:8.0.
4. docker-compose - Run App + DB Together
docker-compose.yml
services:
web:
build: .
ports: ["8080:8080"]
environment:
- ConnectionStrings__Default=Server=db;Database=App;User=sa;Password=YourStrong@Passw0rd
depends_on: [db]
db:
image: mcr.microsoft.com/mssql/server:2022-latest
environment:
- ACCEPT_EULA=Y
- MSSQL_SA_PASSWORD=YourStrong@Passw0rd
ports: ["1433:1433"]
Run: docker-compose up -d. App + SQL Server up in 20s. Destroy: docker-compose down -v.
Stop Here. Think. Container is ephemeral. Logs, uploads, SQLite DB gone on restart.
Mount volumes for data: -v mydata:/app/data. For logs: use stdout + ship to Seq/ELK.
1. The Interview Theory: Images vs Containers
Image: Read-only template. Like a class. Built from Dockerfile. Stored in registry. myapp:1.0
Container: Running instance of image. Like an object. Has writable layer. docker run myapp:1.0
Layer Caching: Docker reuses unchanged layers. Put COPY *.csproj + RUN dotnet restore first. If code changes but packages don't, restore layer cached. Build = 5s not 2min.
2. The #1 Interview Question: "Optimize Dockerfile"
Your Answer: "5 rules. 1. Multi-stage: SDK build, ASPNET runtime. Cuts 1GB β 200MB. 2. Layer cache: Copy csproj + restore before code. 3. .dockerignore: Exclude bin/, obj/, .git. Reduces context size. 4. Non-root user: USER app after RUN adduser app. Security. 5. HEALTHCHECK: HEALTHCHECK CMD curl -f http://localhost:8080/healthz. K8s uses it. Also set ASPNETCORE_URLS=http://+:8080 because containers don't run as admin."
3. Production Dockerfile - Staff Level
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 8080
ENV ASPNETCORE_URLS=http://+:8080
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["MyApp/MyApp.csproj", "MyApp/"]
RUN dotnet restore "MyApp/MyApp.csproj"
COPY . .
WORKDIR "/src/MyApp"
RUN dotnet build "MyApp.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "MyApp.csproj" -c Release -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
# Run as non-root
RUN adduser --disabled-password --home /app --gecos '' appuser && chown -R appuser /app
USER appuser
ENTRYPOINT ["dotnet", "MyApp.dll"]
Why this wins: 1. UseAppHost=false = no extra exe. 2. Non-root = CVE mitigation. 3. Explicit WORKDIR = no path bugs. 4. EXPOSE 8080 = documentation.
4. Environment Variables + Secrets
Dev: docker run -e ASPNETCORE_ENVIRONMENT=Development
Prod: -e ConnectionStrings__Default="..."
K8s: Use secrets: kubectl create secret generic db-secret --from-literal=conn="..."
Code: builder.Configuration.AddEnvironmentVariables(). Double underscore __ = nested JSON.
5. Debugging Containers
| Problem | Command |
| App crashed | docker logs myapp |
| Enter container | docker exec -it myapp /bin/bash |
| Check port | docker port myapp |
| Inspect env | docker inspect myapp |
| CPU/RAM | docker stats |
Career-Killer Mistake #2: Storing data in container.
RUN mkdir /app/uploads β User uploads file β Container restart β File gone.
Fix: Mount volume: docker run -v /host/uploads:/app/uploads. Or use S3/Azure Blob. Containers are cattle, not pets.
What's Next = You Can Ship: You finished Deployment. IIS, Azure, Docker.
Next Track: Advanced C#, Microservices, or K8s. Tell me what team needs and I'll build it. You're production-ready.
Quick Check π§
β οΈ This is not the end
This is V1 Draft Version
We are upgrading. Don't judge book by its cover.
Picture abhi baki hai mere dost π¬
Deployment section complete. Content is V1 for internal review.
Real devs: deploy this, break it, tell us whatβs missing. We're shipping V2 based on your feedback.
Deployment Track Complete! IIS β Azure β Docker. You can now ship code.
Whatβs next? Tell me: Advanced C#, Microservices, K8s, or Testing. I'll build the next section. You choose.
No comments yet. Be the first to share your thoughts!