Dockerize Laravel, Nginx, MariaDB, PhpMyAdmin, Redis and Npm

Reza Khademi
7 min readNov 28, 2022

--

Using docker for developing Laravel web-apps is so fun and will prevent us from a headache of installation and configuration different services for our local environment.

To get started, make sure you have Docker installed on your system, and let’s dive into it. (You can clone the complete repository at this Github Repo.)

Let’s look at our file structure to have a better understand of what’s going on:

dockerfiles/
src/
mysql/
docker-compose.yml
.env

Inside dockerfiles/ folder we will create these:

nginx/
nginx.dockerfile
php.dockerfile

The nginx/ folder is for default.conf and docker files are located here to create our custom images. Inside the nginx/ folder we have a regular config file (default.conf) as below:

nginx default.conf file

And now we can concentrate on our docker environment.

  • Inside nginx.dockerfile we have:

First of all, we pull a light-weight Alpine image and then we set user ID and group ID as a non-root user for docker and if you wonder why, because if our container was running as root and we generated a file from our container through a volume back to our Docker host then the file will be owned by root:root.

That could make it annoying to edit from your environment because you would need elevated privileges to write/delete that file.

By default, UID and GID are 1000 but in a multi-user environment you may end up with something different. If you want to see your UID/GID simply run below command on your terminal:

id

And the output (for me) is:

uid=1000(reza) gid=1000(reza) groups=1000(reza-work),27(sudo),30(dip),46(plugdev),120(lpadmin),131(lxd),132(sambashare),998(docker)

After adding user, by using ADD docker command (which exists on the line 16th of nginx.dockerfile):

Docker Add command nginx default conf

We will copy default.conf file to desired location of nginx image.

Inside php.dockerfile we have:

php dockerfile

Php docker file is pretty straight forward and after configuring Composer, we can install any Php extensions that we need on our project but notice we want to use Laravel and this framework communicates with MySql through PDO, so installing this extension is a must!

We want to use Redis for cache purpose so let’s install phpredis and enable Redis extension.

php docker file

Until now we have our docker files and if you recall our files structure, we need to determine the docker-compose.yml:

dockerfiles/
src/
mysql/
docker-compose.yml
.env

The docker-compose file will have our desired containers as shown below, and we are going to explain each one of them.

docker-compose nginx container

The defined services will have the same network named laravel, which will allow them to communicate with each other without any issues.

On build section we will define the working directory as context and the name of related dockerfile as nginx.dockerfile. So docker compose will go to context directory and use nginx.dockerfile.

First of all we will launch an instance of nginx running in a container and using the created nginx configuration and defined image on ./dockerfile.

We will set UID/GID which we discussed earlier and expose port 80:80 (left one is one our system and right one is on docker). Binding ./src on host to /var/www/html will give access to nginx to serve our Laravel website and depends_on section indicates that this service needs a list of services to run, and without them, nothing goes to happen.

What does delegated mean on/var/www/html:delegated ?

  • Use delegated on Volumes: whenever docker container performs changes, host is in read only mode.
  • Use cached on Volumes: when the host performs changes, the container is in read only mode.
  • Default: whenever both container and host actively and continuously perform changes on data.

Second of all, let’s create a mysql container:

For this one we use official image of MariaDB version 10.6 and restart: unless-stopped option tells us once the container is stopped manually it will not restart automatically even after restarting the docker daemon, we should start it manually.

The tty flag is a related concept to stdin, stdout. A pseudo terminal (also known as a tty) connects a user's terminal with ability of the stdin and stdout stream through a shell such as bash.

By default, whenever we bring down the Docker network, our MySQL data will be removed after the containers are destroyed but we would like to have persistent data that remains after bringing containers so we bind ./mysql folder to /var/www/html.

As all of us know, each database needs some environment variables to deal with application so we will specify environment and even timezone (TZ) to have a more robust settings.

mysql/
docker-compose.yml
.env

The “${DB_DATABASE}” means docker automatically look into .env file on the same directory to complete desired key-values. The .env file contains:

Third of all, we will make php container:

Earlier, we wrote everything that will be needed on the php.dockerfile, so this is a simple section for this container. We just need to make sure the context directory and dockerfile are correct. Port 9000 will be exposed for our application, and the ./src directory will be linked to the container to load our future Laravel web app.

Fourth of all, let’s configure PhpMyAdmin:

We use default image to create Phpmyadmin service and for login credentials, we will use the same mysql .env password. The only important thing is the PMA_HOST which must be equal to myql service name so Phpmyadmin automatically connect to database and we don’t need to deal with IPs in docker.

Fifth of all, Redis container is another part of docker compose file:

Last step is creating Composer, Npm and Artisan containers. They are so simple and we can define them as below:

composer docker compose file

The only thing that is important to know is entrypoint option. This instruction will be used to provide executables that will always execute when the container is launched.

For example if we determine below entrypoint for a test named container:

entrypoint: ["echo", "Hello World"]

After running:

docker run test

The output is:

Hello World

So when the container is run the ENTRYPOINT instruction is executed, and Hello World is echoed.

Let’s have look at our docker-compose.yml:

Quite large docker-compose.yml file, right? but that’s works well and You can clone the complete repository at this Github Repo.

What now?

Next, navigate in your terminal to the directory you cloned above repository and spin up the containers for the web server by running docker-compose up -d --build app.

The following containers are built for our web server, with their exposed ports detailed:

  • nginx:80
  • mysql:3306
  • app :9000
  • redis:6379
  • phpmyadmin:8081

Now we can use our ./src folder by one these instructions:

  • Clone your Laravel project or copy all of the files directly into this src directory.
  • Install a brand new Laravel project by running docker-compose run --rm composer create-project laravel/laravel . in your terminal inside ./src folder.

Three additional containers are included that handle Composer, NPM and Artisan commands without having to have these platforms installed on your local computer.

Use the following command examples from your project root, modifying them to fit your particular use case.

  • docker-compose run --rm composer update
  • docker-compose run --rm npm run dev
  • docker-compose run --rm artisan migrate

Access container as interactive shell and see output:

docker exec -it <container id> sh

Our docker application is accessible through http://localhost:9000.

That’s it.

READ MORE:

--

--