IBM Bluemix Containers

Introduction

IBM Bluemix Containers allow Docker images to be provisioned to IBM’s CloudFoundry based PaaS called Bluemix.

Part 1

Since Docker is Linux-only, we’ll start by setting up a Linux VM using Vagrant. Next we’ll install Docker.  We’ll then add the CloudFoundry CLI and the IBM Containers plugin so that we can access our private Docker registry hosted in Bluemix as well as interact with Docker containers hosted on Bluemix.

Part 2

We’ll create a custom Docker image from a Dockerfile and upload that to our private Docker registry in Bluemix.

Part 3

We’ll deploy our Docker image as a running container in Bluemix. We can optionally configure that container to allow SSH access. Additionally we’ll bind the container to an existing Bluemix service.

Part 1: Setup

Setup A Linux Environment

vagrant-logoSince Docker only works in Linux, if you use Windows or Mac you need to install a Linux VM.

Start with having VirtualBox and Vagrant installed.

The following commands are MacOS, but Windows would be very similar.

vboxmanage --version
vagrant  --version

Create a new VM using Ubuntu 14.04

cd ~/software-development/runtimes/Vagrant
mkdir container-testbed
cd container-testbed
vagrant init ubuntu/trusty64

Vagrant init will generate a Vagrantfile.

Modify this file so that your project directory is (readonly) mounted within it.

config.vm.synced_folder “/Home/bob/myproject”, “/project”, mount_options: [“dmode=544,fmode=444”]

Start up the virtual machine and open a secure shell terminal to it.

vagrant up --provider virtualbox
vagrant ssh

Install Docker

docker-logo2The following commands occur within the Linux VM. The Ubuntu VM does not have docker, so install it

curl -sSL https://get.docker.com/ | sh

This next step is optional. Run docker as non-root vagrant user. This actually adds the user to a ‘docker’ group which the daemon grants rw access to the socket to.

sudo usermod -aG docker vagrant

If you changed the vagrant user group membership above, then exit SSH and relogin with SSH

exit
vagrant ssh

Verify docker installed and functioning.

docker version
docker run hello-world

At this point you have a local environment for playing with Docker.

Start the Linux VM with Vagrant, then SSH into that VM and interact with Docker.

Make Docker CLI Aware of Bluemix Containers

bluemix-logoThe following commands occur within the Linux VM.

Install the CloudFoundry CLI and most importantly the cf CLI plugin for IBM Containers.

Download and install cf CLI

cd ~
curl -L "https://cli.run.pivotal.io/stable?release=linux64-binary&source=github" | tar -zx
sudo mv ~/cf /usr/local/bin
./cf --version

Download and install the IBM Containers plugin for the cf CLI

cf install-plugin https://static-ice.ng.bluemix.net/ibm-containers-linux_x64

Configure the cf CLI and plugin with your Bluemix credentials API endpoint and Docker registry host. Note that these hostnames refer to the US South region. Your preferred region may differ.

cf login -a https://api.ng.bluemix.net -u EMAIL -p PASSWORD
cf ic login -R registry.ng.bluemix.net
cf ic init

From this point you use the “cf ic” commands to interact with remote Bluemix Containers and standard “docker” commands to interact with local (within Linux VM) containers.

It is possible to configure docker to point the the remote Bluemix Docker daemon, but I don’t recommend this as it causes undue confusion. The output of “cf ic init” will give you the specifics of setting up your DOCKER environment variables if you choose to use the docker CLI exclusively.

export DOCKER_HOST=tcp://containers-api.ng.bluemix.net:8443
export DOCKER_CERT_PATH= /home/vagrant/.ice/certs/containers-api.ng.bluemix.net/bff2d08d-a8a7-457a-aba4-f264c6070ef5
export DOCKER_TLS_VERIFY=1

At this point we have:

  1. Installed Docker
  2. (optionally) Configured Docker for non-root usage
  3. Installed CloudFoundry CLI
  4. Installed cf CLI plugin for IBM Containers

