/// tutorial · aws · 22 sep 2026

Running containers in the Athens Local Zone

An EKS cluster split across the backbone: control plane in Frankfurt, worker nodes, load balancer, and storage in Athens — with the Terraform for the cluster, node group, ingress, and local S3 access.
/date
22 September 2026
/series
Athens Local Zone · part 4 of 5
/author
Thanasis Politis · Head of Solutions
/// scenario

Most modern production workloads run on container orchestrators rather than standalone virtual machines. In part 2, deploying an Application Load Balancer and an EC2 fleet in the Athens Local Zone (eu-central-1-ath-1a) brought end-to-end latency down to ~11 ms for users in Greece. In part 3, we set up an in-country S3 One Zone-IA directory bucket for workloads with strict data-residency requirements.

Running containers in a Local Zone does not require provisioning a separate, dedicated Kubernetes cluster. Because Kubernetes cleanly separates the control plane from worker nodes, an Amazon EKS cluster can span both locations. AWS runs the managed control plane in Frankfurt (eu-central-1), while worker nodes run in Athens. Workloads serving Greek traffic or accessing in-country storage are scheduled onto Athens nodes using standard node selectors.

This architecture also keeps compute adjacent to the storage configured in part 3: pods processing sensitive records read the local S3 One Zone-IA bucket over an in-zone gateway endpoint, keeping the data path entirely inside Greece.

This is part 4 of a hands-on series. The architecture and Terraform below were tested in a live AWS account against verified Athens Local Zone capabilities and constraints.
/// the_shape_of_it
One EKS cluster, two locationsWorker nodes, ingress, and data in Athens; managed control plane in Frankfurt.Local Zone • eu-central-1-ath-1aAthens • every user request is served hereLoad Balancer (ALB)zonal, Athens subnetEKS worker nodesself-managed · c7i.largeS3 One Zone-IAdirectory bucketHTTPin-zonePods reach the bucket over a gateway VPC endpoint at thezonal s3express endpoint — the object path never leaves the zone.AWS Region • eu-central-1 (Frankfurt)control plane and registryEKS control planemanaged by AWS · no user trafficAmazon ECRimages pull across the backboneone clusterimage pullExisting clusters extend into Athens as an additional node group targeted via nodeSelector.User traffic and local object operations remain inside the zone; only API sync and image pulls cross the backbone.
An EKS cluster spanning Frankfurt and Athens. The managed control plane stays in Frankfurt (eu-central-1), handling cluster API operations and scheduling. Worker nodes, Application Load Balancers, and the S3 directory bucket run in eu-central-1-ath-1a, keeping user-facing requests and local data operations inside Greece.

The separation between the Kubernetes control plane and worker nodes maps directly onto a Local Zone architecture: the Kubernetes API server runs in Frankfurt, while application pods run on EC2 worker nodes in Athens. The kubelet on each Athens node communicates with the EKS API endpoint in Frankfurt across the AWS backbone for node heartbeats and pod lifecycle management, entirely outside the client request path.

The components handling active client traffic remain in the zone: the Application Load Balancer terminating incoming connections, the pods serving requests, and the S3 One Zone-IA directory bucket.

Assigning workloads to Athens requires only standard Kubernetes scheduling primitives. In deployment manifests, target the Local Zone with a nodeSelector:

deployment.yamlyaml
spec:
  template:
    spec:
      nodeSelector:
        topology.kubernetes.io/zone: eu-central-1-ath-1a

Existing deployments and CI/CD workflows remain unchanged except for this placement rule. The steps below walk through provisioning the underlying AWS infrastructure.

/// build_it

Step 1 — Create the EKS cluster using Region subnets

When provisioning an EKS cluster, the subnets passed to aws_eks_cluster must belong to Availability Zones in the parent Region (such as eu-central-1a, eu-central-1b, or eu-central-1c). AWS provisions control plane elastic network interfaces (ENIs) across these subnets to manage the cluster, and EKS does not support placing control plane ENIs in Local Zone subnets. Athens subnets are attached separately as worker node capacity.

