Running containers in the Athens Local Zone
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.
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:
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.
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.
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.
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.largeprovides 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.
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.
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
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
DaemonSetto 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.
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.
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.
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.
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.