xbe.at

MLOps and deployment

Understanding Kubernetes Pod Configuration

6 min read, 14 sections

Contents
  1. Pod Configuration Structure
  2. Volume Management in Pods
  3. Health Checks and Probes
  4. Resource Management
  5. Security Context Configuration
  6. Pod Affinity and Anti-Affinity
  7. Pod Tolerations and Taints
  8. InitContainers Configuration
  9. Environment Variables and ConfigMaps
  10. Pod Lifecycle Management
  11. Multi-Container Pod Patterns
  12. Pod Network Policies
  13. Pod Quality of Service Classes
  14. Additional Resources

Pod Configuration Structure

Kubernetes Pod configurations follow a hierarchical YAML structure that defines container specifications, volumes, and runtime behaviors. The structure begins with apiVersion and kind declarations, followed by metadata and spec sections that contain the core pod definitions.

from kubernetes import client, config
from yaml import safe_load

def create_basic_pod():
    # Load local kube config
    config.load_kube_config()
    
    # Define pod configuration
    pod_manifest = {
        'apiVersion': 'v1',
        'kind': 'Pod',
        'metadata': {
            'name': 'example-pod',
            'labels': {
                'app': 'myapp',
                'tier': 'frontend'
            }
        },
        'spec': {
            'containers': [{
                'name': 'main-container',
                'image': 'nginx:latest',
                'resources': {
                    'requests': {
                        'memory': '64Mi',
                        'cpu': '250m'
                    },
                    'limits': {
                        'memory': '128Mi',
                        'cpu': '500m'
                    }
                }
            }]
        }
    }
    
    # Create pod
    v1 = client.CoreV1Api()
    return v1.create_namespaced_pod(
        body=pod_manifest,
        namespace='default'
    )

Volume Management in Pods

Volume management in Kubernetes pods requires careful consideration of persistence, access modes, and storage classes. The volume specification defines how storage is provisioned and mounted within containers, supporting various backend storage solutions.

def create_pod_with_volume():
    pod_manifest = {
        'apiVersion': 'v1',
        'kind': 'Pod',
        'metadata': {
            'name': 'pod-with-volume'
        },
        'spec': {
            'containers': [{
                'name': 'main-container',
                'image': 'nginx:latest',
                'volumeMounts': [{
                    'name': 'data-volume',
                    'mountPath': '/data'
                }]
            }],
            'volumes': [{
                'name': 'data-volume',
                'persistentVolumeClaim': {
                    'claimName': 'example-pvc'
                }
            }]
        }
    }
    
    # Create the pod configuration
    v1 = client.CoreV1Api()
    return v1.create_namespaced_pod(
        body=pod_manifest,
        namespace='default'
    )

Health Checks and Probes

Kubernetes probes ensure container health through liveness, readiness, and startup checks. These mechanisms verify application availability, readiness to serve traffic, and successful initialization, contributing to robust container orchestration.

def create_pod_with_probes():
    pod_manifest = {
        'apiVersion': 'v1',
        'kind': 'Pod',
        'metadata': {
            'name': 'pod-with-probes'
        },
        'spec': {
            'containers': [{
                'name': 'app-container',
                'image': 'myapp:latest',
                'livenessProbe': {
                    'httpGet': {
                        'path': '/health',
                        'port': 8080
                    },
                    'initialDelaySeconds': 10,
                    'periodSeconds': 5
                },
                'readinessProbe': {
                    'httpGet': {
                        'path': '/ready',
                        'port': 8080
                    },
                    'initialDelaySeconds': 5,
                    'periodSeconds': 3
                }
            }]
        }
    }
    
    v1 = client.CoreV1Api()
    return v1.create_namespaced_pod(
        body=pod_manifest,
        namespace='default'
    )

Resource Management

Resource management in Kubernetes pods involves specifying CPU and memory requirements through requests and limits. These specifications ensure proper scheduling and prevent resource contention within the cluster.

