Thursday, June 16, 2016

Automated Container Delivery Using Stacksmith with GitHub

When developing with Docker containers, updates to an application’s stack or environment are rolled out by stopping outdated containers and replacing them with an updated container image. Docker is a popular toolchain for developing applications in containers that makes it incredibly easy to conduct these container image updates. However, the process of deploying updated container images is still a repetitive series of manual steps that can be mechanized. Bitnami built Stacksmith to automate this process.

Stacksmith automates the deployment of container images by maintaining a base Dockerfile, and by keeping each stack up-to-date against version updates and security vulnerabilities. Conveniently, Stacksmith integrates with GitHub so that when there’s an update to an application’s stack, a developer simply has to merge an automatically generated pull request from Stacksmith that contains the updated container image.

This post walks through how you can use Stacksmith with your application on GitHub to provide continuous delivery of your application container images.

Before you get started

This tutorial assumes you have Git, Docker (1.10+) and Docker Compose (1.6+) installed, and that you have some familiarity with these tools.

For this tutorial, we we will run Scotch’s Node Todo App on containers. The Node Todo App is a small, multi-tier and open source application that consists of an ExpressJS application server which connects to a MongoDB server for persistence. This architecture is referred to as a MEAN stack.

Once you confirm that you have the correct tools (Git/Docker/Docker Compose) installed, you are ready to get started by forking the Node Todo App repo on GitHub.

Create Your first Stacksmith Node.js stack

Stacksmith uses stacks to define the environments that make up your Dockerfiles. A stack is comprised of one or two components, most typically a runtime, as well as the base operating system. To run our Node Todo App on containers, we will create a stack that contains the Node.js runtime on top of Stacksmith’s Debian base:

On the Stacksmith homepage, select Node in the dropdown and click on ‘Create Stack’ to start configuring your stack.



Next, follow the instructions to connect your GitHub account to Stacksmith, and select your forked repository, the Node Todo App, in the dropdown list. By connecting your GitHub account with your Bitnami account, Stacksmith will be able to automatically add a Dockerfile to your repository that is configured based on your stack specifications. When there is an update to your stack, Stacksmith will automatically submit a pull request to your GitHub repository keep your application’s container image up-to-date.

Now select Node.js in the components dropdown. This will be the main component in our stack. We suggest that you select ‘6.x’ in the version dropdown, to ensure you only automatically update to security and patch fixes.

Once your components are entered, Stacksmith will prompt you to specify the flavor of Dockerfile you need. In this case, the Node Todo App is an ExpressJS application, so you will select ExpressJS in the dropdown to get a Dockerfile that is most suited to running your application.


To complete the stack creation process, leave the base operating system as Debian, and click the ‘Create stack’ button to go ahead and create your stack. The new stack that you created will show up in the ‘Your Stacks’ page with the same name as your GitHub repository.

Merging in your new Dockerfile

To merge your Dockerfile into your forked repository, visit your repository on GitHub by clicking the link at the bottom of your “Stack Info” screen. You will see that Stacksmith automatically opened a pull request to add your new Dockerfile to the repository. Accept the change which adds the Dockerfile to your repository by clicking on the green “Merge pull request” button.

Building and running your application container

Cloning the GitHub repository

Now that your application code has a Dockerfile checked in, you should try it out by running the application. First, clone the repository from GitHub into a directory on your local machine.

> git clone git@github.com:<GITHUB-USERNAME>/node-todo.git
> cd node-todo/

Remember to replace the clone URL with your GitHub repository’s remote URL.

Setting up your Docker Compose file

Docker Compose is a tool that makes it easier to run multi-tiered applications in containers. Using Compose, a developer is able to define each service needed to run their application in a container by creating YAML configuration file. A developer is then able to use Compose to manage the group of containers, specifically by bringing them up and tearing them down as necessary.

Your repository already has a Dockerfile that can be used to run the ExpressJS server, so you can configure Compose to build the image using this Dockerfile with the following directive:

express:
 build: .
 ports:
- 3000:8080
We suggest configuring a port mapping to access the web server from outside the container.

For MongoDB, you will need to reference the Bitnami MongoDB Docker image that can be pulled directly from Docker Hub. This container image will come with everything you need to run a MongoDB server out of the box.

mongodb:
 image: bitnami/mongodb
The full docker-compose.yml file should look like this:
version: “2”
services:
 express:
   build: .
   ports:
 - 3000:8080
