Zum Hauptinhalt springen
Echtzeit-Radar & Feeds
Alle RSS Feeds ➔
👥 Community & Social
Windows Tipps & SecurityGrafikkarte vor Überhitzung schützen: So geht’s(25.09.2026 um 08:00 Uhr)
••••••••••
Windows Tipps & SecurityGrafikkarte vor Überhitzung schützen: So geht’s(25.09.2026 um 08:00 Uhr)
••••••••••
Intelligence View
⚡ tsecurity.de Intelligence

De Cero a Kubernetes Parte 1: Infraestructura con Terraform y Bootstrap con kubeadm

Serie: De Cero a Kubernetes — Parte 1 · Parte 2 · Parte 3 · Parte 4 · Parte 5 Esta es la primera parte de una guía de 5 entregas donde vamos a construir, desde cero absoluto, un cluster Kubernetes completo con Terraform, desplegar un ba…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!

K8s Terraform ArgoCD — Header



Serie: De Cero a Kubernetes — Parte 1 · Parte 2 · Parte 3 · Parte 4 · Parte 5






Esta es la primera parte de una guía de 5 entregas donde vamos a construir, desde cero absoluto, un cluster Kubernetes completo con Terraform, desplegar un backend con base de datos, dos frontends independientes, y gestionarlo todo con GitOps usando ArgoCD.



No es un tutorial de "haz clic aquí y cruza los dedos". Vamos a entender cada pieza. Al final de la serie tendrás un cluster real corriendo en la nube, con TLS automático, deployments reproducibles, y todo el código versionado en GitHub.



Lo que construiremos en esta Parte 1:




  • 3 VMs (1 control-plane + 2 workers) en Hetzner Cloud con Terraform

  • Red privada entre VMs, firewalls con puertos Kubernetes, SSH keys

  • containerd como container runtime en cada nodo


  • kubeadm init en el control-plane, kubeadm join en los workers

  • Calico como CNI (Container Network Interface)

  • Todo automatizado vía cloud-init — en 5 minutos tienes cluster









¿Por qué kubeadm y no un servicio managed?



EKS, GKE y AKS son excelentes. Pero cuando usas un managed service, no tocas el control-plane, no ves etcd, no configuras el CNI, no entiendes qué pasa cuando un nodo no se une al cluster.



kubeadm es la herramienta oficial de Kubernetes para bootstrappear clusters. Es lo que usan los ingenieros que construyen plataformas. Al terminar esta serie, sabrás exactamente qué hace cada componente y podrás reproducir este cluster en cualquier proveedor: Hetzner, AWS EC2, GCP Compute Engine, o tus propias máquinas físicas.









Arquitectura de infraestructura






┌──────────────────────────────────────────────────────┐
│ Hetzner Cloud │
│ │
│ ┌─────────────────────┐ ┌──────────┐ ┌──────────┐ │
│ │ control-plane │ │ worker-0 │ │ worker-1 │ │
│ │ (CX21, 2vCPU/4GB) │ │(CX21) │ │(CX21) │ │
│ │ │ │ │ │ │ │
│ │ api-server │ │ kubelet │ │ kubelet │ │
│ │ etcd │ │ containerd│ │ containerd│ │
│ │ controller-manager │ │ Calico │ │ Calico │ │
│ │ scheduler │ │ │ │ │ │
│ │ kubelet │ │ │ │ │ │
│ │ containerd │ │ │ │ │ │
│ │ Calico │ │ │ │ │ │
│ └────────┬────────────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │
│ └────────────────────┼─────────────┘ │
│ │ │
│ ┌───────────▼───────────┐ │
│ │ Red privada │ │
│ │ (10.0.0.0/16) │ │
│ └───────────────────────┘ │
│ │
│ Firewall: SSH(22) + k8s API(6443) + NodePorts │
│ + Calico networking (179/tcp, 4789/udp) │
└──────────────────────────────────────────────────────┘












Estructura del proyecto Terraform



Creamos un directorio infra/ en nuestro monorepo:




infra/
├── main.tf # Providers, recursos principales
├── variables.tf # Variables de entrada
├── outputs.tf # Outputs: IPs, kubeconfig
├── terraform.tfvars # Valores (no commitear secretos)
├── versions.tf # Versiones de providers
├── cloud-init/
│ ├── control-plane.yaml
│ └── worker.yaml
└── .gitignore












