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…

  1. 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.

  2. 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?

0

There are 0 answers