1

Dockerfile

FROM ruby:2.6.3
RUN apt-get update -qq && apt-get install -y nodejs postgresql-client
RUN mkdir /paper_scammer_docker
WORKDIR /paper_scammer_docker
COPY Gemfile /paper_scammer_docker/Gemfile
COPY Gemfile.lock /paper_scammer_docker/Gemfile.lock
RUN bundle install
COPY . /paper_scammer_docker

# Add a script to be executed every time the container starts.
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

# Start the main process.
CMD ["rails", "server", "-b", "0.0.0.0"]

docker-compose.yml

version: '3'
services:
  db:
    image: postgres:10
    ports:
      - "5432:5432"
    volumes:
      - ./tmp/db:/var/lib/postgresql/data
  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/paper_scammer_docker
    ports:
      - "3000:3000"
    links:
      - "db:db"
    depends_on:
      - db

I am successfully able to build image using the following command

docker-compose build

If i do docker-compose up in project root directory my app runs fine and i can see two containers one for my rails app and other for postgres when i do docker container ls. I observed that postgres image is loaded from library.

database.yml file

# SQLite version 3.x
#   gem install sqlite3
#
#   Ensure the SQLite 3 gem is defined in your Gemfile
#   gem 'sqlite3'
#
default: &default
  adapter: postgresql
  encoding: unicode
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  timeout: 5000
  host: db
  username: postgres
  password:
  # user: gnpsllco_papaer
  # password: sharma@123

development:
  <<: *default
  database: paper_scammer_development
  # user: postgres
  # password: sharma@123

# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
  <<: *default
  database: paper_scammer_test
  # user: postgres
  # password: sharma@123

production:
  <<: *default
  database: gnpsllco_paper_scammer

Problem

I run the following command to start docker container from the image of my rails app.

sudo docker run -p 3000:3000 paperscammer_web

postgres container is not running or missing.

I want to understand how this dockerfile-compose handle this, when i spin the image of rails app which says its depends in postgres service shouldn't it also spin a postgres container and set 'db' as host for connections.

or do it needs to be spinned manually for postgres.

I get the following error when i run http://localhost:3000

could not translate host name "db" to address: Name or service not known

I can see postgres container is not running.

Thanks

user3775217
  • 4,675
  • 1
  • 22
  • 33

3 Answers3

3

sudo docker run -p 3000:3000 paperscammer_web will start only the web server, you need to run docker-compose :

sudo docker-compose up -d --build

second option:

 sudo docker run --name db -p 5432:5432 -v ./tmp/db:/var/lib/postgresql/data postgres:10
 sudo docker run -p 3000:3000 --link db:db -v .:/paper_scammer_docker paperscammer_web
LinPy
  • 16,987
  • 4
  • 43
  • 57
  • yeah but how that scales when deploying in productions, docker-compose up looks for docker file, if you follow this https://docs.docker.com/get-started/part3/ . services defined in docker-compose file should put all the services as containers – user3775217 Jul 04 '19 at 12:28
  • with compose it works fine, but the rails applications image doesn't work fine when i run docker run -p 3000:3000 paperscammer_web. you must be aware docker compose will create image then start. but for production deployments output produced by docker compose build produce a image which will be used to spin containers. – user3775217 Jul 04 '19 at 12:43
  • yeah my app now able to connect to db service, but database is not created error comming this time – user3775217 Jul 05 '19 at 05:05
  • FATAL: database "paper_scammer_development" does not exist , docker run command is not running buundle exec rake db:create as mentioned in docker file – user3775217 Jul 05 '19 at 05:17
  • i think following this should help https://docs.docker.com/engine/examples/postgresql_service/. i have to add create database commands and skip it if database already exists. How you suggest? To have my own dockerfile to create postgres image. – user3775217 Jul 05 '19 at 05:27
  • your answer helped me running database service and creating links, but i can't hook database migrations yet with docker run command. running `sudo docker run -p 3000:3000 --link db:db paperscammer_web bundle exec rake db:create db:migrate` runs only migrations and exit without starting the container. – user3775217 Jul 05 '19 at 09:27
  • i don't understand what do you mean my DB image i am running the command `sudo docker run --name db -p 5432:5432 -v ./tmp/db:/var/lib/postgresql/data postgres:10` just and postgres image is created. Again i don't think it will have anything to do with db image as rails migrations need to run when db image is spinnned in the container. i guess workaround is around my web_app image. – user3775217 Jul 05 '19 at 09:40
2

Solution

./Dockerfile

ROM ruby:2.6.3-alpine

ENV BUNDLER_VERSION=2.0.2

RUN apk add --update --no-cache \
      binutils-gold \
      build-base \
      curl \
      file \
      g++ \
      gcc \
      git \
      less \
      libstdc++ \
      libffi-dev \
      libc-dev \ 
      linux-headers \
      libxml2-dev \
      libxslt-dev \
      libgcrypt-dev \
      make \
      netcat-openbsd \
      nodejs \
      openssl \
      pkgconfig \
      postgresql-dev \
      python \
      tzdata \
      yarn 

RUN mkdir -p /app
WORKDIR /app

COPY Gemfile* ./
RUN gem install bundler
RUN bundle config build.nokogiri --use-system-libraries
RUN bundle check || bundle install 

COPY package.json yarn.lock ./
RUN yarn install --check-files

COPY . ./

COPY ./sh/entrypoints/docker-entrypoint.sh /usr/bin/entrypoint.sh
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]

./.env

APP_NAME=api
APP_PORT=3100

DATABASE_NAME=rails_db
DATABASE_USER=batman
DATABASE_PASSWORD=super_pass_123
DATABASE_PORT=5342
DATABASE_HOST=api_db # must be equal to the name of the postgres service in docker-compose.yml

