Cluster kubernetes gratis su Oracle

Cluster kubernetes gratis su Oracle

Cluster Kubernetes Gratis su Oracle Cloud Infrastructure: Analisi Tecnica e Implementazione per Ambienti Enterprise

Abstract – Cluster kubernetes gratis su Oracle

La crescente adozione di architetture cloud-native e microservizi ha reso Kubernetes lo standard de facto per l’orchestrazione dei container. Questo studio presenta un’analisi approfondita dell’implementazione di cluster Kubernetes utilizzando Oracle Cloud Infrastructure (OCI) Always Free Tier, fornendo una soluzione enterprise-grade senza costi operativi. L’approccio metodologico adottato combina Infrastructure as Code (IaC) con principi DevSecOps per garantire deployment riproducibili, sicuri e conformi alle best practices industriali.

Introduzione e Contesto Tecnologico

Definizione di Kubernetes e Orchestrazione Container

Kubernetes, originariamente sviluppato da Google e ora mantenuto dalla Cloud Native Computing Foundation (CNCF), rappresenta una piattaforma di orchestrazione per container che automatizza deployment, scaling e gestione di applicazioni containerizzate. Il sistema implementa un’architettura distribuita basata su pattern declarativo, dove lo stato desiderato viene specificato tramite manifesti YAML e mantenuto tramite control loops.

Oracle Cloud Infrastructure: Always Free Tier

Oracle Cloud Infrastructure differenzia la propria offerta nel mercato cloud fornendo risorse “sempre gratuite” piuttosto che crediti temporanei. Il modello economico si basa sulla convinzione che fornire infrastruttura stabile e gratuita per sviluppatori generi adozione a lungo termine. Le risorse Always Free includono:

Compute Resources:

  • 4 Arm-based Ampere A1 cores
  • 24 GB memoria RAM
  • 2 VM.Standard.A1.Flex instances

Storage e Networking:

  • 200 GB Block Volume storage
  • 10 GB Object Storage
  • Flexible Load Balancer (10 Mbps bandwidth)
  • 1 Public IP address

Managed Services:

  • Oracle Kubernetes Engine (OKE) control plane
  • Autonomous Database (20 GB)
  • Resource Manager (Terraform-as-a-Service)

Architettura del Sistema Proposto – Cluster kubernetes gratis su Oracle

Il cluster implementato adotta un’architettura multi-tier che integra componenti open-source enterprise-grade:

┌─────────────────────────────────────────────────────────────┐
│                    Control Plane (Managed)                 │
│                     Oracle Kubernetes Engine               │
└─────────────────────────────────┬───────────────────────────┘
                                  │
┌─────────────────────────────────┴───────────────────────────┐
│                    Data Plane                              │
│  ┌──────────────────┐  ┌──────────────────┐              │
│  │   Worker Node 1  │  │   Worker Node 2  │              │
│  │   (ARM64 A1)     │  │   (ARM64 A1)     │              │
│  │   2 vCPU/12GB    │  │   2 vCPU/12GB    │              │
│  └──────────────────┘  └──────────────────┘              │
└─────────────────────────────────────────────────────────────┘
                                  │
┌─────────────────────────────────┴───────────────────────────┐
│                Infrastructure Services                     │
│  • Longhorn (Distributed Storage)                         │
│  • NGINX Ingress Controller                               │
│  • Cert-Manager (SSL/TLS Automation)                      │
│  • External-DNS (DNS Automation)                          │
│  • FluxCD (GitOps Orchestration)                          │
│  • Teleport (Zero-Trust Access)                           │
└─────────────────────────────────────────────────────────────┘

Metodologia di Implementazione

Prerequisiti Tecnici e Configurazione Ambiente

La metodologia adottata segue principi di Infrastructure as Code utilizzando Terraform per garantire idempotenza e riproducibilità. I prerequisiti includono:

Strumenti di Sviluppo:

# Terraform >= 1.6 (compatibilità backend S3)
wget https://releases.hashicorp.com/terraform/1.6.7/terraform_1.6.7_linux_amd64.zip
unzip terraform_1.6.7_linux_amd64.zip
sudo mv terraform /usr/local/bin/

# Oracle CLI con configurazione avanzata
bash -c "$(curl -L https://raw.githubusercontent.com/oracle/oci-cli/master/scripts/install/install.sh)"
oci setup config --profile production

# Kubectl con plugin manager
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl

Configurazione Identità e Accesso (IAM):

Oracle Cloud utilizza un modello IAM bassu su compartimenti gerarchici. La configurazione richiede:

# Configurazione avanzata OCI CLI con profili multipli
oci setup config --profile oke-admin

File di configurazione ~/.oci/config:

[DEFAULT]
user=ocid1.user.oc1..aaaaaaaxxxxx
fingerprint=xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx
tenancy=ocid1.tenancy.oc1..aaaaaaaxxxxx
region=eu-frankfurt-1
key_file=~/.oci/oci_api_key.pem

[oke-admin]
user=ocid1.user.oc1..aaaaaaayyyyy
fingerprint=yy:yy:yy:yy:yy:yy:yy:yy:yy:yy:yy:yy:yy:yy:yy:yy
tenancy=ocid1.tenancy.oc1..aaaaaaaxxxxx
region=eu-frankfurt-1
key_file=~/.oci/oke_admin_key.pem

Fase 1: Preparazione Repository e State Management – Cluster kubernetes gratis su Oracle

Il progetto utilizza un approccio modulare con separazione delle responsabilità:

# Clonazione repository di riferimento
git clone https://github.com/nce/oci-free-cloud-k8s.git
cd oci-free-cloud-k8s

# Analisi struttura del progetto
tree -L 3
├── terraform/
│   ├── infra/          # Infrastruttura base (VCN, OKE, Compute)
│   └── config/         # Configurazione Kubernetes-specific
├── gitops/             # Manifesti FluxCD
└── docs/              # Documentazione tecnica

Configurazione Remote State con Object Storage:

