I just followed this article on Running a Rails Development Environment in Docker. Good article, works great. After setting everything up, I decided to go on and set up a production environment.
GOAL:
I want to rake db:create && rake db:migrate
every time my docker image is run.
PROBLEM:
If I move the database creation and migrations steps...
docker-compose run app rake db:create docker-compose run app rake db:migrate
...into the Dockerfile...
RUN rake db:create && rake db:migrate
...that will throw an error...
could not translate host name "postgres" to address: Name or service not known
...because the host
in my database.yml
...
default: &default adapter: postgresql encoding: unicode pool: 5 timeout: 5000 username: postgres host: postgres port: 5432 development: <<: *default database: rails_five_development
...is set to the postgres
service name specified in my docker-compose.yml
...
version: "2" services: postgres: image: postgres:9.5 ports: - "5432" app: build: . command: rails server -p 3000 -b '0.0.0.0' volumes: - .:/app ports: - "3000:3000" links: - postgres
...since that is the recommended practice as pointed by the article.
QUESTION:
How can I automatically rake db:create && rake db:migrate
every time my docker image is run?
I am trying to achieve the same thing as in this question
Luckily, you can use docker-compose run to execute one-off commands within a container. To run rake db:migrate in the Rails container, say docker-compose run web rake db:migrate . You'll see the migration running, and then you can continue on your merry way.
To run a specific migration up or down, use db:migrate:up or db:migrate:down . The version number in the above commands is the numeric prefix in the migration's filename. For example, to migrate to the migration 20160515085959_add_name_to_users. rb , you would use 20160515085959 as the version number.
A Rails migration is a tool for changing an application's database schema. Instead of managing SQL scripts, you define database changes in a domain-specific language (DSL). The code is database-independent, so you can easily move your app to a new platform.
From https://docs.docker.com/engine/reference/builder/#cmd:
If you would like your container to run the same executable every time, then you should consider using ENTRYPOINT in combination with CMD. See ENTRYPOINT
https://docs.docker.com/engine/reference/builder/#entrypoint
tl;dr
You could define an entrypoint
under app and define a bash file there:
app: entrypoint: [bin/entry] ..
bin/entry file example:
#!/bin/bash set -e rake db:create rake db:migrate exec "$@"
This approach creates the database if the migration is not able to succeed. It also avoids the issue of being unable to start the server because a pid file was left behind. Create the file as app/lib/docker-entrypoint.sh
.
#!/bin/sh # https://stackoverflow.com/a/38732187/1935918 set -e if [ -f /app/tmp/pids/server.pid ]; then rm /app/tmp/pids/server.pid fi bundle exec rake db:migrate 2>/dev/null || bundle exec rake db:setup exec bundle exec "$@"
The docker-compose.yml then includes:
entrypoint: ["/app/lib/docker-entrypoint.sh"] command: ["rails","server","-b","0.0.0.0","-p","3000"]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With