/ DOCKERSYMFONY
 / 10.59350/bfjjg-nrt48

Using Docker for a simple Symfony Console App

CC BY-SA 2.0 WikiCommons:plasticrevolver

Symfony console

For a rather small task we needed to build a standalone command line app to process and copy some files.

Our first approach to that included using the JVM (Java, Kotlin), because it needed to be deployable and runnable without any great hassle.

But going a little further we skipped that approach and remembered the great Symfony Console which provides a quite simple interface.

So the approach ended like that (composer.json):

{
    "type": "project",
    "name": "subugoe/checkfolder",
    "description": "Hotfolder",
    "license": "AGPL-3.0",
    "require": {
        "php": "^7.1.5",
        "guzzlehttp/guzzle": "^6.3",
        "league/flysystem-aws-s3-v3": "^1.0",
        "league/flysystem-sftp": "^1.0",
        "oneup/flysystem-bundle": "^3.0",
        "phpunit/phpunit": "^6.4",
        "symfony/console": "^4.0",
        "symfony/dom-crawler": "^4.0",
        "symfony/framework-bundle": "^4.0",
        "symfony/lock": "^4.0",
        "symfony/monolog-bundle": "^3.1",
        "symfony/yaml": "^4.0"
    },
    "require-dev": {
        "symfony/flex": "^1.0",
        "symfony/dotenv": "^4.0",
        "symfony/debug-bundle": "^4.0",
    },
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "App\\Tests\\": "tests/"
        }
    },
    "scripts": {
        "auto-scripts": {
            "cache:clear": "symfony-cmd",
            "assets:install --symlink --relative %PUBLIC_DIR%": "symfony-cmd"
        },
        "post-install-cmd": [
            "@auto-scripts"
        ],
        "post-update-cmd": [
            "@auto-scripts"
        ]
    }
}

Rather simple. But where went our initial requirement to let it run easily? With only this approach you need to install php and fulfill other dependencies.

Docker to the rescue

I put the complete App into a Docker Container to run it anywhere in our Docker Infrastructure and only have Docker as a runtime requirement on the server.

This is the complete Dockerfile that builds the runnable container:

FROM php:7.1-cli-alpine

ENV COMPOSER_ALLOW_SUPERUSER 1

COPY . /usr/src/checkfolder
WORKDIR /usr/src/checkfolder

RUN apk update && \
    apk add git zlib-dev zip unzip && \
    docker-php-ext-install zip

RUN echo "memory_limit=1024M" > /usr/local/etc/php/conf.d/memory-limit.ini
RUN curl --silent --show-error https://getcomposer.org/installer | php && \
    php composer.phar install --prefer-dist --no-progress --no-suggest --optimize-autoloader --classmap-authoritative  --no-interaction && \
    php composer.phar clear-cache && \
    rm -rf /usr/src/php

CMD ["php", "./bin/console", "app:check-new-files"]

The Dockerfile takes the official PHP Alpine Linux Docker Image as base as it is really small and contains all we need.

The last part of the file CMD ["php", "./bin/console", "app:check-new-files"] executes the Symfony console command when the container is started.

But how do we start the container? This will be the last part of this article.

So, the let’s build the container: docker build -t checkfolder .

Running the App

As stated before, only the Docker runtime is required. We do not need convenience add-ons, such as Docker Compose. Because the App heavily relies on configuration parameters, we pass them as environment variables into the container.

Setting the variables is done with

export APP_ENV=prod;
export APP_DEBUG=0;
export APP_SECRET=023582aefc63220f4c530ec5eff8f8781;
export S3_STORAGE_ENDPOINT=https://s3.our-great-hoster.de;
export S3_STORAGE_KEY=xxx;
export S3_STORAGE_SECRET=xxx;
export INDEXER_DOMAIN=https://indexer.ourdomain.com;

As these variables are set, we are now really going to start everything, I promise!

docker run -it --rm -e APP_ENV -e APP_DEBUG -e APP_SECRET -e S3_STORAGE_ENDPOINT -e S3_STORAGE_KEY -e S3_STORAGE_SECRET -e INDEXER_DOMAIN --name checkfolder-run checkfolder:latest

Quite easy, but I simplified everything here a bit. In production, we use automated Docker image build and automatically put them into a registry. But that’s going to be the topic of a later post here.