Kubernetes: De Cero a Héroe
Guía completa de Kubernetes desde fundamentos hasta producción. Aprende arquitectura, kubectl, k9s, pods, deployments, services, ConfigMaps, Secrets, Helm y más. Con ejemplos prácticos y comandos reales.

Tabla de Contenidos
1. Introducción a Kubernetes
Kubernetes (K8s) es una plataforma de orquestación de contenedores desarrollada por Google. Automatiza el despliegue, escalado y gestión de aplicaciones en contenedores.

¿Qué es Kubernetes?
# Kubernetes (K8s) = Container Orchestration Platform# Developed by Google, now maintained by CNCF# The problem Kubernetes solves:# - How do you manage 100s or 1000s of containers?# - How do you ensure high availability?# - How do you scale automatically?# - How do you update without downtime?# - How do you recover from failures?# Kubernetes provides:# ✓ Automatic container deployment# ✓ Scaling (up/down based on load)# ✓ Load balancing# ✓ Self-healing (restart failed containers)# ✓ Rolling updates & rollbacks# ✓ Service discovery# ✓ Secret & configuration management# ✓ Storage orchestration# Think of K8s as a "datacenter operating system"# It manages your containers like an OS manages processes
El nombre "Kubernetes" viene del griego κυβερνήτης (kybernḗtēs), que significa "timonel". Se abrevia K8s porque hay 8 letras entre la K y la s.
Kubernetes vs Docker
# Kubernetes vs Docker - They're COMPLEMENTARY!# DOCKER:# - Builds container images# - Runs individual containers# - Great for development# - Single host focus# KUBERNETES:# - Orchestrates containers across MULTIPLE hosts# - Manages container lifecycle at scale# - Production-grade features# - Cluster management# Analogy:# Docker = A musician who can play instruments# Kubernetes = The conductor of an orchestra# Docker builds and runs containers# Kubernetes tells containers WHERE and HOW to run# You need BOTH:# 1. Build images with Docker (or alternatives)# 2. Deploy and manage with Kubernetes
Terminología Esencial
# Essential Kubernetes Terminology# CLUSTER# - A set of machines (nodes) running Kubernetes# - Has Control Plane + Worker Nodes# NODE# - A machine (physical or VM) in the cluster# - Worker nodes run your containers# - Control plane nodes manage the cluster# POD# - Smallest deployable unit in K8s# - Contains one or more containers# - Containers in a pod share network/storage# - Pods are ephemeral (can be replaced anytime)# DEPLOYMENT# - Manages pods declaratively# - Defines desired state (replicas, image, etc.)# - Handles rolling updates & rollbacks# SERVICE# - Stable network endpoint for pods# - Load balances traffic to pods# - Types: ClusterIP, NodePort, LoadBalancer# NAMESPACE# - Virtual cluster within a cluster# - Isolates resources (like folders)# - Examples: dev, staging, production# CONFIGMAP & SECRET# - External configuration for pods# - ConfigMap: non-sensitive data# - Secret: sensitive data (encoded)
2. Arquitectura de Kubernetes
Un cluster de Kubernetes consiste en un Control Plane y Worker Nodes. El Control Plane toma decisiones globales; los Workers ejecutan los contenedores.

Componentes del Control Plane
# Control Plane Components (Master Node)# These manage the cluster state# API SERVER (kube-apiserver)# - Front door to Kubernetes# - All communication goes through here# - RESTful API# - Validates and configures data# ETCD# - Distributed key-value store# - Stores ALL cluster state# - The "source of truth"# - Highly available (usually 3+ replicas)# SCHEDULER (kube-scheduler)# - Assigns pods to nodes# - Considers resources, constraints, affinity# - "Where should this pod run?"# CONTROLLER MANAGER (kube-controller-manager)# - Runs controllers (control loops)# - Node Controller: monitors node health# - Replication Controller: maintains pod count# - Endpoints Controller: populates Services# - Service Account Controller: creates accounts# CLOUD CONTROLLER MANAGER# - Integrates with cloud providers# - Manages load balancers, routes, volumes# - Only in cloud deployments
etcd es el cerebro del cluster. Si se pierde, perdemos todo el estado. Por eso siempre se despliega en alta disponibilidad (3+ réplicas) con backups.

Componentes del Worker Node
# Worker Node Components# These run on every worker node# KUBELET# - Agent that runs on each node# - Ensures containers are running in pods# - Communicates with API server# - Reports node and pod status# KUBE-PROXY# - Network proxy on each node# - Implements Service concept# - Manages network rules (iptables/IPVS)# - Enables pod-to-pod communication# CONTAINER RUNTIME# - Runs containers (Docker, containerd, CRI-O)# - Kubernetes is container-runtime agnostic# - containerd is most common today# The flow:# 1. You: kubectl apply -f deployment.yaml# 2. API Server: validates and stores in etcd# 3. Scheduler: assigns pods to nodes# 4. Kubelet: pulls image, starts containers# 5. Kube-proxy: sets up networking
3. Instalación
Hay varias formas de ejecutar Kubernetes localmente. Las más populares son Minikube, Kind y K3s.
Instalar kubectl
# Install kubectl - The Kubernetes CLI# macOS (Homebrew):brew install kubectl# macOS (curl):curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/darwin/amd64/kubectl"chmod +x kubectlsudo mv kubectl /usr/local/bin/# Linux (curl):curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"chmod +x kubectlsudo mv kubectl /usr/local/bin/# Windows (Chocolatey):choco install kubernetes-cli# Verify installation:kubectl version --client# Output:# Client Version: v1.29.0# Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3
Minikube
# Minikube - Local Kubernetes for Development# macOS:brew install minikube# Linux:curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64sudo install minikube-linux-amd64 /usr/local/bin/minikube# Windows:choco install minikube# Start a cluster:minikube start# With specific resources:minikube start --cpus=4 --memory=8192 --driver=docker# Check status:minikube status# Access Kubernetes dashboard:minikube dashboard# Stop cluster:minikube stop# Delete cluster:minikube delete# Useful addons:minikube addons enable ingressminikube addons enable metrics-serverminikube addons list
Kind (Kubernetes in Docker)
# Kind - Kubernetes IN Docker (for CI/CD)# Install Kind:# macOS:brew install kind# Linux:curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.20.0/kind-linux-amd64chmod +x ./kindsudo mv ./kind /usr/local/bin/kind# Create a cluster:kind create cluster# Create with custom name:kind create cluster --name my-cluster# Multi-node cluster (create config file first):cat <<EOF | kind create cluster --config=-kind: ClusterapiVersion: kind.x-k8s.io/v1alpha4nodes:- role: control-plane- role: worker- role: workerEOF# List clusters:kind get clusters# Delete cluster:kind delete cluster --name my-cluster# Load local Docker image to Kind:kind load docker-image my-app:latest
K3s
# K3s - Lightweight Kubernetes for Edge/IoT# Install K3s (single command!):curl -sfL https://get.k3s.io | sh -# Check if running:sudo systemctl status k3s# Get kubeconfig:sudo cat /etc/rancher/k3s/k3s.yaml# Use kubectl (included with k3s):sudo k3s kubectl get nodes# Or copy config for regular kubectl:mkdir -p ~/.kubesudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/configsudo chown $(id -u):$(id -g) ~/.kube/config# Add a worker node:# On master, get token:sudo cat /var/lib/rancher/k3s/server/node-token# On worker:curl -sfL https://get.k3s.io | K3S_URL=https://master-ip:6443 K3S_TOKEN=<token> sh -# Uninstall:/usr/local/bin/k3s-uninstall.sh
Principiantes: Minikube. CI/CD: Kind. Edge/IoT: K3s. Producción cloud: EKS, GKE, AKS.
4. kubectl Básico
kubectl es la herramienta de línea de comandos para interactuar con Kubernetes. Es esencial dominarla.
Configuración
# kubectl Configuration# View current context:kubectl config current-context# List all contexts:kubectl config get-contexts# Switch context:kubectl config use-context my-cluster# View config:kubectl config view# Set default namespace for context:kubectl config set-context --current --namespace=my-namespace# Create a new context:kubectl config set-context my-context \--cluster=my-cluster \--user=my-user \--namespace=my-namespace# Kubeconfig file location:# Default: ~/.kube/config# Override with: export KUBECONFIG=/path/to/config# Merge multiple kubeconfig files:export KUBECONFIG=~/.kube/config:~/.kube/other-configkubectl config view --flatten > ~/.kube/merged-config
Comandos Esenciales
# Essential kubectl Commands# ========== GET RESOURCES ==========kubectl get pods # List pods in current namespacekubectl get pods -A # List pods in ALL namespaceskubectl get pods -o wide # More details (IP, node)kubectl get pods -o yaml # Full YAML outputkubectl get pods -o json # Full JSON outputkubectl get pods --watch # Watch for changeskubectl get pods -l app=nginx # Filter by labelkubectl get nodes # List cluster nodeskubectl get services # List serviceskubectl get deployments # List deploymentskubectl get all # List common resources# ========== DESCRIBE (detailed info) ==========kubectl describe pod my-podkubectl describe node my-nodekubectl describe service my-service# ========== CREATE / APPLY ==========kubectl apply -f manifest.yaml # Create/update from filekubectl apply -f ./manifests/ # Apply all files in directorykubectl apply -f https://url.com/manifest.yamlkubectl create deployment nginx --image=nginxkubectl create namespace my-ns# ========== DELETE ==========kubectl delete pod my-podkubectl delete -f manifest.yamlkubectl delete deployment my-deploykubectl delete pods --all # Delete all pods in namespace
Comandos Avanzados
# Advanced kubectl Commands# ========== LOGS ==========kubectl logs my-pod # View pod logskubectl logs my-pod -c my-container # Specific containerkubectl logs my-pod -f # Follow logs (stream)kubectl logs my-pod --tail=100 # Last 100 lineskubectl logs my-pod --since=1h # Last hourkubectl logs -l app=nginx # Logs by label# ========== EXEC (run commands in pod) ==========kubectl exec my-pod -- ls -lakubectl exec my-pod -- cat /etc/configkubectl exec -it my-pod -- /bin/bash # Interactive shellkubectl exec -it my-pod -c container -- sh# ========== PORT FORWARD ==========kubectl port-forward pod/my-pod 8080:80kubectl port-forward svc/my-service 8080:80kubectl port-forward deploy/my-deploy 8080:80# ========== COPY FILES ==========kubectl cp my-pod:/path/file ./local-filekubectl cp ./local-file my-pod:/path/file# ========== DEBUGGING ==========kubectl get events # Cluster eventskubectl get events --sort-by='.lastTimestamp'kubectl top pods # Resource usagekubectl top nodeskubectl api-resources # List all resource types# ========== DRY RUN (test without applying) ==========kubectl apply -f manifest.yaml --dry-run=clientkubectl apply -f manifest.yaml --dry-run=server
Atajos y Aliases
# kubectl Shortcuts & Aliases# Built-in short names:kubectl get po # podskubectl get svc # serviceskubectl get deploy # deploymentskubectl get ns # namespaceskubectl get no # nodeskubectl get cm # configmapskubectl get secret # secretskubectl get pv # persistentvolumeskubectl get pvc # persistentvolumeclaimskubectl get ing # ingresseskubectl get ds # daemonsetskubectl get sts # statefulsetskubectl get rs # replicasetskubectl get ep # endpointskubectl get sa # serviceaccounts# Recommended bash aliases (~/.bashrc or ~/.zshrc):alias k='kubectl'alias kgp='kubectl get pods'alias kgpa='kubectl get pods -A'alias kgs='kubectl get services'alias kgd='kubectl get deployments'alias kgn='kubectl get nodes'alias kdp='kubectl describe pod'alias kl='kubectl logs'alias klf='kubectl logs -f'alias ke='kubectl exec -it'alias kaf='kubectl apply -f'alias kdf='kubectl delete -f'# Enable kubectl autocompletion:# Bash:echo 'source <(kubectl completion bash)' >> ~/.bashrc# Zsh:echo 'source <(kubectl completion zsh)' >> ~/.zshrc
5. Pods
Un Pod es la unidad más pequeña que Kubernetes puede desplegar. Representa uno o más contenedores que comparten recursos.

Conceptos Básicos
# Pods - The Smallest Deployable Unit# A Pod is:# - One or more containers that share:# - Network namespace (same IP, localhost)# - Storage volumes# - Lifecycle (created/deleted together)# - Ephemeral - can be replaced anytime# - Usually managed by a controller (Deployment)# When to use multi-container pods:# - Sidecar pattern (logging, proxies)# - Adapter pattern (format conversion)# - Ambassador pattern (connection proxying)# Pod lifecycle states:# - Pending: scheduled, waiting for resources# - Running: at least one container running# - Succeeded: all containers completed successfully# - Failed: at least one container failed# - Unknown: cannot determine state
Pod YAML
# pod.yaml - Simple Pod definitionapiVersion: v1kind: Podmetadata:name: my-nginxlabels:app: nginxenvironment: developmentannotations:description: "Demo nginx pod"spec:containers:- name: nginximage: nginx:1.25-alpineports:- containerPort: 80name: httpresources:requests:memory: "64Mi"cpu: "100m"limits:memory: "128Mi"cpu: "200m"env:- name: NGINX_HOSTvalue: "localhost"volumeMounts:- name: html-volumemountPath: /usr/share/nginx/htmlvolumes:- name: html-volumeemptyDir: {}restartPolicy: Always
Pod Multi-Contenedor (Sidecar)
# Multi-container Pod (Sidecar Pattern)apiVersion: v1kind: Podmetadata:name: web-with-sidecarspec:containers:# Main application container- name: web-appimage: nginx:alpineports:- containerPort: 80volumeMounts:- name: shared-logsmountPath: /var/log/nginx# Sidecar: Log shipper- name: log-shipperimage: fluent/fluent-bit:latestvolumeMounts:- name: shared-logsmountPath: /var/log/nginxreadOnly: true- name: fluent-configmountPath: /fluent-bit/etc/# Sidecar: Metrics exporter- name: metrics-exporterimage: nginx/nginx-prometheus-exporter:latestargs:- "-nginx.scrape-uri=http://localhost/nginx_status"ports:- containerPort: 9113name: metricsvolumes:- name: shared-logsemptyDir: {}- name: fluent-configconfigMap:name: fluent-bit-config
Lifecycle Hooks y Probes
# Pod Lifecycle Hooks & ProbesapiVersion: v1kind: Podmetadata:name: lifecycle-demospec:containers:- name: appimage: my-app:latest# Startup Probe - for slow-starting containersstartupProbe:httpGet:path: /healthzport: 8080failureThreshold: 30periodSeconds: 10# Liveness Probe - restart if unhealthylivenessProbe:httpGet:path: /healthzport: 8080initialDelaySeconds: 10periodSeconds: 5failureThreshold: 3# Readiness Probe - remove from service if not readyreadinessProbe:httpGet:path: /readyport: 8080initialDelaySeconds: 5periodSeconds: 3# Lifecycle hookslifecycle:postStart:exec:command: ["/bin/sh", "-c", "echo Started > /tmp/started"]preStop:exec:command: ["/bin/sh", "-c", "nginx -s quit; sleep 10"]
Nunca crees Pods directamente en producción. Usa Deployments o StatefulSets. Los Pods no se recrean automáticamente.
6. Deployments
Los Deployments son la forma recomendada de gestionar aplicaciones. Proporcionan actualizaciones, escalado y auto-recuperación.