def create_pod_with_resources():
    pod_manifest = {
        'apiVersion': 'v1',
        'kind': 'Pod',
        'metadata': {
            'name': 'resource-managed-pod'
        },
        'spec': {
            'containers': [{
                'name': 'app-container',
                'image': 'myapp:latest',
                'resources': {
                    'requests': {
                        'memory': '256Mi',
                        'cpu': '500m',
                        'ephemeral-storage': '1Gi'
                    },
                    'limits': {
                        'memory': '512Mi',
                        'cpu': '1',
                        'ephemeral-storage': '2Gi'
                    }
                }
            }]
        }
    }
    
    v1 = client.CoreV1Api()
    return v1.create_namespaced_pod(
        body=pod_manifest,
        namespace='default'
    )

Security Context Configuration

Security contexts define privilege and access control settings for pods and containers. These settings include user/group IDs, filesystem permissions, and security capabilities that affect container runtime behavior.

def create_secured_pod():
    pod_manifest = {
        'apiVersion': 'v1',
        'kind': 'Pod',
        'metadata': {
            'name': 'secured-pod'
        },
        'spec': {
            'securityContext': {
                'runAsUser': 1000,
                'runAsGroup': 3000,
                'fsGroup': 2000
            },
            'containers': [{
                'name': 'secured-container',
                'image': 'nginx:latest',
                'securityContext': {
                    'allowPrivilegeEscalation': False,
                    'capabilities': {
                        'drop': ['ALL']
                    },
                    'readOnlyRootFilesystem': True
                }
            }]
        }
    }
    
    v1 = client.CoreV1Api()
    return v1.create_namespaced_pod(
        body=pod_manifest,
        namespace='default'
    )

Pod Affinity and Anti-Affinity

Pod affinity and anti-affinity rules influence scheduling decisions by expressing preferences or requirements about node selection. These rules enable complex deployment patterns and ensure optimal workload distribution across the cluster.

def create_pod_with_affinity():
    pod_manifest = {
        'apiVersion': 'v1',
        'kind': 'Pod',
        'metadata': {
            'name': 'pod-with-affinity'
        },
        'spec': {
            'affinity': {
                'podAffinity': {
                    'requiredDuringSchedulingIgnoredDuringExecution': [{
                        'labelSelector': {
                            'matchExpressions': [{
                                'key': 'app',
                                'operator': 'In',
                                'values': ['cache']
                            }]
                        },
                        'topologyKey': 'kubernetes.io/hostname'
                    }]
                },
                'podAntiAffinity': {
                    'preferredDuringSchedulingIgnoredDuringExecution': [{
                        'weight': 100,
                        'podAffinityTerm': {
                            'labelSelector': {
                                'matchExpressions': [{
                                    'key': 'app',
                                    'operator': 'In',
                                    'values': ['web']
                                }]
                            },
                            'topologyKey': 'kubernetes.io/hostname'
                        }
                    }]
                }
            },
            'containers': [{
                'name': 'main-app',
                'image': 'myapp:latest'
            }]
        }
    }
    
    v1 = client.CoreV1Api()
    return v1.create_namespaced_pod(
        body=pod_manifest,
        namespace='default'
    )

Pod Tolerations and Taints

Tolerations allow pods to schedule onto nodes with matching taints, providing control over pod placement and node isolation. This mechanism helps manage specialized workloads and enforce node allocation policies.

def create_pod_with_tolerations():
    pod_manifest = {
        'apiVersion': 'v1',
        'kind': 'Pod',
        'metadata': {
            'name': 'pod-with-tolerations'
        },
        'spec': {
            'tolerations': [{
                'key': 'node-role',
                'operator': 'Equal',
                'value': 'gpu',
                'effect': 'NoSchedule'
            }, {
                'key': 'node-type',
                'operator': 'Exists',
                'effect': 'PreferNoSchedule'
            }],
            'containers': [{
                'name': 'gpu-container',
                'image': 'gpu-workload:latest',
                'resources': {
                    'limits': {
                        'nvidia.com/gpu': '1'
                    }
                }
            }]
        }
    }
    
    v1 = client.CoreV1Api()
    return v1.create_namespaced_pod(
        body=pod_manifest,
        namespace='default'
    )

InitContainers Configuration

InitContainers run and complete before application containers start, ensuring prerequisites are met. They handle setup tasks, data population, and service dependency checks crucial for the main application containers.

