Skip to content

pastuhov/yii2-dockerized

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

35 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Yii 2 Dockerized

Latest Stable Version Total Downloads

A template for Yii 2 applications based on the codemix/yii2-base docker image.

  • Ephemeral container, configured via environment variables
  • Testing container for easy testing
  • Optional local configuration overrides for development/debugging (git-ignored)
  • Base scaffold code for login, signup and forgot-password actions
  • Flat configuration file structure
  • Supports docker image based development workflow

The yii2-base image comes in three flavours:

  • Apache with PHP module (based on php:5.6.6-apache)
  • PHP-FPM (based on php:5.6.6-fpm)
  • HHVM (based on estebanmatias92/hhvm:3.5.1-fastcgi)
  1. Quickstart

You need to have docker (>=1.5.0) and docker-compose installed.

composer create-project --no-install codemix/yii2-dockerized myproject
cd myproject
cp docker-compose-example.yml docker-compose.yml
cp .env-example .env
docker-compose up
# From another terminal window:
docker-compose run --rm web ./yii migrate

It may take some minutes to download the required docker images. When done, you can access the new app from http://localhost:8080.

Note: On Windows and Mac OS you have to use boot2docker. There's also a workaround to make docker-compose available.

  1. How To Use

This project is a template for your own Yii2 applications. You can use it as a starting point and modify it to fit your requirements.

2.1 Starting A New Project

Note: You will do this only once in the lifetime of a project!

As shown in the quickstart you will first create a new project with composer or, if you don't have composer installed, download and uncompress the files into a new directory.

Before you commit the app into your repository, you first will want to set up the project for your purpose.

The first step is to select the yii2-base image flavour in the Dockerfile. So uncomment the apropriate line:

FROM codemix/yii2-base:2.0.4-apache
#FROM codemix/yii2-base:2.0.4-php-fpm
#FROM codemix/yii2-base:2.0.4-hhvm

Then you should check the following files and directories:

  • Dockerfile: Optionally add PHP extensions
  • docker-compose-example.yml: Provide an example machine configuration for other developers
  • config/: Update the default configuration
  • .env-example: Optionally add more environment variables
  • composer.json: Optionally add more dependencies for your project
  • migrations/: Update the initial DB migration to match your DB model
  • README.md: Describe your application

When you're done, you will commit the changes to your repository to make it available for other developers in your team.

2.2 Setting Up The Development Environment

When you have the project in your repository, it's easy to set up a new development environment, e.g. for a new team member:

git clone <your-repo-url> ./myapp
cd myapp
cp docker-compose-example.yml docker-compose.yml
cp .env-example .env
docker-compose up
# From another terminal window:
docker-compose run --rm web ./yii migrate

The local app directory is mapped into the /var/www/html directory of the web container. So you can now work on your local source files and will immediately see the results under the URL of the container.

2.3 Environment Variables

This template follows the 12 factor principles. This means, that all dynamic configuration parameters (for example database credentials or secret API keys) are passed to the container through environment variables.

There are two options how you can set environment variables during development:

  • In the environment section of the docker-compose.yml. This requires to remove and recreate the container each time you change a variable. So we recommend to only put ENABLE_ENV_FILE here and use the next option for the rest.
  • In a .env file in your app directory. Changes there are picked up immediately by the yii app inside the container. But any other command there will usually ignore this file. We have included an example .env-example that you can use to get started.

Variables in docker-compose.yml have precedence over those in the .env file.

In production you will use whatever means are neccessary to set the environment variables. This depends on how you host your docker image (or if you use docker in production at all).

2.3.1 List of environment variables

Note: Some variables can only be set in the docker-compose.yml (marked with dc-only).

Mandatory:

Optional:

  • API_TOKEN (dc-only) the github API token for composer updates.
  • ENABLE_ENV_FILE (dc-only) whether to load env vars from a local .env file. Default is 0.
  • ENABLE_LOCALCONF whether to allow local overrides for web and console configuration (see below). Default is 0.
  • YII_DEBUG whether to enable debug mode for Yii. Default is 0.
  • YII_ENV the Yii app environment. Either prod (default) or dev. Do not use test as this is reserved for the testing container!
  • YII_TRACELEVEL the traceLevel to use for Yii logging. Default is 0.
  • DB_DSN the DSN to use for DB connection. Defaults to mysql:host=db;dbname=web if not set.
  • DB_USER the DB username. Defaults to web if not set.
  • DB_PASSWORD the DB password. Defaults to web if not set.
  • SMTP_HOST the SMTP hostname.
  • SMTP_USER the username for the SMTP server.
  • SMTP_PASSWORD the password for the SMTP server.

2.4 Configuration Files