Ideally, all the previous configuration would be done as part of the Vagrantfile. This really just means all captured in a shell script and invoked when a “vagrant up” is performed. The environment can be recreated from scratch from a recipe each time a VM is needed. Alternatively you can always simply keep the VM image around in a suspended state when not in use. Also you can snapshot the VM image.

Exit your SSH session

exit

Either 1. Suspend the VM image

vagrant suspend
vagrant status

A simple “vagrant up” or “vagrant resume” will restart the Linux VM.

vagrant resume
vagrant ssh

Or 2. Snapshot the VM image. Install a plugin so that vagrant has the ability to use VirtualBox’s snapshot capability.

vagrant plugin install vagrant-vbox-snapshot

Take a snapshot

vagrant snapshot take default ibmcontainers
vagrant snapshot list

Part 2: Build a Docker Image

Building a Custom Docker Image

containerBuild a custom Docker image and upload it to your Bluemix hosted private Docker registry.

The following commands occur within the Linux VM.

Build a Docker Image

Remember that the project directory was mounted read-only into the VM (via Vagrantfile)

config.vm.synced_folder "/Home/bob/myproject", "/project", mount_options: ["dmode=544,fmode=444"]

So /project (inside the Linux VM) maps to /Home/bob/myproject (on the host Mac).

Define a Dockerfile for your project. All the specifics of the Dockerfile are not included here, but much like the Vagrantfile, it is simply a set of instructions on how to recreate the image contents (but unlike the Vagrantfile thankfully Dockerfile has no hint of Ruby).

This sample Dockerfile builds a NodeJS app and only includes the essentials (unlike BASIC the line numbers are not part of the file syntax!).  Line #1 indicates that this new image is to be based on the ibmnode image available in the Bluemix hosted registry at registry.ng.bluemix.net. Lines 3-10 simply copy over files from the current directory (/project – which was mounted from the host machine) and install dependencies (line #6). Line #12 opens up port 80 which is the default the application uses if no port environment variable is passed.  Port 22 is also exposed for SSH access. The final line starts the node process passing it the javascript to launch. We can assume node is already installed in this image since it is based on the ibmnode image (line #1).

  1. FROM  registry.ng.bluemix.net/ibmnode:latest
  2. ENV   project /docker-image-src
  3. COPY  package.json ${project}/package.json
  4. RUN cd ${project}; npm install
  5. COPY /config ${project}/config/
  6. COPY app.js ${project}/app.js
  7. COPY /api ${project}/api/
  8. EXPOSE 80 22
  9. CMD node ${project}/app.js
cd /project
docker build .

Note the period (.); Docker build will look for the Dockerfile in the current directory.

The new image won’t be tagged or associated with a registry, so lookup its Image ID.

docker images

Note the IMAGE ID.

Screen Shot 2015-11-20 at 10.43.57 AM

Run the image locally (in the VM) to create a container

docker run -d -P <IMAGE-ID>
docker ps

Screen Shot 2015-11-20 at 10.54.01 AM

Using the localhost ports that are randomly allocated and mapped to each port EXPOSEd in the Dockerfile you can access the functionality encapsulated in your container.

curl --request GET http://localhost:32770/status

Upload a Docker Image to the Bluemix Private Docker Repository

Use the tag to specify where the image should live, what it should be named and its version.

docker tag <IMAGE-ID> <REGISTRY-HOST>/<NAMESPACE>/<IMAGE-NAME>:<TAG-VERSION>

For REGISTRY-HOST see ‘cf ic info’ under ‘Registry host’

For NAMESPACE:

mynamespace=`cf ic namespace get`

If you haven’t yet defined a namespace for your Docker registry:

cf ic namespace set mybluemixnamespace
docker tag <IMAGE-ID> registry.ng.bluemix.net/$mynamespace/scoutpopcorn:1.0

Push the new docker image to the bluemix private docker repository

