Advanced

Kubernetes for Developers: Moving to the Cloud

Run Kubernetes effectively in the cloud and deploy to Amazon EKS, Azure AKS and Google GKE.

Prerequisites: Basic Kubernetes knowledge, kubectl, containerized architecture, cloud account access


Table of Contents

  1. Course Overview
  2. Running Kubernetes Effectively in the Cloud
  3. Determining What You Need to Build
  4. Hands-On: The Tools
  5. Deployment on Amazon EKS
  6. Deployment on Azure AKS
  7. Deployment on Google GKE
  8. Evaluating Your Options
  9. Architecture Diagrams
  10. Cloud Provider Comparison Tables
  11. Command Reference

1. Course Overview

This course covers deploying and managing a managed Kubernetes cluster in the cloud:

  • Creating Kubernetes clusters in the cloud with Terraform
  • Deploying a Helm chart
  • Comparing cloud approaches: AWS EKS, Azure AKS, Google GKE

Running Kubernetes on a cloud managed service allows you to:

  • Simplify operations (no control plane management)
  • Reduce maintenance costs
  • Improve performance and stability

2. Running Kubernetes Effectively in the Cloud

What is the Cloud?

Running in the cloud means operating your application on a cloud service provider’s infrastructure. Providers manage:

  • Physical data center security (power, cooling)
  • Machines, switches, routers, firewalls, and internet bandwidth
  • 24/7/365 staff to monitor and maintain all resources

Key Cloud Advantages

AdvantageDescription
AgilityImmediate access to a wide range of services — hours instead of weeks
ElasticityAutomatic scale up/down based on load, without overprovisioning
Cost savingsPay-as-you-go model, no hardware CAPEX
Global reachRegions and availability zones worldwide

Interacting with the Cloud

MethodAdvantagesDisadvantages
Web ConsoleEasy access, defaults, wizardsSlow (too many clicks), hard to document and reproduce
CLI (aws, az, gcloud)Scriptable, reproducibleService/provider specific
SDKProgrammatic integrationCode complexity
Infrastructure as Code (IaC)Declarative, versionable, multi-providerInitial learning curve

Terraform allows declaring desired infrastructure in HCL files with patterns similar across cloud providers.


3. Determining What You Need to Build

What’s Included by Default

Decision points when creating the cluster:

  • Kubernetes version: providers may not have the latest version
  • Network configuration: node IP assignments, compatibility with other resources

Additional Services to Configure

ServiceRole
Cluster AutoscalerAdds/removes nodes based on pod count
Ingress ControllerManages incoming traffic to the cluster
Secrets ManagerManages secrets for cluster operations
Certificate ManagerCreates and renews TLS certificates
External DNSCreates routable endpoints with custom domain names
Container RegistryImage repository for deployments

Scale Levels

Trying it out
  └─ Simple cluster with defaults → Familiarization
  
Proof of Concept (PoC)
  └─ Dedicated cluster in a single account → Experimentation
  
Production-grade
  └─ Multi-region, multi-account, high availability → Critical infrastructure

Environment Management Strategies

ApproachDescriptionIsolation
3 distinct accountsOne cluster per cloud accountMaximum
3 clusters in same accountLogical separationStrong
1 cluster with 3 namespacesK8s namespace separationLight

4. Hands-On: The Tools

Required Tools

ToolUsageVerification Command
Terraform 1.5.5Infrastructure as Codeterraform -v
kubectlCluster administrationkubectl version --client
AWS CLI (aws)EKS interactionaws --version
Azure CLI (az)AKS interactionaz -v
Google Cloud CLI (gcloud)GKE interactiongcloud -v
HelmKubernetes package managerhelm version

5. Deployment on Amazon EKS

EKS = Elastic Kubernetes Service (AWS)

CLI Authentication

aws configure
# Access Key ID: <your-access-key>
# Secret Access Key: <your-secret-key>
# Default region name: us-east-1
# Default output format: json

aws eks list-clusters

Terraform — main.tf for EKS