restart: always
depends_on:
     - mongodb
 mongodb:
   image: bitnami/mongodb

Building and running your application using Docker Compose

Now that we’ve setup our Compose file, we can go ahead and run the application. To start all the services, run:
> docker-compose up
Oops, it failed! Check the logs to see what went wrong. The issue seems to be that your ExpressJS container is expecting to run the application using the npm start command, however, the Node Todo App hasn’t been configured to specify the correct start script to run in the package.json. To fix the issue, you can modify your package.json file to run the server.js script when using npm start, or you can more easily change the container startup command in the Stacksmith generated Dockerfile.

We suggest the latter option in order to demonstrate how you can go about customizing the Dockerfile generated by Stacksmith. In your Dockerfile, change the CMD line from:


CMD [“npm”, “start”]


to:


CMD [“node”, “server.js”]


If you rebuild and run the application again, you will see that the Node Todo App crashes because it is unable to connect to MongoDB. By default, the Node Todo App is configured to connect to MongoDB on localhost. The host needs to be changed to use the Service Discovery on the Docker Network that Compose sets up for us. To do this, change config/database.js to:


module.exports = {
   remoteUrl : 'mongodb://node:nodeuser@mongo.onmodulus.net:27017/uwO3mypu',
   localUrl: 'mongodb://mongodb/meanstacktutorials'
};


Now run docker-compose up --build and you will see that both containers start successfully, and you should try to access the Node Todo App in your browser at DOCKER_IP:3000, replacing DOCKER_IP with the IP address of your Docker Machine (if running in a VM), or localhost if running locally.


To find out the IP address of your Docker Machine instance, you can run the following command:


> docker-machine ip $(docker-machine active)

Committing and pushing your changes to GitHub

Now that you have made changes to the Dockerfile to run your container, you should commit and push your changes to GitHub.


After pushing the changes to GitHub, visit Stacksmith to see that your changes have been tracked correctly. This will ensure that when there is an update for your stack, your changes will be kept when you regenerate the Dockerfile.

Automating your container builds using Docker Hub Automated Build

To have your container continuously built when you update your application code, or when there is an update in your stack, you can setup an Automated Build repository in Docker Hub. For documentation on setting this up with your repository, visit the Docker Docs: https://docs.docker.com/docker-hub/builds/

Receiving a stack update from Stacksmith

At this point you should have the following setup:
  1. Stack in Stacksmith that defines your application’s runtime requirements.
  2. Dockerfile generated by Stacksmith for building your application container.
  3. Connection to Docker Hub automated builds that automatically build and push your container to the Docker Hub Registry when you make changes in your repository.

What happens when a new version of Node.js is released? Or what happens when there is a security patch available for either Node.js or one of the packages in the Debian base image? In the container world the existing procedure for dealing with this scenario is to rebuild the whole application container on top of the new, updated and secure stack. Stacksmith introduces a new and easier way to deal with updates to your stack.


For example, it may turn out for you that within days or weeks of creating your stack, an update to Node.js may become available. When an update is released, Stacksmith will notify you via email, Slack, or a custom webhook.


For me, several days after I created my Node Todo App stack I received an email notification that I can update to Node.js 6.2.1. Below are the steps I followed to regenerate my Dockerfile:


Going back to Stacksmith to view my stack, I can see that I am currently using 6.2.0 and I can regenerate my Dockerfile to update to 6.2.1.

I click the “Regenerate” button to instruct Stacksmith to create a new stack with the updated version.

Next, I head over to my forked repository on GitHub where I can see that Stacksmith also created a new pull request with an update to the Dockerfile. The Stacksmith Bot leaves my Dockerfile modifications unchanged, and simply updates the referenced version of Node.js and the metadata about the new stack.


After I merge the pull request from Stacksmith, my Docker Hub integration kicks off an automated build using the new Dockerfile. Then after a few moments, I have a new Docker image for running my Node Todo App on top of the latest Node.js version. I can then reference the new Docker image in the Compose file, or a Kubernetes manifest and re-deploy my application.


If I want a more complete workflow for a production use-case, I can automate the deployment with an existing CI/CD pipeline that will kick-off after the merge of the Stacksmith pull request.


That’s all! If you are using Stacksmith to run your applications in development or production, please let us know! We’re eager to hear how we can improve Stacksmith for you.

Watch a demo of our Stacksmith and GitHub integration: