Wrong PHP version used when installing composer with Alpine's apk command
Asked Answered
T

2

13

I've got a docker image running 8.0 and want to upgrade to 8.1. I have updated the image to run with PHP 8.1 and want to update the dependencies in it.

The new image derives from php:8.1.1-fpm-alpine3.15

I've updated the composer.json and changed require.php to ^8.1 but ran into the following message when running composer upgrade:

Root composer.json requires php ^8.1 but your php version (8.0.14) does not satisfy that requirement.

What I find dazzling is that the composer incorrectly identifies PHP version. I used two commands to determine that:

which php # returns only /usr/local/bin/php
/usr/local/bin/php -v # returns PHP 8.1.1 (cli) (built: Dec 18 2021 01:38:53) (NTS)

So far I've tried:

  • Checking php -v
  • Clearing composer cache
  • Rebuilding image

Composer version 2.1.12 2021-11-09 16:02:04

composer check-platform-reqs | grep php
# returns:
# ...
# php                   8.0.14  project/name requires php (^8.1)                   failed  

All of the commands above (excluding docker commands) are being ran in the container

Dockerfile:

FROM php:8.1.1-fpm-alpine3.15

ENV TZ=Europe/London

# Install php lib deps
RUN apk update && apk upgrade
RUN apk add --update libzip-dev \
        zip \
        unzip \
        libpng-dev \
        nginx \
        supervisor \
        git \
        curl \
        shadow \
        composer \
        yarn && rm -rf /var/cache/apk/*

RUN usermod -u 1000 www-data
RUN usermod -d /var/www www-data

RUN mkdir -p /run/nginx && chown www-data:www-data /run/nginx

ENV SUPERCRONIC_URL=https://github.com/aptible/supercronic/releases/download/v0.1.9/supercronic-linux-amd64 \
    SUPERCRONIC=supercronic-linux-amd64 \
    SUPERCRONIC_SHA1SUM=5ddf8ea26b56d4a7ff6faecdd8966610d5cb9d85

RUN curl -fsSLO "$SUPERCRONIC_URL" \
 && echo "${SUPERCRONIC_SHA1SUM}  ${SUPERCRONIC}" | sha1sum -c - \
 && chmod +x "$SUPERCRONIC" \
 && mv "$SUPERCRONIC" "/usr/local/bin/${SUPERCRONIC}" \
 && ln -s "/usr/local/bin/${SUPERCRONIC}" /usr/local/bin/supercronic

# Install and enable php extensions
RUN docker-php-ext-install sockets mysqli pdo_mysql zip gd bcmath > /dev/null

ARG ENV="development"
# Xdebug install
RUN if [ $ENV = "development" ] ; then \
        apk add --no-cache $PHPIZE_DEPS; \
        pecl install xdebug > /dev/null; \
        docker-php-ext-enable xdebug; \
        echo "error_reporting = E_ALL" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini; \
        echo "display_startup_errors = On" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini; \
        echo "display_errors = On" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini; \
        echo "xdebug.remote_enable=1" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini; \
    fi ;

# Setup working directory
RUN chown -R www-data:www-data /var/www
WORKDIR /var/www
USER www-data


# Install dependencies
#RUN if [ $ENV = "development" ] ; then \
##        composer install -n; \
#    else \
##        composer install -n --no-dev; \
#    fi ;

# Generate doctrine proxies
Tramel answered 21/12, 2021 at 16:59 Comment(3)
It's a single stage build and I've edited the question to add the Dockerfile. I would assume there is no PHP 8.0.14 interpreter installed in the container, so how can it be used?Tramel
Are you sure you did rebuild your image and are using the one that this Dockerfile represents?Garry
docker build / docker-compose build will use cached layers by default, make sure you're rebuilding with the --no-cache (valid for both docker and docker-compose)Alsace
C
11

Huh. This surprised me a bit.

composer is correctly reporting the PHP version it's using. The problem is that it's not using the "correct" PHP interpreter.

The issue arises because of how you are installing composer.

Apparently by doing apk add composer another version of PHP gets installed (you can find it on /usr/bin/php8, this is the one on version 8.0.14).

Instead of letting apk install composer for you, you can do it manually. There is nothing much to install it in any case, no need to go through the package manager. Particularly since PHP has not been installed via the package manager on your base image.

I've just removed the line containing composer from the apk add --update command, and added this somewhere below:

 RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" && \
     php -r "if (hash_file('sha384', 'composer-setup.php') === 'e21205b207c3ff031906575712edab6f13eb0b361f2085f1f1237b7126d785e826a450292b6cfd1d64d92e6563bbde02') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" && \
     php composer-setup.php && \
     php -r "unlink('composer-setup.php');" && \
     mv composer.phar /usr/local/bin/composer;

(The actual checksum will change from version to version, one should update the script with the appropriate checksum from this page, or simply use a script that gets the latest checksum like the one described here).

You could also simply download the latest composer PHAR file from here, and add it to the image, depending on how you want to go.

Now there is a single PHP version, and composer will run correctly on PHP 8.1.1.

Coffle answered 22/12, 2021 at 10:35 Comment(2)
Oh wow, I was not expecting composer to install it's own PHP dependency. All dependencies are listed here - pkgs.alpinelinux.org/package/edge/community/x86_64/composerTramel
the hash has changed recentlyAfter
S
1

This also struck me by a surprise and especially in development or build images that ship with their own PHP versions (e.g. official PHP docker images in the Alpine variant) this makes not much sense.

Not limited but tested on Alpine thought, here an install variant for a specific Composer version with checksum validation (the Composer Download page has all versions and checksums):

FROM php:8.1-alpine

ARG COMPOSER_BIN=/usr/bin/composer
ARG COMPOSER_VERSION=2.2.12
ARG COMPOSER_SHA256SUM=1ce90687eb3f89a99c059d45dd419d08430ed249468544b932b1dad7fb22dda0

RUN set -ex ;\
  wget -O "$COMPOSER_BIN" "https://getcomposer.org/download/$COMPOSER_VERSION/composer.phar" ;\
  printf "%s  %s\n" "$COMPOSER_SHA256SUM" "$COMPOSER_BIN" | sha256sum -c - ;\
  chmod +x -- "$COMPOSER_BIN" ;\
  composer --version ;\
  composer diagnose || printf 'composer diagnose exited: %d\n' $? ;\
  :

Output (exemplary):

Sending build context to Docker daemon  2.048kB # (1)
Step 1/5 : FROM php:8.1-alpine
 ---> 77506786976c
Step 2/5 : ARG COMPOSER_BIN=/usr/bin/composer
 ---> Running in 71db8206ae0b
Removing intermediate container 71db8206ae0b
 ---> 77432ca0a59a
Step 3/5 : ARG COMPOSER_VERSION=2.2.12
 ---> Running in 5d0e6f5bee3d
Removing intermediate container 5d0e6f5bee3d
 ---> 273a0d9d2936
Step 4/5 : ARG COMPOSER_SHA256SUM=1ce90687eb3f89a99c059d45dd419d08430ed249468544b932b1dad7fb22dda0
 ---> Running in 504ad490732a
Removing intermediate container 504ad490732a
 ---> e56499db14c7
Step 5/5 : RUN set -ex ;  wget -O "$COMPOSER_BIN" "https://getcomposer.org/download/$COMPOSER_VERSION/composer.phar" ;  printf "%s  %s\n" "$COMPOSER_SHA256SUM" "$COMPOSER_BIN" | sha256sum -c - ;  chmod +x -- "$COMPOSER_BIN" ;  composer --version ;  composer diagnose || printf 'composer diagnose exited: %d\n' $? ;  :
 ---> Running in 10c303e61d27
+ wget -O /usr/bin/composer https://getcomposer.org/download/2.2.12/composer.phar
Connecting to getcomposer.org (54.36.53.46:443)
saving to '/usr/bin/composer'
composer             100% |********************************| 2312k  0:00:00 ETA
'/usr/bin/composer' saved
+ printf '%s  %s\n' 1ce90687eb3f89a99c059d45dd419d08430ed249468544b932b1dad7fb22dda0 /usr/bin/composer
+ sha256sum -c -
/usr/bin/composer: OK
+ chmod +x -- /usr/bin/composer
+ composer --version
Composer version 2.2.12 2022-04-13 16:42:25
+ composer diagnose
Checking platform settings: OK
Checking git settings: OK
Checking http connectivity to packagist: OK
Checking https connectivity to packagist: OK
Checking github.com rate limit: OK
Checking disk free space: OK
Checking pubkeys: FAIL # (2)
Missing pubkey for tags verification
Missing pubkey for dev verification
Run composer self-update --update-keys to set them up
Checking composer version: You are not running the latest stable version, run `composer self-update` to update (2.2.12 => 2.3.5)
Composer version: 2.2.12
PHP version: 8.1.4
PHP binary path: /usr/local/bin/php
OpenSSL version: OpenSSL 1.1.1n  15 Mar 2022
cURL version: 7.80.0 libz 1.2.12 ssl OpenSSL/1.1.1n
zip: extension not loaded, unzip present, 7-Zip not available
+ printf 'composer diagnose exited: %d\n' 2
+ :
composer diagnose exited: 2
Removing intermediate container 10c303e61d27
...
  1. Dockerfile as TAR, four 512 byte blocks (one file-entry-block, one file content-block, two NUL byte blocks as end-of-archive indicator; compare)
  2. Composer public keys are in use with the self-update command. As this version is installed without the installer, they are not set-up.

It spares the installer (hence no pubkeys) and pins the version (for stable building you would need to pin the installer version or fetch the checksum of the installer via https, Composer outlines it here in their docs: How do I install Composer programmatically?; this is additional info as the previous answer does not mention this explicitly).

I've put the composer diagnose command into the build section so that at least it shows a good overview (from composers perspective) and may give as well some hints on how to improve the image depending on the base image and configuration. E.g. install additional command-line utilities, in a build image you perhaps want to have git(1) as well with composer, not only unzip(1).

Simulant answered 15/4, 2022 at 20:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.