Search code examples
mysqlruby-on-railsdockerdocker-composehostname

Is there a way to use a generic hostname that will work in both Docker and localhost?


I’m on Mac OS Big Sur and running the following Docker versions

$ docker -v
Docker version 20.10.12, build e91ed57
$ docker-compose -v
Docker Compose version v2.2.3

I’m running a Rails 6 app, whose database is configured like so

development:
  adapter: mysql2
  encoding: utf8
  host: host.docker.internal
  database: cfs
  pool: 5
  username: myuser
  password: bypass

I have to use “host.docker.internal” so that the Rails app can access the Docker db when running inside of Docker, set up in my docker-compose.yml like so

services:
  db:
    image: mysql:5.7
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    restart: always
    volumes:
      - ./docker/provision/mysql/init:/docker-entrypoint-initdb.d
    environment:
      MYSQL_ROOT_PASSWORD: bypass
    ports:
      # <Port exposed> : < MySQL Port running inside container>
      - '3306:3306'
    expose:
      # Opens port 3306 on the container
      - '3306'
    …
  web:
    #restart: always
    build: ./my-project
    ports:
      - "3000:3000"
    expose:
      - '3000'
    command: foreman start
    volumes:
    - ./my-project/:/app
    depends_on:
      - db

However if I run the app locally without Docker, I have to change my config files to remove “host.docker.internal” and use “127.0.0.1” instead (or localhost).

Is there a way I can set things up so that I have a single database config file that works in both Docker and without Docker such that I don’t have to change the host around?


Solution

  • You can use ERB markup in the database.yml file, which lets you use an environment variable here. In general I'd suggest making default values for things be whatever default will work in a plain non-Docker development environment.

    # config/database.yml
    development:
      host: <%= ENV['DATABASE_HOST'] || 'localhost' %>
    

    If you're running this in a setup where the database hostname isn't localhost – it's in a sibling container, or you're using a cloud-hosted database like Amazon RDS – you can set that environment variable.

    # docker-compose.yml
    version: '3.8'
    services:
      db:
        image: 'mysql:5.7'
        et: cetera
      web:
        build: .
        ports:
          - '3000:3000'
        depends_on:
          - db
        environment:
          DATABASE_HOST: db  # <-- will be read in database.yml