Cloud Native 20 min read

Master Container Deployment: Docker & Kubernetes Best Practices for Production

This comprehensive guide walks you through containerizing applications, optimizing Docker images, securing containers, designing Kubernetes high‑availability clusters, implementing observability with Prometheus and ELK, automating CI/CD pipelines, applying RBAC and network policies, and cutting costs with autoscaling and resource tuning, all backed by real‑world code examples.

MaGe Linux Operations
MaGe Linux Operations
MaGe Linux Operations
Master Container Deployment: Docker & Kubernetes Best Practices for Production

Container Deployment Practices: Docker and Kubernetes in Production

Why Containerize?

Frequent production incidents caused by environment drift and "it works on my machine" problems can be eliminated by adopting containerization, which ensures consistency across development, testing, and production.

Docker: From Basics to Production

Image Optimization

Reduce image size from >1 GB to <100 MB by using multi‑stage builds and Alpine base images.

# Optimized Dockerfile (image size: 85 MB)
FROM python:3.9‑alpine AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --user -r requirements.txt

FROM python:3.9‑alpine
RUN apk add --no-cache libpq
COPY --from=builder /root/.local /root/.local
COPY --from=builder /app /app
WORKDIR /app
COPY . .
ENV PATH=/root/.local/bin:$PATH
CMD ["python","app.py"]

Use Alpine Linux as the base image.

Apply multi‑stage builds to drop build‑time dependencies.

Combine RUN commands to minimise layers.

Clean caches and temporary files.

Leverage a .dockerignore file.

Production‑grade Docker Security

# docker‑compose.yml security configuration example
version: '3.8'
services:
  app:
    image: myapp:latest
    security_opt:
      - no-new-privileges:true
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE
    read_only: true
    tmpfs:
      - /tmp
    user: "1000:1000"
    networks:
      - internal
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 256M

Run containers as non‑root users.

Drop unnecessary Linux capabilities.

Mount the filesystem read‑only.

Set CPU and memory limits.

Regularly scan images for vulnerabilities.

Docker Network Design

# Create a custom bridge network
docker network create --driver bridge \
  --subnet=172.20.0.0/16 \
  --ip-range=172.20.240.0/20 \
  --gateway=172.20.0.1 \
  production-network

# Connect backend and frontend containers
docker run -d --name backend \
  --network production-network \
  --network-alias api-server \
  myapp:backend

docker run -d --name frontend \
  --network production-network \
  -e API_URL=http://api-server:8080 \
  myapp:frontend

Kubernetes: Building an Enterprise‑grade Cluster

High‑availability Master Nodes

# kubeadm-config.yaml (high‑availability control plane)
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: v1.28.0
controlPlaneEndpoint: "k8s-api.example.com:6443"
networking:
  serviceSubnet: "10.96.0.0/12"
  podSubnet: "10.244.0.0/16"
etcd:
  external:
    endpoints:
      - https://etcd-0.example.com:2379
      - https://etcd-1.example.com:2379
      - https://etcd-2.example.com:2379
    caFile: /etc/kubernetes/pki/etcd/ca.crt
    certFile: /etc/kubernetes/pki/etcd/client.crt
    keyFile: /etc/kubernetes/pki/etcd/client.key

Application Deployment Workflow

# ConfigMap for application configuration
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  namespace: production
data:
  database.conf: |
    host=db.example.com
    port=5432
    pool_size=20
  redis.conf: |
    host=redis.example.com
    port=6379
---
apiVersion: v1
kind: Secret
metadata:
  name: app-secrets
  namespace: production
type: Opaque
data:
  db-password: cGFzc3dvcmQxMjM=
  api-key: YWJjZGVmZ2hpams=
# Deployment example for an API server
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-server
  namespace: production
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  selector:
    matchLabels:
      app: api-server
  template:
    metadata:
      labels:
        app: api-server
    spec:
      containers:
      - name: api-server
        image: registry.example.com/api-server:v2.1.0
        ports:
        - containerPort: 8080
          name: http
        - containerPort: 9090
          name: metrics
        env:
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: app-secrets
              key: db-password
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /ready
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 5
# Service & Ingress for the API server
apiVersion: v1
kind: Service
metadata:
  name: api-server-service
  namespace: production
spec:
  type: ClusterIP
  selector:
    app: api-server
  ports:
  - port: 80
    targetPort: 8080
    name: http
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-ingress
  namespace: production
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: "/"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - api.example.com
    secretName: api-tls-secret
  rules:
  - host: api.example.com
    http:
      paths:
      - path: "/"
        pathType: Prefix
        backend:
          service:
            name: api-server-service
            port:
              number: 80

Autoscaling Strategies

# HorizontalPodAutoscaler (CPU & memory based)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: api-server-hpa
  namespace: production
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api-server
  minReplicas: 3
  maxReplicas: 20
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80
  - type: Pods
    pods:
      metric:
        name: http_requests_per_second
      target:
        type: AverageValue
        averageValue: "1000"
# VerticalPodAutoscaler for fine‑grained resource tuning
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: api-server-vpa
  namespace: production
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api-server
  updatePolicy:
    updateMode: "Auto"
  resourcePolicy:
    containerPolicies:
    - containerName: api-server
      minAllowed:
        cpu: 100m
        memory: 128Mi
      maxAllowed:
        cpu: 2
        memory: 2Gi

Observability

Prometheus + Grafana Monitoring Stack

