How I Set Up Laravel in Docker Container
Today I am explaining how I was set up my first Laravel app in Docker container.
Prerequisites
Before start, I had the following.
- Ubuntu 18.04
- Composer installed
- Installed docker — https://docs.docker.com/install/linux/docker-ce/ubuntu/
- Installed docker compose — https://docs.docker.com/compose/install/
Step 1 — Installed Laravel app
Created a Laravel app via composer create-project
composer create-project — prefer-dist laravel/laravel laradock
Moved to my project directory
cd laradock
Given write permission for thestorage
folder and thecache
folder within the bootstrap
folder.
sudo chmod 777 -R storage/
sudo chmod 777 -R bootstrap/cache/
Next, Then used Docker’s composer image to mount the directories that y I need for your Laravel app and avoid the installing Composer globally.
docker run --rm -v $(pwd):/app composer install
Step 2 — Create Docker Compose File
touch docker-compose.yml
I have used port number 8080 and 8443 for webserver because I have already installed apache web service in my PC. Also, I have used port number 33061 for MySQL because I have already installed MySQL server on my PC.
Step 3 — Persist Data
Docker has features for persisting data. In my application, I had make use of volumes and bind mounts for persisting the database, and application and configuration files.
Under db
service definition in docker-compose.yml
file, defined a volume called dbdata
to persist the MySQL database.
...
#MySQL Service
db:
...
volumes:
- dbdata:/var/lib/mysql
networks:
- app-network
...
The dbdata
volume persists the contents of the var/lib/mysql
folder present inside the container. This allowed to stop and restart the db
service without losing data.
At the end of the compose file, added the definition for the dbdata
volume:
...
#Volumes
volumes:
dbdata:
driver: local
Then, added a bind mount to the db
service for the MySQL configuration files.
...
#MySQL Service
db:
...
volumes:
- dbdata:/var/lib/mysql
- ./mysql/my.cnf:/etc/mysql/my.cnf
...
Next, added bind mounts to the webserver
service. There were will be two: one for your application code and another for the Nginx configuration.
#Nginx Service
webserver:
...
volumes:
- ./:/var/www
- ./nginx/conf.d/:/etc/nginx/conf.d/
networks:
- app-network
Finally, added the following bind mounts to the app
service for the application configuration files and code:
#PHP Service
app:
...
volumes:
- ./:/var/www
- ./php/local.ini:/usr/local/etc/php/conf.d/local.ini
networks:
- app-network
The app service is bind-mounting the laradock
folder, which contains the application code, to the /var/www folder in the container.
Finally the docker-compose.yml
were look like this.
Step 4 — Created the Dockerfile
touch Dockerfile
This docker file will set the base image and specify the required commands and instructions.
Step 5 — Configured PHP
To configure PHP created alocal.ini
file.
mkdir php
touch php/local.ini
I have added the following PHP configurations to this file.
upload_max_filesize=10M
post_max_size=10M
This is the file that I have bind-mounted to /usr/local/etc/php/conf.d/local.ini inside the container in Step 2.
Step 6 — Configure NGINX
To configure Nginx, I have created a fileapp.conf
file with the service configurations in the nginx/conf.d
folder.
mkdir -p nginx/conf.d
touch nginx/conf.d/app.conf
Added the following code to your app.conf
file.
server {
listen 80;
index index.php index.html;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /var/www/public;
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass app:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
location / {
try_files $uri $uri/ /index.php?$query_string;
gzip_static on;
}
}
Step 7 — Configured MySQL
For configuring MySQL I was created a configuration file my.cnf
inside mysql
folder.
mkdir mysql
touch mysql/my.cnf
I have added the following code to my.cnf
enable the query log and set the log file location.
[mysqld]
general_log = 1
general_log_file = /var/lib/mysql/general.log
Step 8 — Ran the containers
At last, I have defined all the services in the docker-compose file and created the configuration files for those services. Then I started the containers by running the command given below.
docker-compose up -d
It downloaded all the necessary Docker images. After that, I have listed all the running containers and their status using the following command.
docker ps
Step 9— Created a MySQL User
To create a new user, execute an interactive bash shell on the db
container with docker-compose exec
:
docker-compose exec db bashroot@18833a170621:/# mysql -u root -p
Then, created a user and given all privileges to the user.
mysql> GRANT ALL ON laravel.* TO 'laraveluser'@'%' IDENTIFIED BY 'my_password';
Flushed the privileges to apply the changes.
mysql> FLUSH PRIVILEGES;
mysql> EXIT;
root@18833a170621:/# exit
Step 10 — Update the environment settings
I edited the environment files of my laravel app.
docker-compose exec app vim .env
Updated the database credentials and app URL.
APP_URL=http://0.0.0.0:8080DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=laraveluser
DB_PASSWORD=my_password
Step 11 — Migrated the database
docker-compose exec app php artisan migr
Finally, I had able to access my Laravel app on http://0.0.0.0:8080/
I have deployed this app to GitHub.