dockercaddyapi-platform

Can't run api platform with local database


API Platform version(s) affected: 3.2

I try to run api platform on production without database service on docker, because I want to use a local database. I start the project with the command provided in api platform docs, bu I run it with a specific compose.yaml and a compose.prod.yaml. I added to compose.prod.yaml file `network_mode: "host"` so I bring to the container the same networking as my host.

But when I run the project, I get this error :

"duration":0.013162129
"err_id":"y7f98si24"
"err_trace":"reverseproxy.statusError (reverseproxy.go:1267)"
"level":"error"` "logger":"http.log.error.log0"
"msg":"dial tcp: lookup pwa on 212.227.123.16:53: no such host"

From what I understand, it doesn't find pwa host. I can't understand why.

I run this command to starting api platform on production :

SERVER_NAME=preprod.website.fr
APP_SECRET=a_secret_key
CADDY_MERCURE_JWT_SECRET=ChangeThisMercureHubJWTSecretKey
docker compose -f compose.yaml -f compose.prod.yaml  up --wait

compose.yaml :

services:
  php:
    image: ${IMAGES_PREFIX:-}app-php   
    restart: unless-stopped
    environment:
      PWA_UPSTREAM: pwa:3000
      SERVER_NAME: ${SERVER_NAME:-localhost}, php:80
      MERCURE_PUBLISHER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET:-!ChangeThisMercure>
      MERCURE_SUBSCRIBER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET:-!ChangeThisMercur>
      TRUSTED_PROXIES: ${TRUSTED_PROXIES:-127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,>
      TRUSTED_HOSTS: ^${SERVER_NAME:-example\.com|localhost}|php$$
      DATABASE_URL: mysql://${MARIADB_USER:-myuser}:${MARIADB_PASSWORD>
      MERCURE_URL: ${CADDY_MERCURE_URL:-http://php/.well-known/mercure}
      MERCURE_PUBLIC_URL: https://${SERVER_NAME:-localhost}/.well-known/mercure
      MERCURE_JWT_SECRET: ${CADDY_MERCURE_JWT_SECRET:-!ChangeThisMercureHubJWTS>
    volumes:
      - caddy_data:/data
      - caddy_config:/config
       ports:
      # HTTP
      - target: 80
        published: ${HTTP_PORT:-80}
        protocol: tcp
      # HTTPS
      - target: 443
        published: ${HTTPS_PORT:-443}
        protocol: tcp
      # HTTP/3
      - target: 443
        published: ${HTTP3_PORT:-443}
        protocol: udp
   pwa:
    image: ${IMAGES_PREFIX:-}app-pwa
    environment:
      NUXT_PUBLIC_ENTRYPOINT: http://php

# Mercure is installed as a Caddy module, prevent the Flex recipe from installi>
###> symfony/mercure-bundle ###
###< symfony/mercure-bundle ###
volumes:
  caddy_data:
  caddy_config:
###> symfony/mercure-bundle ###
###< symfony/mercure-bundle ###

compose.prod.yaml :

# Production environment override
services:
  php:
    build:
      context: ./api
      target: frankenphp_prod
    environment:
      APP_SECRET: ${APP_SECRET}
      MERCURE_PUBLISHER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET}
      MERCURE_SUBSCRIBER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET}
      DATABASE_URL: mysql://${MARIADB_USER:-myuser}:${MARIADB_PASSWORD:-mypassword}@127.0.0.1:3306/${MARIADB_DATABASE:-mydatabase}?serverVersion=mariadb-${MARIADB_VERSION:-10.11>
    network_mode: "host"
  pwa:
    build:
      context: ./pwa
      target: prod
  
  vector:
    container_name: vector
    image: timberio/vector:0.34.0-alpine
    restart: always
    volumes:
      - ./vector.yaml:/etc/vector/vector.yaml
      - /var/run/docker.sock:/var/run/docker.sock:ro    

2024/10/01 UPDATE:

Following this article https://dev.to/mjnaderi/accessing-host-services-from-docker-containers-1a97 I was able to solve my problem. Here's my compose.prod.yaml updated:

  proxy-relay:
    image: alpine/socat:latest
    network_mode: host
    command: TCP-LISTEN:3306,fork,bind=host.docker.internal TCP-CONNECT:127.0.0.1:3306   
    extra_hosts:
      - host.docker.internal:host-gateway
  php:
    build:
      context: ./api
      target: frankenphp_prod
    environment:
      APP_SECRET: ${APP_SECRET}
      MERCURE_PUBLISHER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET}
      MERCURE_SUBSCRIBER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET}
      DATABASE_URL: mysql://${MARIADB_USER:-myuser}:${MARIADB_PASSWORD:-mypassword}@host.docker.internal:3306/${MARIADB_DATABASE:-mydatabase}?serverVersion=mariadb-${MARIADB_VERSION:-10.11.6}&charset=utf8mb4
    extra_hosts:
      - host.docker.internal:host-gateway

Solution

  • network_mode: host disables Docker's networking layer. It's almost never necessary, and if you need it then it either suggests your program shouldn't run in a container (because it's trying to manage the host's network interfaces) or is missing network configuration. You should delete this line.

    In particular, where the base Compose file sets PWA_UPSTREAM: pwa:3000, using host networking disables Docker's inter-container DNS and the pwa host name won't work. The base Compose file also has the ports: setting that you'd need to make the container reachable from outside Docker.

    The one thing in the configuration that isn't likely to work is the DATABASE_URL: ...127.0.0.1... setting. The best approach here is to add the database as an additional container

    services:
      db:
        image: mariadb:${MARIADB_VERSION:-10.11}
        environment:
          MARIADB_USER:
          MARIADB_PASSWORD:
          MARIADB_DATABASE:
          MARIADB_RANDOM_ROOT_PASSWORD: "true"
        volumes:
          - mariadb_data:/var/lib/mysql
      php:
        ...
        environment:
          DATABASE_URL: mysql://${MARIADB_USER:-myuser}:${MARIADB_PASSWORD:-mypassword}@db:3306/${MARIADB_DATABASE:-mydatabase}?serverVersion=mariadb-${MARIADB_VERSION:-10.11>
          #                                      database container name, not 127.0.0.1 ^^
    volumes:
      mariadb_data:
    

    It's also possible to use a database that exists only on the host machine, though this will be harder to reproduce in other environments; see From inside of a Docker container, how do I connect to the localhost of the machine? for the host names and the setups you can use (again, you usually should not set network_mode:).