Can't connect nodejs and mysql in same docker - mysql

I'm new in docker and i'm trying to make my nodejs express run inside it.
I'm trying to install the dependencies using shellscript and its working but in the end I can't connect to mysql.
My docker file install mysql, create an user and a database, and install nodejs too.
Then it runs npm install and try to start my app but knex says it can't connect to the mysql with the message:
Knex:Error Pool2 - Error: connect ECONNREFUSED /var/run/mysqld/mysqld.sock
Here's a gist with the code i'm using. (nodejs part is incomplete, just with the important part):
https://gist.github.com/jradesenv/527f6e59ab2e7985c38fbed3a2084c83
I hope anyone will have a good ideia on how to resolve or debbug this.

The best practice is to keep the components of a micro-service separate in their own container.
See for instance "Learn Docker by building a Microservice" from Dave Kerr.
He does declare two services:
version: '2'
services:
users-service:
build: ./users-service
ports:
- "8123:8123"
depends_on:
- db
environment:
- DATABASE_HOST=db
db:
build: ./test-database
With a dedicated Dockerfile for the database:
FROM mysql:5
ENV MYSQL_ROOT_PASSWORD 123
ENV MYSQL_DATABASE users
ENV MYSQL_USER users_service
ENV MYSQL_PASSWORD 123
ADD setup.sql /docker-entrypoint-initdb.d

Docker containers are designed to run a single command. The mysql installer expects the service it registered to automatically be started on the OS bootup, but that's not the case inside of a container.
The proper solution is to split these into two separate containers, one db container, and another nodejs/app container. Link and run the two together with a docker-compose configuration that automatically sets up the host names.
The less ideal option is supervisord which you can use to run and manage multiple processes inside of the container. You install it just like any other app, configure your db and node app as two services for supervisord to manage, and then launch supervisord as your container's run command.

Use docker-compose and create a dockerfile for your nodejs and one for mysql. Each container is responsible for doing their thing. In your compose, link them. Then point your nodejs db connection to the mysql container.

Related

Trying to establish connection between mysql and web server but getting error with Help of Dockerfile

I am trying to connect two server one is database(mysql) and second one is webserver(httpd). In docker, image created with dockerfile and created two containers and running code in both of them. both are running, web server front-end code working fine when i tried to enter data, got errors. I looked out in /var/log/httpd/error_log ---> mysql connection cannot find host "data".
I want to know that how can i defined host of database in web-server ? Because of 2 Dockerfile connection issue, both IP addr in same subnet. What is the main issue ?
The containers have to be in the same docker network and hostnames are service names (by default).
I advise you to use docker-compose which is designed to run multiple containers with links between them.
A priori, I would make something like that in my docker-compose.yml:
version: '2.4'
services:
db:
build:
context: .
dockerfile: db.dockerfile
environment:
- MYSQL_ROOT_PASSWORD=foo
web:
build:
context: .
dockerfile: web.dockerfile
Then, type docker-compose up -d. Finally, from web container, you would be able to reach the host 'db'.
If you want to work only with dockerfiles, it is also possible if my first sentence of this post is verified. By default, containers are on network bridge, so your containers probably are in the same network but you have to link them so that then can communicate. After you have launched db container, you have to run the web container with the following option:
docker run ... --link <db_container_name>:<db_host_name_in_web_container> ...
Thus, you would be able to reach db from web.

How to tie mysql database in one container to another container running my django blog app (with docker-compose)

