I have been wondering for a really long time how to keep up to date the Dockerfiles in my project. I’ve always had two of them, one for the dev environment, and the second one for building my production container with dependencies, code build, etc. If I needed to change something I had to update both files.
I knew that dockerfiles allow us to define multiple stages, and I had used them, but still had a problem. In my production dockerfile I had stages, like building my frontend application and installing backend dependencies and final stage. I don’t need my code inside the container for development, because I attach my code using volume, so there is no reason to increase the building time of the development environment. So for the dev environment, I was using another one dockerfile.
My dockerfiles looked like those:
## Dockerfile
FROM composer:2.0 as builder
WORKDIR /app
COPY . .
RUN composer install --prefer-dist --no-dev --ignore-platform-reqs
FROM php:7.2-fpm as final
RUN apt update && apt install -y pdo_mysql ... # other required dependencies
COPY --from=builder /app /app
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
## Dockerfile.dev
FROM php:7.2-fpm as final
RUN apt update && apt install -y pdo_mysql ... # other required dependencies
RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"
Do you see it? The final parts are almost the same. Of course, we can build images only for chosen target, but with all previous stages. In these examples, we can’t get the value with that feature.
I had tried to find any solution for this case, and you know what? I found! 😄
It’s so simple that I didn’t think of it at first 😅
FROM php:7.2-fpm as base
RUN apt update && apt install -y pdo_mysql ... # other required dependencies
RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"
FROM composer:2.0 as builder
WORKDIR /app
COPY . .
RUN composer install --prefer-dist --no-dev --ignore-platform-reqs
FROM base as final
COPY --from=builder /app /app
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
Yea, it’s that simple 😄. The one thing that I could not get in this puzzle, was that we can use one stage target as the image in another stage. That was the key. Now if I want the development base image, I need only to build the base target:
docker build . --target=base
And if I want my production container, I just need to build the entire Dockerfile.
docker build .
And that’s it 😉