August 12, 2017

Development Workflow with Docker

We cover how to make running complex Docker commands quickly and easily.

We cover how to make running complex Docker commands quickly and easily.

We saw how we could use docker-compose to easily get a dev environment up and running.

However, we had to run some commands that get pretty long. For example:

docker run -it --rm \
    -v $(pwd)/application:/opt \
    -w /opt \
    --network=zondaroad_appnet \
    shippingdocker/php \
    php artisan make:auth

This gets to be a huge pain when running commands often, such as running phpunit or artisan commands to generate scaffolding.

A Makefile

To combat the pain of writing long Docker commands, we can create a script to help us out. Bash can be used here, but I like using a Makefile, as the syntax is easy to get started with.

For example, which a file named Makefile, we can create command "foo":

foo:
    bar

And use it:

make foo

Pretty easy!

Let's make a simple one:

.PHONY: up down

up:
    docker-compose up

down:
    docker-compose down

We can run make up, make down.

What we've done:

  1. Let Make know that the listed commands are "phony" - they don't generate artifacts (files)
  2. Command up will start our services
  3. Command down will stop our services

More Advanced Makefile

Let's add onto this:

.PHONY: up down

# Set dir of Makefile to a variable to use later
MAKEPATH := $(abspath $(lastword $(MAKEFILE_LIST)))
PWD := $(dir $(MAKEPATH))

up:
    docker-compose up

down:
    docker-compose down

test:
    docker run -it --rm \
        -v $(PWD):/opt \
        -w /opt \
        --network=zondaroad_appnet \
        shippingdocker/php:latest \
        ./vendor/bin/phpunit

We created a command make test which will spin up a PHP container within our network and run phpunit.

Logs

We can tail some logs too. I spent some time to try to get colorized output of log files too:

.PHONY: up down log

# Modified From http://bytefreaks.net/gnulinux/bash/tail-logs-with-color-for-monolog
log:
    tail -f $(PWD)storage/logs/laravel.log | awk '\
        {matched=0}\
        /INFO:/    {matched=1; print "\033[0;37m" $$0 "\033[0m"}\
        /WARNING:/ {matched=1; print "\033[0;34m" $$0 "\033[0m"}\
        /ERROR:/   {matched=1; print "\033[0;31m" $$0 "\033[0m"}\
        /Next/     {matched=1; print "\033[0;31m" $$0 "\033[0m"}\
        /ALERT:/   {matched=1; print "\033[0;35m" $$0 "\033[0m"}\
        /Stack trace:/ {matched=1; print "\033[0;35m" $$0 "\033[0m"}\
        matched==0            {print "\033[0;33m" $$0 "\033[0m"}\
    '

We can use make log to tail the laravel.log file, and use awk to give it some color based on output.

Artisan

Let'see how we can use artisan more easily.

Tinker

I use tinker a bunch, and we can start tinker from the Makefile as well:

.PHONY: up down log tinker

tinker:
    docker run -it --rm \
        -e "HOME=/home" \
        -v $(PWD).tinker:/home/.config \
        -v $(PWD):/opt \
        -w /opt \
        --network=zondaroad_appnet \
        shippingdocker/php:latest \
        php artisan tinker

Similar to our test command, we spin up a container and run tinker. Just type make tinker.

Other Commands

This one is the hairiest, and perhaps warrants a bash script over Makefile, but we can still accomplish our goal of arbitrary artisan commands.

.PHONY: up down log tinker artisan

ART=""
artisan:
    docker run -it --rm \
        -e "HOME=/home" \
        -v $(PWD).tinker:/home/.config \
        -v $(PWD):/opt \
        -w /opt \
        --network=zondaroad_appnet \
        shippingdocker/php:latest \
        php artisan $(ART)

We create a variable ART and give it an empty string value. We also spin up a container and run artisan commands within it, passing the ART altho as our artisan command.

Try make artisan to get a listing of available commands. Use make artisan ART=route:list to get a listing of routes.

It's a little rough, but not too bad.

The Complete Makefile

Here's the complete Makefile:

.PHONY: up down log tinker artisan test

# Set dir of Makefile to a variable to use later
MAKEPATH := $(abspath $(lastword $(MAKEFILE_LIST)))
PWD := $(dir $(MAKEPATH))

up:
    docker-compose up -d

down:
    docker-compose down

log:
    tail -f $(PWD)storage/logs/laravel.log | awk '\
        {matched=0}\
        /INFO:/    {matched=1; print "\033[0;37m" $$0 "\033[0m"}\
        /WARNING:/ {matched=1; print "\033[0;34m" $$0 "\033[0m"}\
        /ERROR:/   {matched=1; print "\033[0;31m" $$0 "\033[0m"}\
        /Next/     {matched=1; print "\033[0;31m" $$0 "\033[0m"}\
        /ALERT:/   {matched=1; print "\033[0;35m" $$0 "\033[0m"}\
        /Stack trace:/ {matched=1; print "\033[0;35m" $$0 "\033[0m"}\
        matched==0            {print "\033[0;33m" $$0 "\033[0m"}\
    '

tinker:
    docker run -it --rm \
        -e "HOME=/home" \
        -v $(PWD).tinker:/home/.config \
        -v $(PWD):/opt \
        -w /opt \
        --network=zondaroad_appnet \
        shippingdocker/php:latest \
        php artisan tinker

ART=""
artisan:
    docker run -it --rm \
        -e "HOME=/home" \
        -v $(PWD).tinker:/home/.config \
        -v $(PWD):/opt \
        -w /opt \
        --network=zondaroad_appnet \
        shippingdocker/php:latest \
        php artisan $(ART)

test:
    docker run -it --rm \
        -v $(PWD):/opt \
        -w /opt \
        --network=zondaroad_appnet \
        shippingdocker/php:latest \
        ./vendor/bin/phpunit

Exec

Lastly, we can also use Docker's exec to make it all a tad easier. Here we'll run bash inside if our already-running PHP container:

docker exec -it  bash
> cd /var/www/html
> php artisan

Looking for a deeper dive into Docker?

Sign up here to get a preview of the Shipping Docker course! Learn how to integrate Docker into your applications and develop a workflow to make using Docker a breeze!

All Topics