Based on the documentation analysis, here are all the practical configuration examples and learning points you should understand:
FROM mcr.microsoft.com/dotnet/sdk:8.0
WORKDIR /app
# User/group setup for security
RUN chown 1001:0 /app
# Switch to root to install tools
USER root
# Install .NET diagnostic tools
RUN dotnet tool install --global dotnet-dump --version 8.*
RUN dotnet tool install --global dotnet-trace --version 8.*
RUN dotnet tool install --global dotnet-counters --version 8.*
RUN dotnet tool install --global dotnet-gcdump --version 8.*
# Add tools to PATH
ENV PATH="${PATH}:/root/.dotnet/tools"
# For sidecar debugging - install to specific path
RUN mkdir -p /app/tools && chown 1001:0 /app/tools && \
dotnet tool install --tool-path /app/tools dotnet-dump --version "8.*" && \
dotnet tool install --tool-path /app/tools dotnet-gcdump --version "8.*" && \
dotnet tool install --tool-path /app/tools dotnet-trace --version "8.*" && \
dotnet tool install --tool-path /app/tools dotnet-counters --version "8.*"
# Switch back to non-root user
USER 1001
Learning Points:
- How to install .NET diagnostic tools in containers
- User permission management in containers
- PATH configuration for global tools
apiVersion: apps/v1
kind: Deployment
metadata:
name: dotnet-memory-leak-app
namespace: dotnet-memory-leak-app
spec:
replicas: 1
selector:
matchLabels:
app: dotnet-memory-leak-app
template:
metadata:
labels:
app: dotnet-memory-leak-app
spec:
serviceAccountName: dotnet-app-sa
containers:
- name: dotnet-app
image: quay.io/your-namespace/dotnet-memory-leak-app:v1
ports:
- containerPort: 8881
env:
# Critical .NET crash dump configuration
- name: COMPlus_DbgEnableElfDumpOnCrash
value: "1"
- name: COMPlus_DbgCrashDumpType
value: "3" # Full dump
- name: COMPlus_DbgMiniDumpName
value: "/app/dumps/dump.dmp"
- name: TMPDIR
value: "/app/dumps/tmp"
volumeMounts:
- name: dump-storage
mountPath: /app/dumps
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "500m"
securityContext:
allowPrivilegeEscalation: false
runAsNonRoot: true
runAsUser: 1001
capabilities:
drop:
- ALL
volumes:
- name: dump-storage
persistentVolumeClaim:
claimName: dotnet-memory-leak-dumps
Learning Points:
- .NET crash dump environment variables
- Resource requests vs limits
- Volume mounting for persistent storage
- Security context configuration
apiVersion: v1
kind: LimitRange
metadata:
name: dotnet-limitrange
namespace: dotnet-memory-leak-app
spec:
limits:
- type: Container
# Default values if not specified
defaultRequest:
cpu: "100m"
memory: "64Mi"
default:
cpu: "500m"
memory: "256Mi"
# Maximum allowed values
max:
cpu: "1"
memory: "1Gi"
# Minimum required values
min:
cpu: "50m"
memory: "32Mi"
Learning Points:
- Resource governance in Kubernetes
- Default resource allocation
- Preventing resource starvation
apiVersion: security.openshift.io/v1
kind: SecurityContextConstraints
metadata:
name: dotnet-scc
allowHostDirVolumePlugin: false
allowHostIPC: false
allowHostNetwork: false
allowHostPID: false
allowHostPorts: false
allowPrivilegedContainer: false
allowedCapabilities:
- SYS_PTRACE # Required for debugging
defaultAddCapabilities: []
fsGroup:
type: RunAsAny
readOnlyRootFilesystem: false
requiredDropCapabilities:
- KILL
- MKNOD
- SETUID
- SETGID
runAsUser:
type: RunAsAny
seLinuxContext:
type: MustRunAs
users:
- system:serviceaccount:dotnet-memory-leak-app:dotnet-app-sa
Learning Points:
- OpenShift security model
- Required capabilities for debugging
- Service account binding
# Navigate to project directory
cd DotNetBuggyApp-main
# Build container image
podman build -t quay.io/your-namespace/dotnet-memory-leak-app:v1 -f Containerfile .
# Push to registry
podman push quay.io/your-namespace/dotnet-memory-leak-app:v1
# For air-gapped environments
podman save -o dotnet-memory-leak-app.tar quay.io/your-namespace/dotnet-memory-leak-app:v1
# Transfer and load in air-gapped environment
sudo podman load -i dotnet-memory-leak-app.tar
sudo podman images # Verify image is loaded
Learning Points:
- Container build workflows
- Registry operations
- Air-gapped deployment strategies
# Deploy using Kustomize
cd DotNetBuggyApp-main/kubernetes
oc apply -k .
# Check deployment status
oc get pods -n dotnet-memory-leak-app --watch
# Get application route
export ROUTE_HOST=$(oc get route dotnet-memory-leak-route -n dotnet-memory-leak-app -o jsonpath='{.spec.host}')
# Trigger memory leak
curl http://$ROUTE_HOST/triggerMemoryLeak
Learning Points:
- Kustomize usage
- Route/Ingress configuration
- Application endpoint testing
# Get pod name
export POD_NAME=$(oc get pods -n dotnet-memory-leak-app -l app=dotnet-memory-leak-app -o jsonpath='{.items[0].metadata.name}')
# Access container shell
oc rsh -c dotnet-app "$POD_NAME"
# Inside container - find process
ps -ef
# Collect dump
dotnet-dump collect --process-id <PID> -o /app/dumps/app_collected_dump.dmp
# Exit container
exit
Learning Points:
- Container shell access
- Process identification
- Manual dump collection
- Why this approach is problematic
# Monitor logs during memory leak
export POD_NAME=$(oc get pods -n dotnet-memory-leak-app -l app=dotnet-memory-leak-app -o jsonpath='{.items[0].metadata.name}')
oc logs "$POD_NAME" -n dotnet-memory-leak-app -f
# After crash, verify dump exists
oc rsh "$POD_NAME" -c dotnet-app -- ls -l /app/dumps/
# Copy dump for analysis
oc cp "$POD_NAME":/app/dumps/dump.dmp ./crash_dump.dmp -n dotnet-memory-leak-app
# Analyze dump locally
dotnet-dump analyze ./crash_dump.dmp
Learning Points:
- Automatic crash dump generation
- Log monitoring techniques
- File extraction from containers
- Local dump analysis
// add-sidecar.json
[
{
"op": "add",
"path": "/spec/template/spec/containers/-",
"value": {
"name": "debugger",
"image": "quay.io/your-namespace/dotnet-debug:v1",
"command": ["sleep", "infinity"],
"env": [
{
"name": "TMPDIR",
"value": "/app/dumps/tmp"
}
],
"volumeMounts": [
{
"mountPath": "/app/dumps",
"name": "dump-storage"
}
]
}
}
]
// remove-sidecar.json
[
{
"op": "remove",
"path": "/spec/template/spec/containers/1"
}
]
# Add sidecar for debugging
oc patch deployment dotnet-memory-leak-app -n dotnet-memory-leak-app --type=json --patch-file add-sidecar.json
# Wait for rollout
oc get pods -n dotnet-memory-leak-app --watch
# Access debugger sidecar
export POD_NAME=$(oc get pods -l app=dotnet-memory-leak-app -n dotnet-memory-leak-app -o jsonpath='{.items[0].metadata.name}')
oc exec -it "$POD_NAME" -n dotnet-memory-leak-app -c debugger -- /bin/bash
# Collect dump from sidecar
ps -ef # Find main app process
/app/tools/dotnet-dump collect -p <PID> -o /app/dumps/dump_SUCCESS.dmp
# Remove sidecar when done
oc patch deployment dotnet-memory-leak-app -n dotnet-memory-leak-app --type=json --patch-file remove-sidecar.json
Learning Points:
- JSON patch operations
- Sidecar container patterns
- Dynamic deployment modification
- Shared volume usage between containers
# Get pod name
export POD_NAME=$(kubectl get pods -n dotnet-memory-leak-app -l app=dotnet-memory-leak-app -o jsonpath='{.items[0].metadata.name}')
# Launch ephemeral debug container
kubectl debug -it "$POD_NAME" --image=quay.io/your-namespace/dotnet-memory-leak-app:v1 --target=dotnet-app -- /bin/bash
# Alternative with SDK image
kubectl debug -it "$POD_NAME" --image=registry.redhat.io/rhel8/dotnet-80:8.0 --target=dotnet-app -- /bin/bash
# Inside ephemeral container
ps -ef # Find main app process
dotnet-dump collect --process-id <PID> -o /app/dumps/ephemeral_collected_dump.dmp
Learning Points:
- Modern Kubernetes debugging features
- Ephemeral containers concept
- Namespace sharing between containers
- kubectl vs oc differences
# Stream application logs
oc logs "$POD_NAME" -n dotnet-memory-leak-app -f
# Expected log output during memory leak:
# info: Program[0]
# Allocated 1516.00 MB this round, Total: 1516.00 MB
# fail: Program[0]
# OutOfMemoryException caught! Application is likely to crash soon.
# System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown.
# Check pod status
oc get pods -n dotnet-memory-leak-app
oc describe pod "$POD_NAME" -n dotnet-memory-leak-app
# Check events
oc get events -n dotnet-memory-leak-app --sort-by='.lastTimestamp'
Learning Points:
- Real-time log monitoring
- Pod lifecycle events
- OutOfMemory behavior patterns
# Common warning messages you'll encounter:
# Warning: would violate PodSecurity "restricted:latest":
# unrestricted capabilities (container "diagnostic-tools-sidecar" must set securityContext.capabilities.drop=["ALL"];
# container "diagnostic-tools-sidecar" must not include "SYS_PTRACE" in securityContext.capabilities.add)
# Error: creating: pods "..." is forbidden: violates PodSecurity "restricted"
# Check current security context constraints
oc get scc
# Describe specific SCC
oc describe scc dotnet-scc
# Check service account permissions
oc describe sa dotnet-app-sa -n dotnet-memory-leak-app
# Verify RBAC
oc describe rolebinding dotnet-app-rolebinding -n dotnet-memory-leak-app
Learning Points:
- Security policy debugging
- RBAC troubleshooting
- Permission escalation patterns
# Check resource usage
oc top pods -n dotnet-memory-leak-app
oc top nodes
# Describe resource limits
oc describe limitrange dotnet-limitrange -n dotnet-memory-leak-app
# Check PVC status
oc get pvc -n dotnet-memory-leak-app
oc describe pvc dotnet-memory-leak-dumps -n dotnet-memory-leak-app
Learning Points:
- Resource consumption monitoring
- Storage management
- Capacity planning
env:
- name: COMPlus_DbgEnableElfDumpOnCrash
value: "1" # Enable crash dumps
- name: COMPlus_DbgCrashDumpType
value: "3" # Full dump (vs mini dump)
- name: COMPlus_DbgMiniDumpName
value: "/app/dumps/dump.dmp" # Output path
- name: TMPDIR
value: "/app/dumps/tmp" # Temp directory for IPC
Learning Points:
- .NET runtime configuration
- Crash dump types and their uses
- Inter-process communication setup
# 1. Build and save image (connected environment)
podman build -t app:v1 .
podman save -o app.tar app:v1
# 2. Transfer to air-gapped environment
scp app.tar user@airgapped-host:~/
# 3. Load in air-gapped environment
sudo podman load -i app.tar
# 4. Deploy using local registry or direct image reference
oc apply -k kubernetes/
Learning Points:
- Offline deployment strategies
- Image transfer techniques
- Registry-less deployments
After working through these examples, you should understand:
- Container Security: How security policies affect debugging capabilities
- Resource Management: Critical importance in single-node clusters
- Debugging Strategies: Multiple approaches for different scenarios
- Production Readiness: Trade-offs between security and observability
- Kubernetes Operations: Real-world deployment and troubleshooting
- .NET Diagnostics: Proper configuration for containerized applications
- Air-Gapped Operations: Deployment in restricted environments
This project provides a comprehensive hands-on learning experience for container orchestration, application debugging, and production operations in Kubernetes/OpenShift environments.