Introduction to Containers
Containers package applications with their dependencies, ensuring consistent behavior across environments. Docker is the most popular containerization platform, while Kubernetes orchestrates containers at scale.
Why Containers?
- Consistency: Same environment from dev to production
- Isolation: Applications don't interfere with each other
- Efficiency: Lighter than virtual machines
- Portability: Run anywhere Docker is installed
Docker Basics
# Run a container
docker run -it ubuntu:22.04 bash
# Run in background with port mapping
docker run -d -p 8080:80 nginx
# List containers
docker ps -a
# View logs
docker logs container_name
# Stop and remove
docker stop container_name
docker rm container_name
# List images
docker images
docker rmi image_name
Dockerfile
Define your container image with a Dockerfile:
# Use official .NET SDK for building
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
# Copy project files
COPY *.csproj ./
RUN dotnet restore
# Copy source and build
COPY . ./
RUN dotnet publish -c Release -o /app
# Use runtime image for final container
FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY --from=build /app ./
# Set environment and expose port
ENV ASPNETCORE_URLS=http://+:80
EXPOSE 80
ENTRYPOINT ["dotnet", "MyApp.dll"]
Docker Compose
Define multi-container applications:
# docker-compose.yml
version: '3.8'
services:
web:
build: .
ports:
- "8080:80"
environment:
- ConnectionStrings__Default=Server=db;...
depends_on:
- db
- redis
db:
image: postgres:15
environment:
POSTGRES_USER: myapp
POSTGRES_PASSWORD: secret
POSTGRES_DB: myappdb
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
postgres_data:
# Start all services
docker-compose up -d
# View logs
docker-compose logs -f web
# Stop and remove
docker-compose down
Kubernetes Basics
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myregistry/myapp:latest
ports:
- containerPort: 80
resources:
limits:
memory: "256Mi"
cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:
name: myapp-service
spec:
selector:
app: myapp
ports:
- port: 80
targetPort: 80
type: LoadBalancer
Best Practices
- Use multi-stage builds to reduce image size
- Don't run as root inside containers
- Use .dockerignore to exclude unnecessary files
- Pin specific image versions in production
- Scan images for vulnerabilities