./docker-compose.yml

version: '3.7'
services:
  api: 
    build:
      context: .
      dockerfile: Dockerfile
    container_name: ${APP_NAME}
    depends_on:     
      - api_db
    ports: 
      - "${APP_PORT}:${APP_PORT}"
    volumes:
      - .:/app
      - gem_cache:/usr/local/bundle/gems
      - node_modules:/app/node_modules
    env_file: .env
    environment:
      RAILS_ENV: development

  api_db: # must be equal to `DATABASE_HOST ` in ./.env
    image: postgres
    command: postgres -c logging_collector=on -c log_destination=stderr -c log_directory=/logs -p ${DATABASE_PORT}
    ports:
      - "${DATABASE_PORT}:${DATABASE_PORT}"
    volumes:
      - db_data:/var/lib/postgresql/data
      - ./log/db:/logs
    environment:
      - POSTGRES_USER=${DATABASE_USER}
      - POSTGRES_PASSWORD=${DATABASE_PASSWORD}
      - POSTGRES_DB=${DATABASE_NAME}

volumes:
  gem_cache:
  db_data:
  node_modules:  

./sh/entrypoints/docker-entrypoint.sh

https://stackoverflow.com/a/59047028/4488252

DB_INITED=0
if db_version=$(bundle exec rake db:version 2>/dev/null)
then
    if [ "$db_version" = "Current version: 0" ]
    then
        echo "DB is empty"
    else
        echo "DB exists"
        DB_INITED=1
    fi
    bundle exec rake db:migrate 
else
    echo "DB does not exist"
    bundle exec rake db:setup
fi

if [ $DB_INITED == 0 ]
then
    echo "Performing initial configuration"
    # init some plugins, updated db if need, add initial data
fi

./config/database.yml

default: &default
  adapter: postgresql
  encoding: unicode
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  database: <%= ENV['DATABASE_NAME'] %>
  username: <%= ENV['DATABASE_USER'] %>
  password: <%= ENV['DATABASE_PASSWORD'] %>
  port: <%= ENV['DATABASE_PORT'] || '5432' %>
  host: <%= ENV['DATABASE_HOST'] %>

development:
  <<: *default

test:
  <<: *default

production:
  <<: *default

./.dockerignore

https://gist.github.com/neckhair/ace5d1679dd896b71403fda4bc217b9e

.git
.gitignore
README.md

#
# OS X
#
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear on external disk
.Spotlight-V100
.Trashes
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk

#
# Rails
#
.env
.env.sample
*.rbc
capybara-*.html
log
tmp
db/*.sqlite3
db/*.sqlite3-journal
public/system
coverage/
spec/tmp
**.orig

.bundle

.ruby-version
.ruby-gemset

.rvmrc

# if using bower-rails ignore default bower_components path bower.json files
vendor/assets/bower_components
*.bowerrc
bower.json

Usage

https://docs.docker.com/compose/reference/down/

build and run: docker-compose up --build -d

https://docs.docker.com/compose/reference/down/

stop: docker-compose down

stop + delete images and volumes: docker-compose down --rmi all --volumes

Vasily Bodnarchuk
  • 24,482
  • 9
  • 132
  • 127
0

docker-compose up and docker run are different commands. Using the latter one won't use the compose file, only the parameters passed to the command.

When you use docker run you must specify which containers you want to run specifically, if you want to run both db and web you should use this command twice.

In the other hand, when you use docker-compose up you run all the containers specified in docker-compose.yml with all its options.

Also, the depends_on property just specifies that the container web will be launched once the container db is successfuly launched.

As a final remark, if you want your containers to be able to communicate with each other you should add a network to the compose file:

version: '3'
services:
  db:
    image: postgres:10
    container_name: db
    ports:
      - "5432:5432"
    volumes:
      - ./tmp/db:/var/lib/postgresql/data
    networks:
      - my-network-name

  web:
    build: .
    container_name: web
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/paper_scammer_docker
    ports:
      - "3000:3000"
    links:
      - "db:db"
    depends_on:
      - db
    networks:
      - my-network-name

networks:
  my-network-name:
    driver: bridge

Also is a good practice to add a container_name for referencing them.

With thoose options now containers can communicate with their names as IPs/hostnames:

http://<container_name>:<port>

For example, the container web will be able to connect to the database in the db container like this:

http://db:5432/gnpsllco_paper_scammer

Notice the IP/hostname is now the name of the container.

As @LinSel pointed, you can build and run all the containers with the command (sudo is not needed):

docker-compose up -d --build
  • but still i this uses source code to build image, i want to find solution for shared images. – user3775217 Jul 05 '19 at 07:15
  • Sorry your question is unclear, what do you mean by 'shared images'? Images that are published in Docker Hub? – Victor Calatramas Jul 05 '19 at 09:27
  • after building the image this image will be registered with dockerhub and few tools work to pick image from dockerhub and spin AWS ECS – user3775217 Jul 05 '19 at 09:33
  • as you mentioned i have to run `docker run` twice, this works fine for me. I am now stuck with how to run database migrations as 'docker run paperscammer bundle exec rake db:migrate` only runs migrations and exit without starting the container – user3775217 Jul 05 '19 at 09:35
  • 1
    Maybe this? https://stackoverflow.com/questions/38089999/docker-compose-rails-best-practice-to-migrate – Victor Calatramas Jul 05 '19 at 09:44
  • Also I suggest to edit your question and make it more clear, adding what you said here in the comments, because this is the real problem. – Victor Calatramas Jul 05 '19 at 09:44
  • yeah i will update and accept answer, just trying this one – user3775217 Jul 05 '19 at 09:52