Il backend remoto garantisce consistenza dello stato in team distribuiti:

# Creazione bucket per Terraform state
export COMPARTMENT_ID=$(oci iam compartment list --compartment-id-in-subtree true --query 'data[?name==`root`].id | [0]' --raw-output)

oci os bucket create \
  --name terraform-states-prod \
  --compartment-id $COMPARTMENT_ID \
  --versioning Enabled \
  --storage-tier Standard \
  --public-access-type NoPublicAccess

Configurazione Backend Terraform:

# terraform/infra/backend.tf
terraform {
  backend "s3" {
    bucket                      = "terraform-states-prod"
    key                        = "oke-infrastructure/terraform.tfstate"
    region                     = "eu-frankfurt-1"
    endpoint                   = "https://namespace.compat.objectstorage.eu-frankfurt-1.oraclecloud.com"
    shared_credentials_file    = "~/.aws/credentials"
    skip_region_validation     = true
    skip_credentials_validation = true
    skip_metadata_api_check    = true
    force_path_style           = true
  }
}

Fase 2: Definizione Infrastruttura con Terraform

Configurazione Variabili di Ambiente:

# terraform/infra/terraform.tfvars
# Compartment e Region Configuration
compartment_id = "ocid1.compartment.oc1..aaaaaaaxxxxx"
region = "eu-frankfurt-1"
availability_domain = "kFRA-AD-1"

# Kubernetes Cluster Configuration  
cluster_name = "oke-free-cluster"
kubernetes_version = "v1.31.1"
cluster_endpoint_visibility = "Private"
cluster_endpoint_subnet_ids = ["ocid1.subnet.oc1.eu-frankfurt-1.aaaaaaaxxxxx"]

# Node Pool Configuration
node_pool_name = "worker-pool-a1"
node_pool_size = 2
node_shape = "VM.Standard.A1.Flex"
node_shape_config_ocpus = 2
node_shape_config_memory_in_gbs = 12

# Networking Configuration
vcn_cidr_block = "10.0.0.0/16"
private_subnet_cidr = "10.0.1.0/24"
public_subnet_cidr = "10.0.100.0/24"
service_cidr = "10.96.0.0/16"
pod_cidr = "10.244.0.0/16"

# Security Configuration
enable_pod_security_policy = true
enable_kubernetes_dashboard = false
enable_tiller = false

# Tagging Strategy
freeform_tags = {
  "Environment" = "production"
  "Project"     = "oke-free-cluster"
  "Owner"       = "platform-team"
  "CostCenter"  = "engineering"
}

Modulo VCN (Virtual Cloud Network):

# terraform/infra/modules/vcn/main.tf
resource "oci_core_vcn" "oke_vcn" {
  compartment_id = var.compartment_id
  cidr_blocks    = [var.vcn_cidr_block]
  display_name   = "${var.cluster_name}-vcn"
  dns_label      = "okefree"

  freeform_tags = var.freeform_tags
}

resource "oci_core_internet_gateway" "oke_igw" {
  compartment_id = var.compartment_id
  vcn_id         = oci_core_vcn.oke_vcn.id
  display_name   = "${var.cluster_name}-igw"
  enabled        = true

  freeform_tags = var.freeform_tags
}

resource "oci_core_nat_gateway" "oke_nat" {
  compartment_id = var.compartment_id
  vcn_id         = oci_core_vcn.oke_vcn.id
  display_name   = "${var.cluster_name}-nat"

  freeform_tags = var.freeform_tags
}

# Security Lists con principio least-privilege
resource "oci_core_security_list" "private_security_list" {
  compartment_id = var.compartment_id
  vcn_id         = oci_core_vcn.oke_vcn.id
  display_name   = "private-security-list"

  # Ingress Rules - Worker Node Communication
  ingress_security_rules {
    protocol    = "6" # TCP
    source      = var.pod_cidr
    description = "Pod to pod communication"
  }

  ingress_security_rules {
    protocol    = "6" # TCP
    source      = var.service_cidr
    description = "Service discovery"
    
    tcp_options {
      min = 30000
      max = 32767
    }
  }

  # Egress Rules - Outbound Internet Access
  egress_security_rules {
    protocol    = "all"
    destination = "0.0.0.0/0"
    description = "All outbound traffic"
  }

  freeform_tags = var.freeform_tags
}

Fase 3: Deploy Cluster OKE con Configurazioni di Sicurezza

Cluster OKE con Enhanced Security:

# terraform/infra/main.tf
resource "oci_containerengine_cluster" "oke_cluster" {
  compartment_id     = var.compartment_id
  kubernetes_version = var.kubernetes_version
  name               = var.cluster_name
  vcn_id             = module.vcn.vcn_id

  # Enhanced Security Configuration
  cluster_pod_network_options {
    cni_type = "FLANNEL_OVERLAY"
  }

  endpoint_config {
    is_public_ip_enabled = false
    subnet_id           = module.vcn.private_subnet_id
    
    # Network Security Groups per micro-segmentazione
    nsg_ids = [oci_core_network_security_group.oke_api_nsg.id]
  }

  options {
    service_lb_subnet_ids = [module.vcn.public_subnet_id]
    
    # Kubernetes API Server Security
    kubernetes_network_config {
      pods_cidr     = var.pod_cidr
      services_cidr = var.service_cidr
    }

    # Admission Controllers avanzati
    admission_controller_options {
      is_pod_security_policy_enabled = var.enable_pod_security_policy
    }

    # Image Policy per container security
    persistent_volume_config {
      defined_tags = {}
      freeform_tags = merge(var.freeform_tags, {
        "Component" = "persistent-storage"
      })
    }
  }

  freeform_tags = var.freeform_tags
}

# Network Security Group per API Server
resource "oci_core_network_security_group" "oke_api_nsg" {
  compartment_id = var.compartment_id
  vcn_id         = module.vcn.vcn_id
  display_name   = "${var.cluster_name}-api-nsg"

  freeform_tags = var.freeform_tags
}