def create_pod_with_init_containers():
    pod_manifest = {
        'apiVersion': 'v1',
        'kind': 'Pod',
        'metadata': {
            'name': 'pod-with-init'
        },
        'spec': {
            'initContainers': [{
                'name': 'init-db',
                'image': 'busybox:latest',
                'command': ['sh', '-c', 
                    'until nslookup db-service; do echo waiting for db; sleep 2; done;'],
            }, {
                'name': 'init-schema',
                'image': 'db-schema:latest',
                'command': ['./init-schema.sh'],
                'env': [{
                    'name': 'DB_HOST',
                    'value': 'db-service'
                }]
            }],
            'containers': [{
                'name': 'app',
                'image': 'myapp:latest'
            }]
        }
    }
    
    v1 = client.CoreV1Api()
    return v1.create_namespaced_pod(
        body=pod_manifest,
        namespace='default'
    )

Environment Variables and ConfigMaps

Environment variables in pods can be sourced from multiple configurations including ConfigMaps, Secrets, and direct values. This flexible approach enables runtime configuration management and separation of application configuration from container images.

def create_pod_with_env_config():
    pod_manifest = {
        'apiVersion': 'v1',
        'kind': 'Pod',
        'metadata': {
            'name': 'pod-with-env'
        },
        'spec': {
            'containers': [{
                'name': 'app-container',
                'image': 'myapp:latest',
                'env': [{
                    'name': 'DATABASE_URL',
                    'valueFrom': {
                        'configMapKeyRef': {
                            'name': 'app-config',
                            'key': 'db_url'
                        }
                    }
                }, {
                    'name': 'API_KEY',
                    'valueFrom': {
                        'secretKeyRef': {
                            'name': 'app-secrets',
                            'key': 'api_key'
                        }
                    }
                }, {
                    'name': 'POD_NAME',
                    'valueFrom': {
                        'fieldRef': {
                            'fieldPath': 'metadata.name'
                        }
                    }
                }],
                'envFrom': [{
                    'configMapRef': {
                        'name': 'app-config'
                    }
                }]
            }]
        }
    }
    
    v1 = client.CoreV1Api()
    return v1.create_namespaced_pod(
        body=pod_manifest,
        namespace='default'
    )

Pod Lifecycle Management

Pod lifecycle management involves handling initialization, running state, and termination gracefully. Proper configuration of lifecycle hooks ensures clean application startup and shutdown procedures.

def create_pod_with_lifecycle():
    pod_manifest = {
        'apiVersion': 'v1',
        'kind': 'Pod',
        'metadata': {
            'name': 'pod-with-lifecycle'
        },
        'spec': {
            'containers': [{
                'name': 'lifecycle-container',
                'image': 'myapp:latest',
                'lifecycle': {
                    'postStart': {
                        'exec': {
                            'command': [
                                '/bin/sh',
                                '-c',
                                'echo "Container started" >> /tmp/log'
                            ]
                        }
                    },
                    'preStop': {
                        'httpGet': {
                            'path': '/shutdown',
                            'port': 8080
                        }
                    }
                },
                'terminationGracePeriodSeconds': 30,
                'startupProbe': {
                    'httpGet': {
                        'path': '/startup',
                        'port': 8080
                    },
                    'failureThreshold': 30,
                    'periodSeconds': 10
                }
            }]
        }
    }
    
    v1 = client.CoreV1Api()
    return v1.create_namespaced_pod(
        body=pod_manifest,
        namespace='default'
    )

Multi-Container Pod Patterns

Multi-container pods implement common patterns like sidecar, ambassador, and adapter configurations. These patterns enable advanced functionality through container cooperation while maintaining separation of concerns.

def create_multicontainer_pod():
    pod_manifest = {
        'apiVersion': 'v1',
        'kind': 'Pod',
        'metadata': {
            'name': 'multi-container-pod'
        },
        'spec': {
            'volumes': [{
                'name': 'shared-data',
                'emptyDir': {}
            }],
            'containers': [{
                'name': 'main-app',
                'image': 'myapp:latest',
                'volumeMounts': [{
                    'name': 'shared-data',
                    'mountPath': '/data'
                }]
            }, {
                'name': 'sidecar-logger',
                'image': 'logger:latest',
                'volumeMounts': [{
                    'name': 'shared-data',
                    'mountPath': '/logs'
                }]
            }, {
                'name': 'metrics-adapter',
                'image': 'prometheus-adapter:latest',
                'ports': [{
                    'containerPort': 9090
                }]
            }]
        }
    }
    
    v1 = client.CoreV1Api()
    return v1.create_namespaced_pod(
        body=pod_manifest,
        namespace='default'
    )

