How to connect Node express server-docker-image to mysql docker image via digitalOcean droplet?

Viewed 126

I have an experimental app where I am working with images. The goal is to make a full working app with docker containers and images which I have managed to do on my local machine. The issue im having is when im deploying it to digitalocean.

from the node-express-server im getting this error response:

{
    "status": "error",
    "statusCode": 500,
    "message": {
        "errno": "ENOTFOUND",
        "code": "ENOTFOUND",
        "syscall": "getaddrinfo",
        "hostname": "dbcontainer",
        "fatal": true
    }
}

Im using docker-compose file:

services:
  mysql:
    build:
      context: ./DbScripts
      dockerfile: ./Dockerfile.prod
    command:
      - "--default-authentication-plugin=mysql_native_password"
    container_name: dbcontainer
    cap_add:
      - SYS_NICE 
    ports:
      - 3307:3306
    restart: always
    networks:
      - mynetwork
    environment:
      MYSQL_DATABASE: todo
      MYSQL_USER: produser
      MYSQL_ROOT_PASSWORD: Password!
      MYSQL_PASSWORD: Password!
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 1s
      retries: 120
  phpmyadmin:
    # build: .
    image: phpmyadmin/phpmyadmin
    container_name: dev_pma
    networks:
      - mynetwork
    environment:
      PMA_HOST: dbcontainer
      PMA_PORT: 3307
      PMA_ARBITRARY: 1
    restart: always
    ports:
      - 8183:80
  server:
    container_name: server
    build:
      context: ./BE
      dockerfile: ./Dockerfile.prod
    networks:
      - mynetwork
    ports:
      - 4000:4000
  client:
    container_name: FE
    build:
      context: ./FE
      dockerfile: ./Dockerfile.prod
    networks:
      - mynetwork
    ports:
      - 3000:3000
    environment:
      - CHOKIDAR_USEPOLLING=true
    tty: true
volumes:
  db_data:
networks:
  mynetwork:

Im also using dockerfiles inside of the docker-compose. The releveant ones are:

mysql Dockerfile:

FROM mysql

ENV MYSQL_ROOT_PASSWORD Dsb2016!
ADD /DumpTodoOnly.sql /docker-entrypoint-initdb.d

EXPOSE 3306

Above im using a sql file to create database and user:

CREATE USER 'produser'@'localhost' IDENTIFIED WITH mysql_native_password BY 'Password!';

GRANT ALL PRIVILEGES ON *.* TO 'produser'@'localhost' WITH GRANT OPTION;

CREATE DATABASE  IF NOT EXISTS `todo` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;
USE `todo`;
-- MySQL dump 10.13  Distrib 8.0.18, for Win64 (x86_64)
--
-- Host: localhost    Database: todo
-- ------------------------------------------------------
-- Server version   8.0.18

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!50503 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;

--
-- Table structure for table `todos`
--


DROP TABLE IF EXISTS `todos`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `todos` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `todotext` varchar(200) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `users`
--

