Using docker in development can be very convenient, but running your actual app (you know, the one you’re coding) in docker introduces various headaches.
- Mounted volumes are slow and error-prone
- You need hacks and shortcuts to run any console/debug commands in containers
- Live updates on code changes are unreliable in docker
- Runtime is slower in docker
- Dependency updates are slower in docker
- Networking is more complicated with docker
What genuinely surprises me, is that often teams don’t consider the obvious: just run your app directly on your machine. I find it to be the sweet spot of dev setup. Let’s see what it would look like.
docker-compose.yml file in your app’s root and only declare your databases in it. For example, this file gives you
- Postgres on
- Redis on
- Fake S3 on
version: '3' services: postgres: image: postgres:10.3-alpine ports: - "5432:5432" volumes: - postgres-data:/var/lib/postgresql/data redis: image: redis:3.2.11-alpine ports: - "6379:6379" volumes: - redis-data:/data minio: image: minio/minio volumes: - minio-data:/data ports: - "9000:9000" entrypoint: sh command: -c "mkdir -p /data/dev /data/test && /usr/bin/minio server /data" environment: MINIO_ACCESS_KEY: access_key MINIO_SECRET_KEY: secret_key volumes: postgres-data: redis-data: minio-data:
2. Use asdf for language runtimes
.tool-versions file in app’s root. Here’s an example for elixir and node setup.
elixir 1.6.4-otp-20 erlang 20.2.4 nodejs 10.8.0
Now you can bootstrap the application by running
asdf install docker-compose up
and in another terminal you run the app itself:
That’s it. Now you have the benefit of quick and simple dev setup without giving up all the convenience of interacting with your app directly, without containers in the middle.
The cool part is that your
database.yml can be committed to the repo, it will always look the same:
default: &default adapter: postgresql username: postgres host: localhost development: <<: *default database: myapp_dev test: <<: *default database: myapp_test production: <<: *default database: myapp
However, there’s a minor issue when using this setup in Rails. You might get an error when trying to install the pg gem or run a
rake db:structure:dump command. Both of these actions rely on postgres being installed locally. To work around it simply add postgres to your
.tool-versions — asdf supports it. You will not be actually running this postgres, only using its cli as a client, and satisfying pg’s dependencies.