# Due to lack of "expressivity" in Compose, we define our own couple of service "pseudo-types":
#
# - image-only services (name: *-image)
# The only goal of these is to build images. No other services build images.
# These have entrypoint overridden to exit immediately.
#
# - base services (name: *-base)
# These contain common configuration and are intended to be extended.
# Their command (not entrypoint, to keep the original one) is overridden to
# exit immediately. Service must support a command to exit immediately.
#
# - task services (name: *-task)
# These are intended for running one-off commands.
# Their default command is overridden to exit immediately. Service must
# support a command to exit immediately.
#
# - "real" services
# These are actual services that stay up and running.
Docker compose should follow the service naming convention, but also should have our internal naming, like web
, worker
, rspec
:
version: '3'
networks:
blinkist:
external:
name: cubitoo
services:
services-base: &services-base
tty: true
stdin_open: true
command: echo services-base is not a real service
build:
dockerfile: Dockerfile-dev
context: .
environment:
- APP_NAME=service_name
- RAILS_ENV=development
volumes:
- .:/app
networks:
- blinkist
console-task:
<< : *services-base
command: bundle exec rails console
rspec-task:
<< : *services-base
entrypoint: bundle exec rspec
command: .
web:
<< : *services-base
command: bundle exec bin/rails s -p 80 -b 0.0.0.0
container_name: service-name.dev
hostname: serfice-name.dev
expose:
- 80
labels:
- 'traefik.frontend.rule=Host:service-name.dev'
In order to make it easier to use the docker-compose, I've created a small snippet alias and bash function you can copy into your ~/.bash_profile
:
# docker-compose utils
alias dcb='docker-compose build'
alias dcu='docker-compose up'
alias dcd='docker-compose down'
function dcr() {
docker-compose run --rm $1-task ${@:2:99}
}
While aliases are self-explanatory (and allow stuff like dcu web worker
), dcr
takes the name of the service (like rspec
), and because it follows the appropriate naming convention, runs docker-compose rspec-task arg1 arg2 ...
)
Dockerfile for development purposes should be a separate file from the production one. Moreover, it should be as simple as possible. Sample Dockerfile-dev
from Messenger:
FROM ruby:2.5.1-alpine
ARG BUNDLE_GITHUB__COM
ENV BUILD_PACKAGES build-base git
ENV RUNTIME_PACKAGES supervisor mysql-dev
RUN apk update && apk upgrade && \
apk add $BUILD_PACKAGES && \
apk add $RUNTIME_PACKAGES
RUN mkdir /app
WORKDIR /app
COPY .ruby-version /app/
COPY Gemfile* /app/
RUN bundle install
COPY . /app