By Fatskills Exam Guides Team — the exam nerds behind 28,500+ quizzes and 2.1M practice questions across 500+ global exams.
Containerization and orchestration are the backbone of modern deployments—especially in high-stakes environments where uptime, security, and reproducibility matter. As an FDE, you’ll use Docker to package applications (ML models, data pipelines, APIs) into portable, isolated units and Kubernetes to manage them at scale. Real-world example: You’re on-site at a military base deploying a computer vision model for drone footage analysis. The network is air-gapped, the hardware is outdated, and the customer’s security team won’t let you use standard Docker images. You need to: 1. Build a minimal, hardened container image offline.2. Deploy it to a Kubernetes cluster running on bare metal with no internet access.3. Debug why the model’s latency spikes under load—while the customer watches over your shoulder.
This guide gives you the practical, battle-tested steps to handle these scenarios.
FDE use case: Shipping a PyTorch model to a classified network where you can’t install Python dependencies manually.
Dockerfile: A text file with instructions for building a Docker image (e.g., FROM python:3.9, COPY . /app, RUN pip install -r requirements.txt).
FROM python:3.9
COPY . /app
RUN pip install -r requirements.txt
FDE tip: Always pin versions (python:3.9-slim instead of python:latest) to avoid breaking changes in the field.
python:3.9-slim
python:latest
Docker Compose: A tool for defining and running multi-container applications (e.g., a Flask app + Redis + Postgres). Uses a docker-compose.yml file.
docker-compose.yml
FDE use case: Spinning up a local replica of a customer’s environment to debug a data pipeline before deploying to their air-gapped cluster.
Kubernetes (K8s): An open-source system for automating deployment, scaling, and management of containerized applications. Runs "pods" (groups of containers) on "nodes" (servers).
FDE tools: kubectl (CLI), helm (package manager), k9s (terminal UI for debugging).
kubectl
helm
k9s
Pod: The smallest deployable unit in Kubernetes. A pod can run one or more containers (e.g., your app + a sidecar logging container).
FDE trap: Never run multiple unrelated containers in one pod—it violates the "single responsibility" principle and makes debugging harder.
Deployment: A Kubernetes object that manages a set of identical pods. Handles rolling updates, rollbacks, and scaling.
FDE example: Updating a model serving API without downtime during a live mission.
Service: Exposes a set of pods as a network service (e.g., ClusterIP for internal traffic, NodePort/LoadBalancer for external access).
ClusterIP
NodePort
LoadBalancer
FDE tip: Use kubectl port-forward to debug a service locally when you can’t expose it publicly.
kubectl port-forward
ConfigMap/Secret: Kubernetes objects for storing configuration data (ConfigMap) or sensitive data (Secrets, e.g., API keys, database passwords).
FDE security: Never hardcode secrets in Dockerfiles or Git. Use kubectl create secret generic or a tool like Vault.
kubectl create secret generic
PersistentVolume (PV) / PersistentVolumeClaim (PVC): Kubernetes objects for managing storage (e.g., databases, model weights). A PV is the actual storage; a PVC is a request for storage.
FDE use case: Deploying a PostgreSQL database in a Kubernetes cluster where the customer requires data to persist across pod restarts.
Helm: A package manager for Kubernetes. Lets you define, install, and upgrade complex applications (e.g., helm install my-app ./charts).
helm install my-app ./charts
FDE tip: Use Helm to templatize deployments for different customers (e.g., one chart for AWS, another for on-prem).
Air-Gapped Deployment: Deploying to a network with no internet access. Requires:
.tar
pip download
FDE tools: docker save, docker load, skopeo (for copying images between registries).
docker save
docker load
skopeo
Immutable Infrastructure: The principle that containers (and infrastructure) should never be modified after deployment. If something breaks, you replace the container instead of fixing it in place.
Scenario: You’re deploying a Python Flask API to a customer’s on-prem server. They won’t let you install Python or dependencies manually.
Steps:1. Write a minimal Dockerfile: ```dockerfile # Use a slim, pinned base image FROM python:3.9-slim
# Set working directory WORKDIR /app
# Copy requirements first (for caching) COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt
# Copy the rest of the app COPY . .
# Run as non-root user (security) RUN useradd -m appuser && chown -R appuser /app USER appuser
# Expose port and set entrypoint EXPOSE 5000 CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"] 2. Build the image:bash docker build -t my-flask-app:1.0.0 . 3. Test locally:bash docker run -p 5000:5000 my-flask-app:1.0.0 curl http://localhost:5000/health 4. Save the image for air-gapped deployment:bash docker save my-flask-app:1.0.0 > flask-app.tar `` - Transferflask-app.tar` to the customer’s network via USB or approved file transfer.
2. Build the image:
3. Test locally:
4. Save the image for air-gapped deployment:
`` - Transfer
bash docker load < flask-app.tar
Scenario: Your Flask API needs Redis for caching. The customer wants to test it locally before deploying to Kubernetes.
Steps:1. Write docker-compose.yml: yaml version: "3.8" services: web: build: . ports: - "5000:5000" depends_on: - redis redis: image: redis:6.2-alpine ports: - "6379:6379" 2. Start the stack: bash docker-compose up -d 3. Test the API: bash curl http://localhost:5000/cache/set?key=foo&value=bar curl http://localhost:5000/cache/get?key=foo # Should return "bar" 4. Debug if something breaks: bash docker-compose logs web # Check Flask logs docker-compose exec web sh # Shell into the container
yaml version: "3.8" services: web: build: . ports: - "5000:5000" depends_on: - redis redis: image: redis:6.2-alpine ports: - "6379:6379"
bash docker-compose up -d
bash curl http://localhost:5000/cache/set?key=foo&value=bar curl http://localhost:5000/cache/get?key=foo # Should return "bar"
bash docker-compose logs web # Check Flask logs docker-compose exec web sh # Shell into the container
Scenario: The customer wants to run your Flask + Redis app in their on-prem Kubernetes cluster.
Steps:1. Create Kubernetes manifests: - deployment.yaml: yaml apiVersion: apps/v1 kind: Deployment metadata: name: flask-app spec: replicas: 2 selector: matchLabels: app: flask-app template: metadata: labels: app: flask-app spec: containers: - name: flask-app image: my-flask-app:1.0.0 ports: - containerPort: 5000 envFrom: - configMapRef: name: flask-config - name: redis image: redis:6.2-alpine ports: - containerPort: 6379 - service.yaml: yaml apiVersion: v1 kind: Service metadata: name: flask-service spec: selector: app: flask-app ports: - protocol: TCP port: 80 targetPort: 5000 type: ClusterIP # Internal-only access - configmap.yaml (for non-sensitive config): yaml apiVersion: v1 kind: ConfigMap metadata: name: flask-config data: REDIS_HOST: "localhost" LOG_LEVEL: "info" 2. Apply the manifests: bash kubectl apply -f configmap.yaml kubectl apply -f deployment.yaml kubectl apply -f service.yaml 3. Verify the deployment: bash kubectl get pods # Check pod status kubectl logs -l app=flask-app # View logs kubectl port-forward svc/flask-service 8080:80 # Test locally curl http://localhost:8080/health 4. Debug common issues: - Pods stuck in Pending: Check kubectl describe pod <pod-name> for resource constraints or node issues. - CrashLoopBackOff: Check logs (kubectl logs <pod-name>) or exec into the container (kubectl exec -it <pod-name> -- sh). - Service not reachable: Verify the selector in the Service matches the pod labels.
deployment.yaml
yaml apiVersion: apps/v1 kind: Deployment metadata: name: flask-app spec: replicas: 2 selector: matchLabels: app: flask-app template: metadata: labels: app: flask-app spec: containers: - name: flask-app image: my-flask-app:1.0.0 ports: - containerPort: 5000 envFrom: - configMapRef: name: flask-config - name: redis image: redis:6.2-alpine ports: - containerPort: 6379
service.yaml
yaml apiVersion: v1 kind: Service metadata: name: flask-service spec: selector: app: flask-app ports: - protocol: TCP port: 80 targetPort: 5000 type: ClusterIP # Internal-only access
configmap.yaml
yaml apiVersion: v1 kind: ConfigMap metadata: name: flask-config data: REDIS_HOST: "localhost" LOG_LEVEL: "info"
bash kubectl apply -f configmap.yaml kubectl apply -f deployment.yaml kubectl apply -f service.yaml
bash kubectl get pods # Check pod status kubectl logs -l app=flask-app # View logs kubectl port-forward svc/flask-service 8080:80 # Test locally curl http://localhost:8080/health
Pending
kubectl describe pod <pod-name>
kubectl logs <pod-name>
kubectl exec -it <pod-name> -- sh
selector
Scenario: The customer’s cluster has no internet access. You need to deploy your app and its dependencies.
Steps:1. Pre-download all images: bash # On a machine with internet: docker pull my-flask-app:1.0.0 docker pull redis:6.2-alpine docker save my-flask-app:1.0.0 > flask-app.tar docker save redis:6.2-alpine > redis.tar 2. Transfer images to the air-gapped network: - Use approved media (USB, secure file transfer).3. Load images on the customer’s nodes: bash docker load < flask-app.tar docker load < redis.tar 4. Push images to a local registry (if available): bash docker tag my-flask-app:1.0.0 local-registry:5000/my-flask-app:1.0.0 docker push local-registry:5000/my-flask-app:1.0.0 5. Update Kubernetes manifests to use the local registry: yaml image: local-registry:5000/my-flask-app:1.0.0 6. Deploy: bash kubectl apply -f .
bash # On a machine with internet: docker pull my-flask-app:1.0.0 docker pull redis:6.2-alpine docker save my-flask-app:1.0.0 > flask-app.tar docker save redis:6.2-alpine > redis.tar
bash docker load < flask-app.tar docker load < redis.tar
bash docker tag my-flask-app:1.0.0 local-registry:5000/my-flask-app:1.0.0 docker push local-registry:5000/my-flask-app:1.0.0
yaml image: local-registry:5000/my-flask-app:1.0.0
bash kubectl apply -f .
latest
redis:6.2-alpine
root
dockerfile RUN useradd -m appuser && chown -R appuser /app USER appuser
.gitignore
yaml resources: requests: cpu: "100m" memory: "256Mi" limits: cpu: "500m" memory: "512Mi"
podman
buildah
kubectl get pods
kubectl logs <pod-name> --previous
kubectl top pod
StatefulSet
PersistentVolumeClaim
Service
docker build -t my-app:1.0.0 .
docker run -p 5000:5000 my-app
docker save my-app > app.tar
docker load < app.tar
docker-compose up -d → Start a multi-container app.
docker-compose up -d
Kubernetes commands:
kubectl apply -f deployment.yaml
kubectl port-forward svc/my-service 8080:80 → Access a service locally.
kubectl port-forward svc/my-service 8080:80
Key ports:
5000
6379
5432
80/443: HTTP/HTTPS.
80/443
Deployment checklist:
✅ Have a rollback plan.
Field traps:
⚠️ Security reviews take time. Start early and involve the customer’s security team from day one.
Acronyms:
Join 4M+ learners. Unlock unlimited quizzes, wrong-answer tracking, flashcards + reminders, study guides, and 1-on-1 challenges.