provider "aws" {
  region = var.region
}

data "aws_availability_zones" "available" {
  filter {
    name   = "opt-in-status"
    values = ["opt-in-not-required"]
  }
}

locals {
  cluster_name = "my-eks-cluster"
}

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "5.1.2"

  name = "kube-vpc"
  cidr = "10.0.0.0/16"
  azs  = slice(data.aws_availability_zones.available.names, 0, 3)

  private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
  public_subnets  = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]

  enable_nat_gateway   = true
  single_nat_gateway   = true
  enable_dns_hostnames = true

  public_subnet_tags = {
    "kubernetes.io/cluster/${local.cluster_name}" = "shared"
    "kubernetes.io/role/elb"                      = 1
  }

  private_subnet_tags = {
    "kubernetes.io/cluster/${local.cluster_name}" = "shared"
    "kubernetes.io/role/internal-elb"             = 1
  }
}

module "eks" {
  source  = "terraform-aws-modules/eks/aws"
  version = "19.16.0"

  cluster_name    = local.cluster_name
  cluster_version = "1.27"
  cluster_endpoint_public_access = true

  vpc_id     = module.vpc.vpc_id
  subnet_ids = module.vpc.private_subnets

  eks_managed_node_groups = {
    one = {
      name           = "node-group-1"
      instance_types = ["t3.small"]
      min_size       = 1
      max_size       = 3
      desired_size   = 2
    }
    two = {
      name           = "node-group-2"
      instance_types = ["t3.medium"]
      min_size       = 1
      max_size       = 2
      desired_size   = 1
    }
  }
}

Helm Provider for EKS

provider "helm" {
  kubernetes {
    host                   = module.eks.cluster_endpoint
    cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data)
    exec {
      api_version = "client.authentication.k8s.io/v1beta1"
      args        = ["eks", "get-token", "--cluster-name", local.cluster_name]
      command     = "aws"
    }
  }
}

resource "helm_release" "hello_kubernetes" {
  name       = "my-hello-kubernetes"
  repository = "https://helmcharts.opsmx.com/"
  chart      = "hello-kubernetes"
}

Deploy the Cluster

terraform init
terraform plan
terraform apply -auto-approve

Configure kubectl (AWS)

aws eks --region $(terraform output -raw region) update-kubeconfig \
  --name $(terraform output -raw cluster_name)

kubectl get pods --all-namespaces
kubectl get nodes

Deploy Helm Chart on EKS

helm repo add opsmx https://helmcharts.opsmx.com/
helm install my-hello-kubernetes opsmx/hello-kubernetes --version 1.0.3

helm list
kubectl get services
# External IP allows browser access (AWS auto-creates a Load Balancer)

helm uninstall my-hello-kubernetes

AWS Cleanup

terraform destroy
aws eks list-clusters

6. Deployment on Azure AKS

AKS = Azure Kubernetes Service

CLI Authentication

az upgrade
az login --allow-no-subscriptions

# Create service principal for Terraform
az ad sp create-for-rbac -n aksdemo --skip-assignment
# Copy appId and password to terraform.tfvars

az aks list

Terraform — main.tf for AKS

provider "azurerm" {
  features {}
}

locals {
  cluster_name = "my-aks-cluster"
}

resource "azurerm_resource_group" "default" {
  name     = "${local.cluster_name}-rg"
  location = "East US"
}

resource "azurerm_kubernetes_cluster" "default" {
  name                = local.cluster_name
  location            = azurerm_resource_group.default.location
  resource_group_name = azurerm_resource_group.default.name
  dns_prefix          = "${local.cluster_name}-k8s"
  kubernetes_version  = "1.27.3"

  default_node_pool {
    name            = "default"
    node_count      = 2
    vm_size         = "standard_b2s"
    os_disk_size_gb = 30
  }

  service_principal {
    client_id     = var.appId
    client_secret = var.password
  }

  role_based_access_control_enabled = true
}

