About Blog Contact
 
 

RSS

January 28, 2020
7 min read

b5 example project with Laravel

laravel-logo

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 "[email protected]"
}

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 "[email protected]"
}

task:halt() {
    docker:docker-compose down "[email protected]"
}

task:composer() {
    docker:command:composer "[email protected]"
}

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 "[email protected]"
}

task:phpunit() {
    docker:command:phpunit "[email protected]"
}

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 "[email protected]"
}

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.

Legal Notice  |  Privacy  |  RSS  |  © 2020 christlieb.eu