Paso 1: Configurar providers y variables



versions.tf — Bloqueamos versiones para reproducibilidad:




terraform {
required_version = ">= 1.9.0"

required_providers {
hcloud = {
source = "hetznercloud/hcloud"
version = "~> 1.47"
}
tls = {
source = "hashicorp/tls"
version = "~> 4.0"
}
}
}






main.tf — El esqueleto:




provider "hcloud" {
token = var.hcloud_token
}

# Red privada
resource "hcloud_network" "k8s" {
name = "k8s-network"
ip_range = "10.0.0.0/16"
}

resource "hcloud_network_subnet" "k8s" {
network_id = hcloud_network.k8s.id
type = "cloud"
network_zone = "eu-central"
ip_range = "10.0.1.0/24"
}












Paso 2: SSH keys






resource "tls_private_key" "k8s" {
algorithm = "ED25519"
}

resource "hcloud_ssh_key" "k8s" {
name = "k8s-cluster-key"
public_key = tls_private_key.k8s.public_key_openssh
}






Terraform guarda la clave privada en el state. Puedes extraerla con terraform output -raw ssh_private_key.









Paso 3: Firewall con los puertos exactos de Kubernetes



No abras todo. Kubernetes necesita puertos específicos:




resource "hcloud_firewall" "k8s" {
name = "k8s-firewall"

# SSH desde cualquier IP (o tu IP fija para producción)
rule {
direction = "in"
protocol = "tcp"
port = "22"
source_ips = ["0.0.0.0/0"]
}

# Kubernetes API (control-plane)
rule {
direction = "in"
protocol = "tcp"
port = "6443"
source_ips = ["0.0.0.0/0"]
}

# NodePort range (30000-32767 para ingress y servicios)
rule {
direction = "in"
protocol = "tcp"
port = "30000-32767"
source_ips = ["0.0.0.0/0"]
}

# Calico BGP (179/tcp) y VXLAN (4789/udp)
rule {
direction = "in"
protocol = "tcp"
port = "179"
source_ips = ["10.0.0.0/16"]
}
rule {
direction = "in"
protocol = "udp"
port = "4789"
source_ips = ["10.0.0.0/16"]
}

# Comunicación interna completa entre nodos del cluster
rule {
direction = "in"
protocol = "tcp"
port = "10250-10256"
source_ips = ["10.0.0.0/16"]
}
}






Explicación de cada puerto:





  • 6443 → API server. kubectl y kubeadm hablan con este endpoint


  • 30000-32767 → Rango NodePort. El ingress nginx se expone por aquí mientras no tengamos LoadBalancer


  • 179/tcp → BGP de Calico para compartir rutas entre nodos


  • 4789/udp → VXLAN de Calico para encapsular tráfico de pods entre nodos


  • 10250 → Kubelet API (logs, exec, métricas)


  • 10256 → kube-proxy health check


  • 10257-10259 → Controller manager y scheduler (solo en control-plane)









Paso 4: Las VMs — el corazón del cluster






# Control-plane
resource "hcloud_server" "control_plane" {
name = "k8s-control-plane"
server_type = "cx21"
image = "ubuntu-24.04"
location = "nbg1"
ssh_keys = [hcloud_ssh_key.k8s.id]
firewall_ids = [hcloud_firewall.k8s.id]

network {
network_id = hcloud_network.k8s.id
ip = "10.0.1.10"
}

# cloud-init ejecuta todo el bootstrap al primer boot
user_data = templatefile("${path.module}/cloud-init/control-plane.yaml", {
pod_network_cidr = "192.168.0.0/16"
})

depends_on = [hcloud_network_subnet.k8s]
}

# Workers
resource "hcloud_server" "worker" {
count = 2

name = "k8s-worker-${count.index}"
server_type = "cx21"
image = "ubuntu-24.04"
location = "nbg1"
ssh_keys = [hcloud_ssh_key.k8s.id]
firewall_ids = [hcloud_firewall.k8s.id]

network {
network_id = hcloud_network.k8s.id
ip = "10.0.1.${20 + count.index}"
}

user_data = templatefile("${path.module}/cloud-init/worker.yaml", {
control_plane_ip = "10.0.1.10"
# El token se genera en el cloud-init del control-plane
# y se comparte vía output de Terraform
})

depends_on = [hcloud_server.control_plane]
}