resource "oci_core_network_security_group_security_rule" "oke_api_ingress" {
  network_security_group_id = oci_core_network_security_group.oke_api_nsg.id
  direction                 = "INGRESS"
  protocol                  = "6"

  description = "Kubernetes API access from worker nodes"
  source      = var.private_subnet_cidr
  source_type = "CIDR_BLOCK"

  tcp_options {
    destination_port_range {
      min = 6443
      max = 6443
    }
  }
}

Node Pool con Security Hardening:

resource "oci_containerengine_node_pool" "oke_node_pool" {
  cluster_id         = oci_containerengine_cluster.oke_cluster.id
  compartment_id     = var.compartment_id
  kubernetes_version = var.kubernetes_version
  name               = var.node_pool_name

  # Node Configuration con security baseline
  node_config_details {
    placement_configs {
      availability_domain = var.availability_domain
      subnet_id          = module.vcn.private_subnet_id
    }
    
    size = var.node_pool_size

    # Security Hardening
    is_pv_encryption_in_transit_enabled = true
    
    # Resource constraints per Always Free compliance
    node_pool_pod_network_option_details {
      cni_type          = "FLANNEL_OVERLAY"
      max_pods_per_node = 31 # Ottimizzato per ARM instances
    }
  }

  # Shape Configuration per ARM instances
  node_shape = var.node_shape
  
  node_shape_config {
    ocpus         = var.node_shape_config_ocpus
    memory_in_gbs = var.node_shape_config_memory_in_gbs
  }

  # Custom Boot Volume con encryption
  node_source_details {
    image_id                = data.oci_containerengine_cluster_option.oke_cluster_option.sources[0].image_id
    source_type             = "IMAGE"
    boot_volume_size_in_gbs = 100
  }

  # SSH Access Configuration
  ssh_public_key = var.ssh_public_key

  freeform_tags = merge(var.freeform_tags, {
    "Component" = "worker-nodes"
    "NodePool"  = var.node_pool_name
  })
}

Fase 4: Implementazione Security e Best Practices

Pod Security Standards Implementation:

# Pod Security Policy per workload isolation
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: restricted-psp
  annotations:
    seccomp.security.alpha.kubernetes.io/allowedProfileNames: '*'
spec:
  privileged: false
  allowPrivilegeEscalation: false
  requiredDropCapabilities:
    - ALL
  volumes:
    - 'configMap'
    - 'emptyDir'
    - 'projected'
    - 'secret'
    - 'downwardAPI'
    - 'persistentVolumeClaim'
  runAsUser:
    rule: 'MustRunAsNonRoot'
  seLinux:
    rule: 'RunAsAny'
  fsGroup:
    rule: 'RunAsAny'

Network Policies per Micro-segmentazione:

# Default deny-all network policy
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress
---
# Allow DNS resolution
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns-access
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to: []
    ports:
    - protocol: UDP
      port: 53
    - protocol: TCP
      port: 53

Fase 5: Configurazione Storage Distribuito con Longhorn

Longhorn fornisce storage block distribuito cloud-native con replica automatica e snapshot:

# Deploy Longhorn via Terraform
cd terraform/config

cat > longhorn.tf << 'EOF'
resource "helm_release" "longhorn" {
  name       = "longhorn"
  repository = "https://charts.longhorn.io"
  chart      = "longhorn"
  namespace  = "longhorn-system"
  version    = "1.5.3"

  create_namespace = true

  values = [
    yamlencode({
      # Security Configuration
      service = {
        ui = {
          type = "ClusterIP"
        }
      }
      
      # Default Settings ottimizzati per ARM instances
      defaultSettings = {
        backupTarget = "s3://longhorn-backup@us-phoenix-1/"
        backupTargetCredentialSecret = "longhorn-backup-secret"
        createDefaultDiskLabeledNodes = true
        defaultDataPath = "/var/lib/longhorn/"
        replicaSoftAntiAffinity = true
        storageOverProvisioningPercentage = 100
        storageMinimalAvailablePercentage = 10
        upgradeChecker = false
        defaultReplicaCount = 2
        guaranteedEngineCPU = 0.25
      }
      
      # Resource Limits per Always Free tier
      longhornManager = {
        resources = {
          limits = {
            cpu = "200m"
            memory = "256Mi"
          }
          requests = {
            cpu = "100m"
            memory = "128Mi"
          }
        }
      }
      
      longhornDriver = {
        resources = {
          limits = {
            cpu = "200m"
            memory = "256Mi"
          }
          requests = {
            cpu = "100m"
            memory = "128Mi"
          }
        }
      }
    })
  ]

  depends_on = [
    kubernetes_namespace.longhorn_system
  ]
}

resource "kubernetes_namespace" "longhorn_system" {
  metadata {
    name = "longhorn-system"
    labels = {
      "name" = "longhorn-system"
      "pod-security.kubernetes.io/enforce" = "privileged"
    }
  }
}
EOF

StorageClass Configuration:

# High-performance StorageClass per workload critici
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: longhorn-fast
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"
provisioner: driver.longhorn.io
allowVolumeExpansion: true
reclaimPolicy: Delete
volumeBindingMode: Immediate
parameters:
  numberOfReplicas: "2"
  staleReplicaTimeout: "30" # minutes
  fromBackup: ""
  fsType: "ext4"
  dataLocality: "best-effort" # Ottimizzazione ARM performance

Fase 6: GitOps Implementation con FluxCD

L’implementazione GitOps utilizza FluxCD v2 con il nuovo Flux Operator:

# Configurazione GitHub Personal Access Token
export GITHUB_TOKEN="ghp_xxxxxxxxxxxxxxxxxxxx"
export GITHUB_USER="your-username"
export GITHUB_REPO="oke-gitops-config"

