Home / Windows Server / Windows Server Containers and Docker: Modern Application Deployment
Windows Server

Windows Server Containers and Docker: Modern Application Deployment

Deploy modern applications with Windows Server containers, Docker Desktop, container images, Kubernetes orchestration, container networking, persistent stora...

What you will learn

Practical execution with concise explanations, real implementation patterns, and production-ready recommendations.

Windows Server Containers and Docker: Modern Application Deployment



## Building and Running Containers

```powershell




## Build image
docker build -t contoso/mywebapp:1.0 .





## View images
docker images





## Run container
docker run -d `
```text
--name mywebapp `
-p 8080:80 `
contoso/mywebapp:1.0

Expected output:

[+] Building 24.3s (12/12) FINISHED
 => naming to docker.io/library/myapp:latest

Terminal output for docker build

View running containers

docker ps

View all containers (including stopped)

docker ps -a

View container logs

docker logs mywebapp

Follow logs

docker logs -f mywebapp

Execute command in container

docker exec -it mywebapp powershell

Stop container

docker stop mywebapp

Remove container

docker rm mywebapp

Remove image

docker rmi contoso/mywebapp:1.0


## Multi-Stage Build Example

```dockerfile




## Multi-stage Dockerfile




## Stage 1: Build
FROM mcr.microsoft.com/dotnet/sdk:6.0-nanoserver-ltsc2022 AS build
WORKDIR /src





## Copy project files
COPY ["MyWebApp/MyWebApp.csproj", "MyWebApp/"]
RUN dotnet restore "MyWebApp/MyWebApp.csproj"





## Copy source and build
COPY . .
WORKDIR "/src/MyWebApp"
RUN dotnet build "MyWebApp.csproj" -c Release -o /app/build





## Stage 2: Publish
FROM build AS publish
RUN dotnet publish "MyWebApp.csproj" -c Release -o /app/publish





## Stage 3: Runtime
FROM mcr.microsoft.com/dotnet/aspnet:6.0-nanoserver-ltsc2022 AS final
WORKDIR /app
COPY --from=publish /app/publish .
EXPOSE 80
ENTRYPOINT ["dotnet", "MyWebApp.dll"]





Expected output:

Build succeeded.
    0 Warning(s)
    0 Error(s)
Time Elapsed 00:00:04.12

Terminal output for dotnet build

IIS Container Example





## IIS with ASP.NET
FROM mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2022





## Install ASP.NET
RUN powershell -Command `
```text
Add-WindowsFeature Web-Asp-Net45

Copy website

COPY website/ C:/inetpub/wwwroot/

Expose port

EXPOSE 80

Start IIS

ENTRYPOINT ["C:\ServiceMonitor.exe", "w3svc"]


## Container Orchestration with Kubernetes

### Installing Kubernetes on Windows





```powershell
## Enable Kubernetes in Docker Desktop




## Docker Desktop → Settings → Kubernetes → Enable Kubernetes





## Or install minikube for testing
choco install minikube





## Start minikube with Windows containers
minikube start --driver=hyperv --container-runtime=docker





## Install kubectl
choco install kubernetes-cli





## Verify installation
kubectl version
kubectl cluster-info





Deploying Windows Containers to Kubernetes

deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mywebapp
  labels:
```yaml
app: mywebapp```
spec:
  replicas: 3
  selector:
```yaml
matchLabels:
  app: mywebapp```
  template:
```yaml
metadata:
  labels:
    app: mywebapp
spec:
  nodeSelector:
    kubernetes.io/os: windows
  containers:
  - name: mywebapp
    image: contoso/mywebapp:1.0
    ports:
    - containerPort: 80
    resources:
      requests:
        memory: "256Mi"
        cpu: "500m"
      limits:
        memory: "512Mi"
        cpu: "1000m"
    env:
    - name: ASPNETCORE_ENVIRONMENT
      value: "Production"

**service.yaml:**

```yaml
apiVersion: v1
kind: Service
metadata:
  name: mywebapp-service
spec:
  type: LoadBalancer
  selector:
```yaml
app: mywebapp```
  ports:
  - protocol: TCP
```yaml
port: 80
targetPort: 80

### Deploying Application