DROP TABLE IF EXISTS `users`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `users` (
  `Id` varchar(36) NOT NULL,
  `Email` varchar(200) NOT NULL,
  `Password` binary(60) NOT NULL,
  `ChangedPassword` bit(1) NOT NULL,
  `FirstName` varchar(45) NOT NULL,
  `LastName` varchar(45) NOT NULL,
  `ImageId` varchar(36) DEFAULT NULL,
  `SeqRef` varchar(36) DEFAULT NULL,
  PRIMARY KEY (`Id`),
  UNIQUE KEY `Email_UNIQUE` (`Email`),
  UNIQUE KEY `Id_UNIQUE` (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci KEY_BLOCK_SIZE=2;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping routines for database 'todo'
--
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

-- Dump completed on 2022-04-12  0:18:13

The connection in my node express:

const connector = mysql.createPool({
  connectionLimit: 20,
  host: "dbcontainer",
  database: "todo",
  user: "produser",
  password: "Password!",
});

Images

I run docker-compose up -d --build and get this:

enter image description here

I copy the imageId of the server, sql and php and for each of these I tag it :

docker tag imageId ghcr.io/userName/imageName:1

And push it to github packages:

 docker push ghcr.io/userName/imageName:1

DigitalOcean

I connect to my github account and pull the images from github packages.

I run mysql image first and after doing that I enter the container to see if my database and user got created which I can verify that they have since both the Todo db and user "produser" are created on digitalOcean:

--------------------
| Database |
--------------------
| information_schema |
| mysql |
| performance_schema |
| sys |
| todo |
--------------------

------------------
| user |
------------------
| root |
| mysql.infoschema |
| mysql.session |
| mysql.sys |
| produser |
| root |
------------------

The containers on digitalocean look like this:

CONTAINER ID   IMAGE                              COMMAND                  CREATED          STATUS          PORTS                                                  NAMES
e8fc8145a30c   ghcr.io/username/phpnewest:1      "/docker-entrypoint.…"   10 minutes ago   Up 10 minutes   0.0.0.0:8183->80/tcp, :::8183->80/tcp                  agitated_antonelli
dab65fd84ddb   ghcr.io/username/serverlatest:1   "docker-entrypoint.s…"   11 minutes ago   Up 11 minutes   0.0.0.0:4000->4000/tcp, :::4000->4000/tcp              unruffled_goldberg
cc3fdf91e7ab   dbcontainer                        "docker-entrypoint.s…"   13 minutes ago   Up 13 minutes   33060/tcp, 0.0.0.0:3307->3306/tcp, :::3307->3306/tcp   friendly_ardinghelli

Again everything worked on my machine but when pushing to digitalocean I get the server error above and on the phpAdmin I get:

mysqli::real_connect(): php_network_getaddresses: getaddrinfo failed: Name or service not known mysqli::real_connect(): (HY000/2002): php_network_getaddresses: getaddrinfo failed: Name or service not known

Where have I gone wrong? Have I missed a configuration somewhere on the server? Im running a droplet with Docker 19.03.12 on ubuntu.

Im new to docker-compose and as I said im building it and then tagging the images seperatly and pushing them, is this correct? Any guidence is appreciated.

EDIT:

Dont know how relevant this is but when I was inside of the dbcontainer I checked to see hon what host the mysql was running and it was "localhost".

Doing the same for the node-express with the following command:

docker exec -it serverid /bash/sh

And then hostname I just got back the container id.

EDIT2:

Maybe to ultral clear about this: I run docker-compose on my local machine(my pc) only. Then I take each image seperatly and try to connect them on a droplet on digitalOceean.

I have also tried to change my docker-compose to this:

version: "3.7"

networks:
  mynet:

volumes:
  mysqldb_data:
  phpmyadmin_data:

services:
  mysql:
    build:
      context: ./DbScripts
      dockerfile: ./Dockerfile.prod
    command:
      - "--default-authentication-plugin=mysql_native_password"
    environment:
      MYSQL_DATABASE: todo
      MYSQL_USER: produser
      MYSQL_ROOT_PASSWORD: Password!
      MYSQL_PASSWORD: Password!
    volumes:
      - ./DbScripts/DumpTodoOnly.sql:/docker-entrypoint-initdb.d/DumpTodoOnly.sql
      - mysqldb_data:/var/lib/mysql
    networks:
      - mynet
  phpmyadmin:
    image: phpmyadmin/phpmyadmin:fpm-alpine
    environment:
      PMA_HOST: mysql
    volumes:
      - phpmyadmin_data:/var/www/html/
    networks:
      - mynet
    depends_on:
      - mysql
    ports:
      - 8183:80
  nginx:
    image: nginx:1.17.4-alpine
    volumes:
      - ./default.conf:/etc/nginx/conf.d/default.conf:ro
      - phpmyadmin_data:/var/www/html/:ro
    ports:
      - "90:80"
    networks:
      - mynet
    depends_on:
      - mysql
      - phpmyadmin

Sadly this docker-compose attempt resulted in the php admin not working where I get connection_refused both on localhost and on the droplet. the datbase and user still get created on the server and local machine. The nginx did not run on local enviorment but did run on the droplet. Not sure what it should do in this scenario though.

For anyone attempting an ansewr please give me a step by step guide.

Right now I am doing the following:

  1. Run docker-compose on local enviorment
  2. Push each individual image to github packages
  3. Connect to digitalOcean
  4. Pull the images
  5. Run each image on specific port.

My process must be obviosly faulty since it does not work.

1 Answers

After 2 weeks of trying I managed to get this spinning.

The core problem was that I did not quite understand the use of docker-compose. My intial thought was that the images it created could just be used as standalone and then they would autmactially link.

The solution is quite simple

I use this docker-compose:

services:
  mysql:
    build:
      context: ./DbScripts
      dockerfile: ./Dockerfile.prod
    command:
      - "--default-authentication-plugin=mysql_native_password"
    container_name: dbcontainer
    cap_add:
      - SYS_NICE # CAP_SYS_NICE
    ports:
      - 3307:3306
    restart: always
    networks:
      - mynetwork
    environment:
      MYSQL_DATABASE: todo
      MYSQL_USER: produser
      MYSQL_ROOT_PASSWORD: Password!
      MYSQL_PASSWORD: Password!
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 1s
      retries: 120
  phpmyadmin:
    # build: .
    image: phpmyadmin/phpmyadmin
    container_name: dev_pma
    networks:
      - mynetwork
    environment:
      PMA_HOST: dbcontainer
      PMA_PORT: 3307
      PMA_ARBITRARY: 1
    restart: always
    ports:
      - 8183:80
  server:
    container_name: server
    build:
      context: ./BE
      dockerfile: ./Dockerfile.prod
    networks:
      - mynetwork
    ports:
      - 4000:4000
  client:
    container_name: FE
    build:
      context: ./FE
      dockerfile: ./Dockerfile.prod
    networks:
      - mynetwork
    ports:
      - 3000:3000
    environment:
      - CHOKIDAR_USEPOLLING=true
    tty: true
volumes:
  db_data:
networks:
  mynetwork: 

I list my images with docker image ls

I tag these images and push them to my github repo.

Now I create a new docker-compose file for production which refers to my finished images:

services:
  mysql:
    build: .
    image: ghcr.io/githubusername/mysql:1
    command:
      - "--default-authentication-plugin=mysql_native_password"
    container_name: dbcontainer
    cap_add:
      - SYS_NICE 
    ports:
      - 3307:3306
    restart: always
    networks:
      - mynetwork
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 1s
      retries: 120
  phpmyadmin:
    build: .
    image: ghcr.io/githubusername/php:1
    container_name: dev_pma
    networks:
      - mynetwork
    environment:
      PMA_HOST: dbcontainer
      PMA_PORT: 3307
      PMA_ARBITRARY: 1
    restart: always
    ports:
      - 8183:80
  server:
    container_name: server
    build: .
    image: ghcr.io/githubusername/server:1
    networks:
      - mynetwork
    ports:
      - 4000:4000
  client:
    build: .
    image: ghcr.io/githubusername/client:1
    container_name: FE
    networks:
      - mynetwork
    ports:
      - 3000:3000
    environment:
      - CHOKIDAR_USEPOLLING=true
    tty: true
volumes:
  db_data:
networks:
  mynetwork:

Now this is basically where the magic happened:

Once inside of DigitalOcean droplet I created a docker-compose file by nano docker.compose.yml

I add the contents of the production file inside and on the droplet I run docker-compose up

Now I can not say how optimal all of this is at this moment more than you should not show your enviorment variables directly in the docker-compose file but It works.

Related