# Terraform configuration per FluxCD
cat > terraform/config/flux.tf << 'EOF'
resource "helm_release" "flux_operator" {
  name       = "flux-operator"
  repository = "oci://ghcr.io/controlplaneio-fluxcd/charts"
  chart      = "flux-operator"
  namespace  = "flux-system"
  version    = "2024.1.1"

  create_namespace = true

  values = [
    yamlencode({
      # Security Context per ARM nodes
      securityContext = {
        runAsNonRoot = true
        runAsUser = 65534
        fsGroup = 65534
      }
      
      resources = {
        limits = {
          cpu = "200m"
          memory = "256Mi"
        }
        requests = {
          cpu = "100m"
          memory = "128Mi"
        }
      }
    })
  ]
}

resource "kubernetes_manifest" "flux_instance" {
  manifest = {
    apiVersion = "fluxcd.controlplane.io/v1"
    kind       = "FluxInstance"
    metadata = {
      name      = "flux"
      namespace = "flux-system"
    }
    spec = {
      distribution = {
        version = "2.2.x"
        registry = "ghcr.io/fluxcd"
      }
      components = [
        "source-controller",
        "kustomize-controller", 
        "helm-controller",
        "notification-controller"
      ]
      cluster = {
        type = "kubernetes"
        multitenant = false
        networkPolicy = true
        domain = "cluster.local"
      }
      kustomize = {
        patches = [
          {
            patch = yamlencode([
              {
                op = "add"
                path = "/spec/template/spec/containers/0/resources"
                value = {
                  limits = {
                    cpu = "200m"
                    memory = "256Mi"
                  }
                  requests = {
                    cpu = "50m"
                    memory = "64Mi"
                  }
                }
              }
            ])
            target = {
              kind = "Deployment"
              name = "source-controller"
            }
          }
        ]
      }
    }
  }

  depends_on = [
    helm_release.flux_operator
  ]
}
EOF

Esempio Pratico: Deploy Applicazione Demo

Implementiamo un’applicazione di esempio che dimostra le capabilities del cluster:

# demo-app/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: demo-app
  labels:
    name: demo-app
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/warn: restricted
---
# demo-app/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: golang-demo
  namespace: demo-app
  labels:
    app: golang-demo
    version: v1.0.0
spec:
  replicas: 2
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
  selector:
    matchLabels:
      app: golang-demo
  template:
    metadata:
      labels:
        app: golang-demo
        version: v1.0.0
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "8080"
        prometheus.io/path: "/metrics"
    spec:
      serviceAccountName: golang-demo-sa
      securityContext:
        runAsNonRoot: true
        runAsUser: 10001
        fsGroup: 10001
        seccompProfile:
          type: RuntimeDefault
      containers:
      - name: golang-demo
        image: ghcr.io/your-org/golang-demo:v1.0.0
        imagePullPolicy: Always
        ports:
        - name: http
          containerPort: 8080
          protocol: TCP
        - name: metrics
          containerPort: 9090
          protocol: TCP
        env:
        - name: PORT
          value: "8080"
        - name: LOG_LEVEL
          value: "info"
        - name: METRICS_PORT
          value: "9090"
        resources:
          limits:
            cpu: 200m
            memory: 256Mi
            ephemeral-storage: 100Mi
          requests:
            cpu: 50m
            memory: 64Mi
            ephemeral-storage: 50Mi
        securityContext:
          allowPrivilegeEscalation: false
          readOnlyRootFilesystem: true
          runAsNonRoot: true
          runAsUser: 10001
          capabilities:
            drop:
            - ALL
        livenessProbe:
          httpGet:
            path: /health
            port: http
          initialDelaySeconds: 30
          periodSeconds: 10
          timeoutSeconds: 5
          failureThreshold: 3
        readinessProbe:
          httpGet:
            path: /ready
            port: http
          initialDelaySeconds: 5
          periodSeconds: 5
          timeoutSeconds: 3
          failureThreshold: 3
        volumeMounts:
        - name: tmp
          mountPath: /tmp
        - name: cache
          mountPath: /app/cache
      volumes:
      - name: tmp
        emptyDir:
          sizeLimit: 100Mi
      - name: cache
        emptyDir:
          sizeLimit: 100Mi
      nodeSelector:
        kubernetes.io/arch: arm64
      tolerations:
      - key: "kubernetes.io/arch"
        operator: "Equal"
        value: "arm64"
        effect: "NoSchedule"
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - golang-demo
              topologyKey: kubernetes.io/hostname
---
# demo-app/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: golang-demo-service
  namespace: demo-app
  labels:
    app: golang-demo
  annotations:
    service.beta.kubernetes.io/oci-load-balancer-shape: "flexible"
    service.beta.kubernetes.io/oci-load-balancer-shape-flex-min: "10"
    service.beta.kubernetes.io/oci-load-balancer-shape-flex-max: "10"
spec:
  type: ClusterIP
  selector:
    app: golang-demo
  ports:
  - name: http
    port: 80
    targetPort: http
    protocol: TCP
  - name: metrics
    port: 9090
    targetPort: metrics
    protocol: TCP
---
# demo-app/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: golang-demo-ingress
  namespace: demo-app
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
    nginx.ingress.kubernetes.io/rate-limit: "100"
    nginx.ingress.kubernetes.io/rate-limit-window: "1m"
    nginx.ingress.kubernetes.io/configuration-snippet: |
      more_set_headers "X-Frame-Options: DENY";
      more_set_headers "X-Content-Type-Options: nosniff";
      more_set_headers "X-XSS-Protection: 1; mode=block";
      more_set_headers "Referrer-Policy: strict-origin-when-cross-origin";
spec:
  tls:
  - hosts:
    - demo.your-domain.com
    secretName: golang-demo-tls
  rules:
  - host: demo.your-domain.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: golang-demo-service
            port:
              number: 80

Deploy dell’Applicazione Demo:

# Applicare i manifesti
kubectl apply -f demo-app/

# Verificare il deployment
kubectl get pods -n demo-app -o wide
kubectl get ingress -n demo-app
kubectl describe ingress golang-demo-ingress -n demo-app

# Monitorare i log
kubectl logs -f deployment/golang-demo -n demo-app