Pod Network Policies

Network policies define how groups of pods communicate with each other and external network endpoints. These configurations implement microsegmentation and secure pod-to-pod communication patterns within the cluster.

def create_pod_with_network_policy():
    network_policy = {
        'apiVersion': 'networking.k8s.io/v1',
        'kind': 'NetworkPolicy',
        'metadata': {
            'name': 'api-network-policy',
            'namespace': 'default'
        },
        'spec': {
            'podSelector': {
                'matchLabels': {
                    'app': 'api'
                }
            },
            'policyTypes': ['Ingress', 'Egress'],
            'ingress': [{
                'from': [{
                    'podSelector': {
                        'matchLabels': {
                            'role': 'frontend'
                        }
                    }
                }],
                'ports': [{
                    'protocol': 'TCP',
                    'port': 8080
                }]
            }],
            'egress': [{
                'to': [{
                    'podSelector': {
                        'matchLabels': {
                            'role': 'database'
                        }
                    }
                }],
                'ports': [{
                    'protocol': 'TCP',
                    'port': 5432
                }]
            }]
        }
    }
    
    networking_v1 = client.NetworkingV1Api()
    return networking_v1.create_namespaced_network_policy(
        body=network_policy,
        namespace='default'
    )

Pod Quality of Service Classes

Quality of Service (QoS) classes in Kubernetes determine pod eviction priority during resource constraints. The configuration of resource requests and limits directly influences the QoS class assignment and pod scheduling behavior.

def create_pods_with_qos():
    guaranteed_pod = {
        'apiVersion': 'v1',
        'kind': 'Pod',
        'metadata': {
            'name': 'guaranteed-pod'
        },
        'spec': {
            'containers': [{
                'name': 'guaranteed-container',
                'image': 'nginx:latest',
                'resources': {
                    'requests': {
                        'memory': '256Mi',
                        'cpu': '500m'
                    },
                    'limits': {
                        'memory': '256Mi',
                        'cpu': '500m'
                    }
                }
            }]
        }
    }
    
    burstable_pod = {
        'apiVersion': 'v1',
        'kind': 'Pod',
        'metadata': {
            'name': 'burstable-pod'
        },
        'spec': {
            'containers': [{
                'name': 'burstable-container',
                'image': 'nginx:latest',
                'resources': {
                    'requests': {
                        'memory': '128Mi',
                        'cpu': '250m'
                    },
                    'limits': {
                        'memory': '256Mi',
                        'cpu': '500m'
                    }
                }
            }]
        }
    }
    
    besteffort_pod = {
        'apiVersion': 'v1',
        'kind': 'Pod',
        'metadata': {
            'name': 'besteffort-pod'
        },
        'spec': {
            'containers': [{
                'name': 'besteffort-container',
                'image': 'nginx:latest'
            }]
        }
    }
    
    v1 = client.CoreV1Api()
    return [
        v1.create_namespaced_pod(body=guaranteed_pod, namespace='default'),
        v1.create_namespaced_pod(body=burstable_pod, namespace='default'),
        v1.create_namespaced_pod(body=besteffort_pod, namespace='default')
    ]

Additional Resources

More in MLOps and deployment

  1. Introduction to Docker and Python Integration6 min

    Docker is a containerization platform that simplifies application deployment and management. This slideshow will cover the basics of integrating Python...

  2. Experiment Tracking in Machine Learning with Python11 min

    Experiment tracking is a crucial aspect of machine learning projects, enabling data scientists to organize, compare, and reproduce their work efficiently. It...

  3. Effective Model Deployment in Machine Learning6 min

    Model deployment in machine learning is the process of making a trained model available for use in a production environment. It's a critical step that...

  4. Dockerfile and Docker Compose8 min

    A Dockerfile is a text document containing instructions to build a Docker image automatically. For Python applications, it defines the base image, working...

  5. Docker Container Lifecycle Management9 min

    Docker containers follow a well-defined lifecycle from creation to termination. Understanding container states and transitions is crucial for effective...

  6. Docker Components Explained14 min

    The Docker SDK for Python provides a high-level API to interact with Docker images programmatically. This implementation demonstrates connecting to Docker...