I have created a blog app with django and attached it to a mysql database stored on my local machine(localhost), which I manage through phpmyadmin.
However, I switched to an ubuntu 18.04 LTS (previously on a windows machine) and wanted to deploy my app with docker containers.
I want to run mysql database in one container, and my blog app in another container, and have them communicate with each other (I am using docker-compose to achieve this).
Below is the DATABASES dictionary on my app:
And here is docker-compose.yml file.
After firing the docker-compose up command, I get this error:
It says '(2006, "Authentication plugin 'caching_sha2_password' cannot be loaded: dlopen(/usr/local/mysql/lib/plugin/caching_sha2_password.so: cannot open shared object file: No such file or diectory")'.
In the DB container, you are only setting password for root user but using test user. So you either need to set MYSQL_PASSWORD env var. Or use root user.
More on the env variables in mysql docker hub docs
My recommendation is to change db service definition to
services:
db:
image: mysql
enviroment:
MYSQL_RANDOM_ROOT_PASSWORD: 1
MYSQL_DATABASE: test
MYSQL_USER: test
MYSQL_PASSWORD: test
This encurages not to use root user, which is considered best practice.
What actually probably causes this errors is that you have wrong version of mysql. On mysql docker hub, you can see that the latest tag (with is the implicit tag if you don't provide any), is the same as 8.0. But a lot of apps is only compatible with the older 5.7. To switch this, in your docker-compose add 5.7 tag:
services:
db:
image: mysql:5.7
(5.7 and 8.0 is actually only one major release apart, and 8.0 was released in 2017)

docker run phpmyadmin inside alpine container

I discovered docker last week and am playing around withit for a decent time.
Now I want to deploy a Website inside a Container. The Website is already finished and I got all the files on my host system. It needs php, java, tomcat and - and here is the problem - a mysql-db.
So I created a Dockerfile, using alpine:latest as base image and after that installing the above named applications one by one.
FROM alpine:latest
ENV http_proxy http://not_important/
RUN apk update
RUN apk --no-cache --quiet add openjdk8
RUN apk --no-cache --quiet add nano
RUN apk --no-cache --quiet add php7
RUN apk --no-cache --quiet add mysql
RUN apk --no-cache --quiet add phpmyadmin
RUN mkdir -p /usr/local/tomcat/
COPY apache-tomcat-9.0.4.tar.gz /usr/local/tomcat/
RUN cd /usr/local/tomcat/ && tar xzf /usr/local/tomcat/apache-tomcat-9.0.4.tar.gz
RUN mv /usr/local/tomcat/apache-tomcat-9.0.4/* /usr/local/tomcat
RUN rm -r /usr/local/tomcat/apache-tomcat-9.0.4
RUN rm -r /usr/local/tomcat/apache-tomcat-9.0.4.tar.gz
CMD ["/usr/local/tomcat/bin/catalina.sh", "run"]
But now, I dont rly know how to finish my work. How am I able to start the mysql-db and access it with phpmyadmin?
I run the container with the following command:
docker run --name alpine_custom -dit -p 30000:8080 -p31000:80 alpine:custom
The tomcat is running on port 30000 without a problem and I want phpmyadmin to be accessable over port 31000. I do have a working MySQL-DB on my Host and manage it with phpmyadmin (meaning, there are two containers, the phpmyadmin container is linked with the database)...
Is it even possible to do it like I want it, or do I have to deploy a second container with a database which is linked with my alpine container (and a third one with phpmyadmin...)?
I am thankful for every answer, thank you in advance
Sincerely
Telvanis :)
PS: I know, the Dockerfile isn't very good but i think its enough for my needs ^^
Try to avoid having it "all-in-one".
This is the idea behind Docker, to go from something "monolithic" to something which is separated to components. This approach gives you an advantage when you want to scale up/down your app, update specific components without rebuilding the whole app... etc.
Try to avoid the installation & configuration of every technology on your own
I remember myself trying to do so with MySQL. I spent much time and had no result. Ended up using the official image. The installation of a software inside docker might have tricky parts and not be the same with the installation one does in a VM.
So, I would propose to start searching for the official images of the technologies that you are trying to put into use. Docker hub has plenty and most of them also provide guidelines on how to use/configure them. For example:
https://hub.docker.com/r/phpmyadmin/phpmyadmin/
https://hub.docker.com/_/mysql/
https://hub.docker.com/_/openjdk/
...you get the idea.
Your running containers will have names. Docker offers a DNS mechanism so that your containers can connect to each other by using these names. For example if you have a container for your MySQL database named my_app_db listening on port 5000, configure the phpmyadmin container to connect there. An important notice here: don't try these on the default network, because it will not work. Define your own test-network.
Dealing with 3,4,5... or maybe more containers will make you type commands to build them, run them, start/stop them. Here is where docker-compose comes in and proves to be very handy. Within a docker-compose.yml file, you can define a "composition" of inter-connecting containers and handle them with single commands like docker-compose up, docker-compose down etc...
Working example:
comes from here, but is slightly modified...
docker-compose.yml file:
version: '2'
services:
mysql:
image: mysql:latest
container_name: phpmyadmin_testing_mysql
environment:
- MYSQL_ROOT_PASSWORD=test123
phpmyadmin:
image: phpmyadmin/phpmyadmin:latest
container_name: phpmyadmin_testing
volumes:
- /sessions
ports:
- 8090:80
environment:
- PMA_ARBITRARY=1
- TESTSUITE_PASSWORD=test123
depends_on:
- mysql
To run, simply use docker-compose up. To connect, use:
server: phpmyadmin_testing_mysql (the name of the MySQL container)
username: root
password: test123

MySQL in Docker container

Currently I have a Docker container that hosts a webpage (mostly php). Right now the database is stored on a server on AWS. For development purposes I want to create a local database in the Docker container. I did some googling around and it seems like most people recommend creating an entire separate container for hosting the mysql. Since this is only a database for development I am wondering if I can avoid the effort of setting up another container and put MySQL in directly in the container that hosts the webpage. To do this I tried installing MySQL-Server:
sudo apt-get install mysql-server
Mysql installed fine doing this. Then I tried to run the MySQL interactive shell:
mysql -u root -p
When I did this I got the following error ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)
Can I run the mysql in the same Docker container or am I going to need to create a separate one?
There is really no effort in setting up separate MySQL container. Real effort is to install it inside existing container.
I would recommend that you create docker compose file and define application and database containers (make sure you have docker compose installed on your dev environment, in most cases it should be already installed).
Create a file docker-compose.yml (you can create it in the same folder where Dockerfile is for you project, usually project root folder) with following content:
version: '2'
services:
app:
image: your_app_docker_image_name
...more config options depending on your project (volumes, ports, etc)
db:
image: mariadb
volumes:
- './user/db:/var/lib/mysql'
environment:
- MYSQL_ALLOW_EMPTY_PASSWORD=true
To start your project run
docker-compose up
This will lift your app container and separate MySQL container (without root password intentionally since this is for dev purpose).
Now you can access mysql server from your app container like this
mysql -h db -u root
Using docker compose you can setup complex environments easily. And when deploying to production or other test environment you don't need to change your Dockerfile.
There are many pros to have separate containers for each service.
To have php+apache+mysql in the same container you either have to find an image like this https://github.com/tutumcloud/lamp, or build it yourself from a Dockerfile.
But try to imagine one day you decide to switch your db storage engine from Mysql to Percona or Maria, or you would like to start using Memcached/Redis for your application. Either of the above won't be any problem if you have your services as separate containers.

Access to mysql container from other container

I have setup docker container with mysql that expose 3306.
I've specified database user, database password and create a test db and give the privileges to new user.
In another container i want to accesso to this db.
So i set up new container with a simply php script that create new table in this db.
I know that mysql container's ip is 172.17.0.2 so :
$mysqli = new mysqli("172.17.0.2", "mattia", "prova", "prova");
Than using mysqli i create new table and all works fine.
But i think that connect to container using his ip address is not good.
Is there another way to specify db host? I tryed with the hostname of the mysql container but it doens't work.
The --link flag is considered a legacy feature, you should use user-defined networks.
You can run both containers on the same network:
docker run -d --name php_container --network my_network my_php_image
docker run -d --name mysql_container --network my_network my_mysql_image
Every container on that network will be able to communicate with each other using the container name as hostname.
You need to link your docker containers together with --link flag in docker run command or using link feature in docker-compose. For instance:
docker run -d -name app-container-name --link mysql-container-name app-image-name
In this way docker will add the IP address of the mysql container into /etc/hosts file of your application container.
For a complete document refer to:
MySQL Docker Containers: Understanding the basics
In your docker-compose.yml file add a link property to your webserver service:
https://docs.docker.com/compose/networking/#links
Then in your query string, the host parameter's value is your database service name:
$mysqli = new mysqli("database", "mattia", "prova", "prova");
If you are using docker-compose, than the database will be accessible under the service name.
version: "3.9"
services:
web:
build: .
ports:
- "8000:8000"
db:
image: postgres
ports:
- "8001:5432"
Then the database is accessible using: postgres://db:5432.
Here the service name is at the same time the hostname in the internal network.
Quote from docker docs:
When you run docker-compose up, the following happens:
A network called myapp_default is created.
A container is created using web’s configuration. It joins the network myapp_default under the name web.
A container is created using db’s configuration. It joins the network myapp_default under the name db.
Source:
https://docs.docker.com/compose/networking/