# Test di carico per validare scaling
kubectl run load-test --image=busybox --rm -it --restart=Never -- \
  sh -c 'while true; do wget -q -O- http://golang-demo-service.demo-app.svc.cluster.local; sleep 0.1; done'

Monitoring e Observability

Implementazione Stack Prometheus/Grafana

# Configurazione Kube-Prometheus-Stack ottimizzata per ARM
cat > terraform/config/monitoring.tf << 'EOF'
resource "helm_release" "kube_prometheus_stack" {
  name       = "kube-prometheus-stack"
  repository = "https://prometheus-community.github.io/helm-charts"
  chart      = "kube-prometheus-stack"
  namespace  = "monitoring"
  version    = "55.5.0"

  create_namespace = true

        values = [
    yamlencode({
      # Prometheus Configuration
      prometheus = {
        prometheusSpec = {
          retention = "7d"
          retentionSize = "8GB"
          resources = {
            limits = {
              cpu = "500m"
              memory = "1Gi"
            }
            requests = {
              cpu = "200m"
              memory = "512Mi"
            }
          }
          storageSpec = {
            volumeClaimTemplate = {
              spec = {
                storageClassName = "longhorn-fast"
                accessModes = ["ReadWriteOnce"]
                resources = {
                  requests = {
                    storage = "10Gi"
                  }
                }
              }
            }
          }
          # ARM64 node selector
          nodeSelector = {
            "kubernetes.io/arch" = "arm64"
          }
        }
      }
      
      # Grafana Configuration
      grafana = {
        enabled = true
        adminPassword = "admin123!" # Cambiare in produzione
        persistence = {
          enabled = true
          storageClassName = "longhorn-fast"
          size = "2Gi"
        }
        resources = {
          limits = {
            cpu = "200m"
            memory = "256Mi"
          }
          requests = {
            cpu = "100m"
            memory = "128Mi"
          }
        }
        nodeSelector = {
          "kubernetes.io/arch" = "arm64"
        }
        # Dashboard pre-configurate
        dashboardProviders = {
          "dashboardproviders.yaml" = {
            apiVersion = 1
            providers = [
              {
                name = "default"
                orgId = 1
                folder = ""
                type = "file"
                disableDeletion = false
                editable = true
                options = {
                  path = "/var/lib/grafana/dashboards/default"
                }
              }
            ]
          }
        }
      }
      
      # AlertManager Configuration
      alertmanager = {
        alertmanagerSpec = {
          resources = {
            limits = {
              cpu = "100m"
              memory = "128Mi"
            }
            requests = {
              cpu = "50m"
              memory = "64Mi"
            }
          }
          storage = {
            volumeClaimTemplate = {
              spec = {
                storageClassName = "longhorn-fast"
                accessModes = ["ReadWriteOnce"]
                resources = {
                  requests = {
                    storage = "2Gi"
                  }
                }
              }
            }
          }
          nodeSelector = {
            "kubernetes.io/arch" = "arm64"
          }
        }
      }
      
      # Node Exporter per metriche nodi
      nodeExporter = {
        enabled = true
      }
      
      # Kube State Metrics
      kubeStateMetrics = {
        enabled = true
      }
    })
  ]
}
EOF

Configurazione Loki per Log Aggregation

# Loki configuration per log centralization
resource "helm_release" "loki_stack" {
  name       = "loki"
  repository = "https://grafana.github.io/helm-charts"
  chart      = "loki-stack"
  namespace  = "monitoring"
  version    = "2.10.2"

  values = [
    yamlencode({
      # Loki Configuration
      loki = {
        enabled = true
        persistence = {
          enabled = true
          storageClassName = "longhorn-fast"
          size = "10Gi"
        }
        config = {
          auth_enabled = false
          server = {
            http_listen_port = 3100
          }
          ingester = {
            lifecycler = {
              address = "127.0.0.1"
              ring = {
                kvstore = {
                  store = "inmemory"
                }
                replication_factor = 1
              }
            }
            chunk_idle_period = "1h"
            max_chunk_age = "1h"
            chunk_target_size = 1048576
            chunk_retain_period = "30s"
          }
          schema_config = {
            configs = [
              {
                from = "2024-01-01"
                store = "boltdb-shipper"
                object_store = "filesystem"
                schema = "v11"
                index = {
                  prefix = "index_"
                  period = "24h"
                }
              }
            ]
          }
          storage_config = {
            boltdb_shipper = {
              active_index_directory = "/loki/boltdb-shipper-active"
              cache_location = "/loki/boltdb-shipper-cache"
              cache_ttl = "24h"
              shared_store = "filesystem"
            }
            filesystem = {
              directory = "/loki/chunks"
            }
          }
          limits_config = {
            reject_old_samples = true
            reject_old_samples_max_age = "168h"
            retention_period = "336h" # 14 giorni
          }
        }
        resources = {
          limits = {
            cpu = "300m"
            memory = "512Mi"
          }
          requests = {
            cpu = "100m"
            memory = "256Mi"
          }
        }
        nodeSelector = {
          "kubernetes.io/arch" = "arm64"
        }
      }
      
      # Promtail per log collection
      promtail = {
        enabled = true
        resources = {
          limits = {
            cpu = "200m"
            memory = "128Mi"
          }
          requests = {
            cpu = "100m"
            memory = "64Mi"
          }
        }
        tolerations = [
          {
            key = "node-role.kubernetes.io/master"
            operator = "Exists"
            effect = "NoSchedule"
          }
        ]
      }
      
      # Grafana integration
      grafana = {
        enabled = false # Già presente nel kube-prometheus-stack
      }
    })
  ]

  depends_on = [
    helm_release.kube_prometheus_stack
  ]
}

Security Hardening e Best Practices – Cluster kubernetes gratis su Oracle

Implementazione Policy di Sicurezza con Kyverno

