Don't use docker to run your app in development
Tags: productivity, docker
Published: 2019-11-19 23:56:12

---
title: Don't use docker to run your app in development
published: true
date: 2018-08-04 00:00:00 UTC
tags: productivity, docker
canonical_url: http://hakunin.com/docker-in-dev
---

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.

1. Mounted volumes are slow and error-prone
2. You need hacks and shortcuts to run any console/debug commands in containers
3. Live updates on code changes are unreliable in docker
4. Runtime is slower in docker
5. Dependency updates are slower in docker
6. 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.

## 1. Use docker-compose for databases and external services

Create a `docker-compose.yml` file in your app’s root and only declare your databases in it. For example, this file gives you

- Postgres on `localhost:5432`
- Redis on `localhost:6379`
- Fake S3 on `localhost:9000`

```
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](https://github.com/asdf-vm/asdf) for language runtimes

Create a `.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
```

[Asdf](https://github.com/asdf-vm/asdf) is like rvm, nvm, and other version managers combined. It has [an extensive list](https://github.com/asdf-vm/asdf-plugins#plugin-list) of things it can manage.

## 3. Setup everything

Now you can bootstrap the application by running

```
asdf install
docker-compose up
```

and in another terminal you run the app itself:

```
mix phx.server
```

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.

## Bonus: How to make local Rails work with dockerized Postgres?

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.

<!--meta
  toc: true
  date: "2018-08-04"
  toc: true
  tldr: Use docker-compose and asdf for local dev
-->