0

I'm trying to link 3 containers run by Docker to a production stage.

The first container is hosting a vuejs 3 application and runs smoothly. The issue arrives when I use the command :

sudo docker compose --env-file .env.production up -d --build Also I have to specify the .env.production otherwise it uses my default .env file (which I don't really understand why ?).

I'm using knex to build my queries to my database and I have this knexfile.js

// Update with your config settings.

/**
 * @type { Object.<string, import("knex").Knex.Config> }
 */
module.exports = {

  development: {
    client: 'sqlite3',
    connection: {
      filename: './dev.sqlite3'
    },
    useNullAsDefault: true
  },

  production: {
    client: 'mysql2',
    connection: {
      host: process.env.DB_HOST,
      user: process.env.DB_USERNAME,
      password: process.env.DB_PASSWORD,
      database: process.env.DB_NAME
    },
    migrations: {
      directory: './migrations'
    },
    seeds: {
      directory: './seeds'
    }
  }
};

So far I have 2 dockerfile, one for my vue application, one for my express server and a one docker-compose.yml :

Dockerfile (for the backend):

FROM node:20.11.1-alpine3.18 AS build

# Set the working directory
WORKDIR /app

# Copy package.json and package-lock.json
COPY package*.json ./

# Install dependencies
RUN npm install

# Copy the rest of the application code
COPY . .

# Add wait-for-it script
COPY wait-for-it.sh /usr/local/bin/wait-for-it.sh
RUN chmod +x /usr/local/bin/wait-for-it.sh

# Add init-db script
COPY init-db.sh /usr/local/bin/init-db.sh
RUN chmod +x /usr/local/bin/init-db.sh

# Rebuild the sqlite3 package to ensure compatibility
RUN npm rebuild sqlite3

# Expose the port the server will run on
EXPOSE 3000

# Start the server
CMD ["node", "index.js"]

The docker-compose.yml :

services:
  node-backend:
    build:
      context: ./backend
      dockerfile: Dockerfile
    env_file:
      - .env.production
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
    depends_on:
      - db-init
    command: >
      sh -c "
      node create_prod_db.js &&
      npx knex migrate:latest &&
      node index.js
      "

  db:
    image: mysql:8
    restart: always
    env_file:
      - .env.production
    environment:
      MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
      MYSQL_DATABASE: ${DB_NAME}
      MYSQL_USER: ${DB_USER}
      MYSQL_PASSWORD: ${DB_PASSWORD}
    ports:
      - "3306:3306"
    volumes:
      - db_data:/var/lib/mysql

  db-init:
    build:
      context: ./backend
      dockerfile: Dockerfile
    depends_on:
      - db
    command: sh /usr/local/bin/init-db.sh

volumes:
  db_data:

And then my container crashes and returns those logs :

2024-06-28 11:08:58 Error creating database: Error: connect ECONNREFUSED 172.31.0.2:3306
2024-06-28 11:08:58     at Object.createConnection (/app/node_modules/mysql2/promise.js:253:31)
2024-06-28 11:08:58     at createDatabase (/app/create_prod_db.js:4:34)
2024-06-28 11:08:58     at Object.<anonymous> (/app/create_prod_db.js:17:1)
2024-06-28 11:08:58     at Module._compile (node:internal/modules/cjs/loader:1376:14)
2024-06-28 11:08:58     at Module._extensions..js (node:internal/modules/cjs/loader:1435:10)
2024-06-28 11:08:58     at Module.load (node:internal/modules/cjs/loader:1207:32)
2024-06-28 11:08:58     at Module._load (node:internal/modules/cjs/loader:1023:12)
2024-06-28 11:08:58     at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:135:12)
2024-06-28 11:08:58     at node:internal/main/run_main_module:28:49 {
2024-06-28 11:08:58   code: 'ECONNREFUSED',
2024-06-28 11:08:58   errno: -111,
2024-06-28 11:08:58   sqlState: undefined
2024-06-28 11:08:58 }
2024-06-28 11:08:58 connect ECONNREFUSED 172.31.0.2:3306
2024-06-28 11:08:58 Error: connect ECONNREFUSED 172.31.0.2:3306
2024-06-28 11:08:58     at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1595:16)
2024-06-28 11:08:58 Using environment: production

I tried to add a wait-for-it.sh (based on this one) :https://github.com/vishnubob/wait-for-it/blob/master/wait-for-it.sh and also added a init-db.sh :

#!/bin/sh

# Wait for the database to be ready
/usr/local/bin/wait-for-it.sh db:3306 --strict --timeout=60 -- echo "Database is up"

# Run the database creation script
node /app/create_prod_db.js

But in the end I still get errors that make my container crash. The errors comes from this create_prod_db.js file :

const mysql = require('mysql2/promise')

async function createDatabase() {
  const connection = await mysql.createConnection({
    host: process.env.DB_HOST,
    user: process.env.MYSQL_USER,
    password: process.env.MYSQL_PASSWORD,
    database: process.env.MYSQL_DATABASE
  })
  await connection.query(`CREATE DATABASE IF NOT EXISTS \`${process.env.DB_NAME}\``)
  await connection.end()
}

createDatabase().then(() => {
  console.log('Database created or already exists.')
}).catch(err => {
  console.error('Error creating database:', err)
})

Any help would be appreciated, thanks !

I tried using a mariadb image in my docker compose but it gave me similar results. I don't know if the problem comes from the structure of my docker-compose.yml or the env variables issue ?

0

Browse other questions tagged or ask your own question.