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.
mkdir example-project && cd example-project
mkdir build
touch build/config.yml
touch build/Taskfile
git init
First we define our project key inside of the config.yml:
project:
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:
version: "3.7"
services:
php:
image: docker.team23.de/docker/php:7.4
volumes:
- ../:/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:
project:
key: example-project
modules:
docker:
commands:
composer:
bin: composer
service: php
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:
#!/usr/bin/env bash
task:composer() {
docker:command:composer "$@"
}
Now we can create the Laravel application with the following command:
b5 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:
version: "3.7"
services:
php:
image: docker.team23.de/docker/php:7.4
volumes:
- ../:/app
web:
image: docker.team23.de/docker/apache:2.4-php
environment:
APACHE_DOCUMENT_ROOT: /app/web/public
volumes:
- ../:/app
ports:
- 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:
#!/usr/bin/env bash
task:run() {
docker:docker-compose up "$@"
}
task:halt() {
docker:docker-compose down "$@"
}
task:composer() {
docker:command:composer "$@"
}
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:
project:
key: example-project
modules:
docker:
commands:
composer:
bin: composer
service: php
workdir: /app/web
phpunit:
bin: [ "php", "./vendor/bin/phpunit" ]
service: php
workdir: /app/web
artisan:
bin: [ "php", "./artisan" ]
service: php
workdir: /app/web
Taskfile:
#!/usr/bin/env bash
# ...
task:artisan() {
docker:command:artisan "$@"
}
task:phpunit() {
docker:command:phpunit "$@"
}
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:
version: "3.7"
services:
# ...
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: docker
MYSQL_USER: docker
MYSQL_PASSWORD: docker
volumes:
- mysql:/var/lib/mysql/
volumes:
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:
# ...
DB_HOST=mysql
DB_DATABASE=docker
DB_USERNAME=docker
DB_PASSWORD=docker
# ...
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.
version: "3.7"
services:
php:
image: docker.team23.de/docker/php:7.4
volumes:
- ../:/app
depends_on:
- mysql
# ...
To check if the connection work, we execute b5 artisan migrate .
The output should look like this:
#Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_000000_create_users_table (0.06 seconds)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated: 2014_10_12_100000_create_password_resets_table (0.03 seconds)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated: 2019_08_19_000000_create_failed_jobs_table (0.02 seconds)
Task 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.
version: "3.7"
services:
# ...
phpmyadmin:
image: phpmyadmin/phpmyadmin:latest
environment:
PMA_HOST: mysql
PMA_USER: root
PMA_PASSWORD: secret
depends_on:
- mysql
ports:
- 8001:80
volumes:
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:
version: "3.7"
services:
# ...
node:
image: node:lts
volumes:
- ../:/app
# ...
Additionally we will define the docker command in the config.yml and the task in the Taskfile .
config.yml:
project:
key: example-project
modules:
docker:
commands:
# ...
npm:
bin: npm
service: node
workdir: /app/web
Taskfile:
#!/usr/bin/env bash
# ...
task:npm() {
docker:command:npm "$@"
}
Now we can execute b5 npm install to instal the defined dependencies form the package.json. The output should look
like this:
Executing task npm
Creating network "example-project_default" with the default driver
npm notice created a lockfile as package-lock.json. You should commit this file.
added 1035 packages from 485 contributors and audited 17259 packages in 82.852s
31 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
Task 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:
version: "3.7"
services:
# ...
redis:
image: redis
# ...
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:
# ...
CACHE_DRIVER=redis
QUEUE_CONNECTION=redis
SESSION_DRIVER=redis
# ...
REDIS_HOST=redis
# ...
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:
version: "3.7"
services:
# ...
mail:
image: mailhog/mailhog
ports:
- 8025:8025
# ...
To use it from Laravel we need to adjust the settings ind the .env file:
# ...
MAIL_DRIVER=smtp
MAIL_HOST=mail
MAIL_PORT=1025
# ...
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:
Mail::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.