Description
When a Docker image has multiple exposed ports (e.g., from a base image like nginx:alpine which has EXPOSE 80 plus a user-added EXPOSE 8080), hx extracts ports by iterating over a Go map build from the results f docker inspect, resulting in non-deterministic port ordering. Since the deployment uses ports[0], any of the ports might get used.
Steps to Reproduce
- Create a Dockerfile using
nginx:alpine as base (which has EXPOSE 80)
- Add
EXPOSE 8080 to the Dockerfile
- Run
hx deploy multiple times
Expected Behavior
The user-specified port (8080) should be consistently used.
Actual Behavior
Sometimes port 80 is selected, sometimes port 8080, depending on Go's map iteration order at runtime.
Root Cause
In internal/build/service.go, ports are extracted by iterating over inspectData.Config.ExposedPorts:
ports := make([]int, 0)
for port := range inspectData.Config.ExposedPorts {
// ...
ports = append(ports, portInt)
}
Go maps have undefined iteration order (per the spec), so the resulting ports slice has non-deterministic ordering.
Impact
Deployments intermittently fail with errors like:
"The container X did not have a container port 8080 defined"
This happens when a previous deployment used port 8080 (lucky iteration order), but a subsequent deployment creates a task definition with port 80 (unlucky iteration order), causing a mismatch with the existing ECS service load balancer configuration.
Description
When a Docker image has multiple exposed ports (e.g., from a base image like
nginx:alpinewhich hasEXPOSE 80plus a user-addedEXPOSE 8080), hx extracts ports by iterating over a Go map build from the results f docker inspect, resulting in non-deterministic port ordering. Since the deployment usesports[0], any of the ports might get used.Steps to Reproduce
nginx:alpineas base (which hasEXPOSE 80)EXPOSE 8080to the Dockerfilehx deploymultiple timesExpected Behavior
The user-specified port (8080) should be consistently used.
Actual Behavior
Sometimes port 80 is selected, sometimes port 8080, depending on Go's map iteration order at runtime.
Root Cause
In
internal/build/service.go, ports are extracted by iterating overinspectData.Config.ExposedPorts:Go maps have undefined iteration order (per the spec), so the resulting
portsslice has non-deterministic ordering.Impact
Deployments intermittently fail with errors like:
This happens when a previous deployment used port 8080 (lucky iteration order), but a subsequent deployment creates a task definition with port 80 (unlucky iteration order), causing a mismatch with the existing ECS service load balancer configuration.