Paso 5: cloud-init — la magia que automatiza todo



Aquí es donde sucede la instalación real de Kubernetes. cloud-init ejecuta estos scripts en el primer boot de cada VM.



cloud-init/control-plane.yaml:




#cloud-config
hostname: control-plane
package_update: true
package_upgrade: true

packages:
- containerd
- apt-transport-https
- ca-certificates
- curl
- gnupg

write_files:
# Configuración de containerd con systemd como cgroup driver
- path: /etc/containerd/config.toml
permissions: '0644'
content: |
version = 2
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
runtime_type = "io.containerd.runc.v2"
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true

# Modprobe overlay y br_netfilter para networking de pods
- path: /etc/modules-load.d/k8s.conf
content: |
overlay
br_netfilter

# Parámetros de kernel para networking
- path: /etc/sysctl.d/k8s.conf
content: |
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1

runcmd:
# 1. Cargar módulos de kernel y sysctl
- modprobe overlay
- modprobe br_netfilter
- sysctl --system

# 2. Desactivar swap (Kubernetes lo requiere)
- swapoff -a
- sed -i '/swap/d' /etc/fstab

# 3. Reiniciar containerd con la nueva config
- systemctl restart containerd
- systemctl enable containerd

# 4. Agregar repo de Kubernetes y instalar kubeadm, kubelet, kubectl
- |
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.31/deb/Release.key | gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.31/deb/ /" > /etc/apt/sources.list.d/kubernetes.list
apt-get update
apt-get install -y kubelet kubeadm kubectl
apt-mark hold kubelet kubeadm kubectl

# 5. Inicializar el cluster
- |
kubeadm init \
--pod-network-cidr=${pod_network_cidr} \
--apiserver-advertise-address=10.0.1.10 \
--upload-certs \
| tee /root/kubeadm-init.log

# 6. Configurar kubeconfig para root
- mkdir -p /root/.kube
- cp /etc/kubernetes/admin.conf /root/.kube/config

# 7. Instalar Calico
- |
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.28.1/manifests/tigera-operator.yaml --kubeconfig=/etc/kubernetes/admin.conf
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.28.1/manifests/custom-resources.yaml --kubeconfig=/etc/kubernetes/admin.conf

# 8. Generar token de join para workers y guardarlo
- kubeadm token create --print-join-command > /root/join-command.sh
- chmod 644 /root/join-command.sh

final_message: "Control-plane bootstrap completado en $UPTIME segundos"






cloud-init/worker.yaml:




#cloud-config
hostname: worker
package_update: true
package_upgrade: true

packages:
- containerd
- apt-transport-https
- ca-certificates
- curl
- gnupg

write_files:
- path: /etc/containerd/config.toml
permissions: '0644'
content: |
version = 2
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
runtime_type = "io.containerd.runc.v2"
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true

- path: /etc/modules-load.d/k8s.conf
content: |
overlay
br_netfilter

- path: /etc/sysctl.d/k8s.conf
content: |
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1

runcmd:
- modprobe overlay
- modprobe br_netfilter
- sysctl --system
- swapoff -a
- sed -i '/swap/d' /etc/fstab
- systemctl restart containerd
- systemctl enable containerd

# Instalar kubeadm, kubelet, kubectl
- |
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.31/deb/Release.key | gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.31/deb/ /" > /etc/apt/sources.list.d/kubernetes.list
apt-get update
apt-get install -y kubelet kubeadm kubectl
apt-mark hold kubelet kubeadm kubectl

# Esperar que el join-command esté disponible
# (esto se resuelve con el script de abajo)

final_message: "Worker bootstrap completado en $UPTIME segundos. Ejecuta join manual luego del init del control-plane."












Paso 6: Unir los workers al cluster



Como el join-command se genera en el control-plane durante el bootstrap, necesitamos que los workers lo obtengan después. Usamos un recurso null_resource en Terraform o lo hacemos manual la primera vez:




# Desde tu máquina local, después del terraform apply:
scp root@<control-plane-ip>:/root/join-command.sh .
scp join-command.sh root@<worker-0-ip>:/root/
ssh root@<worker-0-ip> "bash /root/join-command.sh"
# Repetir para worker-1






