ПІДТРИМАЙ УКРАЇНУ ПІДТРИМАТИ АРМІЮ
Uk Uk

Dockerizing Laravel 10

Dockerizing Laravel 10

Dockerizing Laravel 10 for Ubuntu image using PHP 8.2 FPM and NGINX

Be aware that this article is only about dockerizing a Laravel application and not any other database or filesystem. We will put these as a series procedurally.

Copy the content below inside a file called Docerfile at the root of your project. (Root of a project is where there are files like artisan , composer.json and .env , in case you are confused)

FROM ubuntu:latest AS base

ENV DEBIAN_FRONTEND noninteractive

# Install dependencies
RUN apt update
RUN apt install -y software-properties-common
RUN add-apt-repository -y ppa:ondrej/php
RUN apt update
RUN apt install -y php8.2\
 php8.2-cli\
 php8.2-common\
 php8.2-fpm\
 php8.2-mysql\
 php8.2-zip\
 php8.2-gd\
 php8.2-mbstring\
 php8.2-curl\
 php8.2-xml\
 php8.2-bcmath\
 php8.2-pdo

# Install php-fpm
RUN apt install -y php8.2-fpm php8.2-cli

# Install composer
RUN apt install -y curl
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

# Install nodejs
RUN apt install -y ca-certificates gnupg
RUN mkdir -p /etc/apt/keyrings
RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
ENV NODE_MAJOR 20
RUN 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
RUN apt update
RUN apt install -y nodejs

# Install nginx
RUN apt install -y nginx
RUN echo "\
 server {\n\
 listen 80;\n\
 listen [::]:80;\n\
 root /var/www/html/public;\n\
 add_header X-Frame-Options \"SAMEORIGIN\";\n\
 add_header X-Content-Type-Options \"nosniff\";\n\
 index index.php;\n\
 charset utf-8;\n\
 location / {\n\
 try_files \$uri \$uri/ /index.php?\$query_string;\n\
 }\n\
 location = /favicon.ico { access_log off; log_not_found off; }\n\
 location = /robots.txt { access_log off; log_not_found off; }\n\
 error_page 404 /index.php;\n\
 location ~ \.php$ {\n\
 fastcgi_pass unix:/run/php/php8.2-fpm.sock;\n\
 fastcgi_param SCRIPT_FILENAME \$realpath_root\$fastcgi_script_name;\n\
 include fastcgi_params;\n\
 }\n\
 location ~ /\.(?!well-known).* {\n\
 deny all;\n\
 }\n\
 }\n" > /etc/nginx/sites-available/default

RUN echo "\
 #!/bin/sh\n\
 echo \"Starting services...\"\n\
 service php8.2-fpm start\n\
 nginx -g \"daemon off;\" &\n\
 echo \"Ready.\"\n\
 tail -s 1 /var/log/nginx/*.log -f\n\
 " > /start.sh

COPY . /var/www/html
WORKDIR /var/www/html

RUN chown -R www-data:www-data /var/www/html

RUN composer install

EXPOSE 80

CMD ["sh", "/start.sh"]

Run the build command from terminal and then run the image:

docker build -t MY_IMAGE .
docker run -p "8000:80" MY_IMAGE

Then open your browser and navigate to " http://localhost:8000/ "

Boom! Your Laravel is up!

Dive deeper

If you are in a hurry it is good to just copy/paste the codes above and get your job done. But if you want to know what is happening and how you can customize it based on your needs follow the article. You need a basic understanding of Docker though, so research about Docker for more detailed information.

Base image and stage

In the first line, you can see this line:

FROM ubuntu:latest AS base

This means that we are defining a stage of build called base from the latest Ubuntu image.

Follow the line mentioned above you see an environment variable being set:

ENV DEBIAN_FRONTEND noninteractive

This sets Ubuntu's interface as a non-interactive one. This is done because some commands might ask for user input and since that is not possible to do so and we need our image to build as quickly and as easily as possible, we need to disable input prompts so it does not stop the build process.

We need to update the packages of Ubuntu, hence the line:

RUN apt update

Laravel dependencies

Obviously, every program needs some stuff installed before running and Laravel is not an exception. If you follow the link to Laravel's official deployment documentation you can see the prerequisites to run Laravel.

As Laravel's documentation mentions it needs PHP version 8.1 or higher. We will use PHP 8.2 along with the FPM to run Laravel and NGINX as a reverse proxy.

To install PHP 8.2 on Ubuntu we need to add some repositories since it is not available as a default. A good way to add a repository is to use a tool called add-apt-repository , but again it is not available as a default. The add-apt-repository tool is available in a package called software-properties-common . To install this package we can tell Docker to tell Ubuntu to install it (that seems bizarre LOL):

RUN apt install -y software-properties-common

The flag -y is there to confirm all prompts by default since apt install asks for a confirmation midway through.

After the installation is done we can use add-apt-repository to add the required repository to install php8.2 :

RUN add-apt-repository -y ppa:ondrej/php

Then update the list of packages again to ensure everything will be installed from the newly added repositories:

RUN apt update

Along with PHP itself, we will install Laravel's requirements too:

