Creating and customizing a php docker environment

A free screencast (video) course is available for this post but you need to be signed in order to view it, you can sign in here if you already have an account or register here if you don't have one.

You will first need to install docker and docker-compose on your development machine. I strongly recommend you use a Linux machine; the code below is all using Ubuntu 22.04

  • First, let's create a new Laravel application using composer. If composer is installed on your development host, you can use it directly. Otherwise, you can use the compose Docker official image to do it:
# This command runs the official composer image in interactive mode (--interactive) 
# in a pseudo-TTY (--tty) 
# with the current directory mapped to /app in the container (--volume $PWD:/app) 
# with the current user context (--user $(id -u):$(id -g)).
# It runs the composer command: "composer create-project laravel/laravel laravel-gis"
# which will install Laravel with composer in a directory called larave-gis
# The --rm flag will remove the container once the command as finished

docker run --rm --interactive --tty \
	--volume $PWD:/app \
	--user $(id -u):$(id -g) \
	composer create-project laravel/laravel laravel-gis
  • Create a few extra needed files, folders, and permissions in the new project directory:
cd laravel-gis
touch docker-compose.yml
mkdir -p docker/nginx
touch docker/nginx/nginx-site.conf
sudo chown -R 33:33 .
sudo chmod -R 777 .

We use some pretty dangerous permission settings here. Still, it's a development environment, and we will need write/execute permissions on pretty much all of our project files and directories. We will see how to set up security permissions for our production environment in a future post. Don't use this setup in production

  • We will need two docker services to get our environment working with php-fpm and nginx; create two services in the docker-compose.yml file:
version: "3.7"
networks:
    frontend:
    backend:
services:
# nginx proxy service (based on nginx official image) to act as a web server and proxy server
    proxy:
        image: nginx:latest
# map local port 8080 to containers's port 80
		ports:
            - "8080:80"
# map the current directory to /var/www/app in the container
# and map our the nginx-site.conf to the nginx default site in the container
        volumes:
            - ./:/var/www/app
            - ./docker/nginx/nginx-site.conf:/etc/nginx/conf.d/default.conf
        networks:
            - frontend
            - backend
# php-fpm service (based on php official image) to process our php code 
	php:
        image: php:8.1-fpm
# map the current directory to /var/www/app in the container (the same as for the proxy service)
        volumes:
            - ./:/var/www/app
        networks:
            - backend
  • Put the following content in the docker/nginx/nginx-site.conf file:
server {
    listen 80;
# our root directory points to the public Laravel directory
    root /var/www/app/public;
    index index.php;
    server_name _;
		
# Redirects all queries to routes without extension (/dashboard for instance) to their
# equivalents but with a trailing /index.php (/dashboard/index.php) so it hits the next location
    location / {
         try_files $uri $uri/ /index.php$is_args$args;
    }
		
# Sends all php queries to the php container (named php in our case) on port 9000
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}
  • Run "docker-compose up" and go to http://localhost:8080 in your browser; you should see the blank laravel welcome page confirming that everything is working properly:

Laravel, PHP and Docker

We now have a php-fpm official docker image running our PHP and served through an Nginx proxy. However, we will need a few extra PHP extensions to run Laravel and Postgres. We will need to build our own PHP image based on the official one to do so. We will also install npm (nodejs) and composer in the development image. "Luckily," this can be achieved with a "simple" single one-liner in the Dockerfile.

  • Create a new folder called docker/php and a new file called Dockerfile in it:
mkdir docker/php
touch docker/php/Dockerfile
  • Put the following content in the file:
# php official fpm image
FROM php:8.1-fpm

# installs basic tools, then postgres ppa then nodejs ppa then nodejs and postgresql-client packages 
# (and some other required dependencies). It then installs and configures several php extensions 
# including pdo_pgsql and redis. Finally, it downloads and installs composer in the image.
RUN apt-get update \
    && apt-get install -y gnupg curl wget ca-certificates unzip lsb-release \
    && wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - \
    && echo "deb http://apt.postgresql.org/pub/repos/apt/ `lsb_release -cs`-pgdg main" | tee  /etc/apt/sources.list.d/pgdg.list \
    && curl -sL https://deb.nodesource.com/setup_18.x | bash - \
    && apt-get install -y \
        libicu-dev \
        libpq-dev \
        libzip-dev \
        nodejs \
        postgresql-client-14 \
    && pecl install redis \
    && docker-php-ext-enable redis \
    && docker-php-ext-configure pgsql -with-pgsql=/usr/local/pgsql \
    && docker-php-ext-install intl pdo pdo_pgsql pgsql zip bcmath pcntl exif \
    && php -r "readfile('http://getcomposer.org/installer');" | php -- --install-dir=/usr/bin/ --filename=composer \
    && npm install -g npm \
    && apt-get -y autoremove \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* \
    && chown -R www-data:www-data /var/www

