Sunday, September 28, 2014

More fun with Docker: creating a Drupal site

Cloud computing is enabling some really cool stuff. I just provisioned my Mac laptop for running MySQL and Drupal, and these are provisioned in a way that when I am satisfied with my work (locally), I can fix the relevant containers into uploadable images to be used on Amazon EC2.

Here's how it happens:

Over the weekend, I decided that I wanted to setup a new website for the Boy Scout troop that I serve. I decided to give Drupal a look, and after some searching, discovered that there are already canned images at Dockerhub for just my use case. The image I decided to use is centurylink/drupal:latest. CenturyLink Research also has created a centurylink/mysql image that combines nicely to create a runnable web site on my Mac in very few steps:

[Prerequisite, I already have boot2docker and docker installed on my Mac via homebrew; also, I am registered with Dockerhub and logged in using boot2docker login].

Just to prove that I've managed to truly capture all prerequisites for this blog post,

tk-mbp:~ tommy$ boot2docker destroy; boot2docker init; boot2docker up

That initializes a VirtualBox VM and eventually asks me a few times for the password:

Waiting for VM and Docker daemon to start...
.................................docker@localhost's password: 
.docker@localhost's password: 
docker@localhost's password: 
Started.
docker@localhost's password: 
To connect the Docker client to the Docker daemon, please set:
    export DOCKER_HOST=tcp://192.168.59.103:2375

(docker's password is 'tcuser'). (Also, note for later the Docker VM's IP address).

Next, I obey the "To connect..." instructions:

tk-mbp:~ tommy$ export DOCKER_HOST=tcp://192.168.59.103:2375

And pull the first of 2 needed images:

tk-mbp:~ tommy$ docker pull centurylink/mysql:latest
Pulling repository centurylink/mysql
59db9c7b86b1: Download complete 
511136ea3c5a: Download complete 
9bad880da3d2: Download complete 
25f11f5fb0cb: Download complete 
ebc34468f71d: Download complete 
2318d26665ef: Download complete 
ba5877dc9bec: Download complete 
ffe81f76c463: Download complete 
051896bf3fd4: Download complete 
00d7fda854d9: Download complete 
ca4449180c34: Download complete 
bf3198a99667: Download complete 
18ae1b45e42d: Download complete 
dd873f6ca469: Download complete 
8d18d45011be: Download complete 

Then pulling the second required image:

tk-mbp:~ tommy$ docker pull centurylink/drupal:latest
Pulling repository centurylink/drupal
43297bce5dfd: Download complete 
511136ea3c5a: Download complete 
1c9383292a8f: Download complete 
9942dd43ff21: Download complete 
d92c3c92fa73: Download complete 
0ea0d582fd90: Download complete 
cc58e55aa5a5: Download complete 
c4ff7513909d: Download complete 
eb147da4b095: Download complete 
838940b99c5a: Download complete 
495eacb573db: Download complete 
026cf25a9eaf: Download complete 
7f25d562de47: Download complete 
aa1da918c781: Download complete 
b7c0182f3ac5: Download complete 
c07667399308: Download complete 
1c38105a96e5: Download complete 
b8da458be908: Download complete 
f5d0a962bd6e: Download complete 
24610de6f8bd: Download complete 
5f13cdac8512: Download complete 
b70f83e71710: Download complete 
ed63d3d408f8: Download complete 

The next step is to fire up the mysql image in a container and then link that container when firing up the drupal image:

tk-mbp:~ tommy$ docker run -d -p 3306:3306 --name MYSQL -e MYSQL_ROOT_PASSWORD=pass@word01 -e MYSQL_DATABASE=troop1691 -e MYSQL_USER=troop1691 -e MYSQL_PASSWORD=troop1691 centurylink/mysql:latest
7d78f4ec98a0c338142f1f7a47e9d6a59ebbd90588908bdb9a75d795b4385232

That one's probably worth picking apart. I'm telling docker to run an image in "detached" (background) mode; mapping the host (not the real Mac OS X host, but the boot2docker VirtualBox host) port 3306 to the container port 3306, giving the container the name "MYSQL", and setting some environment variables.