# prometheus-config.yaml (ConfigMap)
apiVersion: v1
kind: ConfigMap
metadata:
  name: prometheus-config
  namespace: monitoring
data:
  prometheus.yml: |
    global:
      scrape_interval: 15s
      evaluation_interval: 15s
    scrape_configs:
    - job_name: 'kubernetes-pods'
      kubernetes_sd_configs:
      - role: pod
      relabel_configs:
      - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
        action: keep
        regex: true
      - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
        action: replace
        target_label: __metrics_path__
        regex: (.+)
      - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
        action: replace
        regex: ([^:]+)(?::\d+)?;(\d+)
        replacement: $1:$2
        target_label: __address__

ELK Log Collection

# Fluentd ConfigMap example
apiVersion: v1
kind: ConfigMap
metadata:
  name: fluentd-config
  namespace: kube-system
data:
  fluent.conf: |
    <source>
      @type tail
      path /var/log/containers/*.log
      pos_file /var/log/fluentd-containers.log.pos
      tag kubernetes.*
      <parse>
        @type json
        time_format %Y-%m-%dT%H:%M:%S.%NZ
      </parse>
    </source>
    <filter kubernetes.**>
      @type kubernetes_metadata
    </filter>
    <match **>
      @type elasticsearch
      host elasticsearch.elastic-system.svc.cluster.local
      port 9200
      logstash_format true
      logstash_prefix kubernetes
      <buffer>
        @type file
        path /var/log/fluentd-buffers/kubernetes.system.buffer
        flush_interval 5s
        retry_type exponential_backoff
        retry_max_interval 30
        chunk_limit_size 2M
        queue_limit_length 8
        overflow_action block
      </buffer>
    </match>

CI/CD Integration

# .gitlab-ci.yml pipeline example
stages:
  - build
  - test
  - security
  - deploy
variables:
  DOCKER_DRIVER: overlay2
  DOCKER_TLS_CERTDIR: ""
  REGISTRY: registry.example.com
  IMAGE_TAG: $CI_COMMIT_SHORT_SHA

build:
  stage: build
  image: docker:20.10
  services:
    - docker:20.10-dind
  script:
    - docker build -t $REGISTRY/$CI_PROJECT_NAME:$IMAGE_TAG .
    - docker push $REGISTRY/$CI_PROJECT_NAME:$IMAGE_TAG
  only:
    - main
    - develop

test:
  stage: test
  image: $REGISTRY/$CI_PROJECT_NAME:$IMAGE_TAG
  script:
    - pytest tests/ --cov=app --cov-report=xml
    - coverage report
  artifacts:
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage.xml

security-scan:
  stage: security
  image: aquasec/trivy:latest
  script:
    - trivy image --severity HIGH,CRITICAL $REGISTRY/$CI_PROJECT_NAME:$IMAGE_TAG
  allow_failure: false

deploy-production:
  stage: deploy
  image: bitnami/kubectl:latest
  script:
    - kubectl set image deployment/api-server api-server=$REGISTRY/$CI_PROJECT_NAME:$IMAGE_TAG -n production
    - kubectl rollout status deployment/api-server -n production
  environment:
    name: production
    url: https://api.example.com
  only:
    - main
  when: manual

Security Hardening

RBAC Permissions

# ServiceAccount, Role, and RoleBinding for read‑only access
apiVersion: v1
kind: ServiceAccount
metadata:
  name: readonly-user
  namespace: production
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: readonly-role
  namespace: production
rules:
- apiGroups: ["", "apps", "batch"]
  resources: ["pods", "services", "deployments", "jobs"]
  verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: readonly-binding
  namespace: production
subjects:
- kind: ServiceAccount
  name: readonly-user
  namespace: production
roleRef:
  kind: Role
  name: readonly-role
  apiGroup: rbac.authorization.k8s.io

NetworkPolicy Isolation

# NetworkPolicy allowing only frontend pods to reach the API server
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-server-netpol
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: api-server
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          name: production
    - podSelector:
        matchLabels:
          app: frontend
    ports:
    - protocol: TCP
      port: 8080
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          name: production
    ports:
    - protocol: TCP
      port: 5432 # PostgreSQL
    - protocol: TCP
      port: 6379 # Redis
    - {} # Allow DNS
    - podSelector:
        matchLabels:
          k8s-app: kube-dns
      ports:
      - protocol: UDP
        port: 53

Cost Optimization

Resource Utilisation with VPA

# VerticalPodAutoscaler to automatically adjust CPU/memory requests
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: api-server-vpa
  namespace: production
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api-server
  updatePolicy:
    updateMode: "Auto"
  resourcePolicy:
    containerPolicies:
    - containerName: api-server
      minAllowed:
        cpu: 100m
        memory: 128Mi
      maxAllowed:
        cpu: 2
        memory: 2Gi

Node Tainting and Tolerations

# Taint a GPU node and add tolerations to pods that need it
kubectl taint nodes gpu-node-1 gpu=true:NoSchedule

# Example tolerations in a pod spec
tolerations:
- key: "gpu"
  operator: "Equal"
  value: "true"
  effect: "NoSchedule"

By following these practices you can build a reliable, secure, and cost‑effective containerised platform that scales from a few services to thousands of pods handling billions of requests per day.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Dockerci/cdKubernetesautoscaling
MaGe Linux Operations
Written by

MaGe Linux Operations

Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.