WORKDIR /var/www/app
USER www-data
  • Now, let's make a few changes to our docker-compose.yml file:
version: "3.7"
networks:
    frontend:
    backend:
services:
    proxy:
        image: nginx:latest
        ports:
            - "8080:80"
        volumes:
            - ./:/var/www/app
            - ./docker/nginx/nginx-site.conf:/etc/nginx/conf.d/default.conf
        networks:
            - frontend
            - backend
    php:		
 		image: php:8.1-fpm
# give docker the build context, docker file and image name and tag
  		build:
  			context: ./docker/php
  			dockerfile: Dockerfile
  		image: laravelgis-php:latest
        volumes:
            - ./:/var/www/app
        networks:
            - backend
  • We can now run "docker-compose build" and see if our image compiles correctly; the process of building the new image can take a few minutes:

Laravel, PHP and Docker

  • Run "docker-compose up" again and browse to http://localhost:8080 to make sure everything is still running correctly

We now have a fully functional Laravel / PHP development environment running in docker; in the next post, we will install and configure Postgresql and Redis.

The commit for this post is available here: laravel-php-and-docker

First published 2 years ago
Latest update 9 months ago
Steve
Posted by Steve 9 months ago

Also posted in #9 nginx reverse proxy as trying to get working using Sail.

I've also come back to also try building a new Docker container directly - would prefer to use this method but very limited experience using Docker (not that I'm much more experienced with Sail)

Initial installation works, local host set up, but docker-compose build falls over after a couple of mins. I've tried the code from above, and amendments in video to update to php 8.2 and postgres 15. The ammended version runs gets futhest but then stops at.

#0 155.7 All settings correct for using Composer

#0 155.7 Downloading...

#0 156.5

#0 156.5 Composer (version 2.5.8) successfully installed to: /usr/bin/composer

#0 156.5 Use it: php /usr/bin/composer

#0 156.5

#0 156.6 /bin/sh: 1: npm: not found


failed to solve: process "/bin/sh -c apt-get update && apt-get install -y gnupg curl wget ca-certificates unzip lsb-release && wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - && echo "deb http://apt.postgresql.org/pub/repos/apt/ lsb_release -cs-pgdg main" | tee /etc/apt/sources.list.d/pgdg.list && curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y libicu-dev libpq-dev libzip-dev nodejs postgresql-client-15 && pecl install redis && docker-php-ext-enable redis && docker-php-ext-configure pgsql -with-pgsql=/usr/local/pgsql && docker-php-ext-install intl pdo pdo_pgsql pgsql zip bcmath pcntl exif && php -r "readfile('http://getcomposer.org/installer');" | php -- --install-dir=/usr/bin/ --filename=composer && npm install -g npm && apt-get -y autoremove && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && chown -R www-data:www-data /var/www" did not complete successfully: exit code: 127


webgisdev
Posted by webgisdev 9 months ago

Hello Steve,

Try changing this line in the Dockerfile:


&& curl -sL https://deb.nodesource.com/setup_16.x | bash - \

with this line:


&& curl -sL https://deb.nodesource.com/setup_18.x | bash - \

Let me know if it works and I will update the post.

Cheers!

Steve
Posted by Steve 9 months ago

Yes, update worked. Thanks very much.

Need to learn more about docker so I know how to keep the configurations upto date.

webgisdev
Posted by webgisdev 9 months ago

Hello Steve,

Thanks for your feedback, I updated the article!

Cheers!

Leo
Posted by Leo 8 months ago

Hello, I had a problem with docker-composer up.

I solved it with.

$ lsb_release -a

No LSB modules are available.

Distributor ID: Debian

Description: Debian GNU/Linux 11 (bullseye)

Release: 11

Codename: bullseye

$

$ docker -v

Docker version 24.0.6, build ed223bc

---OK last version 05sep2023

$ docker-compose up

-sh: 32: docker-compose: not found

$

$ ok RUN with command "docker compose up"


webgisdev
Posted by webgisdev 8 months ago

Hello Leo,

Depending on your local environment, you might have to install docker-compose:

On Ubuntu:


sudo apt install docker-compose

Cheers!

Hiram
Posted by Hiram 6 months ago

