MySQL in Docker container - mysql

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.

Related

Spring-boot failing to connect to mysql container even after supplying proper mysql service name

This might sound repeated question but it is not and this is a crazy bug I feel, however, let me quickly explain my setup:
A simple Spring bootstrap application that runs pretty well on my local and JDBC connection string in application.properites file is as follows.
spring.datasource.url=jdbc:mysql://minesql:3306/datamachine?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=****
The docker running instances are:
I copied (with the help of docker cp command) the war file to alpine (unix container) and running it in interactive mode to test and it is throwing exception as it is unable to ping the mysql server. I am certain that the database configurations are fine and clueless why the springboot app is failing to connect to mysql container instance. Note, the mysql container does have "datamachine" database created manually.
This is the error reported:
Please help me understand what I am missing here or what is going wrong.
Just in-case if you wish to know how I started these containers.
For mysql:
docker run -d --name minesql -e MYSQL_ROOT_PASSWORD=**** -p 3306:3306 mysql
Running Java app from the alpine container and this is how I am starting the alpine,
docker run -it --name unix alpine
The interactive mode present me the bash prompt to run the spring-boot war file. (..and running the war file after installing the java 8 in alpine)
You have two docker containers which are running and connected via default bridge network. From docker bridge documentation
Containers on the default bridge network can only access each other by
IP addresses, unless you use the --link option, which is considered
legacy. On a user-defined bridge network, containers can resolve each
other by name or alias.
If you need the second container to be able to resolve the name minesql from inside, you need to create a user-defined network bridge and connect the docker container containers to that.
Create a new network using
docker network create my-net
And add your containers as specified here
Other alternative is to use docker-compose and avoid manual creation of bridge networks for name resolution. For production environment, that would be ideal.

Switch from docker mysql container to host's mysql without using network-mode="host"

My company has a docker-container based website (Ubuntu containers), deployed via GitHub => CircleCI => AWS. (This was set up by a consultant, who we are not currently working with. I'm trying to make sense out of everything on my own.)
I've copied the source files to my Windows 10 development PC.
Locally, the website is running successfully, until it tries to access MySQL data.
I've installed MySQL (8) locally, with default settings (port 3306) and location (C:\ProgramData\MySQL\MySQL Server 8.0\Data), and imported the database. I've created root user. Running test queries as root from MySQL Workbench works.
I've read Q&A's such as How to connect locally hosted MySQL database with the docker container.
I've successfully bridged to host's IP (on EthernetV; Docker running in Hyper-V) 172.26.92.81 for other purposes, specifically to have XDebug in my website container talk to phpstorm on my Windows 10 host. (I could use host.docker.internal for IP; but I'm making everything as "concrete" as possible, until everything works.)
I just don't understand what I have to change where, for redirecting MySQLi queries (in php as create web pages) to the (development pc) host. (Assume I'm clueless about both MySQL and Docker and Apache, until proven otherwise.)
Relevant parts of (original) docker-compose.yml:
mywebsite:
build:
context: ./mywebsite/
dockerfile: Dockerfile
...
depends_on:
- mysql
links:
- mysql
environment:
MYSQL_HOST: mysql
MYSQL_USER: root
MYSQL_PASS: xxx
MYSQL_SCHEMA: xxx
MYSQL_PORT: 3306
MYSQL_CHARSET: utf8
mysql:
image: mysql:5.7
ports:
- 3305:3306
command: mysqld --sql_mode=""
environment:
MYSQL_DATABASE: xxx
MYSQL_ROOT_PASSWORD: xxx
volumes:
- data:/var/lib/mysql
NOTE: Not going for "best practices" above; I need to see a simple approach working. Security comes later.
I'd prefer a solution that doesn't involve "network_mode: "host" -- solving it that way would avoid details that I need to understand. [The linked Q&A shows that host mode is the simplest solution, but that is "too simple" - obscures some important considerations.]
Host has MySQL on its port 3306. The mysql container shown above: is it using its own copy of MySQL? Or is that already attempting to connect to host's MySQL? And why does it have the port mapping 3305:3306? (I can't change that to 3306:3306; if do so, it is unable to assign the port number. I assume that is because host's MySQL already uses 3306, and that port line is exposing the mysql container's MySQL?)
The volume mapping data:... is where I should move the data to, if I want to use the mysql container as is? That's probably what I will do for now - which may make this SO question moot - but I'd still like to know how to do what I ask.
I'm assuming it is its own database, because it has its own version number (5.7).
From php inside mywebsite:
$connection = new \mysqli(
$_ENV["MYSQL_HOST"],
$_ENV["MYSQL_USER"],
$_ENV["MYSQL_PASS"],
'INFORMATION_SCHEMA',
$_ENV["MYSQL_PORT"]
);
$result = $connection->query("SELECT VERSION();");
# breakpoint: $result > one row > ['VERSION()'] = 5.7.25
which is the version number of that mysql image, not the host's mysql.
similarly, list of databases doesn't include some databases I see on the host mysql from Workbench.
What changes do I need to make in docker-compose.yml?
Do I also need to make changes in mywebsite's Dockerfile?
mywebsite is based on apache2 + php 7.3. Dockerfile:
FROM php:7.3.3-apache-stretch
...
RUN apt-get update && ... docker-php-ext-install ... mysqli \
&& docker-php-ext-enable mysqli ...
...
COPY /php.ini /usr/local/etc/php/
COPY /src/ /var/www/html/
First of all, the declaration:
links:
- mysql
in the mywebiste service is not needed and actually stays in the way of you solving your issue. You should remove it.
After doing that, you can try 2 things (both of them worked for me):
change MYSQL_HOST to point to your computer's IP (not 'localhost', not '127.0.0.1' but your local network IP address) and start only the mywebsite service.
in version 3.0 or higher of docker-compose file you can add extra hosts:
mywebsite:
...
extra_hosts:
- "mysql:<your ip>"
I hope this helps

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)

Can't connect nodejs and mysql in same docker

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.

How Wordpress should be runned on Docker

I am very newbie on all of this stuff of Docker. I've read on some sites that should exist one image per each application is running. This means that for run wordpress I would need at least 2 images: One for MySQL and another for Wordpress (and apache). In fact, the official Wordpress docker image does not include MySQL, requires an external connection.
But I've found some images in which MySQL is embedded on the image among wordpress and Apache. This gives you a more portable image because you only need that to deploy on any server. But if in the system is already running an image of docker you are wasting resources.
So, my question is if Wordpress should be runned on a same image with MySQL or not. And if not, how it should be done to move all data on MySQL to a different location.
The standart way is having a container per service, so you will have a container for MySQL and another one for Apache/PHP with the application.
If your are going to use the official MySQL container, and you want to persist the data, you just can to mount a volume from your host to the datadir in the mysql container:
$ docker run --name some-mysql -v /my/own/datadir:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag
This will create a folder in the /my/own/datadir path of your host with all the content of MySQL.
You can find more information about that in that link:
https://github.com/docker-library/docs/tree/master/mysql#where-to-store-data