# Policy di sicurezza automatizzate con Kyverno
resource "helm_release" "kyverno" {
  name       = "kyverno"
  repository = "https://kyverno.github.io/kyverno/"
  chart      = "kyverno"
  namespace  = "kyverno"
  version    = "3.1.4"

  create_namespace = true

  values = [
    yamlencode({
      # Resource limits per ARM instances
      resources = {
        limits = {
          cpu = "400m"
          memory = "512Mi"
        }
        requests = {
          cpu = "200m"
          memory = "256Mi"
        }
      }
      
      nodeSelector = {
        "kubernetes.io/arch" = "arm64"
      }
      
      # Security Context
      securityContext = {
        runAsNonRoot = true
        runAsUser = 10001
        allowPrivilegeEscalation = false
        readOnlyRootFilesystem = true
        capabilities = {
          drop = ["ALL"]
        }
      }
      
      # Policy enforcement configuration
      config = {
        webhooks = [
          {
            namespaceSelector = {
              matchExpressions = [
                {
                  key = "name"
                  operator = "NotIn"
                  values = ["kube-system", "kyverno"]
                }
              ]
            }
          }
        ]
      }
    })
  ]
}

# ClusterPolicy per image security
resource "kubernetes_manifest" "require_non_root_user" {
  manifest = {
    apiVersion = "kyverno.io/v1"
    kind       = "ClusterPolicy"
    metadata = {
      name = "require-non-root-user"
      annotations = {
        "policies.kyverno.io/title" = "Require Non-Root User"
        "policies.kyverno.io/category" = "Security"
        "policies.kyverno.io/severity" = "medium"
        "policies.kyverno.io/description" = "Containers must run as non-root user"
      }
    }
    spec = {
      validationFailureAction = "enforce"
      background = true
      rules = [
        {
          name = "check-non-root-user"
          match = {
            any = [
              {
                resources = {
                  kinds = ["Pod"]
                }
              }
            ]
          }
          validate = {
            message = "Containers must run as non-root user"
            pattern = {
              spec = {
                "=(securityContext)" = {
                  "=(runAsNonRoot)" = true
                }
                containers = [
                  {
                    "=(securityContext)" = {
                      "=(runAsNonRoot)" = true
                    }
                  }
                ]
              }
            }
          }
        }
      ]
    }
  }

  depends_on = [
    helm_release.kyverno
  ]
}

Container Image Scanning e Signature Verification

# Policy per image signature verification
resource "kubernetes_manifest" "verify_image_signatures" {
  manifest = {
    apiVersion = "kyverno.io/v1"
    kind       = "ClusterPolicy"
    metadata = {
      name = "verify-image-signatures"
      annotations = {
        "policies.kyverno.io/title" = "Verify Image Signatures"
        "policies.kyverno.io/category" = "Security"
        "policies.kyverno.io/severity" = "high"
      }
    }
    spec = {
      validationFailureAction = "enforce"
      background = false
      rules = [
        {
          name = "verify-signature"
          match = {
            any = [
              {
                resources = {
                  kinds = ["Pod"]
                }
              }
            ]
          }
          verifyImages = [
            {
              imageReferences = [
                "ghcr.io/your-org/*"
              ]
              attestors = [
                {
                  entries = [
                    {
                      keys = {
                        publicKeys = <<-EOT
                        -----BEGIN PUBLIC KEY-----
                        MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...
                        -----END PUBLIC KEY-----
                        EOT
                      }
                    }
                  ]
                }
              ]
            }
          ]
        }
      ]
    }
  }

  depends_on = [
    helm_release.kyverno
  ]
}

Gestione degli Aggiornamenti e Maintenance – Cluster kubernetes gratis su Oracle

Procedura di Aggiornamento Cluster

Il processo di aggiornamento segue la metodologia blue-green per minimizzare i downtime:

#!/bin/bash
# upgrade-cluster.sh - Script automatizzato per aggiornamenti

set -euo pipefail

# Configurazione
CLUSTER_ID=$(terraform output -raw k8s_cluster_id)
CURRENT_VERSION=$(oci ce cluster get --cluster-id $CLUSTER_ID --query 'data."kubernetes-version"' --raw-output)
TARGET_VERSION="v1.32.0"

echo "=== Kubernetes Cluster Upgrade Process ==="
echo "Current Version: $CURRENT_VERSION"
echo "Target Version: $TARGET_VERSION"

# Fase 1: Verifica versioni compatibili
echo "Checking available upgrades..."
AVAILABLE_UPGRADES=$(oci ce cluster get --cluster-id $CLUSTER_ID | jq -r '.data."available-kubernetes-upgrades"[]')

if [[ ! "$AVAILABLE_UPGRADES" =~ $TARGET_VERSION ]]; then
    echo "ERROR: Target version $TARGET_VERSION not available for direct upgrade"
    echo "Available versions: $AVAILABLE_UPGRADES"
    exit 1
fi

# Fase 2: Backup configurazioni critiche
echo "Creating backup of critical configurations..."
kubectl get all,configmaps,secrets,pv,pvc --all-namespaces -o yaml > "cluster-backup-$(date +%Y%m%d-%H%M%S).yaml"

# Fase 3: Drain dei nodi (preventivo per preparazione)
echo "Preparing nodes for upgrade..."
for node in $(kubectl get nodes -o jsonpath='{.items[*].metadata.name}'); do
    echo "Cordoning node: $node"
    kubectl cordon $node
done

# Fase 4: Aggiornamento Control Plane
echo "Upgrading control plane to $TARGET_VERSION..."
cd terraform/infra
sed -i.bak "s/kubernetes_version = \"$CURRENT_VERSION\"/kubernetes_version = \"$TARGET_VERSION\"/" terraform.tfvars

terraform plan -var-file="terraform.tfvars"
terraform apply -var-file="terraform.tfvars" -auto-approve

# Attesa completamento upgrade control plane
echo "Waiting for control plane upgrade completion..."
while true; do
    CLUSTER_STATE=$(oci ce cluster get --cluster-id $CLUSTER_ID --query 'data."lifecycle-state"' --raw-output)
    if [[ "$CLUSTER_STATE" == "ACTIVE" ]]; then
        break
    fi
    echo "Cluster state: $CLUSTER_STATE - waiting..."
    sleep 30
