Yung Flizzy
Yung Flizzy

Reputation: 61

Rails app using docker-compose wont connect to the mysql container

Trying to get a rails app running using docker-compose. I run docker-compose build and it completes with no errors. I then run docker-compose up and both of the containers start. Then I run docker-compose run web rake db:create db:migrate and run into an error:

rake aborted! Mysql2::Error::ConnectionError: Can't connect to MySQL server on '127.0.0.1' (111 "Connection refused")

My Dockerfile:

FROM ruby:2.5.3
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs mysql-client sqlite3 zlib1g-dev libxslt-dev git  && \
gem install bundler
RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
COPY . /myapp

Docker-compose

version: '3.3'
services:
  db:
    image: mysql:5.7
    restart: always
    environment:
      MYSQL_DATABASE: 'online_community_development'
      MYSQL_ROOT_PASSWORD: '******'
      MYSQL_HOST: 'localhost'
    ports:
      # <Port exposed> : < MySQL Port running inside container>
      - '3306:3306'
    expose:
      # Opens port 3306 on the container
      - '3306'
      # Where our data will be persisted
    volumes:
      - 'my-db:/var/lib/mysql'
    container_name: datab




  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
    - web-app:/myapp
    ports:
    - "3000:3000"
    depends_on:
    - db
    links:
      - db:db
    restart: always

volumes:
  my-db: {}
  web-app: {}

Database.yml

development:
  adapter: mysql2
  encoding: utf8
  database: online_community_development
  pool: 5
  username: root
  password: slumland
  socket: /var/run/mysqld/mysqld.sock
  host: db

New to docker so not even sure if I am issuing the commands correctly. I need to create and seed the database and have the app container connect to it. I think the issue is related to it trying to connect via localhost, but even when I changed the host to db I still got the same results. Any help would be greatly appreciated.

Upvotes: 5

Views: 3264

Answers (2)

Hermsi1337
Hermsi1337

Reputation: 251

tl;dr:
Try this docker-compose.yml:

version: '3.3'
services:
  db:
    image: mysql:5.7
    restart: always
    environment:
      MYSQL_DATABASE: 'online_community_development'
      MYSQL_ROOT_PASSWORD: '******'
      MYSQL_HOST: 'localhost'
    expose:
    # Opens port 3306 on the container
      - '3306'
    # Where our data will be persisted
    volumes:
      - 'my-db:/var/lib/mysql'
    container_name: datab

  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    environment:
      DATABASE_URL: 'mysql2://db'
      RAILS_ENV: 'development'
    volumes:
    - web-app:/myapp
    ports:
    - "3000:3000"
    depends_on:
    - db
    restart: always

volumes:
  my-db: {}
  web-app: {}

In detail:
First of all your docker-compose-file is kinda misconfigured.
Therefore I will do a small instruction on docker-compose.yml-files before heading over to your question.

The links:-thing is a legacy feature of docker which you should strictly avoid:
https://docs.docker.com/compose/compose-file/#links
Moreover, it is not even required when you're working with docker-compose

Also, you're using expose: and ports: when defining your database-service.
The ports-key is opening up a port on your host-machine and forwards it to your docker-service:
https://docs.docker.com/compose/compose-file/#ports
Using ports-key on database-definitions makes your database accessible to the www - which is not what you want in most cases.

The expose-key opens the port locally, in the created docker network.
https://docs.docker.com/compose/compose-file/#expose
This is what we want for databases.

Editing your docker-compose.yml-file results in the following:

version: '3.3'
services:
  db:
    image: mysql:5.7
    restart: always
    environment:
      MYSQL_DATABASE: 'online_community_development'
      MYSQL_ROOT_PASSWORD: '******'
      MYSQL_HOST: 'localhost'
    expose:
    # Opens port 3306 on the container
      - '3306'
    # Where our data will be persisted
    volumes:
      - 'my-db:/var/lib/mysql'
    container_name: datab

  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
    - web-app:/myapp
    ports:
    - "3000:3000"
    depends_on:
    - db
    restart: always

volumes:
  my-db: {}
  web-app: {}

Getting back to your primary problem:
rake aborted! Mysql2::Error::ConnectionError: Can't connect to MySQL server on '127.0.0.1' (111 "Connection refused")

It looks like rake expects the database to be available at localhost - therefore I think that the cause of this issue is a misconfiguration.
Unfortunately I'm not very familiar with rake but nevertheless your database.yaml looks correct.
I did some research and came across this post:
Rake tasks seem to ignore database.yml configuration
Maybe you could try to set the environment-variable DATABASE_URL in your docker-compose-file: DATABASE_URL=mysql://db
I'd also recommend to set the correct context-environment-variable: RAILS_ENV=development

When you do alle these changes you should come up with the following docker-compose.yml:

version: '3.3'
services:
  db:
    image: mysql:5.7
    restart: always
    environment:
      MYSQL_DATABASE: 'online_community_development'
      MYSQL_ROOT_PASSWORD: '******'
      MYSQL_HOST: 'localhost'
    expose:
    # Opens port 3306 on the container
      - '3306'
    # Where our data will be persisted
    volumes:
      - 'my-db:/var/lib/mysql'
    container_name: datab

  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    environment:
      DATABASE_URL: 'mysql2://db'
      RAILS_ENV: 'development'
    volumes:
    - web-app:/myapp
    ports:
    - "3000:3000"
    depends_on:
    - db
    restart: always

volumes:
  my-db: {}
  web-app: {}

Hope this helps.

Regards,
Hermsi

Upvotes: 5

rdas
rdas

Reputation: 21285

your db seems to be configured to listen on localhost only. Unfortunately this will not work since your app is technically another network host (container) within the compose network. Try making your db listen on all network interfaces.

Upvotes: -1

Related Questions