Reputation: 2648
I wanted to try Docker as a tool for local development — I used docker-compose
to spin up 3 containers: one for the database (postgres), front-end (running webpack and node sass in watch mode) and backend (Elixir/Phoenix).
Everything works great, except that when I hit localhost:4000
the page load is really slow — 10-15 seconds just to get the login page, which is static.
I checked the logs from docker-compose
and the server response times are fast as usual, which to me it means that something is slowing down the connection to the container.
When I ran the server directly in the Terminal again, everything is pretty fast, e.g. takes 1s to load the same page.
I'm new to Docker so I suspect I might be missing something configuration-wise. Any ideas are appreciated. Thank you!
Configuration
docker-compose.yml
version: "3.6"
services:
postgres:
container_name: postgres
image: postgres:11.0-alpine
ports:
- 5432:5432
volumes:
- postgres:/var/lib/postgresql/data
front-end:
container_name: front-end
env_file:
- "docker/dev/.env"
build:
context: "."
dockerfile: "docker/dev/Dockerfile.front-end"
volumes:
- .:/app
- node_modules:/app/node_modules
- static:/app/priv/static
command: npm run dev
backend:
container_name: backend
build:
context: "."
dockerfile: "docker/dev/Dockerfile.backend"
env_file:
- "docker/dev/.env"
depends_on:
- postgres
- front-end
ports:
- 4000:4000
stdin_open: true
tty: true
volumes:
- .:/app
- elixir-deps:/app/deps
- static:/app/priv/static
command: iex -S mix phx.server
volumes:
postgres:
elixir-deps:
node_modules:
static:
driver_opts:
type: "tmpfs"
device: "tmpfs"
Dockerfile.front-end
FROM node:8.10-alpine
WORKDIR /app
COPY package.json ./
COPY package-lock.json ./
RUN npm install
COPY . .
Dockerfile.backend
FROM elixir:1.8-alpine
RUN apk update && apk add build-base inotify-tools postgresql-dev
WORKDIR /app
COPY mix.exs ./
COPY mix.lock ./
RUN mix local.hex --force && mix local.rebar --force \
&& mix deps.get && mix deps.compile
COPY . .
EXPOSE 4000
Versions & other info:
MacOS Mojave 10.14.3
Docker Desktop 2.0.0.3 (Engine 18.09.2, Compose: 1.23.2)
MacBook Pro 13" (Early 2015, 16GB RAM/3.1GHz Core i7)
Upvotes: 5
Views: 11671
Reputation: 2648
Update 5 June 2020:
It is significantly better to use docker-sync
for local development.
First make sure you down
existing services to remove old volumes.
Then create a docker-sync.yml
like so:
version: "2"
options:
# Renamed compose file to `docker-compose.dev.yml`
compose-dev-file-path: 'docker-compose.dev.yml'
syncs:
# This name should be unique and should not clash with
# an existing container or service name. You can use it
# as a volume in docker compose yml.
project:
src: '.'
sync_excludes: ['node_modules', 'deps', '_build']
Now you can use the project
volume instead of - .:/app
for front-end
and backend
services, e.g.
volumes:
- project:/app:nocopy
- elixir-deps:/app/deps
- elixir-build:/app/_build
- static:/app/priv/static:ro
Run docker-sync start
to start it in the background, followed by running docker-compose up --build --detach
as usual.
Original answer:
As one commenter pointed out (@DavidMaze), there are currently known performance issues with Docker for Mac. How much are they linked to my use case I cannot tell, but after reading the Performance tuning guide in the official docs, I managed to make some progress in performance:
docker-compose.yml
version: "3.6"
services:
postgres:
container_name: postgres
image: postgres:11.0-alpine
ports:
- 5432:5432
volumes:
- postgres:/var/lib/postgresql/data
front-end:
container_name: front-end
env_file:
- "docker/dev/.env"
build:
context: "."
dockerfile: "docker/dev/Dockerfile.front-end"
volumes:
- .:/app:delegated
- node_modules:/app/node_modules
- static:/app/priv/static
command: npm run dev
backend:
container_name: backend
build:
context: "."
dockerfile: "docker/dev/Dockerfile.backend"
env_file:
- "docker/dev/.env"
depends_on:
- postgres
- front-end
ports:
- 4000:4000
stdin_open: true
tty: true
volumes:
- .:/app:delegated
- elixir-deps:/app/deps
- elixir-build:/app/_build
- static:/app/priv/static:ro
command: iex -S mix phx.server
volumes:
postgres:
elixir-deps:
elixir-build:
node_modules:
static:
driver_opts:
type: "tmpfs"
device: "tmpfs"
Note the use of :delegated
when declaring the .:/app:delegated
volumes.
Although this is an improvement, it is still much slower for day-to-day development than running things natively, so I'm welcoming other answers to my question. For the time being, I think that's probably the best solution.
Upvotes: 5