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 πŸ˜‰