cluster.tfhcl
resource "aws_eks_cluster" "athens" {
  name     = "athens-lz"
  role_arn = aws_iam_role.cluster.arn
  version  = "1.31"

  vpc_config {
    # Region subnets only. The Athens subnet is attached later,
    # as a self-managed node group.
    subnet_ids = var.region_subnet_ids
  }

  depends_on = [aws_iam_role_policy_attachment.cluster]
}

Step 2 — Configure a self-managed node group in Athens

EKS Managed Node Groups cannot be provisioned into Local Zones. Instead, compute capacity in eu-central-1-ath-1a is deployed as a self-managed node group: an EC2 Launch Template paired with an Auto Scaling Group placed in the Athens subnet defined in part 1. The node bootstraps using the standard EKS bootstrap script passed through user data.

nodes.tfhcl
data "aws_ssm_parameter" "eks_ami" {
  name = "/aws/service/eks/optimized-ami/1.31/amazon-linux-2023/x86_64/standard/recommended/image_id"
}

resource "aws_launch_template" "athens" {
  name_prefix   = "athens-lz-node-"
  image_id      = data.aws_ssm_parameter.eks_ami.value
  instance_type = "c7i.large"

  block_device_mappings {
    device_name = "/dev/xvda"

    ebs {
      volume_size = 50
      volume_type = "gp3"
      encrypted   = true
    }
  }

  user_data = base64encode(<<-EOT
    #!/bin/bash
    /etc/eks/bootstrap.sh ${aws_eks_cluster.athens.name} \
      --apiserver-endpoint '${aws_eks_cluster.athens.endpoint}' \
      --b64-cluster-ca '${aws_eks_cluster.athens.certificate_authority[0].data}'
  EOT
  )
}

resource "aws_autoscaling_group" "athens" {
  name             = "athens-lz-nodes"
  min_size         = 2
  max_size         = 6
  desired_capacity = 2

  # the Local Zone subnet -- this is what puts the pods in Athens
  vpc_zone_identifier = [aws_subnet.athens.id]

  launch_template {
    id      = aws_launch_template.athens.id
    version = "$Latest"
  }

  tag {
    key                 = "kubernetes.io/cluster/${aws_eks_cluster.athens.name}"
    value               = "owned"
    propagate_at_launch = true
  }
}

Key considerations for the node configuration:

  • Instance types: Athens supports the C7i, M7i, and R7i instance families. For general container workloads, c7i.large provides a solid cost-to-performance baseline.
  • Security group routing & CoreDNS: Ensure the security group assigned to Athens nodes allows bidirectional communication with your cluster security group and any Regional nodes. If CoreDNS replicas run in Frankfurt, Athens pods must reach port 53 (TCP/UDP) across the backbone, or cluster DNS resolution will fail.

Step 3 — Connect pods to the local S3 directory bucket

In part 3, we created an S3 One Zone-IA directory bucket in Athens. Directory buckets use the s3express service namespace: data plane operations route to a zonal endpoint within Athens, while bucket metadata operations route to Frankfurt. Adding a gateway VPC endpoint to the Athens route table routes all object traffic directly to the local endpoint without crossing the backbone or passing through a NAT gateway.

s3-access.tfhcl
resource "aws_vpc_endpoint" "s3express" {
  vpc_id            = aws_vpc.main.id
  service_name      = "com.amazonaws.eu-central-1.s3express"
  vpc_endpoint_type = "Gateway"

  # the Local Zone's own route table
  route_table_ids = [aws_route_table.athens.id]
}

# Directory buckets authorise object access through a session.
data "aws_iam_policy_document" "pod_s3" {
  statement {
    actions   = ["s3express:CreateSession"]
    resources = [aws_s3_directory_bucket.residency.arn]
  }
}

Assign this policy to a Kubernetes ServiceAccount using IAM Roles for Service Accounts (IRSA). The AWS SDK automatically discovers and routes requests to the local zonal endpoint (s3express-euc1-ath1-az1.eu-central-1.amazonaws.com) with no changes required in application logic. Gateway VPC endpoints incur no hourly or data transfer fees.

Step 4 — Route ingress traffic via an in-zone Application Load Balancer

Local Zones support Application Load Balancers deployed directly into the Local Zone subnet. With the AWS Load Balancer Controller running in your cluster, creating an Ingress resource annotated with the Athens subnet provisions a zonal ALB in Athens and registers pod IP addresses as direct targets.

