b5 example project with Laravel
This is the third article of the series Local development with Docker, b5 and traefik. If you havent read the first ans second part, then you should, You can read about the intentions why we developed b5 and how it works.
Let's start
Create a new folder for the project with a build
folder inside and a config.yml
and a Taskfile
. As last step we will initialise a git repository.
1mkdir example-project && cd example-project2mkdir build3touch build/config.yml4touch build/Taskfile5git init
First we define our project key
inside of the config.yml:
1project:2 key: example-project
Create a new Laravel application
We assume the we have neither php
nor composer
installed locally.
Lets create a simple docker-compose.yml
file with a single php service:
1version: "3.7"2 3services:4 5 php:6 image: docker.team23.de/docker/php:7.47 volumes:8 - ../:/app
We use the TEAM23 php
image in version 7.4 . It is based on the official php:7.4-fpm-buster
with many php extensions enabled, composer installed, optional xdebug support and preconfigured msmtp. We mount the whole project (we are in the build
folder and we make ../
) into the containers /app
folder.
Next we need to define the composer command in the config.yml
to create the application:
1project:2 key: example-project3modules:4 docker:5 commands:6 composer:7 bin: composer8 service: php9 workdir: /app
As you can see we set the workdir
of the composer command to /app
. Later we will change this to /app/web
but first we need to create the web
folder with the application.
To execute the command we need to define a task in the Taskfile:
1#!/usr/bin/env bash2 3task:composer() {4 docker:command:composer "$@"5}
Now we can create the Laravel application with the following command:
1b5 composer create-project laravel/laravel web
The execution will take some time and at when it finishes we can see a web
folder with a fresh Laravel application.
Add a web server
To use the application we need a web server. So lets define it in the docker-compose.yml
file:
1version: "3.7" 2 3services: 4 5 php: 6 image: docker.team23.de/docker/php:7.4 7 volumes: 8 - ../:/app 9 10 web:11 image: docker.team23.de/docker/apache:2.4-php12 environment:13 APACHE_DOCUMENT_ROOT: /app/web/public14 volumes:15 - ../:/app16 ports:17 - 8000:80
This is also an image form our company but it is open source. Feel free to fork/copy/use it. The mein reason why we use it is the configurable document root. We will also add a port mapping from the containers pro 80 to the host system port 8000.
Now we need to start the docker-compose.yml
. We do this with a b5 task which we have to define in the Taskfile
:
1#!/usr/bin/env bash 2 3task:run() { 4 docker:docker-compose up "$@" 5} 6 7task:halt() { 8 docker:docker-compose down "$@" 9}10 11task:composer() {12 docker:command:composer "$@"13}
Now we can start the project with a simple b5 run
command.
We should now be able to see Laravels welcome page at localhost:8000
.
Lets define a command for artisan and phpunit with there respective tasks. Additionally we can update the composer commands workdir
to /app/web
.
config.yml:
1project: 2 key: example-project 3modules: 4 docker: 5 commands: 6 composer: 7 bin: composer 8 service: php 9 workdir: /app/web10 phpunit:11 bin: ["php", "./vendor/bin/phpunit"]12 service: php13 workdir: /app/web14 artisan:15 bin: ["php", "./artisan"]16 service: php17 workdir: /app/web
Taskfile:
1#!/usr/bin/env bash 2 3# ... 4 5task:artisan() { 6 docker:command:artisan "$@" 7} 8 9task:phpunit() {10 docker:command:phpunit "$@"11}
Now we are able to execute any artisan command with b5 artisan {anything}
from anywhere inside the project. The same with b5 phpunit
. Pretty cool!
We need a MySQL server
The apache and php container are running as expected but until now e have no database. Let’s fix this by adding a mysql service with a volume for persistence to the docker-compose.yml
file:
1version: "3.7" 2 3services: 4 5 # ... 6 7 mysql: 8 image: mysql:5.7 9 environment:10 MYSQL_ROOT_PASSWORD: secret11 MYSQL_DATABASE: docker12 MYSQL_USER: docker13 MYSQL_PASSWORD: docker14 volumes:15 - mysql:/var/lib/mysql/16 17volumes:18 mysql:
As you can see we use the official mysql:5.7
image. The image gives us the option to create a default database with user and password by setting the correct environment variables. We also define the root password
which we need for the next step where we add phpMyAdmin. We also create a volume named db
which will be mountest to the containers /var/lib/mysql
folder. This folder holds all the database information of the MySQL service and persists it.
If the project is still running, execute b5 halt
to stop the project. To let our Laravel application know about the mysql service we need to edit the .env
file in the web
directory:
12# ...34DB_HOST=mysql5DB_DATABASE=docker6DB_USERNAME=docker7DB_PASSWORD=docker89# ...
Lets add the MySQL service as a dependency off the php service in the docker-compose.yml
file. Then we can execute b5 artisan
tasks which interact with the database without starting the project with b5 run
.
1version: "3.7" 2 3services: 4 5 php: 6 image: docker.team23.de/docker/php:7.4 7 volumes: 8 - ../:/app 9 depends_on:10 - mysql11 12 # ...
To check if the connection work, we execute b5 artisan migrate
.
The output should look like this:
1#Migration table created successfully.2Migrating: 2014_10_12_000000_create_users_table3Migrated: 2014_10_12_000000_create_users_table (0.06 seconds)4Migrating: 2014_10_12_100000_create_password_resets_table5Migrated: 2014_10_12_100000_create_password_resets_table (0.03 seconds)6Migrating: 2019_08_19_000000_create_failed_jobs_table7Migrated: 2019_08_19_000000_create_failed_jobs_table (0.02 seconds)8Task exited ok
This tells us that database connection work. To have a graphical user interface for the project we will add a phpMyAdmin container. First stop the project with b5 halt
and open the docker-compose.yml
file.
1version: "3.7" 2 3services: 4 5 # ... 6 7 phpmyadmin: 8 image: phpmyadmin/phpmyadmin:latest 9 environment:10 PMA_HOST: mysql11 PMA_USER: root12 PMA_PASSWORD: secret13 depends_on:14 - mysql15 ports:16 - 8001:8017 18volumes:19 mysql:
We can configure the phpMyAdmin container via environment variables. We will set the PMA_HOST
to the host name of the MySQL service which is simply mysql
. Next we set the PMA_USER
to root
and the PMA_PASSWORD
to secret
which we defined in the MySQL service. We set depends_on
to mysql
. This means that this service will first start the MySQL service. At last we add a mapping form the containers port 80 to the port 8001 of the host system.
To verify that the phpMyAdmin service works, start the project with b5 run
and navigate your browser to localhost:8001
.
…and we see it is working. Cool!
Lets compile our assets with a Node.js service
Laravel ships with Laravel Mix which is a convenient wrapper around webpack.
First stop the project with b5 halt
. To use it we need a Node.js service to our docker-compose.yml
which can execute npm for us:
1version: "3.7" 2 3services: 4 5 # ... 6 7 node: 8 image: node:lts 9 volumes:10 - ../:/app11 12 # ...
Additionally we will define the docker command in the config.yml
and the task in the Taskfile
.
config.yml:
1project: 2 key: example-project 3modules: 4 docker: 5 commands: 6 # ... 7 npm: 8 bin: npm 9 service: node10 workdir: /app/web
Taskfile:
1#!/usr/bin/env bash2 3# ...4 5task:npm() {6 docker:command:npm "$@"7}
Now we can execute b5 npm install
to instal the defined dependencies form the package.json
. The output should look like this:
1Executing task npm 2 3Creating network "example-project_default" with the default driver 4npm notice created a lockfile as package-lock.json. You should commit this file. 5 6added 1035 packages from 485 contributors and audited 17259 packages in 82.852s 7 831 packages are looking for funding 9 run `npm fund` for details1011found 0 vulnerabilities1213Task exited ok
Because we have a generic b5 npm {anything}
command , we can also execute b5 npm run dev
. To compile the assets. Node.js service done. Boom!
Redis FTW
Redis is a in memory key value store which can be used for queues, cache and sessions. Lets add a reds service to the docker-compose.yml
file:
1version: "3.7" 2 3services: 4 5 # ... 6 7 redis: 8 image: redis 9 10 # ...
Since redis is a in memory store we do not need to persist anything (at least in development) , the definition is only 2 lines.
Now update Laravels .env
file to use redis:
1 2# ... 3 4CACHE_DRIVER=redis 5QUEUE_CONNECTION=redis 6SESSION_DRIVER=redis 7 8# ... 910REDIS_HOST=redis1112# ...
Thats all about using redis inside the project. You can see that this is not as hard as you think. Another service done. Boom!
Add MailHog to see Mails sent by Laravel
MailHog is a SMTP testing service written in Go with a web ui to see outgoing mails.
To use it we have to add it as a service in our docker-compose.yml
file:
1version: "3.7" 2 3services: 4 5 # ... 6 7 mail: 8 image: mailhog/mailhog 9 ports:10 - 8025:802511 12 # ...
To use it from Laravel we need to adjust the settings ind the .env
file:
1# ...23MAIL_DRIVER=smtp4MAIL_HOST=mail5MAIL_PORT=10256# ...
Now start the project with b5 run
and navigate the browser to localhost:8025
.
We can see the MailHog web ui.
To verify that the mail thing works from the Laravel site we can use tinker
.
Execute b5 artisan tinker
and Enter the following code to send a mail:
1Mail::raw('Test Mail', function($message){$message->from('[email protected]')->to('[email protected]');})
Now we can see the mail in the MailHog web ui.
And another service done. Boom!
In the next article we will learn about traefik and how we can use it to custom domains in our development environment.
I hope you enjoyed my tutorial. If you have any questions about it feel free to reach out to me via mail.