I’ve been trying to make some modifications to the default ‘docker-compose.yml’ and Dockerfiles autogenerated by Laravel Sail after it’s installed into my Laravel project. I’ve been attempting this because those images are, by default, based on either Ubuntu or Debian, so I tried to rebuild them based on an Alpine Linux image to improve their performance and gain more experience with Docker.
After a lot of work, I managed to reduce the main image of the project from over 900 MB to almost 300 MB, which is about three times smaller. I also easily replaced the default ‘mariadb’ image set by Laravel Sail, which is based on Debian, with a ‘mariadb’ image based on Alpine, also with similar results.
However, I’m finding it difficult to achieve the same with my ‘phpMyAdmin’ image, as I haven’t been able to find an existing Alpine-based image that works the same as the Debian-based one.
So then, I’ve been trying to create it by myself, by writing my own Dockerfile from the Alpine base Docker image.
Here’s my ‘docker-compose.yml’ (at root project path):
version: "1.0"
services:
laravel.test:
build:
context: ./
dockerfile: ./docker/8.3/Dockerfile
args:
WWWGROUP: '${WWWGROUP}'
image: sail-8.3/app
#command: sh -c "npm install && npm run build"
extra_hosts:
- 'host.docker.internal:host-gateway'
ports:
- '${APP_PORT:-80}:80'
- '${VITE_PORT:-5173}:${VITE_PORT:-5173}'
environment:
WWWUSER: '${WWWUSER}'
LARAVEL_SAIL: 1
XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}'
XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}'
IGNITION_LOCAL_SITES_PATH: '${PWD}'
volumes:
- '.:/var/www/html'
#- './docker/init.sh:/init.sh'
#- './docker/8.3/start-container:start-container'
# - './docker/8.3/install-deps.sh:/usr/local/bin/install-deps.sh'
networks:
- sail
depends_on:
- mariadb
- phpmyadmin
mariadb:
#image: 'mariadb:10'
image: yobasystems/alpine-mariadb:10
ports:
- '${FORWARD_DB_PORT:-3306}:3306'
environment:
MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
MYSQL_ROOT_HOST: '%'
MYSQL_DATABASE: '${DB_DATABASE}'
MYSQL_USER: '${DB_USERNAME}'
MYSQL_PASSWORD: '${DB_PASSWORD}'
MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
volumes:
- 'sail-mariadb:/var/lib/mysql'
- './docker/mysql/create-testing-database.sh:/docker-entrypoint-initdb.d/10-create-testing-database.sh'
networks:
- sail
healthcheck:
test:
- CMD
- mysqladmin
- ping
- '-p${DB_PASSWORD}'
retries: 3
timeout: 5s
phpmyadmin:
image: 'phpmyadmin:latest'
#image: jackgruber/phpmyadmin
#image: 'phpmyadmin:fpm-alpine'
ports:
- 8081:80
networks:
- sail
environment:
- PMA_ARBITRARY=1
networks:
sail:
driver: bridge
volumes:
sail-mariadb:
driver: local
Then, in my ‘/docker/8.3’ path I have:
‘Dockerfile’:
FROM alpine:latest AS fswatch
RUN apk add --no-cache autoconf alpine-sdk
RUN rm /usr/include/sys/inotify.h
RUN wget https://github.com/emcrisostomo/fswatch/releases/download/1.17.1/fswatch-1.17.1.tar.gz
&& tar -xzvf fswatch-1.17.1.tar.gz
&& cd fswatch-1.17.1
&& ./configure
&& make
&& make install
&& rm -rf /fswatch-1.17.1
FROM alpine:latest
COPY --from=fswatch /usr/local/bin/fswatch /usr/local/bin/fswatch
COPY --from=fswatch /usr/local/lib/libfswatch.so* /usr/local/lib/
LABEL maintainer="Taylor Otwell"
ARG WWWGROUP
ARG NODE_VERSION=20
WORKDIR /var/www/html
ENV TZ=UTC
ENV SUPERVISOR_PHP_COMMAND="/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan serve --host=0.0.0.0 --port=80"
ENV SUPERVISOR_PHP_USER="sail"
# Instalar dependencias
RUN apk update &&
apk add --no-cache
gnupg
curl
ca-certificates
zip
unzip
git
supervisor
libpng-dev
libjpeg
librsvg
nano
php83
php83-cli
php83-dev
php83-pdo_pgsql
php83-gd
php83-curl
php83-xml
php83-mbstring
php83-openssl
php83-json
php83-dom
php83-ctype
php83-tokenizer
php83-session
php83-fileinfo
php83-xmlwriter
php83-simplexml
php83-tokenizer
php83-pdo_mysql
nodejs
npm
mysql-client
&& rm -rf /var/cache/apk/*
RUN apk add --no-cache php83-phar
RUN set -eux;
apk add --no-cache --virtual .gosu-deps
dpkg
gnupg
openssl
&& dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')";
curl -fsSL "https://github.com/tianon/gosu/releases/download/1.14/gosu-$dpkgArch.asc" -o /usr/local/bin/gosu.asc
&& curl -fsSL "https://github.com/tianon/gosu/releases/download/1.14/gosu-$dpkgArch" -o /usr/local/bin/gosu
&& chmod +x /usr/local/bin/gosu
&& gosu --version
&& rm /usr/local/bin/gosu.asc
&& apk del .gosu-deps
# ToDo: Configurar zona horaria
#RUN cp /usr/share/zoneinfo/$TZ /etc/localtime &&
# echo $TZ > /etc/timezone
RUN apk add --no-cache libcap
# Configurar capacidades para PHP
RUN cp /usr/bin/php83 /usr/bin/php
RUN setcap "cap_net_bind_service=+ep" /usr/bin/php
RUN curl -sLS https://getcomposer.org/installer | php -- --install-dir=/usr/bin/ --filename=composer
# Definir el identificador del grupo y del usuario
ARG WWWGROUP=1000
ARG USER_ID=1337
# Crear el grupo y el usuario con los identificadores especificados
RUN addgroup -g $WWWGROUP sail &&
adduser -D -s /bin/sh -G sail -u $USER_ID sail
RUN apk add --no-cache
shadow
supervisor
# Crear directorios necesarios
RUN mkdir -p /var/log/supervisor
# Copiar scripts y configuraciones
COPY ./docker/8.3/start-container /usr/local/bin/start-container
COPY ./docker/8.3/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
COPY ./docker/8.3/php.ini /etc/php83/cli/conf.d/99-sail.ini
# Establecer permisos
RUN chmod +x /usr/local/bin/start-container
# Exponer puerto
EXPOSE 8000
# Punto de entrada
ENTRYPOINT ["start-container"]
‘install-deps.sh’:
#!/usr/bin/env sh
npm install
‘php.ini’:
[PHP]
post_max_size = 100M
upload_max_filesize = 100M
variables_order = EGPCS
pcov.directory = .
‘start-container’:
#!/usr/bin/env sh
if [ "$SUPERVISOR_PHP_USER" != "root" ] && [ "$SUPERVISOR_PHP_USER" != "sail" ]; then
echo "You should set SUPERVISOR_PHP_USER to either 'sail' or 'root'."
exit 1
fi
if [ ! -z "$WWWUSER" ]; then
usermod -u $WWWUSER sail
fi
#if [ ! -d /var/www/html/node_modules ]; then
# cd /var/www/html
# npm install
# chmod 777 ./node_modules -R
# npm run build
#fi
if [ ! -d /.composer ]; then
mkdir /.composer
fi
chmod -R ugo+rw /.composer
if [ $# -gt 0 ]; then
if [ "$SUPERVISOR_PHP_USER" = "root" ]; then
exec "$@"
else
exec gosu $WWWUSER "$@"
fi
else
exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
fi
‘supervisord.conf’:
[supervisord]
nodaemon=true
user=root
logfile=/var/log/supervisor/supervisord.log
pidfile=/var/run/supervisord.pid
[program:php]
command=%(ENV_SUPERVISOR_PHP_COMMAND)s
user=%(ENV_SUPERVISOR_PHP_USER)s
environment=LARAVEL_SAIL="1"
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
The app works fine, and also the phpMyadmin service, showing a login page like this:
However, when trying to build my own ‘phpmyadmin’ image, based on Alpine, I can’t achieve that the login page show the ‘Server’ field, like the one I have working in my app.
Here’s my ‘Dockerfile’ (located in a separate folder):
FROM alpine
ENV SUPERVISOR_PHP_USER="sail"
RUN apk update
RUN apk add apache2
RUN echo "ServerName localhost" >> /etc/apache2/httpd.conf
RUN apk add openrc
RUN rc-update add apache2 && openrc default
RUN apk add --no-cache
gnupg
curl
ca-certificates
zip
unzip
git
supervisor
libpng-dev
libjpeg
librsvg
nano
php83
php83-cli
php83-dev
php83-pdo_pgsql
php83-gd
php83-curl
php83-xml
php83-mbstring
php83-openssl
php83-json
php83-dom
php83-ctype
php83-tokenizer
php83-session
php83-fileinfo
php83-xmlwriter
php83-simplexml
php83-tokenizer
php83-pdo_mysql
php83-mysqli
php83-phar
mysql-client
&& rm -rf /var/cache/apk/*
RUN set -eux;
apk add --no-cache --virtual
dpkg
gnupg
openssl
RUN apk add --no-cache libcap
RUN cp /usr/bin/php83 /usr/bin/php
RUN setcap "cap_net_bind_service=+ep" /usr/bin/php
# Definir el identificador del grupo y del usuario
ARG WWWGROUP=1000
ARG USER_ID=1337
# Crear el grupo y el usuario con los identificadores especificados
RUN addgroup -g $WWWGROUP sail &&
adduser -D -s /bin/sh -G sail -u $USER_ID sail
RUN apk add php83-apache2
RUN rc-update add apache2 default
RUN apk add phpmyadmin
RUN chown -R apache:apache /etc/phpmyadmin
WORKDIR /var/www/localhost/htdocs
RUN rm index.html
RUN cp -r /usr/share/webapps/phpmyadmin/* .
RUN echo -e "<?phpnphpinfo();n?>" >> ./info.php
#RUN rc-service apache2 start
#CMD ["rc-service", "apache2", "start"]
CMD ["httpd", "-D", "FOREGROUND"]
This are the commands I’ve been trying to use to setup the eviroment variables, needed to display the wanter ‘Server’ field on login page:
leandro@leandro-Lenovo-B50-10:~/sail/apache_alpine$ docker build -t my-apache2 .
[+] Building 134.7s (25/25) FINISHED docker:default
=> [internal] load build definition from Dockerfile 1.0s
=> => transferring dockerfile: 1.82kB 0.0s
=> [internal] load metadata for docker.io/library/alpine:latest 4.3s
=> [auth] library/alpine:pull token for registry-1.docker.io 0.0s
=> [internal] load .dockerignore 0.4s
=> => transferring context: 2B 0.0s
=> CACHED [ 1/20] FROM docker.io/library/alpine:latest@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b 0.3s
=> => resolve docker.io/library/alpine:latest@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b 0.3s
=> [ 2/20] RUN apk update 5.0s
=> [ 3/20] RUN apk add apache2 4.7s
=> [ 4/20] RUN echo "ServerName localhost" >> /etc/apache2/httpd.conf 2.2s
=> [ 5/20] RUN apk add openrc 4.3s
=> [ 6/20] RUN rc-update add apache2 && openrc default 2.9s
=> [ 7/20] RUN apk add --no-cache gnupg curl ca-certificates zip unzip git supervisor libpng-dev libjpeg 43.1s
=> [ 8/20] RUN set -eux; apk add --no-cache --virtual dpkg gnupg openssl 5.4s
=> [ 9/20] RUN apk add --no-cache libcap 4.8s
=> [10/20] RUN cp /usr/bin/php83 /usr/bin/php 2.3s
=> [11/20] RUN setcap "cap_net_bind_service=+ep" /usr/bin/php 2.4s
=> [12/20] RUN addgroup -g 1000 sail && adduser -D -s /bin/sh -G sail -u 1337 sail 2.4s
=> [13/20] RUN apk add php83-apache2 6.5s
=> [14/20] RUN rc-update add apache2 default 2.0s
=> [15/20] RUN apk add phpmyadmin 12.2s
=> [16/20] RUN chown -R apache:apache /etc/phpmyadmin 2.2s
=> [17/20] WORKDIR /var/www/localhost/htdocs 1.2s
=> [18/20] RUN rm index.html 2.1s
=> [19/20] RUN cp -r /usr/share/webapps/phpmyadmin/* . 6.4s
=> [20/20] RUN echo -e "<?phpnphpinfo();n?>" >> ./info.php 2.1s
=> exporting to image 11.9s
=> => exporting layers 11.5s
=> => writing image sha256:87594483041eab34efe44f18fd96e02c2e21906867ce4d66b0ca935659ee7968 0.1s
=> => naming to docker.io/library/my-apache2 0.1s
View build details: docker-desktop://dashboard/build/default/default/p3o1665s7ilubtk1b96nm6aqr
Reduce build time with Docker Build Cloud: https://docs.docker.com/go/docker-build-cloud
And then:
leandro@leandro-Lenovo-B50-10:~/sail/apache_alpine$ docker run --env 'PMA_ARBITRARY=1' -dit --name my-running-app -p 8080:80 my-apache2
e7d3490bfed251662065e64e14ef4bf9d469d6737cb1debb960a81e83c846f65
So, I’m having a result like this:
Any suggestions? If there’s more info needed, please tell me.
Thank’s a lot!
Leandro