done

# Fase 5: Aggiornamento Worker Nodes (rolling)
echo "Starting worker nodes rolling upgrade..."
NODES=$(kubectl get nodes -o jsonpath='{.items[*].metadata.name}')

for node in $NODES; do
    echo "Processing node: $node"
    
    # Drain node
    kubectl drain $node --ignore-daemonsets --delete-emptydir-data --force --timeout=300s
    
    # Get instance ID from node
    INSTANCE_ID=$(kubectl get node $node -o jsonpath='{.spec.providerID}' | sed 's/.*\///')
    
    echo "Terminating instance: $INSTANCE_ID"
    oci compute instance terminate --instance-id $INSTANCE_ID --force
    
    # Wait for new node to be ready
    echo "Waiting for replacement node..."
    while true; do
        READY_NODES=$(kubectl get nodes --no-headers | grep " Ready " | wc -l)
        if [[ $READY_NODES -eq 2 ]]; then
            break
        fi
        echo "Ready nodes: $READY_NODES/2 - waiting..."
        sleep 30
    done
    
    # Wait for Longhorn volumes to be healthy
    echo "Waiting for storage volumes to be healthy..."
    while true; do
        DEGRADED_VOLUMES=$(kubectl get volumes.longhorn.io --all-namespaces --no-headers | grep -c "Degraded" || echo "0")
        if [[ $DEGRADED_VOLUMES -eq 0 ]]; then
            break
        fi
        echo "Degraded volumes: $DEGRADED_VOLUMES - waiting..."
        sleep 30
    done
    
    echo "Node $node upgrade completed"
done

# Fase 6: Verifica post-upgrade
echo "Running post-upgrade verification..."
kubectl get nodes
kubectl get pods --all-namespaces | grep -v Running | grep -v Completed || echo "All pods running correctly"

# Test delle applicazioni critiche
kubectl run upgrade-test --image=busybox --rm -it --restart=Never -- \
    sh -c 'nslookup kubernetes.default.svc.cluster.local'

echo "=== Cluster upgrade completed successfully ==="
echo "New cluster version: $(kubectl version --short)"

Monitoring della Salute del Cluster – Cluster kubernetes gratis su Oracle

#!/bin/bash
# health-check.sh - Monitoraggio continuo del cluster

check_cluster_health() {
    echo "=== Cluster Health Check ==="
    
    # Verifica nodi
    echo "Node Status:"
    kubectl get nodes
    
    # Verifica componenti sistema
    echo -e "\nSystem Pods Status:"
    kubectl get pods -n kube-system | grep -E "(0/|Error|CrashLoopBackOff|Pending)"
    
    # Verifica storage Longhorn
    echo -e "\nLonghorn Status:"
    kubectl get pods -n longhorn-system | grep -E "(0/|Error|CrashLoopBackOff)"
    kubectl get volumes.longhorn.io --all-namespaces | grep -E "(Degraded|Faulted)" || echo "All volumes healthy"
    
    # Verifica certificati
    echo -e "\nCertificate Status:"
    kubectl get certificates --all-namespaces | grep -E "(False|Unknown)" || echo "All certificates valid"
    
    # Verifica risorse
    echo -e "\nResource Usage:"
    kubectl top nodes 2>/dev/null || echo "Metrics server not available"
    
    # Test connettività
    echo -e "\nConnectivity Test:"
    kubectl run connectivity-test --image=busybox --rm -it --restart=Never --timeout=30s -- \
        sh -c 'nslookup kubernetes.default.svc.cluster.local && echo "DNS Resolution: OK"' 2>/dev/null || echo "DNS test failed"
}

# Esecuzione health check
check_cluster_health

# Setup monitoring continuo (opzionale)
if [[ "${1:-}" == "--monitor" ]]; then
    echo "Starting continuous monitoring (every 5 minutes)..."
    while true; do
        sleep 300
        echo -e "\n$(date): Running health check..."
        check_cluster_health
    done
fi

Disaster Recovery e Backup Strategy – Cluster kubernetes gratis su Oracle

Backup Automatizzato con Velero

Velero per backup completo del cluster

yaml# Velero per backup completo del cluster
resource "helm_release" "velero" {
  name       = "velero"
  repository = "https://vmware-tanzu.github.io/helm-charts"
  chart      = "velero"
  namespace  = "velero"
  version    = "5.4.0"

  create_namespace = true

  values = [
    yamlencode({
      # Configurazione per Oracle Object Storage
      configuration = {
        provider = "aws"
        backupStorageLocation = {
          name = "default"
          provider = "aws"
          bucket = "velero-backups"
          config = {
            region = "eu-frankfurt-1"
            s3ForcePathStyle = true
            s3Url = "https://namespace.compat.objectstorage.eu-frankfurt-1.oraclecloud.com"
          }
        }
        volumeSnapshotLocation = {
          name = "default"
          provider = "csi"
        }
      }
      
      # Credentials per Object Storage
      credentials = {
        useSecret = true
        secretContents = {
          cloud = <<-EOT
            [default]
            aws_access_key_id=${var.oci_access_key}
            aws_secret_access_key=${var.oci_secret_key}
          EOT
        }
      }
      
      # Resource optimization per ARM
      resources = {
        limits = {
          cpu = "200m"
          memory = "256Mi"
        }
        requests = {
          cpu = "100m"
          memory = "128Mi"
        }
      }
      
      nodeSelector = {
        "kubernetes.io/arch" = "arm64"
      }
      
      # Backup schedules
      schedules = {
        daily = {
          disabled = false
          schedule = "0 2 * * *"
          template = {
            ttl = "720h" # 30 giorni
            includedNamespaces = ["*"]
            excludedNamespaces = ["kube-system", "velero"]
            snapshotVolumes = true
          }
        }
        
        weekly = {
          disabled = false
          schedule = "0 3 * * 0"
          template = {
            ttl = "2160h" # 90 giorni
            includedNamespaces = ["production", "staging"]
            snapshotVolumes = true
          }
        }
      }
    })
  ]
}

