Database in a Docker application - mysql

I have a Docker web application with its database which I have set up:
-v /home/stephane/dev/php/learnintouch/docker/mysql/data:/usr/bin/mysql/install/data
It works fine but I wonder if that is the recommended way to go.
For I see we can also create a named volume by giving a name instead of an absolute path on the host:
-v learnintouch-data:/usr/bin/mysql/install/data
But then, how can I associate the volume name learnintouch-data with the host location at /home/stephane/dev/php/learnintouch/docker/mysql/data ?
Here is my current docker-compose.yml file:
learnintouch.com-startup:
image: stephaneeybert/learnintouch.com-startup
container_name: learnintouch.com-startup
ports:
- "80:80"
links:
- mysql
- redis
- nodejs-learnintouch
nodejs-learnintouch:
image: stephaneeybert/nodejs-learnintouch
container_name: nodejs-learnintouch
ports:
- "9001:9001"
links:
- redis
mysql:
image: stephaneeybert/mysql:5.6.30
container_name: mysql
ports:
- "3306:3306"
environment:
- MYSQL_ROOT_PASSWORD=root
volumes:
- "/home/stephane/dev/php/learnintouch/docker/mysql/data:/usr/bin/mysql/install/data"
redis:
image: stephaneeybert/redis:3.0.7
container_name: redis
ports:
- "6379:6379"

Using a named volume (or more specifically a volume created using the Docker Engine volume API) with a defined host path doesn't have much of an advantage over the method you've used. Technically, it is "easier" to create a new container, but only because you no longer have to remember the path. You can also use the volume API to "manage" the volume independently from the application container, but this is equally easy using the docker container API.
If you insist, to create a named volume with an absolute host path, you need to use a volume-driver. I would suggest local-persist. It is quite simple to install and works well.
https://github.com/CWSpear/local-persist

Related

Docker mysql container doesn't persist data despite using volumes. Why?

I am running two docker containers.
mysql
adminer
I want to persist my database, therefore I use volumes in my docker-compose file. Still I lose data whenever I restart the containers (docker-compose down and up).
What I am missing? (I am on ubuntu 20.04)
services:
adminer:
image: adminer
restart: always
ports:
- 8080:8080
db:
image: mysql:latest
restart: always
environment:
MYSQL_ROOT_PASSWORD: 'example' # TODO: Change this
volumes:
- "./config/my.conf:/etc/mysql/conf.d/config-file.cnf"
- "./data:/var/lib/mysql:rw"
Use docker-compose stop instead of docker-compose down.
From the documentation:
docker-compose down:
Stops containers and removes containers, networks, volumes, and images created by up.

Where is docker mysql file persisted on local system

