Why is my multi stage php image is so large?

Hello :slight_smile:
I’m a beginner with docker and i’m trying to build a multi stage image. But in my opinion my image is too large and i don’t know why.
The php:8.1.1-fpm-alpine image has 91MB and my files are about 30MB. So my guess would be, that it has 120MB max. But is has 213MB.
I don’t understand that.
Maybe somebody has a hint for me here?

I build it with buildkit enabled with this command:

DOCKER_BUILDKIT=1 docker build -t simple -f .docker/online/php/Dockerfile .

The content of my Dockerfile:

### NPM BUILD

FROM node:16 AS npm-build

WORKDIR /frontend

COPY ./resources/assets /frontend/resources/assets
COPY ./resources/views /frontend/resources/views
COPY ./storage/framework/views /frontend/storage/framework/views
COPY ./tailwind.config.js /frontend/tailwind.config.js
COPY ./webpack.mix.js /frontend/webpack.mix.js
COPY ./package.json /frontend/package.json
COPY ./package-lock.json /frontend/package-lock.json
COPY ./tsconfig.json /frontend/tsconfig.json

RUN npm install --global npm@8

RUN npm install

RUN npm run production



#### PHP BASE



FROM php:8.1.1-fpm-alpine AS php-base

WORKDIR /var/www/simplemap

# set timezone
RUN apk add tzdata
RUN cp /usr/share/zoneinfo/Europe/Berlin /etc/localtime
RUN echo "Europe/Berlin" > /etc/timezone
RUN apk del tzdata

RUN mv /usr/local/etc/php/php.ini-production /usr/local/etc/php/php.ini
COPY ./.docker/online/php/php-ini-overrides.ini /usr/local/etc/php/conf.d/

# install php extensions and use an external script for that
ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/

RUN chmod +x /usr/local/bin/install-php-extensions && sync && \
    install-php-extensions \
    gd \
    intl \
    redis \
    pdo_mysql \
    opcache \
    pcntl \
    bz2 \
    bcmath \
    zip \
    yaml




#### PHP BUILD



FROM php-base AS php-build

RUN mkdir public

# Copy folders
COPY ./config /var/www/simplemap/config
COPY ./database /var/www/simplemap/database
COPY ./bootstrap /var/www/simplemap/bootstrap
COPY ./src /var/www/simplemap/src
COPY ./app /var/www/simplemap/app
COPY ./resources /var/www/simplemap/resources
COPY ./routes /var/www/simplemap/routes
COPY ./storage /var/www/simplemap/storage
COPY ./artisan /var/www/simplemap/artisan

# Copy files
COPY ./composer.json /var/www/simplemap
COPY ./composer.lock /var/www/simplemap

# Get latest Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

RUN composer install --no-dev --optimize-autoloader

# Symlink storage
RUN chmod +x artisan
RUN php artisan storage:link


### PHP SIMPLEMAP



FROM php-base AS php-simplemap

# Copy from npm build
COPY --from=npm-build /frontend/public /var/www/simplemap/public
# Copy leaflet images
COPY --from=npm-build /frontend/images /var/www/simplemap/public/images

# Copy from php-build
COPY --from=php-build /var/www/simplemap/config /var/www/simplemap/config
COPY --from=php-build /var/www/simplemap/database /var/www/simplemap/database
COPY --from=php-build /var/www/simplemap/src /var/www/simplemap/src
COPY --from=php-build /var/www/simplemap/app /var/www/simplemap/app
COPY --from=php-build /var/www/simplemap/resources/views /var/www/simplemap/resources/views
COPY --from=php-build /var/www/simplemap/resources/lang /var/www/simplemap/resources/lang
COPY --from=php-build /var/www/simplemap/storage /var/www/simplemap/storage
COPY --from=php-build /var/www/simplemap/public/storage /var/www/simplemap/public/storage
COPY --from=php-build /var/www/simplemap/routes /var/www/simplemap/routes
COPY --from=php-build /var/www/simplemap/vendor /var/www/simplemap/vendor
COPY --from=php-build /var/www/simplemap/bootstrap /var/www/simplemap/bootstrap
COPY --from=php-build /var/www/simplemap/artisan /var/www/simplemap/artisan

# Copy files
COPY ./public/index.php /var/www/simplemap/public/
COPY ./public/robots.txt /var/www/simplemap/public/
COPY ./public/.htaccess /var/www/simplemap/public/
COPY ./public/sm16.png /var/www/simplemap/public/
COPY ./public/sm32.png /var/www/simplemap/public/
COPY ./server.php /var/www/simplemap/server.php
COPY ./.env.example /var/www/simplemap/.env

# chown to www-data
RUN chown -R www-data:www-data /var/www/simplemap

USER www-data

EXPOSE 7000

RUN php artisan key:generate
RUN php artisan cache:clear
RUN php artisan route:cache

CMD ["php-fpm"]
# CMD php artisan serve --host=0.0.0.0 --port=7000

And the output of docker history simple:

7b5a92381af9   32 hours ago   CMD ["/bin/sh" "-c" "php artisan serve --hos…   0B        buildkit.dockerfile.v0
<missing>      32 hours ago   RUN /bin/sh -c php artisan route:cache # bui…   7.1kB     buildkit.dockerfile.v0
<missing>      32 hours ago   RUN /bin/sh -c php artisan cache:clear # bui…   0B        buildkit.dockerfile.v0
<missing>      32 hours ago   RUN /bin/sh -c php artisan key:generate # bu…   948B      buildkit.dockerfile.v0
<missing>      32 hours ago   EXPOSE map[7000/tcp:{}]                         0B        buildkit.dockerfile.v0
<missing>      32 hours ago   USER www-data                                   0B        buildkit.dockerfile.v0
<missing>      32 hours ago   RUN /bin/sh -c chown -R www-data:www-data /v…   20.6MB    buildkit.dockerfile.v0
<missing>      32 hours ago   COPY ./.env.example /var/www/simplemap/.env …   897B      buildkit.dockerfile.v0
<missing>      32 hours ago   COPY ./server.php /var/www/simplemap/server.…   563B      buildkit.dockerfile.v0
<missing>      32 hours ago   COPY ./public/sm32.png /var/www/simplemap/pu…   703B      buildkit.dockerfile.v0
<missing>      32 hours ago   COPY ./public/sm16.png /var/www/simplemap/pu…   384B      buildkit.dockerfile.v0
<missing>      32 hours ago   COPY ./public/.htaccess /var/www/simplemap/p…   603B      buildkit.dockerfile.v0
<missing>      32 hours ago   COPY ./public/robots.txt /var/www/simplemap/…   24B       buildkit.dockerfile.v0
<missing>      32 hours ago   COPY ./public/index.php /var/www/simplemap/p…   1.71kB    buildkit.dockerfile.v0
<missing>      32 hours ago   COPY /var/www/simplemap/artisan /var/www/sim…   1.69kB    buildkit.dockerfile.v0
<missing>      32 hours ago   COPY /var/www/simplemap/bootstrap /var/www/s…   17.2kB    buildkit.dockerfile.v0
<missing>      32 hours ago   COPY /var/www/simplemap/vendor /var/www/simp…   20MB      buildkit.dockerfile.v0
<missing>      32 hours ago   COPY /var/www/simplemap/routes /var/www/simp…   2.11kB    buildkit.dockerfile.v0
<missing>      32 hours ago   COPY /var/www/simplemap/public/storage /var/…   29.5kB    buildkit.dockerfile.v0
<missing>      32 hours ago   COPY /var/www/simplemap/storage /var/www/sim…   185kB     buildkit.dockerfile.v0
<missing>      32 hours ago   COPY /var/www/simplemap/resources/lang /var/…   20.4kB    buildkit.dockerfile.v0
<missing>      32 hours ago   COPY /var/www/simplemap/resources/views /var…   6.02kB    buildkit.dockerfile.v0
<missing>      32 hours ago   COPY /var/www/simplemap/app /var/www/simplem…   12.6kB    buildkit.dockerfile.v0
<missing>      32 hours ago   COPY /var/www/simplemap/src /var/www/simplem…   2.44kB    buildkit.dockerfile.v0
<missing>      32 hours ago   COPY /var/www/simplemap/database /var/www/si…   4.42kB    buildkit.dockerfile.v0
<missing>      32 hours ago   COPY /var/www/simplemap/config /var/www/simp…   49.4kB    buildkit.dockerfile.v0
<missing>      32 hours ago   COPY /frontend/images /var/www/simplemap/pub…   6.5kB     buildkit.dockerfile.v0
<missing>      32 hours ago   COPY /frontend/public /var/www/simplemap/pub…   189kB     buildkit.dockerfile.v0
<missing>      8 days ago     RUN /bin/sh -c chmod +x /usr/local/bin/insta…   76.5MB    buildkit.dockerfile.v0
<missing>      8 days ago     ADD https://github.com/mlocati/docker-php-ex…   126kB     buildkit.dockerfile.v0
<missing>      8 days ago     COPY ./.docker/online/php/php-ini-overrides.…   464B      buildkit.dockerfile.v0
<missing>      8 days ago     RUN /bin/sh -c mv /usr/local/etc/php/php.ini…   72.9kB    buildkit.dockerfile.v0
<missing>      8 days ago     RUN /bin/sh -c apk del tzdata # buildkit        51.1kB    buildkit.dockerfile.v0
<missing>      8 days ago     RUN /bin/sh -c echo "Europe/Berlin" > /etc/t…   14B       buildkit.dockerfile.v0
<missing>      8 days ago     RUN /bin/sh -c cp /usr/share/zoneinfo/Europe…   2.3kB     buildkit.dockerfile.v0
<missing>      8 days ago     RUN /bin/sh -c apk add tzdata # buildkit        3.65MB    buildkit.dockerfile.v0
<missing>      8 days ago     WORKDIR /var/www/simplemap                      0B        buildkit.dockerfile.v0
<missing>      5 weeks ago    /bin/sh -c #(nop)  CMD ["php-fpm"]              0B        
<missing>      5 weeks ago    /bin/sh -c #(nop)  EXPOSE 9000                  0B        
<missing>      5 weeks ago    /bin/sh -c #(nop)  STOPSIGNAL SIGQUIT           0B        
<missing>      5 weeks ago    /bin/sh -c set -eux;  cd /usr/local/etc;  if…   26.6kB    
<missing>      5 weeks ago    /bin/sh -c #(nop) WORKDIR /var/www/html         0B        
<missing>      5 weeks ago    /bin/sh -c #(nop)  ENTRYPOINT ["docker-php-e…   0B        
<missing>      5 weeks ago    /bin/sh -c docker-php-ext-enable sodium         51.1kB    
<missing>      5 weeks ago    /bin/sh -c #(nop) COPY multi:7d7d4b016ee2e2e…   6.86kB    
<missing>      5 weeks ago    /bin/sh -c set -eux;  apk add --no-cache --v…   70.1MB    
<missing>      5 weeks ago    /bin/sh -c #(nop) COPY file:ce57c04b70896f77…   587B      
<missing>      5 weeks ago    /bin/sh -c set -eux;   apk add --no-cache --…   11.8MB    
<missing>      5 weeks ago    /bin/sh -c #(nop)  ENV PHP_SHA256=33c09d76d0…   0B        
<missing>      5 weeks ago    /bin/sh -c #(nop)  ENV PHP_URL=https://www.p…   0B        
<missing>      5 weeks ago    /bin/sh -c #(nop)  ENV PHP_VERSION=8.1.1        0B        
<missing>      7 weeks ago    /bin/sh -c #(nop)  ENV GPG_KEYS=528995BFEDFB…   0B        
<missing>      7 weeks ago    /bin/sh -c #(nop)  ENV PHP_LDFLAGS=-Wl,-O1 -…   0B        
<missing>      7 weeks ago    /bin/sh -c #(nop)  ENV PHP_CPPFLAGS=-fstack-…   0B        
<missing>      7 weeks ago    /bin/sh -c #(nop)  ENV PHP_CFLAGS=-fstack-pr…   0B        
<missing>      7 weeks ago    /bin/sh -c set -eux;  mkdir -p "$PHP_INI_DIR…   0B        
<missing>      7 weeks ago    /bin/sh -c #(nop)  ENV PHP_INI_DIR=/usr/loca…   0B        
<missing>      7 weeks ago    /bin/sh -c set -eux;  adduser -u 82 -D -S -G…   4.68kB    
<missing>      7 weeks ago    /bin/sh -c apk add --no-cache   ca-certifica…   3.56MB    
<missing>      7 weeks ago    /bin/sh -c #(nop)  ENV PHPIZE_DEPS=autoconf …   0B        
<missing>      8 weeks ago    /bin/sh -c #(nop)  CMD ["/bin/sh"]              0B        
<missing>      8 weeks ago    /bin/sh -c #(nop) ADD file:9233f6f2237d79659…   5.59MB  

I also tried it without Buildkit and had the same result.

Thanks for your time in advance :slight_smile:

You actually shared the answer for yourself :slight_smile: In the output of the docker history you can see the size of the layers. The sum of all is indeed about 213MB. You use multiple commands that downloads or generates new files. First you installed php extensions, then changed the owner of files. Note that when you use “chown” or “chmod” on a folder recursively which was created in a previous layer, you actually recreate the whole content of that folder since you can’t write any previous layer.

Bonus tip: Try not to use too many layers. There is a maximum number of layers you can create including the layers of the base images and the layer of the container’s writable filesystem. Overlayfs2 supports maximum 128 layers and Docker has at least one special layer too.

Since you have multi-staged build, you could copy multiple files to one stage, change the owner where you need and then copy those in one step to the last stage creating one layer.