RUN apt install -y php8.2\
 php8.2-cli\
 php8.2-common\
 php8.2-fpm\
 php8.2-mysql\
 php8.2-zip\
 php8.2-gd\
 php8.2-mbstring\
 php8.2-curl\
 php8.2-xml\
 php8.2-bcmath\
 php8.2-pdo

If you wonder what are all those back-slashes (), they are there to tell docker that the new line character should be escaped.

PHP FPM & CLI

So far everything is fine for a Laravel application to run, but we want to give it some more speed and we are going to use PHP FPM. (More info about PHP FPM here )

Here we will install FPM:

RUN apt install -y php8.2-fpm php8.2-cli

PHP CLI also needs to be installed as it is essential to run many commands especially php artisan .

Composer

As you might know, Composer is a package manager for PHP projects and Laravel uses it too. To install Composer we need to download the installer file and run it with PHP. To download something we can use wget or curl . Here we will use curl to download and pipe the result to PHP for installation.

First, install curl:

RUN apt install -y curl

Then, download the file and pip it to PHP:

RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

Node.js

If you are using Laravel as a full-stack framework (both front-end and back-end), you need Node.js too.

Node's official documentation suggests installing Node on Debian/Ubuntu-based distros (on which our image is based) through Node binary distributions. ( Documentation for Debian/Ubuntu 

I am not going to dive into full details of the commands since full description is available in the documentation provided above. So once again we will tell Docker to tell ubuntu to run the commands, thus the codes:

RUN apt install -y ca-certificates gnupg
RUN mkdir -p /etc/apt/keyrings
RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
ENV NODE_MAJOR 20
RUN 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
RUN apt update
RUN apt install -y nodejs

NGINX

We will install and configure as a reverse proxy.

To install NGINX:

RUN apt install -y nginx

Once NGINX is installed, we need to add our website configuration. The default website's configuration is located at /etc/nginx/sites-available/default so we echo our configuration inside this file and overwrite it:

RUN echo "\
 server {\n\
 listen 80;\n\
 listen [::]:80;\n\
 root /var/www/html/public;\n\
 add_header X-Frame-Options \"SAMEORIGIN\";\n\
 add_header X-Content-Type-Options \"nosniff\";\n\
 index index.php;\n\
 charset utf-8;\n\
 location / {\n\
 try_files \$uri \$uri/ /index.php?\$query_string;\n\
 }\n\
 location = /favicon.ico { access_log off; log_not_found off; }\n\
 location = /robots.txt { access_log off; log_not_found off; }\n\
 error_page 404 /index.php;\n\
 location ~ \.php$ {\n\
 fastcgi_pass unix:/run/php/php8.2-fpm.sock;\n\
 fastcgi_param SCRIPT_FILENAME \$realpath_root\$fastcgi_script_name;\n\
 include fastcgi_params;\n\
 }\n\
 location ~ /\.(?!well-known).* {\n\
 deny all;\n\
 }\n\
 }\n" > /etc/nginx/sites-available/default

This is the same configuration suggested by Laravel's official documentation with minor tweaks:

  • We don't need server_name since this container is used server only Laravel and should respond to everything.
  • Changed the root to /var/www/html/public as it is the root of where our application is going to be deployed.
  • fastcgi_pass 's fpm socket is changed to unix:/run/php/php8.2-fpm.sock as php8.2-fpm's socket in our scenario is placed here.

Custom shell script to run our application

At this step, we will create a custom shell script to prepare the system and run the app each time the container is started.

Here is how our bash script looks:

#!/bin/sh
echo "Starting services..."
service php8.2-fpm start
nginx -g "daemon off;" &
echo "Ready."
tail -s 1 /var/log/nginx/*.log -f

This script starts the FPM service then runs the entry point of nginx and sends it to the background and finally starts printing nginx logs.

To create this file we can echo it inside a file like below:

RUN echo "\
 #!/bin/sh\n\
 echo \"Starting services...\"\n\
 service php8.2-fpm start\n\
 nginx -g \"daemon off;\" &\n\
 echo \"Ready.\"\n\
 tail -s 1 /var/log/nginx/*.log -f\n\
 " > /start.sh

I've named the file start.sh and placed it at the root of the container. You are free to name it anything and place it anywhere you want.

Deploying Laravel

Now that our environment is ready let's move to deploying Laravel.

First, copy the current files to /var/www/html :

COPY . /var/www/html

Then change the working directory of Docker to the same address:

WORKDIR /var/www/html

Since Laravel needs access to this folder as well we set the permission of the directory:

RUN chown -R www-data:www-data /var/www/html

And finally, ask Composer to install the ph packages required by Laravel:

RUN composer install

Note: don't run composer install before setting the permissions. Setting permission of every folder is done recursively and it's better run before all those packages installed since it will take way longer in that case.

Expose port 80

NGINX will try to listen to post 80 and needs to be exposed in order to be bound:

EXPOSE 80

Run the server

Remember the shell script we've created? It is time to run the script when the container is started:

CMD ["sh", "/start.sh"]

And over!

Build and run

To build and runt he image use the commands below where a docker instance is available:

docker build -t MY_IMAGE .
docker run -p "8000:80" MY_IMAGE

Replace MY_IMAGE with the desired name for your Docker image.

Ресурс : dev.to


Scroll to Top