detached bae2d02

fix: ensure label port in container bindings, improve docs

- Add labeled proxy port to ContainerConfig.Ports if missing from
  EXPOSE directives, so Docker creates the host port binding
- Update auto-route docs to describe HTTP-port preference fallback
- Add propagated image labels subsection to docker-labels reference
- Update docker inspect example to show gordon.proxy.port
commit
bae2d02b6ad22eb5687e7795fc6f452e792c4fb4
author
brice · · 2026-03-15 08:42 UTC
parent
5dc1b42
signature
unsigned
3 files · +25 -2
M docs/config/auto-route.md +1 -1
@@ -203,7 +203,7 @@ When you push an image with Gordon labels:
203203
204204 1. Gordon reads the `gordon.domains` label
205205 2. Creates routes for each domain automatically
206-3. Uses `gordon.proxy.port` for the proxy target (or first EXPOSE port)
206+3. Uses `gordon.proxy.port` for the proxy target, otherwise auto-detects an exposed port preferring common HTTP ports
207207 4. Configures health checks if `gordon.health` is set
208208 5. Extracts environment variables from `gordon.env-file` if specified
209209
@@ -203,7 +203,7 @@ When you push an image with Gordon labels:
203 203
204 1. Gordon reads the `gordon.domains` label204 1. Gordon reads the `gordon.domains` label
205 2. Creates routes for each domain automatically205 2. Creates routes for each domain automatically
206-3. Uses `gordon.proxy.port` for the proxy target (or first EXPOSE port)206+3. Uses `gordon.proxy.port` for the proxy target, otherwise auto-detects an exposed port preferring common HTTP ports
207 4. Configures health checks if `gordon.health` is set207 4. Configures health checks if `gordon.health` is set
208 5. Extracts environment variables from `gordon.env-file` if specified208 5. Extracts environment variables from `gordon.env-file` if specified
209 209
M docs/reference/docker-labels.md +12 -0
@@ -14,6 +14,17 @@ Gordon adds these labels to managed containers:
1414 | `gordon.route` | Domain name | Route this container handles |
1515 | `gordon.created` | Timestamp | When Gordon created the container |
1616
17+### Propagated Image Labels
18+
19+When an image defines these labels, Gordon copies them onto the container for runtime use (readiness probing, proxy routing):
20+
21+| Label | Example | Description |
22+|-------|---------|-------------|
23+| `gordon.proxy.port` | `"3000"` | Port the proxy routes HTTP traffic to |
24+| `gordon.health` | `"/healthz"` | Health check endpoint for readiness probing |
25+
26+These labels only appear on containers whose source image defined them.
27+
1728 ### Attachment Labels
1829
1930 Additional labels for attachment containers:
@@ -107,6 +118,7 @@ Example output:
107118 "gordon.domain": "app.mydomain.com",
108119 "gordon.image": "myapp:latest",
109120 "gordon.managed": "true",
121+ "gordon.proxy.port": "3000",
110122 "gordon.route": "app.mydomain.com"
111123 }
112124 ```
@@ -14,6 +14,17 @@ Gordon adds these labels to managed containers:
14 | `gordon.route` | Domain name | Route this container handles |14 | `gordon.route` | Domain name | Route this container handles |
15 | `gordon.created` | Timestamp | When Gordon created the container |15 | `gordon.created` | Timestamp | When Gordon created the container |
16 16
17+### Propagated Image Labels
18+
19+When an image defines these labels, Gordon copies them onto the container for runtime use (readiness probing, proxy routing):
20+
21+| Label | Example | Description |
22+|-------|---------|-------------|
23+| `gordon.proxy.port` | `"3000"` | Port the proxy routes HTTP traffic to |
24+| `gordon.health` | `"/healthz"` | Health check endpoint for readiness probing |
25+
26+These labels only appear on containers whose source image defined them.
27+
17 ### Attachment Labels28 ### Attachment Labels
18 29
19 Additional labels for attachment containers:30 Additional labels for attachment containers:
@@ -107,6 +118,7 @@ Example output:
107 "gordon.domain": "app.mydomain.com",118 "gordon.domain": "app.mydomain.com",
108 "gordon.image": "myapp:latest",119 "gordon.image": "myapp:latest",
109 "gordon.managed": "true",120 "gordon.managed": "true",
121+ "gordon.proxy.port": "3000",
110 "gordon.route": "app.mydomain.com"122 "gordon.route": "app.mydomain.com"
111 }123 }
112 ```124 ```
M internal/usecase/container/service.go +12 -1
@@ -241,10 +241,21 @@ func (s *Service) buildContainerConfig(in containerConfigInput) *domain.Containe
241241 }
242242 }
243243
244+ // Ensure the label-specified proxy port is included in exposed ports
245+ // so Docker creates a host port binding for it.
246+ ports := in.ExposedPorts
247+ if portStr, ok := labels[domain.LabelProxyPort]; ok {
248+ if port, err := strconv.Atoi(portStr); err == nil && port > 0 && port <= 65535 {
249+ if !slices.Contains(ports, port) {
250+ ports = append(ports, port)
251+ }
252+ }
253+ }
254+
244255 return &domain.ContainerConfig{
245256 Image: in.ImageRef,
246257 Name: containerName,
247- Ports: in.ExposedPorts,
258+ Ports: ports,
248259 Env: in.EnvVars,
249260 Volumes: in.Volumes,
250261 NetworkMode: in.NetworkName,
@@ -241,10 +241,21 @@ func (s *Service) buildContainerConfig(in containerConfigInput) *domain.Containe
241 }241 }
242 }242 }
243 243
244+ // Ensure the label-specified proxy port is included in exposed ports
245+ // so Docker creates a host port binding for it.
246+ ports := in.ExposedPorts
247+ if portStr, ok := labels[domain.LabelProxyPort]; ok {
248+ if port, err := strconv.Atoi(portStr); err == nil && port > 0 && port <= 65535 {
249+ if !slices.Contains(ports, port) {
250+ ports = append(ports, port)
251+ }
252+ }
253+ }
254+
244 return &domain.ContainerConfig{255 return &domain.ContainerConfig{
245 Image: in.ImageRef,256 Image: in.ImageRef,
246 Name: containerName,257 Name: containerName,
247- Ports: in.ExposedPorts,258+ Ports: ports,
248 Env: in.EnvVars,259 Env: in.EnvVars,
249 Volumes: in.Volumes,260 Volumes: in.Volumes,
250 NetworkMode: in.NetworkName,261 NetworkMode: in.NetworkName,

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close