docker push registry.ng.bluemix.net/$mynamespace/scoutpopcorn:1.0

Check the remote Bluemix repository for the new image.

cf ic images

Part 3: Deploy to IBM Containers

Provisioning a Docker Image into Bluemix

bluemix-logoAt this point you have your custom Docker image built and uploaded to your private Bluemix Docker registry. Now that the image is uploaded, the following commands can be run from anywhere with docker CLI, cf CLI and cf plugin for IBM Containers installed. However since we have it all installed and configured within our Linux VM we will continue to work from there.

cf ic run --name <CONTAINER-NAME> -m <MEMORY-LIMIT-MEGABYTES> -p <PORT> registry.ng.bluemix.net/<REGISTRY-NAMESPACE>/<IMAGE-NAME>:<TAG>
mynamespace=`cf ic namespace get`
cf ic run --name scoutpopcorn-container -m 128 -p 80 registry.ng.bluemix.net/$mynamespace/scoutpopcorn:1.0

The container exposes port 80, but is not yet accessible since no public IP address is associated with the container. First check if you have any unallocated IP addresses.

cf ic ip list

If not, but still have quota for another public IP address, request one

cf ic ip request

Bind the IP address to the container.

cf ic ip bind <IP> <CONTAINER-NAME>
cf ic ip bind 1.2.3.4  scoutpopcorn-container

Verify container is running

cf ic ps

Enable Secure Shell Access to an IBM Container Instance

ssh-pictureWhile technically possible, this is not a recommended practice and in fact causes the image scanning policies to flag a violation whenever a Docker image is uploaded to the Bluemix registry.

First generate public and private keys for the ssh session.

ssh-keygen -t rsa -f <CONTAINER-NAME>.key

Next you need to get the public key into the container via the CCS_SSH_KEY environment variable and expose port 22 for SSH access.

mykey=`cat <CONTAINER-NAME>.key.pub`
mynamespace=`cf ic namespace get`
cf ic run --name <CONTAINER-NAME> -m 128 -p 80 -p 22 -e "CCS_SSH_KEY=$mykey" registry.ng.bluemix.net/$mynamespace/scoutpopcorn:1.0

Bind the IP address to the container.

cf ic ip bind <IP> <CONTAINER-NAME>
cf ic ip bind 1.2.3.4  scoutpopcorn-container

Login to container instance

ssh -i <CONTAINER-NAME>.key root@<IP>

Bind an IBM Container Instance to a Service

In order for the VCAP_SERVICES details to be visible to the container, a zero-runtime application is required as an intermediary. This is typically known as a “bridge app”.

First create something to push.

cd ~
mkdir bridge-app
touch bridge-app/empty.txt
cf push <APP-NAME> -p <APP-DIR> -i <INSTANCES> -d <DOMAIN -k <DISK-LIMIT> -m <MEMORY-LIMIT> --no-hostname --no-manifest --no-route --no-start
cf push bridge-app -p bridge-app -i 1 -d mybluemix.net -k 1M -m 64M --no-hostname --no-manifest --no-route --no-start

Assuming a service already exists, look up its name.

cf services

Bind the zero-runtime app to the service.

cf bind-service <APP-NAME> <SERVICE-NAME>
cf bind-service bridge-app myservice

Launch the Docker image to create a running container instance. Bind the container to the app with the CCS_BIND_APP environment variable.

cf ic run --name <CONTAINER-NAME> -m <MEMORY-LIMIT-MEGABYTES> -p <PORT> registry.ng.bluemix.net/<REGISTRY-NAMESPACE>/<IMAGE-NAME>:<TAG>
mynamespace=`cf ic namespace get`
cf ic run --name scoutpopcorn-container -m 128 -p 80 -e "CCS_BIND_APP=bridge-app" registry.ng.bluemix.net/$mynamespace/scoutpopcorn:1.0

Bind the IP address to the container.

cf ic ip bind 1.2.3.4  scoutpopcorn-container

 

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s