Conceptos
# Deployments - Declarative Pod Management# A Deployment:# - Manages ReplicaSets (which manage Pods)# - Ensures desired number of pods are running# - Handles rolling updates# - Supports rollbacks# - Self-healing (replaces failed pods)# Why use Deployments instead of Pods?# - Pods are ephemeral, no self-healing# - Deployments maintain desired state# - Easy scaling (kubectl scale)# - Rolling updates without downtime# - Rollback to previous versions# Deployment → ReplicaSet → Pods# The Deployment creates ReplicaSets# ReplicaSets ensure pod count# You rarely interact with ReplicaSets directly
deployment.yaml
# deployment.yaml - Production-ready exampleapiVersion: apps/v1kind: Deploymentmetadata:name: nginx-deploymentlabels:app: nginxspec:replicas: 3selector:matchLabels:app: nginx# Update strategystrategy:type: RollingUpdaterollingUpdate:maxUnavailable: 1 # Max pods that can be unavailablemaxSurge: 1 # Max pods above desired counttemplate:metadata:labels:app: nginxspec:containers:- name: nginximage: nginx:1.25-alpineports:- containerPort: 80resources:requests:memory: "64Mi"cpu: "100m"limits:memory: "128Mi"cpu: "200m"livenessProbe:httpGet:path: /port: 80initialDelaySeconds: 10periodSeconds: 5readinessProbe:httpGet:path: /port: 80initialDelaySeconds: 5periodSeconds: 3
Comandos
# Deployment Commands# Create deployment imperatively:kubectl create deployment nginx --image=nginx:1.25kubectl create deployment nginx --image=nginx --replicas=3# Apply from file:kubectl apply -f deployment.yaml# View deployments:kubectl get deploymentskubectl get deploy nginx-deployment -o yamlkubectl describe deployment nginx-deployment# ========== SCALING ==========kubectl scale deployment nginx-deployment --replicas=5# Autoscaling (HPA):kubectl autoscale deployment nginx-deployment \--min=2 --max=10 --cpu-percent=80# ========== UPDATES ==========# Update image:kubectl set image deployment/nginx-deployment nginx=nginx:1.26# Update via edit (opens editor):kubectl edit deployment nginx-deployment# ========== ROLLOUT STATUS ==========kubectl rollout status deployment/nginx-deploymentkubectl rollout history deployment/nginx-deployment# ========== ROLLBACK ==========kubectl rollout undo deployment/nginx-deploymentkubectl rollout undo deployment/nginx-deployment --to-revision=2# Pause/resume rollout:kubectl rollout pause deployment/nginx-deploymentkubectl rollout resume deployment/nginx-deployment# ========== DELETE ==========kubectl delete deployment nginx-deployment

7. Services
Los Services proporcionan una dirección de red estable para acceder a Pods. Son esenciales para la comunicación.