```powershell
## Apply deployment
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml





## View deployments
kubectl get deployments





## View pods
kubectl get pods





## View services
kubectl get services





## Scale deployment
kubectl scale deployment mywebapp --replicas=5





## View pod details
kubectl describe pod <pod-name>





## View logs
kubectl logs <pod-name>









## Execute command in pod
kubectl exec -it <pod-name> -- powershell





## Delete deployment
kubectl delete -f deployment.yaml





Expected output:

deployment.apps/myapp-api created
service/myapp-api-svc created

Terminal output for kubectl apply

ConfigMaps and Secrets

ConfigMaps and Secrets

Figure: Azure Key Vault blade – secrets list with expiry dates and access policies.





## configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  database_server: "sql.contoso.com"
  database_name: "AppDB"
  log_level: "Information"





## secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: app-secrets
type: Opaque
stringData:
  database_password: "P@ssw0rd123!"
  api_key: "abc123xyz789"





## deployment with configmap and secret
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mywebapp
spec:
  template:
```yaml
spec:
  containers:
  - name: mywebapp
    image: contoso/mywebapp:1.0
    env:
    - name: DatabaseServer
      valueFrom:




        configMapKeyRef:
          name: app-config
          key: database_server
    - name: DatabasePassword
      valueFrom:
        secretKeyRef:
          name: app-secrets
          key: database_password

## Container Networking

### Docker Network Types





```powershell
## List networks
docker network ls





## Create NAT network (default)
docker network create -d nat mynat





## Create Transparent network (external connectivity)
docker network create -d transparent mytransparent





## Create Overlay network (multi-host)
docker network create -d overlay --attachable myoverlay





## Inspect network
docker network inspect nat





## Run container with specific network
docker run -d --network=mynat --name web1 nginx:nanoserver





## Connect container to network
docker network connect mynat web1





## Disconnect container
docker network disconnect mynat web1





Container DNS and Service Discovery





## Create custom network with DNS
docker network create --driver nat --subnet=172.20.0.0/16 mynet





## Run containers on same network
docker run -d --network=mynet --name database mcr.microsoft.com/mssql/server:2019-latest
docker run -d --network=mynet --name webapp contoso/mywebapp:1.0





## Containers can communicate using container names as hostnames




## From webapp container: ping database

Port Mapping





## Map host port to container port
docker run -d -p 8080:80 contoso/mywebapp:1.0





## Map all exposed ports randomly
docker run -d -P contoso/mywebapp:1.0





## View port mappings
docker port <container-name>





## Multiple port mappings
docker run -d `
```text
-p 8080:80 `
-p 8443:443 `
contoso/mywebapp:1.0





## Persistent Storage

### Docker Volumes





```powershell
## Create volume
docker volume create mydata





## List volumes
docker volume ls





## Inspect volume
docker volume inspect mydata





## Run container with volume
docker run -d `
```text
--name database `
-v mydata:C:\data `
mcr.microsoft.com/mssql/server:2019-latest

Backup volume

docker run --rm `

-v mydata:C:\source `
-v C:\Backup:C:\backup `
mcr.microsoft.com/windows/servercore:ltsc2022 `
powershell -Command "Compress-Archive -Path C:\source\* -DestinationPath C:\backup\mydata.zip"

Remove volume

docker volume rm mydata

Remove unused volumes

docker volume prune


## Bind Mounts

```powershell




## Mount host directory to container
docker run -d `
```text
--name webapp `
-v C:\HostData:C:\app\data `
contoso/mywebapp:1.0

Read-only mount

docker run -d `

-v C:\Config:C:\app\config:ro `
contoso/mywebapp:1.0





## Kubernetes Persistent Volumes

```yaml




## persistent-volume.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-data
spec:
  capacity:
```yaml
storage: 10Gi```
  accessModes:
```text
- ReadWriteOnce```
  persistentVolumeReclaimPolicy: Retain
  storageClassName: manual
  hostPath:




```yaml
path: "C:\\k8s-data"
type: DirectoryOrCreate

```yaml
## persistent-volume-claim.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-data
spec:
  accessModes:
```text
- ReadWriteOnce```
  resources:
```yaml
requests:
  storage: 5Gi```
  storageClassName: manual





## deployment with PVC
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  template:
```yaml
spec:
  containers:
  - name: myapp
    image: contoso/myapp:1.0
    volumeMounts:
    - name: data-volume
      mountPath: C:\app\data




  volumes:
  - name: data-volume
    persistentVolumeClaim:
      claimName: pvc-data

## Container Registry

### Azure Container Registry





```powershell
## Login to ACR
az acr login --name contosoregistry





## Tag image for ACR
docker tag contoso/mywebapp:1.0 contosoregistry.azurecr.io/mywebapp:1.0





## Push image to ACR
docker push contosoregistry.azurecr.io/mywebapp:1.0





## Pull image from ACR
docker pull contosoregistry.azurecr.io/mywebapp:1.0





## Create Kubernetes secret for ACR
kubectl create secret docker-registry acr-secret `
```text
--docker-server=contosoregistry.azurecr.io `
--docker-username=<service-principal-id> `
--docker-password=<service-principal-password>

Use secret in deployment

spec:

imagePullSecrets:

- name: acr-secret






## Private Docker Registry

