I have a project developed with PHP and I want to move it inside a Docker container. I want to import database automatically inside Dockerfile.
If I import the database after building the container all works fine (docker exec -it my-laravel-app bash
then mysql -u user -p1993 -h db bsp < /var/www/database/bsp.sql
).
I get the error failed to solve: process "/bin/sh -c wait-for-it -t 30 ${DB_HOST}:${DB_PORT} if [ -f /var/www/database/bsp.sql ]; then mysql -u ${DB_USERNAME} -p${DB_PASSWORD} -h ${DB_HOST} ${DB_DATABASE} < /var/www/database/bsp.sql; fi" did not complete successfully: exit code: 2
.
Dockerfile
# Set the base image for subsequent instructions
FROM php:8.2-fpm
# Install dependencies
RUN apt-get update && apt-get install -y \
build-essential \
libpng-dev \
libonig-dev \
libxml2-dev \
zip \
curl \
unzip \
git \
libzip-dev \
libfreetype6-dev \
libjpeg62-turbo-dev \
default-mysql-client \
wait-for-it \
libpng-dev && \
docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd zip
# Clear cache
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
# Install Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# Set working directory
WORKDIR /var/www
# Remove default server definition
RUN rm -rf /var/www/html
# Copy existing application directory contents
COPY . /var/www
# Copy existing application directory permissions
COPY --chown=www-data:www-data . /var/www
# Change current user to www
USER www-data
ENV DB_HOST=db
ENV DB_PORT=3306
ENV DB_DATABASE=bsp
ENV DB_USERNAME=user
ENV DB_PASSWORD=1993
# Wait for the database to be ready and import SQL dump
USER root
RUN wait-for-it -t 30 ${DB_HOST}:${DB_PORT} \
if [ -f /var/www/database/bsp.sql ]; then \
mysql -u ${DB_USERNAME} -p${DB_PASSWORD} -h ${DB_HOST} ${DB_DATABASE} < /var/www/database/bsp.sql; \
fi
# Expose port 9000 and start php-fpm server
EXPOSE 9000
CMD ["php-fpm"]
I have a project developed with PHP and I want to move it inside a Docker container. I want to import database automatically inside Dockerfile.
If I import the database after building the container all works fine (docker exec -it my-laravel-app bash
then mysql -u user -p1993 -h db bsp < /var/www/database/bsp.sql
).
I get the error failed to solve: process "/bin/sh -c wait-for-it -t 30 ${DB_HOST}:${DB_PORT} if [ -f /var/www/database/bsp.sql ]; then mysql -u ${DB_USERNAME} -p${DB_PASSWORD} -h ${DB_HOST} ${DB_DATABASE} < /var/www/database/bsp.sql; fi" did not complete successfully: exit code: 2
.
Dockerfile
# Set the base image for subsequent instructions
FROM php:8.2-fpm
# Install dependencies
RUN apt-get update && apt-get install -y \
build-essential \
libpng-dev \
libonig-dev \
libxml2-dev \
zip \
curl \
unzip \
git \
libzip-dev \
libfreetype6-dev \
libjpeg62-turbo-dev \
default-mysql-client \
wait-for-it \
libpng-dev && \
docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd zip
# Clear cache
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
# Install Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# Set working directory
WORKDIR /var/www
# Remove default server definition
RUN rm -rf /var/www/html
# Copy existing application directory contents
COPY . /var/www
# Copy existing application directory permissions
COPY --chown=www-data:www-data . /var/www
# Change current user to www
USER www-data
ENV DB_HOST=db
ENV DB_PORT=3306
ENV DB_DATABASE=bsp
ENV DB_USERNAME=user
ENV DB_PASSWORD=1993
# Wait for the database to be ready and import SQL dump
USER root
RUN wait-for-it -t 30 ${DB_HOST}:${DB_PORT} \
if [ -f /var/www/database/bsp.sql ]; then \
mysql -u ${DB_USERNAME} -p${DB_PASSWORD} -h ${DB_HOST} ${DB_DATABASE} < /var/www/database/bsp.sql; \
fi
# Expose port 9000 and start php-fpm server
EXPOSE 9000
CMD ["php-fpm"]
It is simple. Your database do not run in this application container. Rather, it is probably running in a different container (i.e. hostname db
in your environment).
When your image is building, it has no access to other running container(s).
So instead of using RUN
to do things in build time, you should probably have script in your container to run the import when you first run the image against your environment, which provides proper access to the database.
This is a problem with the RUN directive, more specifically the command in it:
RUN wait-for-it -t 30 ${DB_HOST}:${DB_PORT} \
if [ -f /var/www/database/bsp.sql ]; then \
mysql -u ${DB_USERNAME} -p${DB_PASSWORD} -h ${DB_HOST} ${DB_DATABASE} < /var/www/database/bsp.sql; \
fi
What we can see is, that these compound commands do result in exit code 2.
This is a hint that it is a syntax error, because in the first line the wait-for-it command is not separated from the if that follows.
Insert a semicolon ";" and additionally set the sh(1) shell options to errexit (-e) and xtrace (-x) to have it more straight forward:
RUN set -ex; \
wait-for-it -t 30 ${DB_HOST}:${DB_PORT}; \
if [ -f /var/www/database/bsp.sql ]; then \
mysql -u ${DB_USERNAME} -p${DB_PASSWORD} -h ${DB_HOST} ${DB_DATABASE} < /var/www/database/bsp.sql; \
fi
Additionally look into the build log for messages like
sh: syntax error near unexpected token `then'
or similar.
There are some other sloppy things in the Dockerfile, double check also the COPY lines, it looks like you are copying two times the same files. Before adding new functionality into the build, clean up first and commit the files to version control. Then it's easier to throw things around with Dockerfiles.
I've did it, thanks for your answers! This is the complete docker-compose.yml file. I've used /docker-entrypoint-initdb.d/ directory where I placed the database to be imported.
services:
app:
build:
context: .
dockerfile: Dockerfile
image: my-laravel-app
container_name: my-laravel-app
restart: unless-stopped
working_dir: /var/www
volumes:
- ./:/var/www
- ./.env:/var/www/.env
environment:
- APP_ENV=local
networks:
- app-network
nginx:
image: nginx:alpine
container_name: my-nginx
ports:
- "8000:80"
- "${VITE_PORT:-5173}:${VITE_PORT:-5173}"
volumes:
- ./:/var/www
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
- ./docker/php/local.ini:/usr/local/etc/php/conf.d/local.ini
depends_on:
- app
networks:
- app-network
node:
platform: linux/arm64/v8
build:
context: .
dockerfile: Dockerfile.node
image: my-laravel-node
container_name: my-laravel-node
ports:
- "3000:3000"
restart: unless-stopped
working_dir: /var/www
volumes:
- ./:/var/www
- /var/www/node_modules
networks:
- app-network
db:
platform: linux/x86_64
image: mysql:8.0
container_name: my-mysql
restart: unless-stopped
environment:
MYSQL_DATABASE: ${DB_DATABASE}
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
MYSQL_PASSWORD: ${DB_PASSWORD}
MYSQL_USER: ${DB_USERNAME}
volumes:
- dbdata:/var/lib/mysql
- ./data.sql:/docker-entrypoint-initdb.d/data-dump.sql
networks:
- app-network
ports:
- "3306:3306"
networks:
app-network:
driver: bridge
volumes:
dbdata:
driver: local
docker build
ing the image,docker push
ing it to a repository, and thendocker run
ning it on a different machine with a different database container; it won't see any database updates that happened on the build system. – David Maze Commented Jan 21 at 16:23