DEV Community

Cover image for Day 43: A Port Is Closed Until You Publish It, and an AZ Name Is Not an AZ
Nnamdi Felix Ibe
Nnamdi Felix Ibe

Posted on AI-assisted

Day 43: A Port Is Closed Until You Publish It, and an AZ Name Is Not an AZ

Today both tasks turned on reading a label correctly. A port number on the host is not the port inside the container, and they do not have to match. An availability zone name is not the availability zone, and in someone else's account it points somewhere else entirely.

One Docker task, one AWS task. Publish a container port on a different host port, then provision an EKS control plane. The tasks come from the KodeKloud Engineer platform.

Publishing, and the direction of the colon

docker pull nginx:stable
docker run -d --name demo -p 6000:80 nginx:stable
curl http://localhost:6000
Enter fullscreen mode Exit fullscreen mode

Host first, container second. -p 6000:80 listens on 6000 on the host and forwards to 80 inside. Reverse it and you get a host listening on 80, forwarding to a container port nothing is bound to, and a connection that opens and returns nothing.

The two numbers are independent, which is the part worth internalising. nginx is still on 80 inside the container and has no idea the host calls it 6000. Nothing in the image changes to publish it elsewhere.

And without -p the container is not broken, it is just not reachable from outside. Docker puts it plainly: ports on bridge networks are accessible from the Docker host and from other containers on the same network, and are not accessible from outside the host or, by default, from containers on other networks.

That splits cleanly against yesterday's task. The network decides which containers can see each other. Publishing decides whether the host's port space does. Two different questions, and EXPOSE in a Dockerfile answers neither, since it only documents which port the application listens on.

One habit worth forming early: -p 127.0.0.1:6000:80 binds to loopback only. Plain -p 6000:80 binds on every interface, which on a public host means the internet.

The error names a zone that does not generalise

The EKS task was a control plane to a specific configuration. Named cluster, latest stable Kubernetes, default VPC, three availability zones, Auto Mode off, private endpoint.

Passing all six subnets in the default VPC produced this:

Cannot create cluster because EKS does not support creating control plane instances in us-east-1e
Enter fullscreen mode Exit fullscreen mode

Clear enough, and I nearly wrote it down as the rule. It is not the rule.

AWS documents the restriction against availability zone IDs, not zone names. Subnets cannot sit in use1-az3 in us-east-1, usw1-az2 in us-west-1, or cac1-az3 in ca-central-1. Zone names are mapped to zone IDs independently per account, so us-east-1e is this account's name for use1-az3, and in your account use1-az3 may well be called something else.

Which means "avoid us-east-1e" is a note that works in exactly one account and silently avoids the wrong zone everywhere else. The portable version:

aws ec2 describe-availability-zones --query 'AvailabilityZones[].{Name:ZoneName,Id:ZoneId}'
Enter fullscreen mode Exit fullscreen mode

This is the kind of thing that only shows up when you go and read the documentation for something you already appeared to understand. The error told me the truth about my account and nothing about the rule.

Shorthand cannot hold a list inside a struct

--resources-vpc-config subnetIds=subnet-a,subnet-b,subnet-c,endpointPublicAccess=false
Enter fullscreen mode Exit fullscreen mode

AWS CLI shorthand separates struct fields with commas. It also separates list items with commas. So that string is genuinely ambiguous, and the parser cannot tell where subnetIds ends and the next field begins.

JSON removes the question:

--resources-vpc-config "{\"subnetIds\":[$SUBNET_JSON],\"endpointPublicAccess\":false,\"endpointPrivateAccess\":true}"
Enter fullscreen mode Exit fullscreen mode

That is now the third list convention in this challenge. elbv2 create-load-balancer --subnets wants spaces. ecs create-service wants commas inside brackets. eks create-cluster wants a JSON array. There is no rule, only the habit of checking, and the working heuristic is to reach for JSON the moment a struct contains a list.

Two smaller things, and one honest caveat

Resolve the version rather than hardcoding it. aws eks describe-cluster-versions returns what is currently valid, and Kubernetes ships three minor releases a year, so a hardcoded version is wrong within months. Same habit as SSM parameters for AMIs and orderable instance options for RDS engine versions: ask AWS what is valid now.

The service principal for an EKS cluster role is eks.amazonaws.com. That is the fourth different principal in this run, after lambda.amazonaws.com, ec2.amazonaws.com and ecs-tasks.amazonaws.com. Mostly it is <service>.amazonaws.com, with ECS as the exception. A wrong one gives you a role that looks right in the console and can never be assumed.

And the caveat, because the task says "ready for workloads" and that sentence is doing some work. The cluster is ACTIVE and has no compute attached. No managed node group, no Fargate profile, nothing. Schedule a pod today and it sits Pending forever with no nodes available. That is the correct scope, since the task specified nothing about nodes and inventing a node group would have been inventing requirements. But ACTIVE is not schedulable, and the node role that comes next needs three managed policies and is a different role from the cluster role.

Labels are not the things they label

6000 on the host and 80 in the container are the same service under two names. us-east-1e and use1-az3 are one zone under two names, one of which travels and one of which does not.

The port case is harmless because you chose both numbers. The zone case is not, because the name was chosen for you, per account, and the error message hands you the local one as though it were universal.

So here is the Day 43 question. The last error message you turned into a rule, was it telling you about the system, or about your particular instance of it?

Day 43 down. Fifty-seven to go.

Top comments (0)