Conceptos
# Services - Stable Network Endpoints# Problem: Pods are ephemeral# - Pods get new IPs when recreated# - How do other pods find them?# - How does external traffic reach them?# Solution: Services# - Stable DNS name and IP# - Load balances to healthy pods# - Uses labels to select pods# Service Types:# 1. ClusterIP (default)# - Internal cluster IP only# - Only reachable within cluster# - Use for internal communication# 2. NodePort# - Exposes on each node's IP# - Port range: 30000-32767# - External access without load balancer# 3. LoadBalancer# - Provisions cloud load balancer# - External IP assigned by cloud provider# - Most common for production# 4. ExternalName# - Maps to external DNS name# - No proxying, just DNS CNAME
ClusterIP Service
# ClusterIP Service (default)apiVersion: v1kind: Servicemetadata:name: backend-servicespec:type: ClusterIP # Optional, this is defaultselector:app: backend # Selects pods with this labelports:- name: httpport: 80 # Service porttargetPort: 8080 # Container portprotocol: TCP---# Headless Service (no load balancing, direct pod DNS)apiVersion: v1kind: Servicemetadata:name: database-headlessspec:clusterIP: None # Makes it headlessselector:app: databaseports:- port: 5432targetPort: 5432# DNS resolution:# ClusterIP: backend-service.namespace.svc.cluster.local# Headless: pod-name.database-headless.namespace.svc.cluster.local
NodePort Service
# NodePort ServiceapiVersion: v1kind: Servicemetadata:name: web-nodeportspec:type: NodePortselector:app: webports:- name: httpport: 80 # Internal cluster porttargetPort: 8080 # Container portnodePort: 30080 # External port (30000-32767)# If not specified, K8s assigns random port---# Access the service:# http://<any-node-ip>:30080# Get node IPs:# kubectl get nodes -o wide# With Minikube:# minikube service web-nodeport --url
LoadBalancer Service
# LoadBalancer ServiceapiVersion: v1kind: Servicemetadata:name: web-loadbalancerannotations:# Cloud-specific annotationsservice.beta.kubernetes.io/aws-load-balancer-type: nlbservice.beta.kubernetes.io/aws-load-balancer-internal: "false"spec:type: LoadBalancerselector:app: webports:- name: httpport: 80targetPort: 8080- name: httpsport: 443targetPort: 8443# Optional: specify desired external IP# loadBalancerIP: 1.2.3.4# Optional: limit source IPs# loadBalancerSourceRanges:# - 10.0.0.0/8---# Check external IP:# kubectl get svc web-loadbalancer# NAME TYPE EXTERNAL-IP PORT(S)# web-loadbalancer LoadBalancer 203.0.113.10 80:31234/TCP
8. ConfigMaps & Secrets
ConfigMaps y Secrets permiten separar la configuración del código. ConfigMaps para datos no sensibles, Secrets para sensibles.
ConfigMaps
# ConfigMaps - External Configuration# ConfigMaps store non-sensitive configuration:# - Environment variables# - Configuration files# - Command-line arguments# Benefits:# - Separate config from container image# - Update config without rebuilding# - Share config across multiple pods# - Environment-specific values
Ejemplos de ConfigMap
# ConfigMap Examples# From literal values:kubectl create configmap app-config \--from-literal=DATABASE_HOST=postgres \--from-literal=LOG_LEVEL=info# From file:kubectl create configmap nginx-config --from-file=nginx.conf# From directory:kubectl create configmap configs --from-file=./config-dir/---# configmap.yamlapiVersion: v1kind: ConfigMapmetadata:name: app-configdata:# Simple key-value pairsDATABASE_HOST: "postgres.default.svc.cluster.local"DATABASE_PORT: "5432"LOG_LEVEL: "info"# Multi-line configuration fileapp.properties: |server.port=8080server.host=0.0.0.0feature.enabled=truenginx.conf: |server {listen 80;location / {proxy_pass http://backend:8080;}}
Uso en Pods
# Using ConfigMaps in PodsapiVersion: v1kind: Podmetadata:name: app-with-configspec:containers:- name: appimage: my-app:latest# Method 1: Environment variables from ConfigMapenv:- name: DB_HOSTvalueFrom:configMapKeyRef:name: app-configkey: DATABASE_HOST# Method 2: All keys as environment variablesenvFrom:- configMapRef:name: app-config# optional: true # Don't fail if ConfigMap missing# Method 3: Mount as filesvolumeMounts:- name: config-volumemountPath: /etc/configreadOnly: true# Method 4: Mount specific key as file- name: nginx-configmountPath: /etc/nginx/nginx.confsubPath: nginx.confvolumes:- name: config-volumeconfigMap:name: app-config- name: nginx-configconfigMap:name: app-configitems:- key: nginx.confpath: nginx.conf
Secrets
# Secrets - Sensitive Data Storage# Secrets store sensitive data:# - Passwords# - API keys# - TLS certificates# - SSH keys# Important security notes:# - Secrets are base64 encoded (NOT encrypted!)# - Enable encryption at rest in etcd# - Use RBAC to limit access# - Consider external secret managers# (HashiCorp Vault, AWS Secrets Manager)# Secret types:# - Opaque: arbitrary user-defined data# - kubernetes.io/tls: TLS certificates# - kubernetes.io/dockerconfigjson: Docker registry credentials# - kubernetes.io/basic-auth: basic authentication# - kubernetes.io/ssh-auth: SSH authentication
Ejemplos de Secrets
# Secret Examples# Create from literal (auto base64 encodes):kubectl create secret generic db-credentials \--from-literal=username=admin \--from-literal=password='S3cr3tP@ssw0rd!'# Create TLS secret:kubectl create secret tls my-tls \--cert=path/to/tls.crt \--key=path/to/tls.key# Create Docker registry secret:kubectl create secret docker-registry regcred \--docker-server=ghcr.io \--docker-username=user \--docker-password=token \--docker-email=user@example.com---# secret.yaml (values must be base64 encoded)apiVersion: v1kind: Secretmetadata:name: db-credentialstype: Opaquedata:# echo -n 'admin' | base64username: YWRtaW4=# echo -n 'password123' | base64password: cGFzc3dvcmQxMjM=---# Using stringData (auto-encodes, easier to read)apiVersion: v1kind: Secretmetadata:name: db-credentialstype: OpaquestringData:username: adminpassword: password123
Uso de Secrets
# Using Secrets in PodsapiVersion: v1kind: Podmetadata:name: app-with-secretsspec:containers:- name: appimage: my-app:latest# Method 1: Environment variable from Secretenv:- name: DB_PASSWORDvalueFrom:secretKeyRef:name: db-credentialskey: password# Method 2: All keys as environment variablesenvFrom:- secretRef:name: db-credentials# Method 3: Mount as filesvolumeMounts:- name: secret-volumemountPath: /etc/secretsreadOnly: truevolumes:- name: secret-volumesecret:secretName: db-credentials# Optional: set file permissionsdefaultMode: 0400---# Using Docker registry secretapiVersion: v1kind: Podmetadata:name: private-image-podspec:containers:- name: appimage: ghcr.io/myorg/private-app:latestimagePullSecrets:- name: regcred
Los Secrets solo están en base64, NO encriptados. Usa encryption at rest y considera HashiCorp Vault o AWS Secrets Manager.
9. Volúmenes y Almacenamiento
Kubernetes ofrece varios tipos de almacenamiento: temporal, persistente, y dinámico mediante StorageClasses.
Tipos de Volúmenes
# Kubernetes Storage Concepts# VOLUMES - Temporary or persistent storage for pods# Volume Types:# 1. emptyDir - temporary, deleted with pod# 2. hostPath - mounts host filesystem (dangerous!)# 3. configMap/secret - configuration data# 4. persistentVolumeClaim - persistent storage# 5. nfs - Network File System# 6. cloud volumes - AWS EBS, GCE PD, Azure Disk# PERSISTENT VOLUMES (PV)# - Cluster-level storage resource# - Provisioned by admin or dynamically# - Independent of pod lifecycle# PERSISTENT VOLUME CLAIMS (PVC)# - Request for storage by user# - Binds to a matching PV# - Used by pods to access storage# STORAGE CLASSES# - Define "classes" of storage# - Enable dynamic provisioning# - Examples: fast-ssd, standard, slow-hdd
Ejemplos de Volúmenes
# Volume ExamplesapiVersion: v1kind: Podmetadata:name: volume-demospec:containers:- name: appimage: nginxvolumeMounts:# emptyDir - shared between containers- name: cachemountPath: /cache# hostPath - access host filesystem- name: host-logsmountPath: /var/log/host# configMap as volume- name: configmountPath: /etc/configreadOnly: truevolumes:# Temporary storage, deleted with pod- name: cacheemptyDir:sizeLimit: 500Mi# Mount host directory (use with caution!)- name: host-logshostPath:path: /var/logtype: Directory# ConfigMap as files- name: configconfigMap:name: my-config
PersistentVolume & PVC
# PersistentVolume (cluster resource)apiVersion: v1kind: PersistentVolumemetadata:name: my-pvspec:capacity:storage: 10GivolumeMode: FilesystemaccessModes:- ReadWriteOnce # RWO - single node# - ReadOnlyMany # ROX - multiple nodes read-only# - ReadWriteMany # RWX - multiple nodes read-writepersistentVolumeReclaimPolicy: Retain# Retain: keep data after PVC deleted# Delete: delete volume after PVC deleted# Recycle: deprecatedstorageClassName: standardhostPath:path: /data/my-pv---# PersistentVolumeClaim (user request)apiVersion: v1kind: PersistentVolumeClaimmetadata:name: my-pvcspec:accessModes:- ReadWriteOnceresources:requests:storage: 5GistorageClassName: standard---# Using PVC in PodapiVersion: v1kind: Podmetadata:name: app-with-pvcspec:containers:- name: appimage: nginxvolumeMounts:- name: datamountPath: /datavolumes:- name: datapersistentVolumeClaim:claimName: my-pvc
StorageClass
# StorageClass for dynamic provisioningapiVersion: storage.k8s.io/v1kind: StorageClassmetadata:name: fast-ssdprovisioner: kubernetes.io/aws-ebs # Cloud-specificparameters:type: gp3iopsPerGB: "50"fsType: ext4reclaimPolicy: DeleteallowVolumeExpansion: truevolumeBindingMode: WaitForFirstConsumer---# AWS EBS StorageClassapiVersion: storage.k8s.io/v1kind: StorageClassmetadata:name: ebs-scprovisioner: ebs.csi.aws.comparameters:type: gp3encrypted: "true"reclaimPolicy: DeletevolumeBindingMode: WaitForFirstConsumer---# GKE StorageClassapiVersion: storage.k8s.io/v1kind: StorageClassmetadata:name: ssd-scprovisioner: pd.csi.storage.gke.ioparameters:type: pd-ssdreclaimPolicy: DeletevolumeBindingMode: WaitForFirstConsumer---# PVC using StorageClass (dynamic provisioning)apiVersion: v1kind: PersistentVolumeClaimmetadata:name: dynamic-pvcspec:accessModes:- ReadWriteOncestorageClassName: fast-ssdresources:requests:storage: 20Gi
10. Networking & Ingress
Kubernetes tiene un modelo de red plano donde todos los pods pueden comunicarse entre sí. Ingress proporciona acceso HTTP externo.
Modelo de Red
# Kubernetes Networking Model# Fundamental rules:# 1. All pods can communicate with all other pods (no NAT)# 2. All nodes can communicate with all pods (no NAT)# 3. Pod sees itself with same IP others see it# Network implementations (CNI plugins):# - Calico: most popular, network policies# - Cilium: eBPF-based, advanced features# - Flannel: simple, overlay network# - Weave: mesh network# - AWS VPC CNI: native AWS networking# Service Discovery:# - DNS: my-service.my-namespace.svc.cluster.local# - Environment variables: MY_SERVICE_HOST, MY_SERVICE_PORT# Network Policies:# - Firewall rules for pods# - Control ingress/egress traffic# - Require CNI that supports them
NetworkPolicy
# NetworkPolicy ExamplesapiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata:name: deny-allnamespace: productionspec:podSelector: {} # Applies to all podspolicyTypes:- Ingress- Egress# No rules = deny all traffic---# Allow ingress from specific podsapiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata:name: allow-frontendspec:podSelector:matchLabels:app: backendpolicyTypes:- Ingressingress:- from:- podSelector:matchLabels:app: frontendports:- protocol: TCPport: 8080---# Allow egress to specific external IPsapiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata:name: allow-external-apispec:podSelector:matchLabels:app: my-apppolicyTypes:- Egressegress:- to:- ipBlock:cidr: 203.0.113.0/24ports:- protocol: TCPport: 443

