I am pretty new to this whole subject, so excuse me if those are silly questions. I want to run unit tests in Docker containers like so:
I am currently struggling running the migration. I create the service image FROM
my prod image and RUN npm install --only=dev
. My docker-compose.yml
looks like this:
version: "3.7"
services:
db:
image: postgres
environment:
POSTGRES_PASSWORD: test_pw
POSTGRES_USER: test_user
POSTGRES_DB: test_db
ports:
- '5432:5432'
web:
image: docker_tests
environment:
DATABASE_URL: postgres://test_user:test_pw@db:5432/test_db?ssl=false
DATABASE_SSL: "false"
DATABASE_PW: test_pw
DATABASE_USER: test_user
DATABASE_NAME: test_db
DATABASE_HOST: db
depends_on:
- db
ports:
- '1337:1337'
And my Dockerfile:
FROM docker_service
ENV NODE_ENV TEST
WORKDIR /usr/src/app
RUN npm install --only=dev
RUN ["./node_modules/.bin/node-pg-migrate", "up"]
EXPOSE 1337
CMD ["npm", "run", "test"]
When running the composition, both containers start and I even get
No migrations to run!
Migration complete!
However, if I run tests, no tables are available. The migration was not applied to my Postgres container and when adding RUN ["printenv"]
after migration it becomes clear why: the necessary DATABASE_URL is not there. I googled and found that the env-variables specified in docker-compose.yml
are only available at runtime, not during buildtime. However, when i add ENV DATABASE_URL ...
to my Dockerfile, of course it cannot connect to the database since the Postgres container hasn't yet started.
How do I solve the problem? One possible soltion would be to run ./node_modules/.bin/node-pg-migrate up
in web as soon as both containers are up, but Docker can only have one CMD, right? And I use it to run my unit tests.
TL;DR: How do I run migrations in a Docker Postgres-container using node-pg-migrate from a Docker service-container before running unit tests?
Thanks a lot!
I couldn't test this, but here's the idea:
docker-entrypoint.sh
script in the same folder as Dockerfile#!/usr/bin/env bash
./node_modules/.bin/node-pg-migrate up
exec "$@"
FROM docker_service
ENV NODE_ENV TEST
WORKDIR /usr/src/app
RUN npm install --only=dev
COPY docker-entrypoint.sh /usr/local/bin/
RUN chmod 777 /usr/local/bin/docker-entrypoint.sh && \
ln -s usr/local/bin/docker-entrypoint.sh / # backwards compat
ENTRYPOINT ["docker-entrypoint.sh"]
EXPOSE 1337
CMD ["npm", "run", "test"]
This way the docker-entrypoint.sh
script will be executed every time you create container and will execute npm run test
afterwards because of exec "$@"
. Every DB image has this kind of setup and I advise you to take a look at the PostgreSQL Dockerfile and entrypoint script.
You might need something like wait-for-it to make sure the DB has started, before executing migration scripts. depends_on
helps you with start order but doesn't wait for the service to be healthy.