Docker Tip #8: Overriding Your Dockerfile's CMD
If you've built any type of real world web app, chances are you've wanted to run different services from the same Docker image. Here's how.
Last week we covered the difference between CMD
and RUN
in a Dockerfile
, and
today I’d like to cover leveraging the same Docker image for multiple services.
This is made possible by overriding the default CMD
in your Dockerfile
.
Before we get into that, here’s a very common use case:
Let’s say that you have a standard Ruby on Rails or Flask / Django application. It is composed of a database, your web app server and a background worker.
With Rails, that could be PostgreSQL
, Puma
(app server) and Sidekiq
(background worker).
With Flask or Django, that might be PostgreSQL
, gunicorn
(app server)
and Celery
(background worker).
Chances are you have your Rails or Flask / Django application running in its
own Docker container, and you have a single Dockerfile
.
Your Dockerfile
also likely has a CMD
which starts your app server (Puma
or gunicorn
).
But, you also want to run your background worker in its own container. This way you can independently scale it from your web app server. This is considered a best practice.
Docker makes this very easy. All you have to do is supply a new command to run
when you start your Docker image, and it will override the CMD
in your
Dockerfile
.
For example (using Rails):
Your CMD
might be bundle exec puma -C config/puma.rb
.
Here’s how to override that with Docker Compose:
website:
build: .
sidekiq:
build: .
command: sidekiq -C config/sidekiq.yml
That’s all there is to it. Now you have a completely separate service for your
background worker and it will use the same exact Dockerfile
as your main
web application. The command:
property’s value will take precedence over
your Dockerfile
’s CMD
.
The same can be done on the command line with docker run
. You would just
supply the custom command at the end of your docker run
command.