"port is missing" for one container image but EXPOSE hasn't changed

Problem statement
one version of a container is working fine, the next version of the container throws the error "port is missing." The EXPOSE line of the Dockerfile hasn't changed and I'm not really sure where this bug is coming from.

Version info

$ docker --version
Docker version 26.1.2, build 211e74b
# traefik version
Version:      3.0.0
Codename:     beaufort
Go version:   go1.22.2
Built:        2024-04-29T14:25:59Z
OS/Arch:      linux/amd64

Other relevant details
method: docker compose
image that works: ghcr.io/esphome/esphome:2024.5.0
image that doesn't: ghcr.io/esphome/esphome:2024.5.1

$ docker inspect --format='{{.Config.ExposedPorts}}' ghcr.io/esphome/esphome:2024.5.1
map[6052/tcp:{}]

$ docker inspect --format='{{.Config.ExposedPorts}}' ghcr.io/esphome/esphome:2024.5.0
map[6052/tcp:{}]
$ grep -n 'image' compose/esphome.yml
3:    image: ghcr.io/esphome/esphome:2024.5.0
$ docker compose up -d
# no errors in traefik, everything works
$ sed -i 's/2024.5.0/2024.5.1/' compose/esphome.yml
$ grep -n 'image' compose/esphome.yml
3:    image: ghcr.io/esphome/esphome:2024.5.1
$ docker compose up -d
$ docker logs --tail 1 traefik
2024-05-20T12:35:31Z ERR error="service \"esphome-docker\" error: port is missing" container=esphome-docker-6c119f88f5a7100d1402f724a56ca0a1e2135b36cb3328afc2a11add38530159 providerName=docker

Compose file for ESPHome

services:
  esphome:
    image: ghcr.io/esphome/esphome:2024.5.0
    container_name: esphome
    hostname: esphome
    env_file:
      - ${SECRETS}/.env.esphome
    environment:
      - USERNAME
      - PASSWORD
    volumes:
      - ${DOCKER_APPDATA}/esphome:/config
      - /etc/localtime:/etc/localtime:ro
    ports:
      - 6052:6052
    restart: unless-stopped
    networks:
      traefik_proxy: {}
      macvlan:
        ipv4_address: 192.168.10.101
    labels:
      - "traefik.enable=true"
      - "com.centurylinklabs.watchtower.enable=true"

compose file for traefik:

services:
  traefik:
    container_name: traefik
    image: traefik:latest
    restart: unless-stopped
    domainname: ${DOMAINNAME}
    networks:
      - default
      - traefik_proxy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ${DOCKER_APPDATA}/traefik/config:/etc/traefik
    env_file:
      - ${SECRETS}/.env.traefik
    environment:
      - DUCKDNS_TOKEN
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.api.middlewares=traefik-basic-auth"
      - "traefik.http.routers.api.service=api@internal"
      - "traefik.http.middlewares.traefik-basic-auth.basicauth.users=${BASIC_AUTH}"
      - "traefik.http.middlewares.traefik-basic-auth.basicauth.removeheader=true"

      # Traefik Forward Auth (OAuth)
      - "traefik.http.middlewares.traefik-forward-auth.forwardauth.address=http://traefik-forward-auth:4181"
      - "traefik.http.middlewares.traefik-forward-auth.forwardauth.authResponseHeaders=X-Forwarded-User"
      - "com.centurylinklabs.watchtower.enable=true"

docker-compose.yml

include:
  - compose/esphome.yml
  - compose/traefik.yml

networks:
  traefik_proxy:
    external: true
    name: traefik_proxy
  default:
    driver: bridge
  macvlan:
    driver: macvlan
    driver_opts:
      parent: eno1
    ipam:
      config:
        - subnet: 192.168.10.0/24

Why do you open port 6052 on esphome service? That way any potential Traefik security middlewares can be circumvented.

Also I don't see any Traefik router/service declared on esphome. Have you tried to declare the port to use?

From simple Traefik example:

  whoami:
    image: traefik/whoami:v1.10
    networks:
      - proxy
    labels:
      - traefik.enable=true
      - traefik.http.routers.mywhoami.rule=Host(`whoami.example.com`) || Host(`www.whoami.example.com`)
      - traefik.http.services.mywhoami.loadbalancer.server.port=80

