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 ?