En producción esto se automatiza con Vault o un bucket S3 compartido. Para el tutorial, este paso manual de 2 minutos es suficiente y te deja ver exactamente qué pasa.









Paso 7: Verificación






$ terraform apply
# ... (2-3 minutos para crear VMs + cloud-init)

$ ssh root@<control-plane-ip>

root@control-plane:~# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-control-plane Ready control-plane 5m v1.31.0
k8s-worker-0 Ready <none> 2m v1.31.0
k8s-worker-1 Ready <none> 2m v1.31.0

root@control-plane:~# kubectl get pods -A
NAMESPACE NAME READY STATUS RESTARTS AGE
calico-system calico-kube-controllers-xxxxx 1/1 Running 0 4m
calico-system calico-node-xxxxx 1/1 Running 0 4m
calico-system calico-node-xxxxx 1/1 Running 0 2m
calico-system calico-node-xxxxx 1/1 Running 0 2m
kube-system coredns-xxxxx 1/1 Running 0 5m
kube-system coredns-xxxxx 1/1 Running 0 5m
kube-system etcd-control-plane 1/1 Running 0 5m
kube-system kube-apiserver-control-plane 1/1 Running 0 5m
kube-system kube-controller-manager-control-plane 1/1 Running 0 5m
kube-system kube-proxy-xxxxx 1/1 Running 0 5m
kube-system kube-scheduler-control-plane 1/1 Running 0 5m






Tres nodos Ready, todos los pods del sistema corriendo. Cluster listo.









Outputs de Terraform






output "control_plane_ip" {
value = hcloud_server.control_plane.ipv4_address
}

output "worker_ips" {
value = [for w in hcloud_server.worker : w.ipv4_address]
}

output "ssh_private_key" {
value = tls_private_key.k8s.private_key_pem
sensitive = true
}

output "kubeconfig" {
value = "${path.module}/kubeconfig.yaml" # lo copiamos con un provisioner
sensitive = true
}












Costos reales
































Recurso Precio mensual
3× CX21 (2vCPU, 4GB RAM, 40GB SSD) €11.97
Red privada €0.00
Firewall €0.00
Tráfico (20TB incluido) €0.00
Total ≈ €12/mes


Menos de $13 USD al mes por un cluster Kubernetes real con control-plane dedicado. Compáralo con EKS que cobra $0.10/hora solo por el control-plane ($72/mes) más las VMs aparte.









Qué aprendiste en esta parte




  • Estructura de un proyecto Terraform profesional para Kubernetes

  • Puertos exactos que Kubernetes necesita (y por qué cada uno)

  • cloud-init como herramienta de automatización de bootstrap

  • containerd como container runtime (no Docker — Kubernetes deprecó Docker en v1.24)

  • kubeadm init y los flags críticos (pod-network-cidr, advertise-address)

  • Calico como CNI para networking de pods entre nodos

  • El concepto de control-plane + workers y qué corre en cada uno



En la Parte 2, tomaremos este cluster vacío y lo convertiremos en una plataforma lista para producción: namespaces, ingress controller con TLS automático, storage persistente, y RBAC. Todo con Terraform, sin un solo kubectl apply manual.






En Guayoyo Tech diseñamos y desplegamos arquitecturas Kubernetes como esta para empresas reales. Terraform, kubeadm, GitOps, CI/CD — lo armamos contigo, sin humo y sin vendor lock-in. Si quieres que tu infraestructura se parezca a lo que acabas de leer, hablemos gratis 15 minutos. Tu cluster, tu nube, tus reglas — nosotros ponemos la ingeniería.

2. Cyber Threat Intelligence & Forensik

CTI Threat Relationship Graph2 Knoten / 1 Relationen
CVE / Incident Software MITRE ATT&CK CWE Weakness IoC
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten De Cero a Kubernetes Parte 1: Infraestructura con Terraform y Bootstrap con kubeadm

Thematisch verwandte Begriffe: Cero, Kubernetes, Parte, Infraestructura · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

💬 Kommentare werden geladen…
Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-101042 | Parse Server is an open-source backend server. In versions >= 9.0.0 < 9…
Advisory →
tsecurity.de Icon
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag