skip to Main Content

After many attempt to tidy up my laravel docker deployment, i’ve come with the Dockerfile below. But still, my image is still over 2Gb in size, which is enormous. Is there any thing I can do to optimize my final image size?
Heres is my Dockerfile

FROM alpine:latest

WORKDIR /var/www/html/

# Essentials
RUN apk add --no-cache tzdata
ENV TZ=Asia/Jakarta

RUN apk add --no-cache zip unzip curl nginx supervisor

# Installing bash
RUN apk add bash
RUN sed -i 's/bin/ash/bin/bash/g' /etc/passwd

# Installing PHP
RUN apk add --no-cache php82 
    php82-common 
    php82-fpm 
    php82-pdo 
    php82-opcache 
    php82-zip 
    php82-gd 
    php82-phar 
    php82-iconv 
    php82-cli 
    php82-curl 
    php82-openssl 
    php82-mbstring 
    php82-exif 
    php82-tokenizer 
    php82-fileinfo 
    php82-json 
    php82-xml 
    php82-xmlreader 
    php82-xmlwriter 
    php82-simplexml 
    php82-dom 
    php82-pdo_mysql 
    php82-tokenizer 
    php82-pecl-redis

RUN ln -s /usr/bin/php82 /usr/bin/php

# Installing composer
RUN curl -sS https://getcomposer.org/installer -o composer-setup.php
RUN php composer-setup.php --install-dir=/usr/local/bin --filename=composer
RUN rm -rf composer-setup.php

RUN apk add nodejs yarn

# Configure supervisor
RUN mkdir -p /etc/supervisor.d/
COPY ./docker/supervisor/supervisord.ini /etc/supervisor.d/supervisord.ini

# Configure PHP
RUN mkdir -p /run/php/
RUN touch /run/php/php8.2-fpm.pid

COPY ./docker/php/php-fpm.conf /etc/php82/php-fpm.conf
COPY ./docker/php/php.ini-production /etc/php82/php.ini

# Configure nginx
COPY ./docker/nginx/nginx.conf /etc/nginx/
COPY ./docker/nginx/webserver.conf /etc/nginx/http.d/default.conf

RUN mkdir -p /run/nginx/
RUN touch /run/nginx/nginx.pid

RUN ln -sf /dev/stdout /var/log/nginx/access.log
RUN ln -sf /dev/stderr /var/log/nginx/error.log

# Building process
COPY . .
RUN composer install
RUN chown -R nobody:nobody /var/www/html/storage
RUN yarn

# Run a cron job
ADD ./docker/cron/crontab.txt /crontab.txt
RUN /usr/bin/crontab /crontab.txt

# add log for supervisor laravel worker
RUN touch /var/www/html/storage/logs/worker.log

# Generate Laravel app encryption key
RUN cp .env.example .env
RUN php artisan key:generate --ansi
RUN php artisan vendor:publish --all

RUN chown -R nginx:nginx /var/www/html -v
RUN chmod -R 777 /var/www/html -v
RUN chown -R nginx:nginx /var/lib/nginx -v
RUN chmod -R 755 /var/lib/nginx -v
RUN chmod -R 755 /var/log/nginx -v

# Exposing port 80 (http)
EXPOSE 80

# Auto start supervisor on start
CMD ["/usr/bin/supervisord"]

I tried to do multi stage before but the result image is still fairly big in size.
did i miss some crucial step in creating my docker file?

2

Answers


    • Each RUN command adds a new layer to your Docker image. Combine related commands into a single RUN statement where possible.
    • Evaluate if every file added with COPY or ADD is necessary, or if they can be condensed. Use a .dockerignore file to ensure only necessary files are being added to the context and thus to the image.

    Here is the modified version of your Dockerfile:

    FROM alpine:latest as builder
    
    WORKDIR /var/www/html/
    
    RUN apk add --no-cache tzdata 
        zip 
        unzip 
        curl 
        nginx 
        supervisor 
        bash 
        nodejs 
        yarn 
        php82 
        php82-common 
        php82-fpm 
        php82-pdo 
        php82-opcache 
        php82-zip 
        php82-gd 
        php82-phar 
        php82-iconv 
        php82-cli 
        php82-curl 
        php82-openssl 
        php82-mbstring 
        php82-exif 
        php82-tokenizer 
        php82-fileinfo 
        php82-json 
        php82-xml 
        php82-xmlreader 
        php82-xmlwriter 
        php82-simplexml 
        php82-dom 
        php82-pdo_mysql 
        php82-pecl-redis && 
        ln -s /usr/bin/php82 /usr/bin/php && 
        curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
    
    COPY ./docker/php/php-fpm.conf /etc/php82/php-fpm.conf
    COPY ./docker/php/php.ini-production /etc/php82/php.ini
    COPY ./docker/nginx/nginx.conf /etc/nginx/
    COPY ./docker/nginx/webserver.conf /etc/nginx/http.d/default.conf
    COPY ./docker/supervisor/supervisord.ini /etc/supervisor.d/supervisord.ini
    COPY . .
    
    RUN composer install --no-dev --optimize-autoloader && 
        yarn --production && 
        yarn cache clean && 
        rm -rf node_modules
    
    FROM alpine:latest
    
    WORKDIR /var/www/html/
    
    COPY --from=builder /var/www/html /var/www/html
    COPY --from=builder /etc/php82 /etc/php82
    COPY --from=builder /etc/nginx /etc/nginx
    COPY --from=builder /etc/supervisor.d/supervisord.ini /etc/supervisor.d/supervisord.ini
    COPY --from=builder /usr/local/bin/composer /usr/local/bin/composer
    COPY --from=builder /usr/bin/php /usr/bin/php
    
    RUN mkdir -p /run/php/ && 
        mkdir -p /run/nginx/ && 
        touch /run/php/php8.2-fpm.pid && 
        touch /run/nginx/nginx.pid && 
        ln -sf /dev/stdout /var/log/nginx/access.log && 
        ln -sf /dev/stderr /var/log/nginx/error.log && 
        chown -R nginx:nginx /var/www/html && 
        chmod -R 755 /var/www/html
    
    RUN chown -R nobody:nobody /var/www/html/storage && 
        chown -R nginx:nginx /var/lib/nginx && 
        chmod -R 755 /var/lib/nginx && 
        chmod -R 755 /var/log/nginx
    
    EXPOSE 80
    
    CMD ["/usr/bin/supervisord"]
    
    Login or Signup to reply.
  1. I would add to the answer above. I would also put everything related to nginx into a separate container.

    and also consider all the packages that are needed only for assembly and remove them later

    RUN set -ex 
    && apk add --no-cache --virtual .build-deps 
    && .... all dev packages ...
    .......................
    && apk del .build-deps 
    && rm -rf /tmp/* /var/cache/apk/*
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search