'How to run Sequelize migrations inside Docker

I'm trying to docerize my NodeJS API together with a MySQL image. Before the initial run, I want to run Sequelize migrations and seeds to have the tables up and ready to be served.

Here's my docker-compose.yaml:

version: '3.8'
services: 
  mysqldb:
    image: mysql
    restart: unless-stopped
    environment:
      MYSQL_ROOT_USER: myuser
      MYSQL_ROOT_PASSWORD: mypassword
      MYSQL_DATABASE: mydb
    ports:
      - '3306:3306'
    networks:
      - app-connect
    volumes: 
      - db-config:/etc/mysql
      - db-data:/var/lib/mysql
      - ./db/backup/files/:/data_backup/data
  app:
    build:
      context: .
      dockerfile: ./Dockerfile
    image: node-mysql-app
    depends_on:
      - mysqldb
    ports:
      - '3030:3030'
    networks:
      - app-connect
    stdin_open: true
    tty: true
volumes: 
  db-config:
  db-data:
networks:
  app-connect:
      driver: bridge

Here's my app's Dockerfile:

FROM node:lts-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3030
ENV PORT 3030
ENV NODE_ENV docker
RUN npm run db:migrate:up
RUN npm run db:seeds:up
CMD [ "npm", "start" ]

And here's my default.db.json that the Sequelize migration uses (shortened):

{
  "development": {
    
  },
  "production": {
    
  },
  "docker": {
    "username": "myuser",
    "password": "mypassword",
    "database": "mydb",
    "host": "mysqldb",
    "port": "3306",
    "dialect": "mysql"
  }
}

Upon running compose up the DB installs well, the image deploys, but when it reaches the RUN npm run db:migrate:up (which translates into npx sequelize-cli db:migrate) I get the error:

npx: installed 81 in 13.108s

Sequelize CLI [Node: 14.17.0, CLI: 6.2.0, ORM: 6.6.2]

Loaded configuration file "default.db.json".
Using environment "docker".


ERROR: getaddrinfo EAI_AGAIN mysqldb
npm ERR! code ELIFECYCLE
npm ERR! errno 1

If I change the "host" in the default.db.json to "127.0.0.1", I get ERROR: connect ECONNREFUSED 127.0.0.1:3306 in place of the ERROR: getaddrinfo EAI_AGAIN mysqldb.

What am i doing wrong, and what host should I specify so the app can see the MySQL container? Should I remove the network? Should I change ports? (I tried combinations of both to no avail, so far).



Solution 1:[1]

I solved my issue by using Docker Compose Wait. Essentially, it adds a wait loop that samples the DB container, and only when it's up, runs migrations and seeds the DB.

My next problem was: those seeds ran every time the container was run - I solved that by instead running a script that runs the seeds, and touchs a semaphore file. If the file exists already, it skips the seeds.

Solution 2:[2]

I found a really clean solution wanted to share it. First of all I used docker-compose, so if you are using only docker, it might not help. First thig first, I created a docker file which looks like that.I am using typescript, so if you are using js, you don't need to download typescript and build it!

FROM node:current-alpine
WORKDIR /app
COPY . ./
COPY .env.development ./.env


RUN npm install
RUN npm install -g typescript

RUN npm install -g sequelize-cli
RUN npm install -g nodemon

RUN npm run build
RUN rm -f .npmrc

RUN cp -R res/ dist/
RUN chmod 755 docker/entrypoint.sh
EXPOSE 8000

EXPOSE 3000
EXPOSE 9229
CMD ["sh", "-c","--","echo 'started';while true; do sleep 1000; done"]

Till here it is standart. In order to do things in right order, I need a docker compose and entrypoint file. Entrypoint file is a file, that runs when your containers start. Here is docker-compose file.

version: '3'

services:
  app:
    build:
      context: ..
      dockerfile: docker/Dockerfile.development
    entrypoint: docker/development-entrypoint.sh
    ports:
      - 3000:3000
    env_file:
      - ../.env.development
    depends_on:
      - postgres
      
  
  postgres:
    image: postgres:alpine
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=test
    volumes:
      - ./docker_postgres_init.sql:/docker-entrypoint-initdb.d/docker_postgres_init.sql

As you can see, I am using postgresql for db. My docker file, docker-compose and also entrypoint files are in a folder called docker, thats why the paths starts wtih docker, change it according to your file structure. Last and the best part is the entrypoint file. It is really simple.

#!/bin/sh

echo "Starting get ready!!!"
sequelize db:migrate
nodemon ./dist/index.js

Ofcourse change the path of the index.js file according to your settings. Hope it helps!

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Traveling Tech Guy
Solution 2 Emre