Hello I have a problem with docker-compose build:

454.5 Setting up python3.11-minimal (3.11.2-6) ...

455.7 [Errno 13] Permission denied: '/usr/lib/python3.11/pycache/future.cpython-311.pyc.136018649643168'dpkg: error processing package python3.11-minimal (--configure):

455.7 installed python3.11-minimal package post-installation script subprocess returned error exit status 1

456.1 Errors were encountered while processing:

456.1 python3.11-minimal

456.2 E: Sub-process /usr/bin/dpkg returned an error code (1)


failed to solve: process "/bin/sh -c apt-get update && apt-get install -y gnupg curl wget ca-certificates unzip lsb-release software-properties-common && wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - && echo "deb http://apt.postgresql.org/pub/repos/apt/ lsb_release -cs-pgdg main" | tee /etc/apt/sources.list.d/pgdg.list && curl -sL https://deb.nodesource.com/setup_20.x | bash - && apt-get install -y -f libicu-dev libpq-dev libzip-dev nodejs postgresql-client-15 && pecl install redis && docker-php-ext-enable redis && docker-php-ext-configure pgsql -with-pgsql=/usr/local/pgsql && docker-php-ext-install intl pdo pdo_pgsql pgsql zip bcmath pcntl exif && php -r "readfile('http://getcomposer.org/installer');" | php -- --install-dir=/usr/bin/ --filename=composer && npm install -g npm && apt-get -y autoremove && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && chown -R www-data:www-data /var/www" did not complete successfully: exit code: 100


Kyle
Posted by Kyle 5 months ago

I had some issues getting this to work as well. I received an error when trying to install node, and when trying to access the certificates. I updated my file as follows and the image built:

FROM php:8.1-fpm

RUN apt-get update \

&& apt-get install -y gnupg curl wget ca-certificates unzip lsb-release \

&& wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - \

&& echo "deb http://apt.postgresql.org/pub/repos/apt/ `lsb_release -cs`-pgdg main" | tee  /etc/apt/sources.list.d/pgdg.list \

&& curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg\

        && NODE_MAJOR=20 \

    && echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | \

        tee /etc/apt/sources.list.d/nodesource.list \

&& apt-get update && apt-get install -y \

    libicu-dev \

    libpq-dev \

    libzip-dev \

    postgresql-client-14 \

    nodejs \

&& pecl install redis \

&& docker-php-ext-enable redis \

&& docker-php-ext-configure pgsql -with-pgsql=/usr/local/pgsql \

&& docker-php-ext-install intl pdo pdo_pgsql pgsql zip bcmath pcntl exif \

&& php -r "readfile('http://getcomposer.org/installer');" | php -- --install-dir=/usr/bin/ --filename=composer \

&& npm install -g npm \

&& apt-get -y autoremove \

&& apt-get clean \

&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* \

&& chown -R www-data:www-data /var/www

WORKDIR /var/www/app

USER www-data

It could probably be improved, but it works for now.

Hiram
Posted by Hiram 5 months ago

My postgres:latest container keeps on exiting(1) after running docker compose up. How can this be resolved?

docker logs gives me this error

initdb: error: could not create directory "/var/lib/postgresql/data/pg_wal": No space left on device

I have cleaned up my images using docker system prune and restarted the whole process but that doesn't help.

here's my df

Filesystem 1K-blocks Used Available Use% Mounted on

/dev/mapper/dmroot 20327908 19915732 0 100% /

none 20327908 19915732 0 100% /usr/lib/modules

tmpfs 1048576 0 1048576 0% /dev/shm

tmpfs 56156 1300 54856 3% /run

tmpfs 5120 0 5120 0% /run/lock

/dev/xvdb 20565716 4849808 15699524 24% /rw

tmpfs 28076 48 28028 1% /run/user/1000

overlay 20327908 19915732 0 100% /var/lib/docker/overlay2/4b5abbf80b25e987b263eed79125c7de0fac2e1fee51c50aafa5f63407ff6548/merged

overlay 20327908 19915732 0 100% /var/lib/docker/overlay2/01b9525ad4298b3c96f66f57de621a6b7253a40cecd2992fccbef938f2322680/merged

overlay 20327908 19915732 0 100% /var/lib/docker/overlay2/93091825d7944b8df07e7028ec7c083684c0204b26473827ab935f6842359078/merged

ckayhernandez
Posted by ckayhernandez 1 month ago

How to deploy this using laravel forge?


No response yet
You need to be signed in to post comments, you can sign in here if you already have an account or register here if you don't.