Note that you should set docker.network with providers.docker or the dynamic router when using multiple Docker networks.

You don't show your Traefik static config.

yeah, that's fine. it's not exposed at the edge. it was declared just for testing.

sorry about that! here's my static config. I want to preface this by saying that everything (else) is working how I'd like it. If I declare the port with the service it works but I'd prefer not to. I'm using the defaults in the docker provider and port detection should be working (Traefik Docker Documentation - Traefik). What I don't understand is why the port detection isn't working when there is only a single port exposed. I don't see any changes between the two Dockerfiles for ESPHome version 2024.5.0 and 2024.5.1 that would cause this. There's still a single port being EXPOSE'd (line 14: 2024.5.0; 2024.5.1).

global:
  checkNewVersion: true
  sendAnonymousUsage: true
serversTransport:
  insecureSkipVerify: true
entryPoints:
  http:
    address: :80
    http:
      redirections:
        entrypoint:
          to: https
          scheme: https
  https:
    address: :443
    asDefault: true
    proxyProtocol:
      trustedIPs:
        - "192.168.0.0/16"
        - "172.16.0.0/12"
    forwardedHeaders:
      trustedIPs:
        - "192.168.0.0/16"
        - "172.16.0.0/12"
    http:
      tls:
        certResolver: default
providers:
  providersThrottleDuration: 2s
  docker:
    defaultRule: "Host(`{{ index .Labels \"com.docker.compose.service\" }}.example.com`)"
    exposedByDefault: false
    network: traefik_proxy
    watch: true
    endpoint: unix:///var/run/docker.sock
  file:
    directory: /etc/traefik/dynamic
api:
  dashboard: true
log:
  level: DEBUG
certificatesResolvers:
  default:
    acme:
      email: myemail
      storage: /etc/traefik/acme/acme.json
      dnsChallenge:
        provider: my_provider
        delayBeforeCheck: 10s

my dynamic config:

http:
  routers:
    obico:
      rule: Host(`obico.example.com`)
      service: obico
      tls: true
      entrypoints:
        - https

  services:
    obico:
      loadBalancer:
        servers:
          - url: http://192.168.10.104:3334

I noticed the same, a container with EXPOSE that never required an explicit port now fails with missing port. Adding an explicit port makes the error go away. Could it be the 3.0.2 update from 10 June?

In this specific case the container is bound to two networks, docker default, and macvlan.

I quickly tested with simple Traefik example, removed explicit port (loadbalancer.server.port), worked without error.

can you try with image: ghcr.io/esphome/esphome:2024.5.0 and image: ghcr.io/esphome/esphome:2024.5.1? as I said in the original post it isn't happening for all containers.

ghcr.io/esphome/esphome:2024.5.1

works for me without explicit port, with fresh pulled traefik:latest.

I tried to repro using whoami, and I got it to report the same error, but it is not reliably repeatable.

services:

  whoami:
    image: docker.io/traefik/whoami # EXPOSE 80
    container_name: whoami-test
    domainname: home.insanegenius.net
    restart: unless-stopped
    user: 1001:100 #nonroot:users
    #ports:
    #  - 80:8080
    networks:
      aaa_publicnet: # macvlan
        ipv4_address: 192.168.1.10 # test.home.insanegenius.net/192.168.1.10
      localnet: # bridge
    labels:
      - traefik.enable=true
      - traefik.http.routers.whoami-test.rule=Host(`test-web.home.insanegenius.net`) #address=/test-web.home.insanegenius.net/192.168.1.34

networks:
  aaa_publicnet:
    external: true
  localnet:
    external: true

# docker compose --file whoami-test.yml up --detach
# docker compose --file whoami-test.yml down

# 2024-06-11T02:05:51-07:00 INF Traefik version 3.0.2 built on 2024-06-10T14:38:51Z version=3.0.2
# 2024-06-16T08:42:33-07:00 ERR error="service \"whoami-pieter\" error: port is missing" container=whoami-pieter-064ebd907b423882967be2c07ec36452bcb90da375b2b3761b9b362c74a280e2 providerName=docker