All configuration lives in three files in the config/ directory.

  • web.php configuration for the web application
  • console.php configuration for the console application
  • params.php application parameters for both web and console application

These three files are committed to your repository. But sometimes it's useful during development, to override some settings, without accidentally committing them to the repository. Therefore you can create local override files (requires ENABLE_LOCALCONF to be set):

  • local.php local overrides for the web configuration
  • console-local.php local overrides for the console configuration

Both files are merged with the respective configuration. Thus you can override specific parts of the web or console configuration there.

2.5 PHP-FPM + Nginx Based setups

If you prefer to use the php-fpm base image, you will need two containers, one for the php-fpm process and one for nginx. There's already a commented out example in the docker-compose-example.yml file.

You may also want to modify the Nginx configuration in nginx/nginx.conf. The most important setting there is the hostname of the php-fpm container. This must match whatever you have used in your docker-compose.yml for the app container. Default is app:

fastcgi_pass   app:9000;
  1. Testing

We have included a basic test setup that gets you started with testing in no time. It uses another docker-compose.yml where the test infrastructure is defined.

Note: If you host more than one yii2-dockerized project on your host you should set the COMPOSE_PROJECT envirnoment variable to a unique name for each project, before you run any of the below commands. Otherwhise you will get conflicts as each test container will automatically be called like tests_test_1 due to the same tests/ directory name.

3.1 Setup test database

Before you run the tests for the first time, you have to set up the DB:

cd tests/
docker-compose run --rm test ./yii migrate

Note: This may fail the first time because the DB is not up. In this case try again. If this doesn't help either, try to run docker-compose up in another terminal window first, then try the above command again.

3.2 Writing tests

To write tests, you simply create the respective classes in the acceptance, functional and unit directories in the tests/codeception folder. You may also have to provide Page classes for acceptance and functional tests in the _pages directory or add some fixtures in the fixtures directory.

We have included some simple examples that should help you to get started. For further details on how to write tests, please refer to the codeception and Yii 2 documentation.

3.3 Running tests

To run test you only need one simple command inside the tests/ directory:

docker-compose run --rm test

You can also specify a specific codecept command:

docker-compose run --rm test codecept run functional

3.4 Files and Directories

The many files in the tests/ directory can be overwhelming. So here's a summary of what each file and directory is used for.

  - tests
     - codeception/             the codeception/ directory
        - _output/              temporary outputs (gitignored)
        - _pages/               pages shared by acceptance and functional tests
        - acceptance/           acceptance tests
        - config/               Yii app configuration ...
           acceptance.php       ... for acceptance tests
           config.php           ... shared by all tests
           functional.php       ... for functional tests
           unit.php             ... for unit tests
        - fixtures/             fixtures for all tests
           - templates/         templates for yii2-faker
        - functional/           functional tests
        - unit/                 unit tests
        _bootstrap.php          bootstrap file for all tests (load env and Yii.php)
        acceptance.suite.yml    configuration for acceptance tester
        functional.suite.yml    configuration for functional tester
        unit.suite.yml          configuration for unit tester
     codeception.yml            main configuration for codeception
     docker-compose.yml         docker compose configuration for testing
     yii                        CLI for the testing environment (migrations, fixtures, ...)

3.5 Creating fixtures

Before you can generate fixtures, you have to provide the respective template files for yii2-faker in the codeception/templates directory. Then you can create fixtures with:

docker-compose run --rm test ./yii fixture/generate <tablename>
  1. Workflows

Docker is very versatile so you can come up with different workflows.

4.1 Dockerfile Based

  • No docker registry required
  • Slower deployment due to extra build step

This is a very simple workflow: In each environment the runtime image is built from the Dockerfile. Developers need to be informed whenever the Dockerfile changes so that they rebuild their local image.

No images are shared between developers, so the initial and also each consecutive build step could take quite some time, depending on how much the Dockerfile has changed since the last build in this environment.

4.2 Docker Image Based

  • Requires a docker registry (either self-hosted or from 3rd party)
  • Quick and simple deployment

Here we can take two approaches: With or without a base image. In both cases the Dockerfile should be organized in a way, that the rather static or less changing parts should be on top of the Dockerfile and the dynamic or frequently changing parts (e.g. COPY . /var/www/html) at the bottom of the file.

4.2.1 Without A Base Image

We use a single Dockerfile and each time we want to make a deployment, we create a new tagged image and push it to the registry. This image can then be pulled to production.

One drawback here is, that each deployment image contains a full copy of your source code, even if you only changed a couple of lines since the last deployed image.

It's also important that the developers alway pull the last deployed image to their machine, as otherwhise docker couldn't reuse cached layers the next time it builds a new image.