```powershell




## Run private registry container
docker run -d `
```text
-p 5000:5000 `
--name registry `
-v C:\registry:C:\registry `
registry:latest

Tag image for private registry

docker tag contoso/mywebapp:1.0 localhost:5000/mywebapp:1.0

Push to private registry

docker push localhost:5000/mywebapp:1.0

Pull from private registry

docker pull localhost:5000/mywebapp:1.0


## Hybrid Windows/Linux Workloads

### Docker Compose with Mixed Containers





**docker-compose.yml:**

```yaml
version: '3.8'

services:
  # Linux container
  database:
```yaml
image: postgres:14
platform: linux
environment:
  POSTGRES_PASSWORD: P@ssw0rd123!
volumes:
  - db-data:/var/lib/postgresql/data
networks:
  - app-network

Windows container

webapp:

image: contoso/mywebapp:1.0
platform: windows
ports:
  - "8080:80"
environment:
  - ConnectionStrings__Database=Host=database;Database=myapp;Username=postgres;Password=P@ssw0rd123!
depends_on:
  - database
networks:
  - app-network

volumes: db-data:

networks: app-network:

driver: nat

```powershell
## Start services
docker-compose up -d





## View logs
docker-compose logs

## Stop services
docker-compose down





Monitoring and Troubleshooting

Container Diagnostics

## View container resource usage
docker stats





## Inspect container
docker inspect <container-id>





## View container processes
docker top <container-name>





## Copy files from container
docker cp <container-name>:C:\logs\app.log C:\Temp\





## Copy files to container
docker cp C:\Config\app.config <container-name>:C:\app\





## Export container filesystem
docker export <container-name> -o container.tar





Kubernetes Monitoring

Kubernetes Monitoring

Figure: AKS cluster workloads – pod status, node pools, and horizontal autoscaler.





## View cluster events
kubectl get events --sort-by=.metadata.creationTimestamp





## View node status
kubectl get nodes -o wide





## View resource usage
kubectl top nodes
kubectl top pods





## Describe pod (detailed troubleshooting)
kubectl describe pod <pod-name>





## View pod logs (previous container)
kubectl logs <pod-name> --previous





## Port forward for debugging
kubectl port-forward pod/<pod-name> 8080:80





Architecture Decision and Tradeoffs

When designing server infrastructure solutions with Windows Server, consider these key architectural trade-offs:

Approach Best For Tradeoff
Managed / platform service Rapid delivery, reduced ops burden Less customisation, potential vendor lock-in
Custom / self-hosted Full control, advanced tuning Higher operational overhead and cost

Recommendation: Start with the managed approach for most workloads and move to custom only when specific requirements demand it.

Validation and Versioning

  • Last validated: April 2026
  • Validate examples against your tenant, region, and SKU constraints before production rollout.
  • Keep module, CLI, and SDK versions pinned in automation pipelines and review quarterly.

Security and Governance Considerations

  • Apply least-privilege access using RBAC roles and just-in-time elevation for admin tasks.
  • Store secrets in managed secret stores and avoid embedding credentials in scripts or source files.
  • Enable audit logging, data protection policies, and periodic access reviews for regulated workloads.

Cost and Performance Notes

  • Define budgets and alerts, then monitor usage and cost trends continuously after go-live.
  • Baseline performance with synthetic and real-user checks before and after major changes.
  • Scale resources with measured thresholds and revisit sizing after usage pattern changes.

Official Microsoft References

  • https://learn.microsoft.com/windows-server/
  • https://learn.microsoft.com/windows/security/
  • https://learn.microsoft.com/azure/azure-arc/

Public Examples from Official Sources

  • These examples are sourced from official public Microsoft documentation and sample repositories.
  • Documentation examples: https://learn.microsoft.com/windows-server/
  • Sample repositories: https://github.com/microsoft/Windows-Containers
  • Prefer adapting these examples to your tenant, subscriptions, and governance requirements before production use.

Key Takeaways

  • Windows Server containers enable portable application deployment
  • Process isolation shares kernel, Hyper-V isolation provides stronger security
  • Docker simplifies container image creation and management
  • Kubernetes orchestrates multi-container applications at scale
  • Container networking enables service discovery and communication
  • Persistent volumes retain data across container restarts
  • Azure Container Registry provides secure image storage
  • Docker Compose simplifies multi-container applications
  • Hybrid workloads combine Windows and Linux containers
  • Monitoring tools help diagnose container issues

Next Steps

  • Containerize existing .NET applications
  • Set up Azure Container Registry
  • Deploy Kubernetes cluster for production
  • Implement CI/CD pipeline for container images
  • Configure monitoring and logging
  • Establish container security policies

Additional Resources


Build. Ship. Run. Anywhere.

Discussion