ingress.yamlyaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app
  annotations:
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/subnets: subnet-0athens...   # the Local Zone subnet
spec:
  ingressClassName: alb
  rules:
    - http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: app
                port:
                  number: 80
/// backbone_traffic

Operating a split topology requires accounting for which network flows remain inside Athens and which traverse the Frankfurt backbone.

Control plane communication: Kubelet communication with the EKS API server involves periodic heartbeat signals, state synchronization, and pod status reporting. This traffic is lightweight, occurs over the encrypted AWS backbone, and remains completely out of the end-user request path.

Container image pulls (ECR): Amazon ECR registries operate from the parent Region. When an Athens node pulls an image layer not already present in its local containerd cache, the data transfers across the Frankfurt–Athens link. To minimize pod startup delays and inter-zone bandwidth:

  • Optimize layer caching: Structure container images so base operating system libraries and runtime dependencies remain in stable, cached layers. Deployments then only transfer application binaries or code diffs.
  • Maintain baseline node capacity: Configure Auto Scaling Group minimum thresholds (min_size >= 2) so scaling events schedule pods onto running nodes with cached images, avoiding cold node boots.
  • Pre-pull critical images: For latency-sensitive workloads that scale dynamically, use a lightweight DaemonSet to pre-pull target container images whenever a new node joins the cluster.

Local request and data paths: Client TLS termination, HTTP routing through the ALB, application execution, and S3 directory bucket I/O remain entirely within eu-central-1-ath-1a. Traffic only leaves the zone if application code explicitly calls Regional dependencies like RDS or external APIs.

/// workload_placement

Placement strategy

Workloads should be scheduled between the Athens Local Zone and the Frankfurt Region based on latency sensitivity and compliance requirements:

  • Target Athens (topology.kubernetes.io/zone: eu-central-1-ath-1a): End-user facing APIs, latency-critical web applications serving Greek traffic, and microservices that read or write to in-country S3 buckets.
  • Retain in Frankfurt (eu-central-1): Background batch jobs, queue workers, data analytics pipelines, and services tightly integrated with Region-only managed offerings like Amazon RDS, Amazon Aurora, or ElastiCache.

A single cluster handles both patterns concurrently using node labels, selectors, and taints, avoiding the overhead of maintaining distinct cluster environments.

/// cost_and_operations

Pricing follows standard AWS models: the managed EKS control plane incurs the standard $0.10 per cluster hour, EC2 instances are billed at Athens Local Zone hourly rates, and the ALB incurs standard hourly and LCU charges. The S3 gateway VPC endpoint is free, and in-zone S3 data transfer carries no bandwidth charges.

Operational considerations for production:

  • AMI lifecycle management: Because node groups in Local Zones are self-managed, AMI updates and Kubernetes version upgrades are managed by updating the launch template AMI ID and initiating an Auto Scaling instance refresh.
  • Amazon ECS alternative: ECS is also supported in the Athens Local Zone, but requires EC2 capacity. AWS Fargate is Region-only and cannot place tasks into Local Zone subnets.
  • High availability and failure domains: A Local Zone represents a single Availability Zone (eu-central-1-ath-1a). High-availability architectures should retain a fallback node group in Frankfurt, using weighted DNS routing or pod topology spread to ensure service continuity if the Local Zone experiences an outage.
github.com/Nexxion-ai/aws-athens-local-zone

The complete Terraform definitions for the cluster, launch template, Auto Scaling group, S3 gateway endpoint, and IRSA role, along with the Kubernetes Ingress manifest, are available in the 04-containers directory of the repository. Run terraform destroy to tear down resources when done.

/// free_readiness_assessment

Book a free readiness assessment

In a short working session we help you understand what the Athens Local Zone means for your business. Together we identify:

  • Whether the Local Zone is relevant for your current architecture
  • Which workloads could benefit from the AWS Local Zone in Greece
  • Where data residency, latency, or DR requirements may create new opportunities
  • What the first migration or modernization step could look like

The goal is simple: decide whether the Athens AWS Local Zone matters for your environment — and what to do next.