Rails on Docker: Using an Entrypoint File in your Containers
When using Docker to run your Rails apps in development, you might come across a leftover server.pid
file in your app's tmp/
folder.
This file is created when you run rails server
to start your app. If your container is not shut down properly, this server.pid
file is not removed. This prevents you from starting a new container; as the file is copied into the new container, you will be confronted with the following message when you try to run your app:
web_1 | A server is already running. Check /usr/src/app/tmp/pids/server.pid.
...
web_1 | Exiting
Of course, the simple way to resolve this is to remove the offending file ($ rm tmp/pids/server.pid
) and restart your container.
This can quickly become annoying, though, and won't help if (for example) you are trying to scale the number of containers in your development environment. Every new container will inherit the tmp/pids/server.pid
file, and so exit immediately.
Using an Entrypoint File
To properly handle this situation is to use a docker entrypoint file. This is a simple shell script that becomes the command that is called when your container starts.
Entrypoint files are commonly used to set up or configure a container at runtime. For example, when you run the postgres
or mariadb
containers, their entrypoint files create and configure a default database.
An example entrypoint file for our Rails app to resolve the problem above might be:
#!/bin/sh
rm -f tmp/pids/server.pid
bin/rails server -b 0.0.0.0 -p $PORT
Save this file as docker-entrypoint.sh
in your app's folder (in the same location as Dockerfile
). You'll also need to make sure it is executable by modifying its permissions:
$ chmod u+x ./docker-entrypoint.sh
Next, in your app's Dockerfile
, set the CMD
line to run your new entrypoint file:
# Dockerfile
FROM ruby:2.5
# ...
EXPOSE $PORT
CMD ./docker-entrypoint.sh
Note that you could use the _ENTRYPOINT_
command in this instance, but as we're supplying default arguments (_server_
, _-b_
and _-p_
) to the _bin/rails_
command, I prefer to use _CMD_
in line with the Docker documentation.
Alternatively, if you only want to use your entrypoint file for local development, you could simply override the container's default command in your docker-compose.yml
file:
# docker-compose.yml
# ...
web:
build: .
command: ./docker-entrypoint.sh
# ...
Now you can spin up your container(s) in the normal way using Docker compose:
$ docker-compose up -d --scale web=2
Next Steps
In this simple example, you've seen how to use an entrypoint file to initialise the state of a container at runtime. You can also use entrypoint files to perform much more complicated setup, such as creating runtime files and databases, configuring local services, and more.
👋 Thanks for reading - I hope you enjoyed this post. If you find it helpful and want to support further writing and tutorials like this one, please consider supporting my work with a coffee!
Support ☕️