Ingress Conceptos
# Ingress - HTTP/HTTPS Routing# Ingress provides:# - External access to services# - URL-based routing# - SSL/TLS termination# - Name-based virtual hosting# - Load balancing# Requires an Ingress Controller:# - NGINX Ingress (most popular)# - Traefik# - HAProxy# - AWS ALB Ingress Controller# - GKE Ingress# - Istio Gateway# Without Ingress:# External → LoadBalancer → Service → Pods# With Ingress:# External → Ingress → Service → Pods# ↘ Ingress → Service → Pods
Ingress YAML
# Ingress ExamplesapiVersion: networking.k8s.io/v1kind: Ingressmetadata:name: simple-ingressannotations:nginx.ingress.kubernetes.io/rewrite-target: /spec:ingressClassName: nginxrules:- host: myapp.example.comhttp:paths:- path: /pathType: Prefixbackend:service:name: web-serviceport:number: 80---# Multiple hosts and pathsapiVersion: networking.k8s.io/v1kind: Ingressmetadata:name: multi-path-ingressspec:ingressClassName: nginxrules:- host: api.example.comhttp:paths:- path: /v1pathType: Prefixbackend:service:name: api-v1port:number: 80- path: /v2pathType: Prefixbackend:service:name: api-v2port:number: 80- host: web.example.comhttp:paths:- path: /pathType: Prefixbackend:service:name: web-frontendport:number: 80
Ingress TLS
# Ingress with TLSapiVersion: networking.k8s.io/v1kind: Ingressmetadata:name: tls-ingressannotations:# Redirect HTTP to HTTPSnginx.ingress.kubernetes.io/ssl-redirect: "true"# Use cert-manager for auto-renewalcert-manager.io/cluster-issuer: "letsencrypt-prod"spec:ingressClassName: nginxtls:- hosts:- myapp.example.comsecretName: myapp-tls-secretrules:- host: myapp.example.comhttp:paths:- path: /pathType: Prefixbackend:service:name: web-serviceport:number: 80---# Create TLS secret manually:# kubectl create secret tls myapp-tls-secret \# --cert=tls.crt --key=tls.key# Or use cert-manager for automatic Let's Encrypt:# 1. Install cert-manager# 2. Create ClusterIssuer for Let's Encrypt# 3. Add annotation to Ingress
11. K9s - Terminal UI
K9s es una interfaz de terminal para Kubernetes que facilita la navegación y gestión de recursos del cluster.

Instalación
# K9s - Terminal UI for Kubernetes# Install K9s:# macOS:brew install derailed/k9s/k9s# Linux (via curl):curl -sS https://webinstall.dev/k9s | bash# Linux (via snap):sudo snap install k9s# Windows (via chocolatey):choco install k9s# Verify installation:k9s version# Launch k9s (uses current kubectl context):k9s# Launch with specific context:k9s --context my-cluster# Launch with specific namespace:k9s -n my-namespace# Launch in read-only mode:k9s --readonly
Navegación y Atajos
# K9s Navigation & Shortcuts# GLOBAL SHORTCUTS# : Command mode (type resource name)# / Filter/search# ? Help# Ctrl+a Show all resources# Ctrl+d Delete resource# Esc Back / Cancel# q Quit k9s# NAVIGATION# :pods Switch to pods view# :svc Switch to services view# :deploy Switch to deployments view# :ns Switch to namespaces view# :nodes Switch to nodes view# :secrets Switch to secrets view# :cm Switch to configmaps view# :pv Switch to persistent volumes# :pvc Switch to persistent volume claims# ON A RESOURCE# Enter View details# d Describe# l View logs# s Shell into container# y View YAML# e Edit resource# k Kill/delete# Ctrl+k Kill pod (force)# LOGS VIEW# w Toggle wrap# s Toggle auto-scroll# 0 Jump to start# Shift+g Jump to end# / Search in logs
Funciones Avanzadas
# K9s Advanced Features# FILTERING# /nginx Filter by name containing "nginx"# /app=web Filter by label# /-n default Filter by namespace# /!running Exclude "running" from results# CONTEXT SWITCHING# :ctx List contexts# Enter on ctx Switch to that context# BENCHMARKING# :be HTTP benchmarks view# (on a pod) b to run benchmark# PORT FORWARDING# (on a pod) Shift+f to port forward# XRAY VIEW# :xray deploy Shows deployment tree# :xray svc Shows service endpoints# PULSE VIEW# :pulse Cluster health metrics# CONFIGURATION (~/.config/k9s/config.yml)# k9s:# refreshRate: 2# maxConnRetry: 5# readOnly: false# noIcons: false# logger:# tail: 100# buffer: 5000# sinceSeconds: 60# currentContext: minikube# currentCluster: minikube
Custom Hotkeys
# K9s Custom Hotkeys (~/.config/k9s/hotkey.yml)# Define custom hotkeys:hotKey:# Shift-1: Switch to pods in all namespacesshift-1:shortCut: Shift-1description: View all podscommand: pods# Shift-2: Switch to deploymentsshift-2:shortCut: Shift-2description: View deploymentscommand: deploy# Shift-3: Switch to servicesshift-3:shortCut: Shift-3description: View servicescommand: svc# Shift-4: Show node resourcesshift-4:shortCut: Shift-4description: View nodescommand: nodes# Shift-l: Logs with timestampsshift-l:shortCut: Shift-Ldescription: Logs with timestampscommand: "pods -c <pod>"
K9s es mucho más rápido que kubectl para tareas interactivas. Usa / para filtrar, l para logs, s para shell, y d para describe.
12. Helm Charts
Helm es el gestor de paquetes de Kubernetes. Permite instalar aplicaciones complejas con un solo comando.