resource "azurerm_kubernetes_cluster_node_pool" "additional" {
  name                  = "second"
  kubernetes_cluster_id = azurerm_kubernetes_cluster.default.id
  vm_size               = "standard_b2ms"
  node_count            = 2
}

Configure kubectl (Azure)

az aks get-credentials \
  --resource-group $(terraform output -raw resource_group_name) \
  --name $(terraform output -raw kubernetes_cluster_name)

kubectl get pods --all-namespaces
kubectl get nodes

Azure Cleanup

terraform destroy
az aks list

7. Deployment on Google GKE

GKE = Google Kubernetes Engine

CLI Authentication

gcloud init
gcloud auth application-default-login
# Enable in Google Cloud Console: Compute Engine API, Kubernetes Engine API

gcloud container clusters list

Terraform — main.tf for GKE

data "google_client_config" "default" {}

resource "google_container_cluster" "primary" {
  name     = "my-gke-cluster"
  project  = var.project
  location = var.region
  remove_default_node_pool = true
  initial_node_count       = 1

  networking_mode   = "VPC_NATIVE"
  ip_allocation_policy {}
}

resource "google_container_node_pool" "primary_nodes" {
  project    = var.project
  name       = "primary-node-pool"
  location   = var.region
  cluster    = google_container_cluster.primary.name
  node_count = 1

  node_config {
    machine_type = "e2-small"
    disk_size_gb = 30
    oauth_scopes = [
      "https://www.googleapis.com/auth/logging.write",
      "https://www.googleapis.com/auth/monitoring",
    ]
  }
}

resource "google_container_node_pool" "secondary_nodes" {
  project    = var.project
  name       = "secondary-node-pool"
  location   = var.region
  cluster    = google_container_cluster.primary.name
  node_count = 1

  node_config {
    machine_type = "e2-medium"
    disk_size_gb = 30
    oauth_scopes = [
      "https://www.googleapis.com/auth/logging.write",
      "https://www.googleapis.com/auth/monitoring",
    ]
  }
}

Helm Provider for GKE

provider "helm" {
  kubernetes {
    host                   = "https://${google_container_cluster.primary.endpoint}"
    token                  = data.google_client_config.default.access_token
    cluster_ca_certificate = base64decode(google_container_cluster.primary.master_auth.0.cluster_ca_certificate)
  }
}

resource "helm_release" "hello_kubernetes" {
  name       = "my-hello-kubernetes"
  repository = "https://helmcharts.opsmx.com/"
  chart      = "hello-kubernetes"
  depends_on = [google_container_cluster.primary]
}

Configure kubectl (GKE)

gcloud components install gke-gcloud-auth-plugin

gcloud container clusters get-credentials \
  $(terraform output -raw kubernetes_cluster_name) \
  --region $(terraform output -raw region)

kubectl get pods --all-namespaces
kubectl get nodes

GKE Cleanup

terraform destroy
gcloud container clusters list

8. Evaluating Your Options

Complementary Services

ProviderNative IaCContainer Registry
AWSCloudFormationAmazon ECR
AzureAzure Resource Manager (ARM)Azure Container Registry (ACR)
Google CloudCloud Deployment ManagerArtifact Registry

Cost Considerations

CategoryDetail
StorageBased on performance needs and size
Node typesBalance cost/performance per workload
Spot/Preemptible instancesSignificant savings — ideal for K8s since node failures are handled automatically
Commitment plansDiscounts for reserved usage

Advice: Mastering one cloud provider in depth lets you leverage services designed to work together, bringing simplicity and efficiency.


9. Architecture Diagrams

General Architecture: Managed Kubernetes in the Cloud