I've created a simple React/spring-boot/mysql app which I've now ported into docker, including data persisting between deletions of the mysql container. According to docker-compose.yml, the local storage should be at /var/lib/mysql, but I don't see it there.
This makes me nervous - where is the data being stored? I want to make sure it's on the local filesystem and not in some container which I might easily delete.
Here's the docker-compose.yml file:
version: "3"
services:
# Backend Service
app-server:
image: licensing-app
ports:
- "8080:8080"
networks:
- backend
depends_on:
- mysqldb
environment:
- "SPRING_PROFILES_ACTIVE=prod"
- "AWS_ACCESS_KEY_ID=xxxxx"
- "AWS_SECRET_ACCESS_KEY=xxxxxxx"
# Frontend Service
app-client:
image: license_front_end
ports:
- "3000:80"
restart: always
depends_on:
- app-server
networks:
- backend
# Database Service (Mysql)
mysqldb:
image: mysql:8
ports:
- "3307:3306"
environment:
MYSQL_ROOT_PASSWORD: mypass
MYSQL_DATABASE: license_db
volumes:
- db-data:/var/lib/mysql
networks:
- backend
# Volumes
volumes:
db-data:
# Networks to be created to facilitate communication between containers
networks:
backend:
It's in a Docker named volume. You can't (*) directly access it, but it will get persisted across runs. Repeating docker-compose up will reuse an existing volume, even if the database container is deleted and recreated; by default docker-compose down will not delete the volume (you explicitly need a --volumes option).
If you want to be able to directly see the files (and have an easier time backing them up) you can use a bind-mounted host directory instead. Depending on your host OS, these could have rather different performance and permission characteristics. (On MacOS especially, bind mounts are very slow, so if you're in a development setup and recreating the database is possible, you might prefer a named volume if the database content is totally opaque anyways.)
services:
mysqldb:
volumes:
# Relative or absolute path, but not a bare name
- ./db-data:/var/lib/mysql
(*) If you go poking around in /var/lib/docker on a native-Linux host you can find the named-volume contents, but this is an implementation detail, and I don't think Docker actually makes any stability guarantees about the format of what's stored in that directory; using a bind mount is much better practice than poking around in Docker's internal storage.

MariaDB volume in docker-compose clears out data

I'm using the yobasystems/alpine-mariadb docker image to run an instance for a development environment. I'm mounting the data directory for MySQL to a docker volume and this has worked in the past. Every so often I lose data but not the table structure and I cannot work out why.
db:
image: yobasystems/alpine-mariadb
restart: always
environment:
- MYSQL_ROOT_PASSWORD=password
- MYSQL_DATABASE=database
- MYSQL_USER=user
- MYSQL_PASSWORD=password
ports:
- "33333:3306"
volumes:
- mariadb:/var/lib/mysql
I suspect that in your case the volume is getting removed(may be via docker-compose down -v or dockere-compose rm -v).
Please specify that the volume is external using -
volumes:
mariadb:
external: true
From docker docs - external: If set to true, specifies that this volume has been created outside of Compose. docker-compose up does not attempt to create it, and raises an error if it doesn’t exist.
You may create the volume prior to docker-compose up with docker volume create mariadb

Docker compose wait for database service initialisation

I have a spring boot project which I'd like to containerize using docker.
I have a couple of spring boot applications which connect to same MySql server.
My spring applications requires the database to be completely setup (i.e. all the tables to be created and some data to be inserted in some of the tables) in order to start.
I am using Docker version 18.09.0 and docker-compose version 1.23.1 and ubuntu 16.04 LTS
I have two files create.sql and insert.sql, which I use to initialise the database to be used by the application.
I create the images using the command docker-compose.yml and it runs successfully and creates the images.
I have the following questions.
I assume when using docker-compose, a container starts as soon as all its dependent containers have started. Is there a way to wait for the mysql server to be up and ready to accept connections, before my API container gets started?
If I chose to create containers separately for the applications and mysql, and not use docker-compose, how do I make sure that my applications connect to the mysql container?
Is there any other tool which might help me achieve this?
Note:
I have tried to use docker inspect <container_id> to find the the IpAddress for the mysql container and use it to connect, but it doesn't work as well.
The following are the files I am using to create images.
docker-compose.yml file.
version: '3'
services:
demo-mysql:
image: demo-mysql
build: ./demo-mysql
volumes:
- /mnt/data/mysql-data:/var/lib/mysql
ports:
- 3306:3306
environment:
- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE=demo
- MYSQL_PASSWORD=root
demo-api:
image: demo-api-1.0
build: ./api
depends_on:
- demo-mysql
ports:
- 8080:8080
environment:
- DATABASE_HOST=demo-mysql
- DATABASE_USER=root
- DATABASE_PASSWORD=root
- DATABASE_NAME=demo
- DATABASE_PORT=3306
demo1-app:
image: demo1-app-1.0
build: ./demo1
depends_on:
- demo-mysql
ports:
- 8090:8090
environment:
- DATABASE_HOST=demo-mysql
- DATABASE_USER=root
- DATABASE_PASSWORD=root
- DATABASE_NAME=demo
- DATABASE_PORT=3306
The following is the Dockerfile for the spring boot project
FROM java:8
VOLUME /tmp
ARG DATA_PATH=/src/main/resources
ARG APP_PORT=8080
EXPOSE ${APP_PORT}
ADD /build/libs/demo-api.jar demo-api.jar
ENTRYPOINT ["java","-jar","demo-api.jar"]
The following is the Dockerfile I used to create my mysql image
FROM mysql:5.7
ENV MYSQL_DATABASE=demo \
MYSQL_USER=root \
MYSQL_ROOT_PASSWORD=root
ADD ./1.0/create.sql /docker-entrypoint-initdb.d
ADD ./1.0/insert.sql /docker-entrypoint-initdb.d
EXPOSE 3306
Use the healthcheck feature of docker-compose (https://docs.docker.com/compose/compose-file/#healthcheck).
Something like this:
services:
demo-mysql:
image: demo-mysql
build: ./demo-mysql
volumes:
- /mnt/data/mysql-data:/var/lib/mysql
ports:
- 3306:3306
environment:
- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE=demo
- MYSQL_PASSWORD=root
healthcheck:
test: ["CMD-SHELL", 'mysqladmin ping']
interval: 10s
timeout: 2s
retries: 10
The depending containers will not start until the demo-mysql container is healthy
After trying several approaches, IMO the simplest and most elegant option is using the jwilder/dockerize utility image with its -wait flag. Here is a simple example where I need a MySQL database to be ready before starting my app:
version: "3.8"
services:
# Start MySQL.
db:
image: mysql
# Wait for MySQL to be joinable.
check-db-started:
image: jwilder/dockerize:0.6.1
depends_on:
- db
command: 'dockerize -wait=tcp://db:3306'
# Only start myapp once MySQL is joinable.
myapp:
image: myapp:latest
depends_on:
- check-db-started

How to create Mysql test database in dockerized Rails application?

I managed to dockerize my existing Rails application running on a Mysql database. But I wonder if it is possible to setup docker-compose to create the test database in the same container?
Here is my docker-compose.yml and it wirks fine with the mysql for developing
version: '2'
volumes:
db-data:
services:
db:
image: mysql:5.5
restart: always
ports:
- "3307:3306"
environment:
MYSQL_ROOT_PASSWORD: verysecret
MYSQL_USER: appdb
MYSQL_PASSWORD: secret
MYSQL_DATABASE: appdb
volumes:
- db-data:/var/lib/mysql
web:
build: .
command: bundle exec rails s -p 3000
volumes:
- .:/app
ports:
- "3000:3000"
links:
- db
depends_on:
- db
Can I add a darabase more in environment part somehow?
You can create only one DB per Mysql container with docker compose. In your case, I think you should create a second DB container for the second database (isolated from the "real" DB, which is a good practice).
If you really want to have the 2 databases in the same container, you will have to create a Dockerfile based on the Mysql image, and add your command lines (RUN) to create the second DB.
HTH
Yes, you can, but it won't necessarily be as a single container, but a manager for coupling containers. If this is okay, I've added some steps that will help you configure your project. If not, I've added how to run a single image from a docker-compose file
You will want to start off by creating a docker-compose.yml file in the source directory for your project.
Then you'll want to add something like this inside your yml file.(this was taken from Docker's quick-start documentation. Modified to show mysql instead of postgres)
version: '3'
services:
db:
image: mysql
web:
build: .
command: bundle exec rails s -p 3306 -b '0.0.0.0'
volumes:
- .:/myapp
ports:
- "3000:3000"
depends_on:
- db
Detail on how they create one can be found here:
https://docs.docker.com/compose/rails/#define-the-project.
Things to note:
web is the details about the rails container. So you will want to add an image property if you have already created your rails image.
Also, build: . is expecting your Dockerfile to be in the same location as your project. So if you create this docker-compose.yml somewhere else, you'll have to provide the path.
depends_on allows your app to build the DB before running rails
Once you finished creating the docker-compose.yml file run:
docker-compose build
followed by:
docker-compose up
If separating the containers, isn't what you are looking for: then you might want to look into creating a single image running both applications. Then use something like this to run from docker-compose.
version: '3'
services:
app:
image: {your-app-image}
build: .
volumes:
- .:/myapp
ports:
- "3000:3000"
- "3306:3306"
Note: somethings might vary on how you create your image from the Dockerfile.