Hi I have many ongoing website projects, each with their own docker-compose.yml. They basically use the same services (PHP, MySQL, Nginx, etc).
I do use unique COMPOSE_PROJECT_NAME in .env for each project and they have dynamic container names :
mysql:
image: 'mysql:8.0'
container_name: '${APP_NAME}_mysql'
/projects
/project1
/.env
/docker-compose.yml
/project2
/.env
/docker-compose.yml
My problem is the following : database created for project1 is visible in the mysql of the project2 and vice versa rebuilding or destroying mysql for project2, destroys it for project1 also, so I lose database. this becomes a nightmare because I have a lot more than 2 projects.
More info: it also happens that some projects are in PHP7.x and others in PHP8.x, and when I edit my Dockerfile for the PHP service and change the version and rebuild, than all projects are now on the new PHP version, which obviously might break them.
Environment : windows10pro + wsl2 Ubuntu
Adding docker compose file for completeness:
# For more information: https://laravel.com/docs/sail
version: '3'
services:
#PHP Service
app:
build:
context: .
dockerfile: Dockerfile
image: digitalocean.com/php
container_name: ${APP_NAME}_app
restart: unless-stopped
extra_hosts:
- "host.docker.internal:${HOST_GATEWAY}"
tty: true
environment:
SERVICE_NAME: app
SERVICE_TAGS: dev
working_dir: /var/www
volumes:
- ./:/var/www
- ./docker/php/local.ini:/usr/local/etc/php/conf.d/local.ini
- ./docker/php/docker-php-ext-xdebug.ini:/usr/local/etc/php/conf.d/xdebug.ini
networks:
- sail
depends_on:
- mysql
- redis
- mailhog
#Nginx Service
webserver:
image: nginx:alpine
container_name: ${APP_NAME}_webserver
restart: unless-stopped
tty: true
ports:
- "80:80"
- "443:443"
volumes:
- ./:/var/www
- ./docker/nginx/conf.d/:/etc/nginx/conf.d/
- ./docker/certs:/etc/nginx/certs
networks:
- sail
extra_hosts:
- "host.docker.internal:host-gateway"
mysql:
image: mysql:5.7.22
container_name: ${COMPOSE_PROJECT_NAME}_db
restart: unless-stopped
tty: true
ports:
- '${FORWARD_DB_PORT:-3306}:3306'
environment:
MYSQL_DATABASE: '${DB_DATABASE}'
MYSQL_USER: '${DB_USERNAME}'
MYSQL_PASSWORD: '${DB_PASSWORD}'
MYSQL_ROOT_PASSWORD: '${DB_ROOT_PASSWORD}'
MYSQL_ROOT_HOST: "%"
MYSQL_ALLOW_EMPTY_PASSWORD: 1
SERVICE_TAGS: dev
SERVICE_NAME: mysql
volumes:
- /docker/mysql-dump:/var/lib/mysql
- ./docker/mysql/my.cnf:/etc/mysql/my.cnf
networks:
- sail
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-p${DB_PASSWORD}"]
retries: 3
timeout: 5s
pma:
image: phpmyadmin/phpmyadmin
container_name: ${APP_NAME}_pma
restart: always
depends_on:
- mysql
environment:
PMA_HOST: ${DB_HOST}
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
UPLOAD_LIMIT: 300M
ports:
- '8282:80'
networks:
- sail
redis:
image: 'redis:alpine'
container_name: ${APP_NAME}_redis
ports:
- '${FORWARD_REDIS_PORT:-6379}:6379'
volumes:
- 'sail-redis:/data'
networks:
- sail
healthcheck:
test: ["CMD", "redis-cli", "ping"]
retries: 3
timeout: 5s
mailhog:
image: 'mailhog/mailhog:latest'
container_name: ${APP_NAME}_mailhog
ports:
- '${FORWARD_MAILHOG_PORT:-1025}:1025'
- '${FORWARD_MAILHOG_DASHBOARD_PORT:-8025}:8025'
networks:
- sail
networks:
sail:
driver: bridge
volumes:
sail-mysql:
driver: local
sail-redis:
driver: local
Adding Dockerfile
FROM php:8.2-fpm
# Copy composer.lock and composer.json
# COPY composer.lock composer.json /var/www/
# Set working directory
WORKDIR /var/www
# Install dependencies
RUN apt-get update && apt-get install -y \
build-essential \
libpng-dev \
libjpeg62-turbo-dev \
libfreetype6-dev \
libwebp-dev \
locales \
libzip-dev \
jpegoptim optipng pngquant gifsicle \
vim \
unzip \
git \
curl \
libicu-dev \
g++ \
libxml2-dev \
libonig-dev
# Clear cache
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
# Install extensions
RUN docker-php-ext-install pdo_mysql
RUN docker-php-ext-install mbstring
RUN docker-php-ext-install zip
RUN docker-php-ext-install exif
RUN docker-php-ext-install pcntl
RUN docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp
RUN docker-php-ext-install gd
RUN docker-php-ext-configure intl \
&& docker-php-ext-install intl
RUN docker-php-ext-install soap
RUN docker-php-ext-install bcmath
RUN docker-php-ext-install mysqli pdo pdo_mysql && docker-php-ext-enable mysqli
RUN yes | pecl install xdebug \
&& echo "zend_extension=$(find /usr/local/lib/php/extensions/ -name xdebug.so)" > /usr/local/etc/php/conf.d/xdebug.ini \
&& echo "xdebug.remote_enable=on" >> /usr/local/etc/php/conf.d/xdebug.ini \
&& echo "xdebug.remote_autostart=off" >> /usr/local/etc/php/conf.d/xdebug.ini
RUN apt-get -y update
RUN apt-get -y install vim nano
RUN apt-get -y update
RUN apt-get -y install default-mysql-client
# Install composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
# Add user for laravel application
RUN groupadd -g 1000 www
RUN useradd -u 1000 -ms /bin/bash -g www www
# Copy existing application directory contents
COPY docker /var/www
# Copy existing application directory permissions
COPY --chown=www:www docker /var/www
# Change current user to www
USER www
# Expose port 9000 and start php-fpm server
EXPOSE 9000
CMD ["php-fpm"]
You said that your databases share their data in your setup. The only way (ignoring networking) that the containers could share data is via volumes and there is the catch. The 'volumes', as in the -v
/--volume
parameter of docker
command or the docker compose volumes
property, are really two different things:
Volumes are stored in a part of the host filesystem which is managed by Docker (
/var/lib/docker/volumes/
on Linux). Non-Docker processes should not modify this part of the filesystem. Volumes are the best way to persist data in Docker.
Bind mounts may be stored anywhere on the host system. They may even be important system files or directories. Non-Docker processes on the Docker host or a Docker container can modify them at any time.
From docker manual.
The former one, the "real" volumes, are shared on the host.[1] So if another compose file define volume with the same name it points to the same storage space.
That's the reason why the redis data are shared. Oddly enough, as pointed out by the @SIMULATAN in the Q comments, the mysql uses an absolute path therefore the data are shared via bind mounting to a common directory in the host system.
The solution is either to bind mount the data using a paths to unique locations (typically relative paths) or you could use the volumes with names that aren't shared where you don't want. There is pros and cons listed in the already mentioned docs.
If you go with the second option, it could be useful that the volume names could be even set "dynamicaly":
volumes:
mysql:
name: "${MY_VAR}" #overrides the name `data` specified in the line above
[1] The docs said you could define anonymous volume, which could not be shared as they don't have predefined name