¿Qué es Helm?
# Helm - The Package Manager for Kubernetes# What is Helm?# - Package manager for Kubernetes# - Uses "charts" (packages of K8s resources)# - Templating engine for YAML# - Release management & upgrades# - Rollback capability# Key concepts:# - Chart: Package of K8s resources# - Release: Instance of a chart# - Repository: Collection of charts# - Values: Configuration for a chart# Why use Helm?# - Avoid repetitive YAML# - Parameterize deployments# - Share configurations# - Version control releases# - Easy upgrades and rollbacks
Instalación
# Install Helm# macOS:brew install helm# Linux (script):curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash# Linux (snap):sudo snap install helm --classic# Windows:choco install kubernetes-helm# Verify installation:helm version# Add popular chart repositories:helm repo add bitnami https://charts.bitnami.com/bitnamihelm repo add ingress-nginx https://kubernetes.github.io/ingress-nginxhelm repo add jetstack https://charts.jetstack.iohelm repo add prometheus-community https://prometheus-community.github.io/helm-charts# Update repositories:helm repo update# Search for charts:helm search repo nginxhelm search hub wordpress
Comandos Esenciales
# Essential Helm Commands# ========== REPOSITORY MANAGEMENT ==========helm repo list # List reposhelm repo add name url # Add repohelm repo remove name # Remove repohelm repo update # Update all repos# ========== SEARCH ==========helm search repo nginx # Search in reposhelm search hub wordpress # Search Helm Hub# ========== INSTALL ==========helm install release-name chart # Install charthelm install my-nginx bitnami/nginx# With custom values:helm install my-nginx bitnami/nginx -f values.yamlhelm install my-nginx bitnami/nginx --set replicas=3# Install in namespace:helm install my-nginx bitnami/nginx -n my-namespace# Dry run (preview):helm install my-nginx bitnami/nginx --dry-run# ========== MANAGE RELEASES ==========helm list # List releaseshelm list -A # All namespaceshelm status my-nginx # Release statushelm history my-nginx # Release history# ========== UPGRADE ==========helm upgrade my-nginx bitnami/nginxhelm upgrade my-nginx bitnami/nginx -f new-values.yaml# ========== ROLLBACK ==========helm rollback my-nginx # Rollback to previoushelm rollback my-nginx 2 # Rollback to revision 2# ========== UNINSTALL ==========helm uninstall my-nginx
Estructura de un Chart
# Helm Chart Structuremy-chart/├── Chart.yaml # Chart metadata├── values.yaml # Default values├── charts/ # Chart dependencies├── templates/ # K8s manifests (templates)│ ├── deployment.yaml│ ├── service.yaml│ ├── ingress.yaml│ ├── configmap.yaml│ ├── secret.yaml│ ├── _helpers.tpl # Template helpers│ ├── NOTES.txt # Post-install notes│ └── tests/ # Test hooks└── .helmignore # Files to ignore# Chart.yaml example:apiVersion: v2name: my-appdescription: My application charttype: applicationversion: 1.0.0 # Chart versionappVersion: "2.0.0" # App versiondependencies:- name: postgresqlversion: "12.1.0"repository: "https://charts.bitnami.com/bitnami"condition: postgresql.enabled
Ejemplo de Template
# Helm Template Example# templates/deployment.yamlapiVersion: apps/v1kind: Deploymentmetadata:name: {{ include "my-app.fullname" . }}labels:{{- include "my-app.labels" . | nindent 4 }}spec:replicas: {{ .Values.replicaCount }}selector:matchLabels:{{- include "my-app.selectorLabels" . | nindent 6 }}template:metadata:labels:{{- include "my-app.selectorLabels" . | nindent 8 }}spec:containers:- name: {{ .Chart.Name }}image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"ports:- containerPort: {{ .Values.service.port }}{{- if .Values.resources }}resources:{{- toYaml .Values.resources | nindent 10 }}{{- end }}env:{{- range $key, $value := .Values.env }}- name: {{ $key }}value: {{ $value | quote }}{{- end }}# values.yaml (defaults)replicaCount: 2image:repository: nginxtag: "1.25"service:port: 80resources:requests:cpu: 100mmemory: 128Milimits:cpu: 200mmemory: 256Mienv:LOG_LEVEL: info
13. Namespaces & RBAC
Los Namespaces proporcionan aislamiento lógico. RBAC controla quién puede hacer qué en el cluster.
Namespaces
# Namespaces - Virtual Clusters# Namespaces provide:# - Resource isolation# - Access control boundaries# - Resource quotas per namespace# - Network policy scoping# Default namespaces:# - default: for resources without namespace# - kube-system: K8s system components# - kube-public: publicly readable# - kube-node-lease: node heartbeats# When to use namespaces:# - Separate environments (dev/staging/prod)# - Separate teams or projects# - Separate customers (multi-tenancy)# - Resource quota enforcement
Comandos
# Namespace Commands# Create namespace:kubectl create namespace my-namespace# From YAML:kubectl apply -f - <<EOFapiVersion: v1kind: Namespacemetadata:name: my-namespacelabels:environment: developmentEOF# List namespaces:kubectl get namespaceskubectl get ns# Switch default namespace:kubectl config set-context --current --namespace=my-namespace# Run command in namespace:kubectl get pods -n my-namespacekubectl get all -n my-namespace# Delete namespace (DELETES ALL RESOURCES IN IT):kubectl delete namespace my-namespace
ResourceQuota & LimitRange
# ResourceQuota - Limit namespace resourcesapiVersion: v1kind: ResourceQuotametadata:name: compute-quotanamespace: developmentspec:hard:# Compute resourcesrequests.cpu: "4"requests.memory: 8Gilimits.cpu: "8"limits.memory: 16Gi# Object countspods: "20"services: "10"secrets: "20"configmaps: "20"persistentvolumeclaims: "5"---# LimitRange - Default limits for podsapiVersion: v1kind: LimitRangemetadata:name: default-limitsnamespace: developmentspec:limits:- type: Containerdefault:cpu: 200mmemory: 256MidefaultRequest:cpu: 100mmemory: 128Mimax:cpu: "2"memory: 2Gimin:cpu: 50mmemory: 64Mi
RBAC Conceptos
# RBAC - Role-Based Access Control# RBAC controls WHO can do WHAT on WHICH resources# Key concepts:# - Subject: user, group, or service account# - Role: set of permissions (verbs on resources)# - RoleBinding: binds role to subject# Role types:# - Role: namespace-scoped# - ClusterRole: cluster-scoped# Binding types:# - RoleBinding: binds to namespace# - ClusterRoleBinding: binds cluster-wide# Verbs (actions):# get, list, watch, create, update, patch, delete# Common ClusterRoles:# - view: read-only access# - edit: read/write (no RBAC)# - admin: full access (no RBAC)# - cluster-admin: superuser
RBAC Ejemplos
# RBAC Examples# Role - namespace permissionsapiVersion: rbac.authorization.k8s.io/v1kind: Rolemetadata:name: pod-readernamespace: developmentrules:- apiGroups: [""]resources: ["pods", "pods/log"]verbs: ["get", "list", "watch"]- apiGroups: [""]resources: ["pods/exec"]verbs: ["create"]---# RoleBinding - bind role to userapiVersion: rbac.authorization.k8s.io/v1kind: RoleBindingmetadata:name: read-podsnamespace: developmentsubjects:- kind: Username: janeapiGroup: rbac.authorization.k8s.io- kind: ServiceAccountname: my-appnamespace: developmentroleRef:kind: Rolename: pod-readerapiGroup: rbac.authorization.k8s.io---# ClusterRole - cluster-wide permissionsapiVersion: rbac.authorization.k8s.io/v1kind: ClusterRolemetadata:name: secret-readerrules:- apiGroups: [""]resources: ["secrets"]verbs: ["get", "list"]---# ClusterRoleBindingapiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata:name: read-secrets-globalsubjects:- kind: Groupname: developersapiGroup: rbac.authorization.k8s.ioroleRef:kind: ClusterRolename: secret-readerapiGroup: rbac.authorization.k8s.io
ServiceAccount
# ServiceAccount - Identity for podsapiVersion: v1kind: ServiceAccountmetadata:name: my-appnamespace: defaultautomountServiceAccountToken: true---# Use ServiceAccount in PodapiVersion: v1kind: Podmetadata:name: my-app-podspec:serviceAccountName: my-appcontainers:- name: appimage: my-app:latest---# Create token for ServiceAccount (K8s 1.24+)kubectl create token my-app# Or create long-lived secret token:apiVersion: v1kind: Secretmetadata:name: my-app-tokenannotations:kubernetes.io/service-account.name: my-apptype: kubernetes.io/service-account-token
14. Monitoreo y Logging
El monitoreo es esencial para operar Kubernetes en producción. Prometheus + Grafana es el stack más popular.
Stack de Monitoreo
# Kubernetes Monitoring Stack# Common monitoring tools:# - Prometheus: metrics collection# - Grafana: visualization# - Alertmanager: alerting# - Loki: log aggregation# - Jaeger/Zipkin: distributed tracing# Metrics types:# - Node metrics (CPU, memory, disk)# - Pod metrics (container resources)# - Application metrics (custom)# - Cluster metrics (API server, etcd)# Built-in:# - metrics-server: basic CPU/memory# - kubectl top pods/nodes# Install metrics-server:kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml# View metrics:kubectl top nodeskubectl top podskubectl top pods -A --sort-by=memory
Instalar Prometheus
# Install Prometheus with Helm# Add repository:helm repo add prometheus-community https://prometheus-community.github.io/helm-chartshelm repo update# Install full stack (Prometheus + Grafana + Alertmanager):helm install monitoring prometheus-community/kube-prometheus-stack \-n monitoring --create-namespace \--set prometheus.prometheusSpec.retention=30d \--set grafana.adminPassword=admin# Port forward to Grafana:kubectl port-forward -n monitoring svc/monitoring-grafana 3000:80# Access at http://localhost:3000 (admin/admin)# Port forward to Prometheus:kubectl port-forward -n monitoring svc/monitoring-kube-prometheus-prometheus 9090:9090# Access at http://localhost:9090# List installed resources:kubectl get all -n monitoring
Métricas de Aplicación
# Application Metrics with Prometheus# ServiceMonitor - auto-discover metrics endpointsapiVersion: monitoring.coreos.com/v1kind: ServiceMonitormetadata:name: my-app-monitornamespace: monitoringlabels:release: monitoring # Must match Prometheus selectorspec:selector:matchLabels:app: my-appnamespaceSelector:matchNames:- defaultendpoints:- port: metricspath: /metricsinterval: 30s---# PodMonitor - monitor pods directlyapiVersion: monitoring.coreos.com/v1kind: PodMonitormetadata:name: my-app-podsnamespace: monitoringspec:selector:matchLabels:app: my-apppodMetricsEndpoints:- port: metricspath: /metricsinterval: 15s
Logging (Loki)
# Kubernetes Logging# Log collection options:# - Fluentd / Fluent Bit# - Loki + Promtail# - ELK Stack (Elasticsearch + Logstash + Kibana)# - Cloud solutions (CloudWatch, Stackdriver)# Install Loki Stack:helm repo add grafana https://grafana.github.io/helm-chartshelm repo updatehelm install loki grafana/loki-stack \-n logging --create-namespace \--set promtail.enabled=true \--set grafana.enabled=false # Use existing Grafana# Add Loki as datasource in Grafana:# URL: http://loki.logging:3100# View logs in Grafana:# 1. Go to Explore# 2. Select Loki datasource# 3. Use LogQL: {namespace="default", app="my-app"}# LogQL examples:# {job="my-app"} |= "error"# {namespace="default"} | json | level="error"# rate({app="nginx"}[5m])
15. Mejores Prácticas
Estas prácticas te ayudarán a ejecutar cargas de trabajo de producción de manera segura y eficiente.
Gestión de Recursos
# Best Practices: Resource Management# ALWAYS set resource requests and limitsresources:requests:cpu: 100m # Minimum neededmemory: 128Milimits:cpu: 200m # Maximum allowedmemory: 256Mi# Guidelines:# - Start with requests = actual usage# - Set limits 2-3x requests initially# - Monitor and adjust based on metrics# - Use VPA (Vertical Pod Autoscaler) for recommendations# CPU:# - 1 CPU = 1000m (millicores)# - 100m = 0.1 CPU = 10% of a core# - Requests: for scheduling# - Limits: throttled if exceeded# Memory:# - Use Mi (mebibytes) or Gi (gibibytes)# - Requests: for scheduling# - Limits: OOMKilled if exceeded# Anti-patterns to avoid:# - No limits (can starve other pods)# - Limits too low (constant throttling)# - Requests too high (wasted resources)
Seguridad
# Best Practices: Security# 1. Run as non-rootsecurityContext:runAsNonRoot: truerunAsUser: 1000runAsGroup: 1000fsGroup: 1000# 2. Read-only filesystemsecurityContext:readOnlyRootFilesystem: truevolumeMounts:- name: tmpmountPath: /tmpvolumes:- name: tmpemptyDir: {}# 3. Drop all capabilitiessecurityContext:capabilities:drop:- ALL# 4. Use NetworkPolicies# - Default deny all ingress/egress# - Explicitly allow needed traffic# 5. Secrets management# - Never commit secrets to git# - Use external secret managers# - Rotate secrets regularly# 6. Image security# - Use specific image tags (not :latest)# - Scan images for vulnerabilities# - Use private registries# - Sign and verify images
Alta Disponibilidad
# Best Practices: High Availability# 1. Multiple replicasspec:replicas: 3 # At least 2 for HA# 2. Pod Anti-Affinity (spread across nodes)affinity:podAntiAffinity:preferredDuringSchedulingIgnoredDuringExecution:- weight: 100podAffinityTerm:labelSelector:matchLabels:app: my-apptopologyKey: kubernetes.io/hostname# 3. Pod Disruption BudgetapiVersion: policy/v1kind: PodDisruptionBudgetmetadata:name: my-app-pdbspec:minAvailable: 2 # or maxUnavailable: 1selector:matchLabels:app: my-app# 4. Topology Spread ConstraintstopologySpreadConstraints:- maxSkew: 1topologyKey: topology.kubernetes.io/zonewhenUnsatisfiable: DoNotSchedulelabelSelector:matchLabels:app: my-app# 5. Proper health checkslivenessProbe:httpGet:path: /healthzport: 8080initialDelaySeconds: 10periodSeconds: 5readinessProbe:httpGet:path: /readyport: 8080initialDelaySeconds: 5periodSeconds: 3
Prácticas Generales
# General Best Practices# 1. Use declarative YAML (not imperative commands)kubectl apply -f deployment.yaml # Goodkubectl create deployment ... # Avoid in production# 2. Use namespaces# - Separate environments# - Apply resource quotas# - Control access with RBAC# 3. Label everythingmetadata:labels:app: my-appversion: v1.0.0environment: productionteam: backend# 4. Use ConfigMaps and Secrets# - Don't hardcode config in images# - Separate config from code# 5. Implement GitOps# - Store manifests in git# - Use ArgoCD or Flux# - Automated deployments# 6. Monitoring and alerting# - Set up Prometheus + Grafana# - Create dashboards# - Configure alerts# 7. Regular backups# - Backup etcd# - Backup PersistentVolumes# - Test restore procedures# 8. Keep clusters updated# - Regular K8s version upgrades# - Update node OS# - Patch security vulnerabilities
16. Ejemplos del Mundo Real
Un ejemplo completo de aplicación full-stack desplegada en Kubernetes con base de datos, cache, backend, frontend e Ingress.
Aplicación Full-Stack (Parte 1)
# Full Stack Application Deployment# 1. NamespaceapiVersion: v1kind: Namespacemetadata:name: my-app---# 2. ConfigMapapiVersion: v1kind: ConfigMapmetadata:name: app-confignamespace: my-appdata:DATABASE_HOST: postgres-serviceREDIS_HOST: redis-serviceLOG_LEVEL: info---# 3. SecretapiVersion: v1kind: Secretmetadata:name: app-secretsnamespace: my-apptype: OpaquestringData:DATABASE_PASSWORD: supersecretJWT_SECRET: jwt-secret-key---# 4. PostgreSQL StatefulSetapiVersion: apps/v1kind: StatefulSetmetadata:name: postgresnamespace: my-appspec:serviceName: postgresreplicas: 1selector:matchLabels:app: postgrestemplate:metadata:labels:app: postgresspec:containers:- name: postgresimage: postgres:15-alpineports:- containerPort: 5432env:- name: POSTGRES_PASSWORDvalueFrom:secretKeyRef:name: app-secretskey: DATABASE_PASSWORDvolumeMounts:- name: datamountPath: /var/lib/postgresql/datavolumeClaimTemplates:- metadata:name: dataspec:accessModes: ["ReadWriteOnce"]resources:requests:storage: 10Gi
Aplicación Full-Stack (Parte 2)
# Full Stack Application (continued)# 5. PostgreSQL ServiceapiVersion: v1kind: Servicemetadata:name: postgres-servicenamespace: my-appspec:selector:app: postgresports:- port: 5432targetPort: 5432clusterIP: None---# 6. Redis DeploymentapiVersion: apps/v1kind: Deploymentmetadata:name: redisnamespace: my-appspec:replicas: 1selector:matchLabels:app: redistemplate:metadata:labels:app: redisspec:containers:- name: redisimage: redis:7-alpineports:- containerPort: 6379---# 7. Redis ServiceapiVersion: v1kind: Servicemetadata:name: redis-servicenamespace: my-appspec:selector:app: redisports:- port: 6379targetPort: 6379---# 8. Backend API DeploymentapiVersion: apps/v1kind: Deploymentmetadata:name: backendnamespace: my-appspec:replicas: 3selector:matchLabels:app: backendtemplate:metadata:labels:app: backendspec:containers:- name: backendimage: myapp/backend:v1.0.0ports:- containerPort: 8080envFrom:- configMapRef:name: app-config- secretRef:name: app-secretsresources:requests:cpu: 100mmemory: 256Milimits:cpu: 500mmemory: 512MilivenessProbe:httpGet:path: /healthport: 8080initialDelaySeconds: 10readinessProbe:httpGet:path: /readyport: 8080
Aplicación Full-Stack (Parte 3)
# Full Stack Application (final)# 9. Backend ServiceapiVersion: v1kind: Servicemetadata:name: backend-servicenamespace: my-appspec:selector:app: backendports:- port: 80targetPort: 8080---# 10. Frontend DeploymentapiVersion: apps/v1kind: Deploymentmetadata:name: frontendnamespace: my-appspec:replicas: 2selector:matchLabels:app: frontendtemplate:metadata:labels:app: frontendspec:containers:- name: frontendimage: myapp/frontend:v1.0.0ports:- containerPort: 80env:- name: API_URLvalue: "http://backend-service"---# 11. Frontend ServiceapiVersion: v1kind: Servicemetadata:name: frontend-servicenamespace: my-appspec:selector:app: frontendports:- port: 80targetPort: 80---# 12. IngressapiVersion: networking.k8s.io/v1kind: Ingressmetadata:name: app-ingressnamespace: my-appannotations:nginx.ingress.kubernetes.io/ssl-redirect: "true"cert-manager.io/cluster-issuer: letsencrypt-prodspec:ingressClassName: nginxtls:- hosts:- myapp.example.com- api.myapp.example.comsecretName: myapp-tlsrules:- host: myapp.example.comhttp:paths:- path: /pathType: Prefixbackend:service:name: frontend-serviceport:number: 80- host: api.myapp.example.comhttp:paths:- path: /pathType: Prefixbackend:service:name: backend-serviceport:number: 80
CI/CD Pipeline
# CI/CD Pipeline with Kubernetes# GitHub Actions workflow example:name: Deploy to Kuberneteson:push:branches: [main]jobs:build-and-deploy:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v4- name: Build Docker imagerun: |docker build -t myapp:${{ github.sha }} .docker tag myapp:${{ github.sha }} ghcr.io/myorg/myapp:${{ github.sha }}- name: Push to registryrun: |echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u ${{ github.actor }} --password-stdindocker push ghcr.io/myorg/myapp:${{ github.sha }}- name: Configure kubectluses: azure/k8s-set-context@v3with:kubeconfig: ${{ secrets.KUBE_CONFIG }}- name: Deploy to Kubernetesrun: |kubectl set image deployment/myapp \myapp=ghcr.io/myorg/myapp:${{ github.sha }} \-n productionkubectl rollout status deployment/myapp -n production
Ahora que conoces los fundamentos, practica creando tu propio cluster con Minikube o Kind, y despliega una aplicación simple. La práctica es la mejor forma de aprender Kubernetes.