Next, I tell Docker to fire up the drupal image in another container (on the same VirtualBox VM) and link to the MYSQL container as "DB":

tk-mbp:~ tommy$ docker run -d --name DRUPAL -P --link MYSQL:DB centurylink/drupal:latest
a6e2eccb3d4539de6339e8db3ede094b2bad84a23b9f58de46eec8bdfd3aa746

At this point, all that's left is to connect my web browser to the running Drupal and get to work on the real problem that I wanted to work on. To facilitate that, I just have to figure out what port is listening on the VirtualBox VM:

tk-mbp:~ tommy$ docker ps
CONTAINER ID        IMAGE                       COMMAND                CREATED             STATUS              PORTS                    NAMES
a6e2eccb3d45        centurylink/drupal:latest   "/bin/sh -c 'exec su   2 minutes ago       Up 2 minutes        0.0.0.0:49153->80/tcp    DRUPAL              
7d78f4ec98a0        centurylink/mysql:latest    "/usr/local/bin/run"   8 minutes ago       Up 8 minutes        0.0.0.0:3306->3306/tcp   DRUPAL/DB,MYSQL     

This shows that the "DRUPAL" container is listening on host (VM) port 49153. Putting the VM's IP address into /etc/hosts with the name 'drupal', and firing up my web browser, I'm ready to complete Drupal setup and begin work on my site, which was the real task I wanted to be working on anyway.


(there's actually one more minor thing, enabled by the container linking, that ends up being useful: I told Drupal to use the hostname "db" since that was the link name given for the MYSQL container at the time I instantiated the DRUPAL container:





Wednesday, September 24, 2014

Trying out Amazon's "Elastic Beanstalk", with a detour through "Docker"

I'm trying out a new way of deploying my Spring Boot apps into the "cloud". This time it's AWS "Elastic Beanstalk". EBS offers platforms such as Ruby, Python, Node.js, PHP, .NET, and yes, Java. However, none of the Amazon-provided platform images were quite what I was looking for: a place to just run an app in a .jar.

That's because the EBS Java offering comes pre-loaded with Tomcat and expects you to supply a .war, but these days I build my Java web apps using Spring Boot, so I've already got an embedded servlet container and my build products are runnable .jars. Yes, I know, I could convert my Spring Boot project to build a .war file, but what I'm really interested in is being able to deploy my apps *anywhere* that there's a Java runtime. I want to be able to deploy the same .jar onto the private PaaS (a customized Cloud Foundry) at the office, or onto Heroku, or onto AppFog, or onto some random bare metal I happen to have lying around the house, so long as it has a Java runtime and a gateway to the Internet.

Enter Docker. I've formed a tentative conclusion that Docker is to EBS what custom "buildpacks" are  to Heroku and Cloud Foundry. Docker allows me to define my own platform image and combine that with my runnable jars, so that the platform is as lean as I want it to be (no "extra" external servlet container bloating the image). What's more, using Docker gives me full control of the Java runtime version - right down to the bug-fix update of my choice.

As I write this, I am uploading my first-cut at a "java8" image to Docker. Assuming that completes successfully, it will be publicly available here: https://registry.hub.docker.com/u/w7tek/java8/. This image I've created starts with another Docker image, vettl/amazon-linux:2014.03, and from there uses rpm to install the JDK RPM of my choice from Oracle, then sets the stage for folks to reuse my image by using it in their own Dockerfile. Of course, when I say "folks", I mean "probably nobody but just me" but even if that's the case, I've got a personalized, reusable image that I can reuse with any Java/Spring Boot/Maven projects.

Well, it looks like my 1.07GB upload - painfully slow as it was over CenturyLink DSL in Herriman, UT - has completed. Happily, when I made "one more tweak" to the Docker image, it only took a few seconds to upload the new changes. Now, to see if theory matches practice: I'm going to use that image as the basis for the image I want to deploy onto EBS, and the next step is figuring out how to supply the database connection credentials to my app from the process environment… wish me luck!