Procedura di Disaster Recovery – Cluster kubernetes gratis su Oracle

#!/bin/bash
# disaster-recovery.sh - Procedura di ripristino completo

set -euo pipefail

BACKUP_NAME="${1:-latest}"
NEW_CLUSTER_NAME="${2:-oke-dr-cluster}"

echo "=== Disaster Recovery Procedure ==="
echo "Backup: $BACKUP_NAME"
echo "Target Cluster: $NEW_CLUSTER_NAME"

# Fase 1: Deploy nuovo cluster
echo "Deploying new cluster infrastructure..."
cd terraform/infra
sed -i.bak "s/cluster_name = \".*\"/cluster_name = \"$NEW_CLUSTER_NAME\"/" terraform.tfvars
terraform apply -var-file="terraform.tfvars" -auto-approve

# Fase 2: Setup Velero sul nuovo cluster
echo "Installing Velero on new cluster..."
export KUBECONFIG="./.kube.config"
helm repo add vmware-tanzu https://vmware-tanzu.github.io/helm-charts
helm install velero vmware-tanzu/velero --namespace velero --create-namespace \
    --set configuration.provider=aws \
    --set configuration.backupStorageLocation.bucket=velero-backups \
    --set configuration.backupStorageLocation.config.region=eu-frankfurt-1

# Fase 3: Restore dal backup
echo "Restoring from backup: $BACKUP_NAME"
if [[ "$BACKUP_NAME" == "latest" ]]; then
    BACKUP_NAME=$(velero backup get -o jsonpath='{.items[0].metadata.name}')
fi

velero restore create restore-$(date +%Y%m%d-%H%M%S) --from-backup $BACKUP_NAME --wait

# Fase 4: Verifica ripristino
echo "Verifying restore..."
kubectl get namespaces
kubectl get pods --all-namespaces | grep -v Running | grep -v Completed || echo "All pods restored successfully"

# Fase 5: Test applicazioni
echo "Testing restored applications..."
kubectl run dr-test --image=busybox --rm -it --restart=Never -- \
    sh -c 'nslookup kubernetes.default.svc.cluster.local'

echo "=== Disaster Recovery completed successfully ==="

Conclusioni e Raccomandazioni per la Formazione IT – Cluster kubernetes gratis su Oracle

L’implementazione di un cluster Kubernetes enterprise-grade su Oracle Cloud Infrastructure Always Free Tier rappresenta un caso studio significativo che dimostra come tecnologie cloud-native possano essere accessibili senza barriere economiche. Tuttavia, la complessità intrinseca di tali architetture distributed computing richiede un approccio metodologico alla formazione del personale tecnico.

Competenze Tecniche Fondamentali – Cluster kubernetes gratis su Oracle

La gestione efficace di cluster Kubernetes multi-tenant richiede competenze multidisciplinari che spaziano dall’ingegneria del software all’architettura delle infrastrutture. Le aree di competenza critica includono:

Container Orchestration e Microservices:

  • Comprensione dei pattern architetturali cloud-native
  • Progettazione di applicazioni stateless e fault-tolerant
  • Implementazione di service mesh per communication security

Infrastructure as Code e DevOps:

  • Padronanza di Terraform per infrastrutture immutable
  • Implementazione di CI/CD pipeline con GitOps
  • Metodologie di testing per infrastrutture (policy-as-code)

Security e Compliance:

  • Zero-trust networking con Network Policies
  • Container image scanning e signature verification
  • Secrets management e certificate lifecycle

Site Reliability Engineering:

  • Observability attraverso metrics, logs, e traces
  • Incident response e post-mortem analysis
  • Capacity planning e performance optimization

Metodologie di Apprendimento Raccomandate

La formazione efficace per ambienti cloud-native deve combinare teoria e pratica attraverso:

Laboratori Hands-on: Implementazione di scenari realistici in ambienti sandbox controllati, permettendo sperimentazione senza rischi operativi.

Chaos Engineering: Introduzione deliberata di failure scenarios per testare resilienza e response capabilities del team.

Game Days: Simulazioni di incident response che coinvolgono cross-functional teams in scenario di crisis management.

Continuous Learning: Aggiornamento costante su evolving best practices attraverso community engagement e certification programs.

Investimento Strategico nella Formazione – Cluster kubernetes gratis su Oracle

Le organizzazioni che investono sistematicamente nella formazione del personale IT ottengono vantaggi competitivi misurabili:

  • Riduzione del Time-to-Market: Team preparati implementano feature più rapidamente e con maggiore qualità
  • Operational Excellence: Riduzione significativa di downtime e security incidents
  • Innovation Capability: Personale formato può adottare nuove tecnologie più rapidamente
  • Risk Mitigation: Competenze interne riducono dipendenza da vendor esterni

La complessità crescente delle architetture cloud-native richiede un approccio proattivo alla formazione. Organizzazioni che considerano la formazione come investimento strategico, piuttosto che costo operativo, sono meglio posizionate per gestire la digital transformation e mantenere competitive advantage in mercati sempre più dinamici.

L’implementazione di questo cluster Kubernetes su Oracle Cloud rappresenta non solo un’opportunità tecnica, ma un catalizzatore per lo sviluppo di competenze advanced che enableranno team IT a gestire progetti di crescente complessità e criticità per il business.

Innovaformazione, scuola informatica specialistica segue costantemente i trend i di mercato ed affianca le aziende nella formazione dei team DevOps e di sviluppatori. Trovate l’offerta formativa a catalogo per i corsi microservices sul nostro sito QUI.

Per altri articoli tecnici consigliamo invece di navigare sul nostro blog QUI.

INFO: info@innovaformazione.net – tel. 3471012275 (Dario Carrassi)

(fonte) (fonte) (fonte) (fonte)

Ti potrebbe interessare

Articoli correlati