Docker for the long-time Vagrant user (Laravel, Nginx, PHP with Xdebug, MySQL, Redis)
November 15, 2022 ≈ 5 minutes 14 seconds
Why did I decide to try Docker after being totally happy with Vagrant for such a long time? Well, I switched to the new dev machine, based on an M1 processor, which is unsupported by VirtualBox. Also for the speed, less disc consumption, ease of networking between containers and other benefits of containerized approach, such as when I'm working on a quick project with only a PHP built-in web server and need MySQL, Redis or Mailhog right away. With Docker, I just run a MySQL container attached to a volume, and that's it.
What to do with current Laravel Homestead virtual machines?
My initial thought was to use Laravel Sail which simplifies the process of creating a new Docker container. But I decided to build a container from scratch to be more fluent with Docker and be able to do more precise configuration like I did with Vagrant VMs. So, in this article, I'll go through the process of creating a Docker container for an existing Laravel project step-by-step. We'll use 'beaubus.test' as the project name and 'artist' as user.
1. Create folder structure
cd beaubus.test
mkdir -p .provision/mysql_datadir
We keep all Docker-related files inside .provision folder, to not bloat the project index with Docker configuration. Also, we use mysql_datadir/ folder as a data directory for MySQL to persist data when we remove the container.
2. Download .sql files from production
# On production
sudo mysqldump beaubus > beaubus.sql
# Download into .provision/ folder
3. Copy id_rsa.pub into .provision
cp ~/.ssh/id_rsa.pub .provision
We need public key to connect to the container via SSH. We also copy it to the .provision/ folder because we cannot use it directly (paths outside of build context are not allowed in Dockerfile)
4. Create .provision/nginx.conf
# beaubus.test
server {
server_name .beaubus.test www.beaubus.test;
listen 443 ssl;
ssl_certificate /var/www/default/.provision/nginx-beaubus-selfsigned.crt;
ssl_certificate_key /var/www/default/.provision/nginx-beaubus-selfsigned.key;
if ($host = beaubus.test) {
return 301 https://www.beaubus.test$request_uri;
}
root /var/www/default/public;
index index.html index.htm index.php;
charset utf-8;
location = /favicon.ico { log_not_found off; access_log off; }
location = /robots.txt { log_not_found off; access_log off; }
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.0-fpm.sock;
}
error_page 404 /index.php;
}
server {
server_name .beaubus.test www.beaubus.test;
return 301 https://www.beaubus.test$request_uri;
}
5. Create .provision/my_overrides.cnf
[mysqld]
datadir = /var/www/default/.provision/mysql_datadir
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
We tell mysqld to use the data directory that we created earlier it the .provision/ folder.
6. Create .provision/xdebug.ini
;add extension for zend engine (php language core)
zend_extension = xdebug.so
;color output of var_dump in cli mode
xdebug.cli_color = 1
; Enables Step Debugging. This can be used to step through your code while it is running, and analyse values of variables.
xdebug.mode = debug
xdebug.idekey = phpstorm
;gateway from route -n command (IP or hostname of machine running IDE)
xdebug.client_host=host.docker.internal
xdebug.client_port=9000
'host.docker.internal' is a special DNS name which resolves to the internal IP address used by the host
7. Create .provision/beaubus-worker.conf
Which is configuration file for supervisor running Laravel workers.
[program:beaubus-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/default/artisan queue:work --sleep=3 --tries=3
autostart=true
autorestart=true
user=www-data
umask = 002
numprocs=2
redirect_stderr=true
stdout_logfile=/var/www/default/storage/logs/worker.log
stopwaitsecs=3600
8. Create .provision/Dockerfile
We add after.sh to entrypoint and make it executable, so it runs automatically every time we run a container.
9. Create .provision/after.sh
#!/bin/bash
cd /var/www/default
sudo service php8.0-fpm start
sudo service redis-server start
sudo service ssh start
# check for beaubus file in MySQL datadir an if not, provision mysql
if [ ! -d /var/www/default/.provision/mysql_datadir/beaubus ]
then
chown mysql:mysql /var/www/default/.provision/mysql_datadir
chmod 750 /var/www/default/.provision/mysql_datadir
sudo mysqld --initialize-insecure --user=mysql
sudo service mysql start
echo "Setting up MySQL..."
sudo mysql -e "CREATE USER \`homestead\`@'%' IDENTIFIED BY 'secret'"
sudo mysql -e "CREATE DATABASE \`beaubus\`"
sudo mysql -e "grant all privileges on *.* to 'homestead'@'%'"
sudo mysql -e "FLUSH PRIVILEGES"
sudo mysql beaubus < .provision/beaubus.sql
else
sudo service mysql start
fi
# run supervisor with website worker
sudo service supervisor start
sudo service nginx start
# generate wildcard certificate for beaubus.test if it's not exist
if [ ! -f .provision/nginx-beaubus-selfsigned.key ] || [ ! -f .provision/nginx-beaubus-selfsigned.crt ]
then
openssl req -x509 -nodes -days 3650 -subj "/C=CA/ST=QC/O=BEAUBUS/CN=BEAUBUS" -newkey rsa:2048 -keyout .provision/nginx-beaubus-selfsigned.key -out .provision/nginx-beaubus-selfsigned.crt -addext "subjectAltName=DNS:beaubus.test,DNS:*.beaubus.test,IP:127.0.0.1"
fi
After creating, make it executable: chmod u+x after.sh
10. Build an image
docker build -t beaubus-image .provision
--tag , -t
Name and optionally a tag in the ‘name:tag’ format
The .provision at the end of the docker build command tells that Docker should look for the Dockerfile in .provision directory
11. Run the container
docker run -it -p 80:80 -p 443:443 -p 3306:3306 -p 2222:22 -e TZ=UTC+4 --rm --name beaubus-app -v "$(pwd)":/var/www/default beaubus-image
-d
Run the container in detached mode (background)
--rm
Automatically remove the container when it exits
--name
Assign a name to the container
-p 2222:22
Map 22 port of container to 2222 on host
To access console run docker exec -it beaubus-app /bin/bash
To access console via SSH run: ssh artist@localhost -p 2222
To read log run docker logs -f beaubus-app
To run Laravel tests: docker exec -it beaubus-app php artisan test --testsuite=Acceptance
(testsuites specified in phpunit.xml)
To run composer install: docker exec -it beaubus-app composer install
To run tinker : docker exec -it beaubus-app php artisan tinker
12. Add environmental variables into phpunit.xml
<server name="PHP_IDE_CONFIG" value="serverName=beaubusconsole"/>
<env name="XDEBUG_CONFIG" value="xdebug.idekey=phpstorm"/>
'beaubusconsole' is the server from PHP > Servers in PhpStorm
13. Configure PhpStorm
— Add CLI Interpreter 'artist@localhost:2222', php located in /usr/bin/php
— Add CLI Interpreter in PHP > Test Frameworks
— Add XDEBUG_CONFIG="xdebug.idekey=phpstorm"
into PHPUnit configuration template
— Add 'beaubusconsole' server with host 172.17.0.2 (IP of Docker container) and port 22
— Add beaubus.test, port 443
To get Docker container ip, run docker inspect -f "{{ .NetworkSettings.IPAddress }}" beaubus-app
-f
Format the output using the given Go template
14. Add https certificate on macOS
Open 'keychain Access.app'. Open 'Login -> Certificates' tab. Drag .crt file from '.provision' folder. Double click on each dragged file -> Trust -> SSL -> Always trust
15. Add to .gitignore
/.provision/mysql_datadir
/.provision/*.pub
/.provision/*.crt
/.provision/*.key
That's it. Thank you for reading!
I intentionally didn't comment on configuration files, assuming that the reader will have prior experience with Vagrant boxes and manual configuration of common services. If you find this article useful, please share it and click on ❤️ in the top right corner to let me know.
Reference to command line commands: docker | Docker Documentation
You didn't provide any data, entered invalid email or already subscribed.
Try again. And if you still can't subscribe—write us.
Address successfully subscribed!
Subscribe to our newsletter
If you provide url of your website, we send you free design concept of one element (by our choice)
Subscribing to our newsletter, you comply with subscription terms and Privacy Policy