graph TB
    subgraph Cloud["Cloud Provider (AWS / Azure / GCP)"]
        subgraph Network["Network (VPC / VNet)"]
            subgraph ManagedK8s["Managed Kubernetes (EKS / AKS / GKE)"]
                CP["Control Plane\n(managed by provider)"]
                subgraph NodeGroup1["Node Group 1"]
                    N1["Node 1"] 
                    N2["Node 2"]
                end
                subgraph NodeGroup2["Node Group 2"]
                    N3["Node 3"]
                end
                subgraph Pods["Pods"]
                    APP1["App Pod 1"]
                    APP2["App Pod 2"]
                end
            end
            LB["Load Balancer\n(External IP)"]
            REG["Container Registry"]
        end
    end
    
    DEV["Developer"] -->|kubectl / Helm| CP
    TF["Terraform"] -->|terraform apply| CP
    INTERNET["Internet"] --> LB
    LB --> Pods
    Pods -->|pull images| REG

Migration Flow: Local → Cloud

flowchart LR
    subgraph Local["Local / On-premise"]
        L1["Docker local"]
        L2["minikube / kind"]
        L1 --> L2
    end

    subgraph IaC["Infrastructure as Code"]
        T1["Terraform .tf files"]
        T2["terraform apply"]
        T1 --> T2
    end

    subgraph CloudK8s["Managed Cloud K8s"]
        C1["Cluster created\n(EKS / AKS / GKE)"]
        C2["Node Groups configured"]
        C3["kubeconfig generated"]
        C4["Helm Charts deployed"]
        C1 --> C2 --> C3 --> C4
    end

    Local --> IaC
    IaC --> CloudK8s
    CloudK8s --> DONE["Application online"]

10. Cloud Provider Comparison Tables

Managed Kubernetes Service Comparison

FeatureAWS EKSAzure AKSGoogle GKE
Service nameElastic Kubernetes ServiceAzure Kubernetes ServiceGoogle Kubernetes Engine
CLIaws eksaz aksgcloud container
kubeconfigupdate-kubeconfigget-credentialsget-credentials
Auth pluginBuilt-inBuilt-ingke-gcloud-auth-plugin
Container RegistryAmazon ECRAzure ACRGoogle Artifact Registry
Native IaCCloudFormationARM TemplatesCloud Deployment Manager
IaC moduleterraform-aws-modules/eksazurerm_kubernetes_clustergoogle_container_cluster

11. Command Reference

General Kubectl

kubectl get pods --all-namespaces
kubectl get nodes
kubectl get services
kubectl get deployments
kubectl describe pod <pod-name>
kubectl logs <pod-name>

Helm

helm repo add opsmx https://helmcharts.opsmx.com/
helm repo update
helm search repo hello-kubernetes
helm install my-release opsmx/hello-kubernetes
helm list
helm uninstall my-release

AWS EKS

aws configure
aws eks list-clusters
aws eks --region $(terraform output -raw region) update-kubeconfig \
  --name $(terraform output -raw cluster_name)

Azure AKS

az upgrade
az login --allow-no-subscriptions
az aks list
az aks get-credentials \
  --resource-group $(terraform output -raw resource_group_name) \
  --name $(terraform output -raw kubernetes_cluster_name)

Google Cloud GKE

gcloud init
gcloud auth application-default-login
gcloud container clusters list
gcloud components install gke-gcloud-auth-plugin
gcloud container clusters get-credentials \
  $(terraform output -raw kubernetes_cluster_name) \
  --region $(terraform output -raw region)

Key Concepts

  • Toil (SRE): manual, repetitive, automatable work — reduce via IaC and automation
  • Managed Kubernetes: cloud provider manages the control plane, you manage worker nodes and workloads
  • Terraform state: always manage resources via Terraform to maintain declared state consistency
  • Node Pool: group of nodes sharing the same configuration (instance type, disk size, labels)
  • Helm: K8s package manager — prefer managing via Terraform for IaC consistency
  • kubeconfig: configuration file generated by the provider CLI to connect kubectl to the cloud cluster

Search Terms

kubernetes · developers · moving · cloud · containers · gke · eks · azure · configure · helm · kubectl · aks · authentication · aws · cleanup · cli · deployment · main.tf · provider · terraform · architecture · comparison · deploy · google

Interested in this course?

Contact us to book it or get a custom training plan for your team.