Road to Docker Part 1

Let me be perfectly honest, there will probably not be a part 2. Easy as docker is, there’s still a bit of a barrier to entry. I’m a software dev, I don’t really want to configure vms, but, well, devops. I don’t need to know how to do everything, but I want some understanding of how these pieces fit together. So I took one of our projects and spent some time yesterday to containerized it. I’m going to go through how I went about it.

Step 1. The Search for Tutorials

I spent a while looking through tutorials. Trying to find a good one. Spoiler: I didn’t. I was able to make use of this one mostly: https://www.digitalocean.com/community/tutorials/docker-explained-how-to-containerize-python-web-applications It’s a very long tutorial that I was able to pick and choose some things out of. I’m really sad there isn’t a better tutorial. (That 5 minute docker tutorial is cute, but ultimately worthless.)

Step 2. Installing Docker on a Mac

I wanted to create docker containers on my laptop. It didn’t take long to discover this isn’t really something you can do directly. I wanted to avoid creating a vagrant-virtualbox just to create docker images, so I searched for the standard of what people do. The answer is they use something called boot2docker (https://github.com/boot2docker/osx-installer/releases/tag/v1.4.1), which, as it turns out, just just a linux virtualbox to run docker on. Go figure.

Step 3. Creating a Container — Dockerfile

Upon reading how to create a container manually, it seemed silly to not just create a Dockerfile. A Dockerfile is just a config file that allows docker to create the image. Having mild familiarity with vagrant configs and puppet, the Dockerfile is a way to keep a simple, replicable record of the docker image being created. And simple it is. The format is more readable than it’s cousin, Vagrantfile. It was a simple thing to create the Dockerfile for my Django app. (https://gist.github.com/jazahn/aca49f3e3f9a5b819bce) It uses only a few simple keywords. The most useful being RUN.

Step 4. Creating the Image — build

This was just a simple docker build command

docker build -t docker_image_label .

This creates a new image, labelled with the -t param.

Step 4.5. Finding and Removing Images

docker images

This will list all images (on the boot2docker vm) which you can choose to

docker rm <name>

Step 5. Running the Image — run

This was just a simple docker run command. There are several ways to run, I went with the following:

docker run -d -p 8080:8080 --name docker_instance_name docker_image_label

This just uses -d to run it as a daemon, -p to forward the ports* *It must be noted that “forwarding the ports” is only relevant to the boot2docker virtualbox. To see the result, you should make use of the built in ip reporting for boot2docker.

boot2docker ip

http://viget.com/extend/how-to-use-docker-on-os-x-the-missing-guide

Step 5.5. Stopping Docker, Killing Docker

docker ps

This will give a listing of the running docker instances, so you can

docker kill <name>

Step 6. Docker Hub

One thing that was neato to discover is that knowledge of github / git was translatable to docker. They have designed the usage of Docker Hub around “push” and “pull” concepts. It’s just a matter of pushing images up so they can be pulled down later. What I wasn’t able to find was how to actually send the Dockerfile along with the image. It’s not strictly necessary, but I’ve seen it on other projects, so I know it’s possible…

Conclusion

Getting the container up and running and distributable was no big deal, but this was not enough. Next steps would be to grab a mysql docker image from the hub and have the two communicate with each other. Right now I’m really just using the container as a VM, which isn’t really the point of docker.

Getting Travis-CI to work with a PHP Project

First off, Travis CI is only usable through github. It’s a great service that allows tests to be run before pull requests are merged, helping to ensure code stability. It’s a very new service, and PHP support is in flux. Almost daily information changes. So I fear this will be outdated tomorrow. Regardless, I wanted to get this written down.

The magic all happens in the .travis.yml file. It’s a config file that tells travis what to run. It only has a few sections, but they can be tricky. Here is the example .travis.yml for PHP:

language: php

# list any PHP version you want to test against
php:
  # using major version aliases

  # aliased to 5.2.17
  - 5.2
  # aliased to a recent 5.3.x version
  - 5.3
  # aliased to a recent 5.4.x version
  - 5.4

# optionally specify a list of environments, for example to test different RDBMS
env:
  - DB=mysql
  - DB=pgsql

# execute any number of scripts before the test run, custom env's are available as variables
before_script:
  - if [[ "$DB" == "pgsql" ]]; then psql -c "DROP DATABASE IF EXISTS hello_world_test;" -U postgres; fi
  - if [[ "$DB" == "pgsql" ]]; then psql -c "create database hello_world_test;" -U postgres; fi
  - if [[ "$DB" == "mysql" ]]; then mysql -e "create database IF NOT EXISTS hello_world_test;" -uroot; fi

# omitting "script:" will default to phpunit
# use the $DB env variable to determine the phpunit.xml to use
script: phpunit --configuration phpunit_$DB.xml --coverage-text

# configure notifications (email, IRC, campfire etc)
notifications:
  irc: "irc.freenode.org#travis"

Not included libs

Currently this will not work. Their phpunit is requiring libraries that aren’t included in the vm that’s created. Regardless of if your project is using these libraries:

before_script:
  # everything after this point is needed to just use phpunit
  - pear channel-discover pear.phpunit.de
  - pear install phpunit/PHP_Invoker
  - pear install phpunit/DbUnit
  - pear install phpunit/PHPUnit_Selenium
  - pear install phpunit/PHPUnit_Story

Database usage

I use mysql currently. The problem I hit was you can create users, but you can’t grant them privilages. So you HAVE to use the default root user with no password.

env:
  - DB=mysql

# execute any number of scripts before the test run, custom env's are available as variables
before_script:
  - mysql -e 'CREATE DATABASE `quizmo_dev`;'
  # The following is fine, but travis won't allow granting privilages
  # - mysql -e "CREATE USER 'quizmo_dev'@'localhost' IDENTIFIED BY 'quizmo_dev';"
  # - mysql -e "GRANT ALL PRIVILEGES ON *.* TO 'quizmo_dev'@'localhost' WITH GRANT OPTION;"
  # migrating adds all tables
  - quizmo/protected/yiic migrate --interactive=0

Notifications don’t work

I’m assuming this is something they’ll fix soon. I’m just trying to use email notifications — but it never sends an email.

Continuous Integration with PHP on Travis CI and Github

People on high have been preaching the wonder of continuous integration for a while now. It’s been all about Jenkins forever. Jenkins is still the #1 choice for most people, but I recently ran into Travis CI and at least short term, this is going to be the solution for our shop.

What is Continuous Integration for PHP?

CI to most people involves building and running integration tests. PHP clearly doesn’t build, but good PHP still has unit tests / integration tests / functional tests — so CI for PHP is running those tests before code merges.

What makes Travis CI good?

Probably ease of use. There is no setup of a “travis server”. It’s a service that they run. You hook it to a repo you have access to and set up a config file and it’s good to go.

But this only works with github?

That’s probably the biggest detractor. It’s currently built exclusively for use with github. Which is awesome for github projects, but not every project can be on github. We don’t always have control over where our repos are — and not everyone is an open source person.

Posted in Development, Open Source, PHP. Tags: , , , , , . Comments Off on Continuous Integration with PHP on Travis CI and Github »