I've got a 4 stage Dockerfile, show below, however I can't quite work out the best way to optimise the build when I don't want to use the cache (to ensure that the latest images, and packages are used)…
FROM composer:latest as api_platform_composer
FROM php:7.4-fpm-alpine AS api_platform_php
RUN apk upgrade --no-cache
RUN apk add --no-cache {some packages}
RUN set -eux; \
apk add --no-cache --virtual .build-deps $PHPIZE_DEPS {some packages}; \
docker-php-ext-configure {some packages}; \
docker-php-ext-install -j$(nproc) {some packages}; \
pecl install {some packages}; \
pecl clear-cache; \
docker-php-ext-enable {some packages}; \
runDeps="$( \
scanelf --needed --nobanner --format '%n#p' --recursive /usr/local/lib/php/extensions \
| tr ',' '\n' \
| sort -u \
| awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \
)"; \
apk add --no-cache --virtual .phpexts-rundeps $runDeps; \
apk del .build-deps
COPY --from=api_platform_composer /usr/bin/composer /usr/bin/composer
# … various other steps…
# etc.
FROM openresty/openresty:1.17.8.2-alpine AS api_platform_nginx
RUN apk upgrade --no-cache
RUN echo -e "env UPSTREAM;\n$(cat /usr/local/openresty/nginx/conf/nginx.conf)" > /usr/local/openresty/nginx/conf/nginx.conf
COPY src/docker/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf
WORKDIR /srv/api/public
COPY --from=api_platform_php /srv/api/public ./
FROM alpine:3 as api_platform_ssh
# No dependencies from above
Currently I build each of the php
, nginx
& ssh
containers individually with the following commands…
docker build --target api_platform_php \
--cache-from registry.digitalocean.com/good-technologies/crm:latest-php,registry.digitalocean.com/good-technologies/crm:1.0.0-beta2-php \
--build-arg BUILDKIT_INLINE_CACHE=1 \
--build-arg BASE_COMPOSER_IMAGE=gitlab.com/good-technologies/dependency_proxy/containers/composer:latest \
--build-arg BASE_PHP_IMAGE=gitlab.com/good-technologies/dependency_proxy/containers/php:7.4-fpm-alpine \
--build-arg BASE_OPENRESTY_IMAGE=gitlab.com/good-technologies/dependency_proxy/containers/openresty/openresty:1.17.8.2-alpine \
--build-arg BASE_SSH_IMAGE=gitlab.com/good-technologies/dependency_proxy/containers/alpine:3 \
--build-arg BASE_MONGODB_IMAGE=gitlab.com/good-technologies/dependency_proxy/containers/mongo:4.4 \
--build-arg BASE_VARNISH_IMAGE=gitlab.com/good-technologies/dependency_proxy/containers/varnish:6.4 \
--tag registry.digitalocean.com/good-technologies/crm:1.0.0-beta2-php \
--progress=plain \
--no-cache \
--pull \
--secret id=php-secrets,src=.secrets/php/.secrets \
.
docker build --target api_platform_nginx \
--cache-from registry.digitalocean.com/good-technologies/crm:latest-nginx,registry.digitalocean.com/good-technologies/crm:1.0.0-beta2-php,registry.digitalocean.com/good-technologies/crm:1.0.0-beta2-nginx \
--build-arg BUILDKIT_INLINE_CACHE=1 \
--build-arg BASE_COMPOSER_IMAGE=gitlab.com/good-technologies/dependency_proxy/containers/composer:latest \
--build-arg BASE_PHP_IMAGE=gitlab.com/good-technologies/dependency_proxy/containers/php:7.4-fpm-alpine \
--build-arg BASE_OPENRESTY_IMAGE=gitlab.com/good-technologies/dependency_proxy/containers/openresty/openresty:1.17.8.2-alpine \
--build-arg BASE_SSH_IMAGE=gitlab.com/good-technologies/dependency_proxy/containers/alpine:3 \
--build-arg BASE_MONGODB_IMAGE=gitlab.com/good-technologies/dependency_proxy/containers/mongo:4.4 \
--build-arg BASE_VARNISH_IMAGE=gitlab.com/good-technologies/dependency_proxy/containers/varnish:6.4 \
--tag registry.digitalocean.com/good-technologies/crm:1.0.0-beta2-nginx \
--progress=plain \
--no-cache \
--pull \
--secret id=php-secrets,src=.secrets/php/.secrets \
.
docker build --target api_platform_ssh \
--cache-from registry.digitalocean.com/good-technologies/crm:latest-ssh,registry.digitalocean.com/good-technologies/crm:1.0.0-beta2-ssh \
--build-arg BUILDKIT_INLINE_CACHE=1 \
--build-arg BASE_COMPOSER_IMAGE=gitlab.com/good-technologies/dependency_proxy/containers/composer:latest \
--build-arg BASE_PHP_IMAGE=gitlab.com/good-technologies/dependency_proxy/containers/php:7.4-fpm-alpine \
--build-arg BASE_OPENRESTY_IMAGE=gitlab.com/good-technologies/dependency_proxy/containers/openresty/openresty:1.17.8.2-alpine \
--build-arg BASE_SSH_IMAGE=gitlab.com/good-technologies/dependency_proxy/containers/alpine:3 \
--build-arg BASE_MONGODB_IMAGE=gitlab.com/good-technologies/dependency_proxy/containers/mongo:4.4 \
--build-arg BASE_VARNISH_IMAGE=gitlab.com/good-technologies/dependency_proxy/containers/varnish:6.4 \
--tag registry.digitalocean.com/good-technologies/crm:1.0.0-beta2-ssh \
--progress=plain \
--no-cache \
--pull \
--secret id=php-secrets,src=.secrets/php/.secrets \
.
The problem with this is, because I'm using the --no-cache
flag, each subsequent stage re-builds that of the earlier stages that they depend on.
Sometimes I may only want to build a subset of the container images.
What are my options for optimising this? I can think of the following…
Work out which is the last desired image we want to build based on the order in the Dockerfile, and build the last one first using the
--no-cache
flag, then build all the rest without the--no-cache
flag.Use a random value build arg in each of the steps that I need to ensure don't use the cache, something like this…
FROM php:7.4-fpm-alpine AS api_platform_php ARG TIMESTAMP RUN X="${TIMESTAMP}" apk upgrade --no-cache # … etc. FROM openresty/openresty:1.17.8.2-alpine AS api_platform_nginx ARG TIMESTAMP RUN X="${TIMESTAMP}" apk upgrade --no-cache # … etc.
… and then pass in the same timestamp for each of the build commands.
Am I on the right track with one of these, or are there any other options that would be better?