4.2.2 Using A Base Image

Here we use two Dockerfiles:

  • One for the base image, e.g. Dockerfile.base and
  • one for the final image(s), which extends from the base image

The base image stays the same for some time and is used as basis for many deployment images. This has the advantage that (hopefully) many files from the base image can be reused, whenever a new deployment image is built. So the actual release image layer will have a very small footprint and, in effect, once a base image is shared among developers and on production, there's not much data to be moved around with each release.

To start we'd first move the current Dockerfile and create a base image:

mv Dockerfile Dockerfile.base
docker build -f Dockerfile.base -t myregistry.com:5000/myapp:base-1.0.0
docker push myregistry.com:5000/myapp:base-1.0.0

Now we have a base image as version base-1.0.0. For ongoing development we take it from there and use a minimal second Dockerfile that is based on this image:

FROM myregistry.com:5000/myapp:base-1.0.0
COPY composer.json /var/www/html/
COPY composer.lock /var/www/html/
RUN composer self-update && \
    composer install --no-progress
COPY . /var/www/html
RUN mkdir runtime web/assets \
    && chown www-data:www-data runtime web/assets

So other developers will now use this simplified Dockerfile for their daily work. They don't have to rebuild all the layers from the base image and will only stack their local changes on top.

We'll also use this file for the final deployment images:

docker build -t myregistry.com:5000/myapp:1.0.0
docker build -t myregistry.com:5000/myapp:1.0.1
docker build -t myregistry.com:5000/myapp:1.0.2
...

Note: Version numbers here are only used to make the example clearer. You'd probably use a different versioning scheme, especially if you do continous deployments.

After some releases your latest code will differ more and more from the base image. So more and more files will have changed since it was created and this will make your deployment images bigger and bigger with each release. To avoid this you can create an updated base image from your latest code:

docker build -f Dockerfile.base -t myregistry.com:5000/myapp:base-1.1.0
docker push myregistry.com:5000/myapp:base-1.1.0

Note: You may want to modify Dockerfile.base to extend from your old base image first. This will save extra space, but add more file layers to your docker images over time, which is limited to 127.

Now we have an updated base image and can use that for ongoing development. We therefore have to update the FROM line in the Dockerfile:

FROM myregistry.com:5000/myapp:base-1.1.0
  1. FAQ

5.1 How Can I Run Yii Console Commands?

docker-compose run --rm web yii migrate
docker-compose run --rm web yii mycommand/myaction

5.2 Where Are Composer Packages Installed?

Composer packages are installed inside the container under /var/www/vendor. So they live outside of the app directory. This is because during development we usually mount the local app directory into the /var/www/html directory of the container. This would override any vendor packages we have there. So you would either have to locally install all the packages in vendor/ or somehow make sure, that the composer packages are updated after the local dir was shared.

By keeping the directory outside, we circumvent this issue. The docker images will always contain all required composer dependencies and use those at runtime.

5.3 How can I Update Or Install New Composer Packages?

To update or install new packages you first need an updated local composer.lock file. Then the next time you issue docker-compose build it will pick up the changed file and create a new docker image with the updated packages inside:

docker-compose run --rm web composer update my/package
docker-compose build

Note: If you face the nasty API rate limit issue with github, you can create a personal API token and expose it in your docker-compose.yml file as API_TOKEN env var.

5.4 How can I make composer packages available locally?

Some IDE's may require a copy of the vendor directory somewhere on your local host for autocompleting commands or providing inline help. You can therefore copy the vendor directory to your local directory:

docker-compose run --rm web cp -r /var/www/vendor .

5.5 How Can I Log To A File?

The default log configuration follows the Docker convention to log to STDOUT and STDERR. You should better not change this for production. But you can use a local configuration file as explained above and configure a log route as usual. If you log to the default directory, you should find the logfiles in your local runtime/logs/ directory. Note, that this directory will never be copied into the container, so there's no risk, that you end up with a bloated image.

5.6 How Can I Add PHP / HHVM Extensions?

Since the codemix/yii2-base image extends from the official php image, you can use docker-php-ext-install in your Dockerfile. Here's an example:

RUN apt-get update \
    && apt-get -y install \
            libfreetype6-dev \
            libjpeg62-turbo-dev \
            libmcrypt-dev \
            libpng12-dev \
        --no-install-recommends \
    && rm -r /var/lib/apt/lists/* \
    && docker-php-ext-install iconv mcrypt \
    && docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \
    && docker-php-ext-install gd

For HHVM extension please check the hhvm base image for details.

About

A template for docker based Yii 2 applications

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages

  • PHP 98.1%
  • Other 1.9%