How to build a container

I want to describe another way to run the  Highscores-Service of the #BlueCloudMirror game . In the game I use  IBM Cloud Foundry apps, now I want to explore IBM Cloud Kubernetes.

Note: The #BlueCloudMirror game we  @Niklas, @Harald and I made, is available as an Pattern on IBM Developer.

Let’s get started with the first step, building a container which contains the Scores-Service using Docker .

This blog post is all about building and running a docker container on a local machine.

Topics you will find in this post: my experience of  learning how configure a Dockerfile along  with my creation of the Dockerfile for the score-service, including following steps:

  • Choosing the base image
  • Installing the needed packaging tools
  • Defining the source code location and copying the source code into the container
  • Configuring a new user and group for Bower , a package manager
  • Setting up the Score-Service
  • Running the Score-Service container locally

Note: This is not a blueprint, this is just how I did it and I share my experience with you.

Architecture of the Scores-Service

This is the relevant architecture for building the Docker container.  The Scores-Service UI and the Scores Core Service will run in the Docker container locally. The Cloudant service still runs on IBM Cloud.

scores-service-docker

 

Choosing the base docker image

I haven’t done much research, which Node image on Dockerhub fits best to my requirements. Usually search is what you should do first and this is known as a best practice for using containers to reduce your maintenance effort in the future.

My decision was to build the container image from scratch and I chose the open source centos as my starting point for the container.

The following steps describe: How to create the Dockerfile in detail

Get started with the first line in the Docker file, build the container based on the centos image with the FROM instruction.

FROM centos

Installing the needed packaging tools

These are the tools I need to run my scores-service inside the container:

  • Node
  • Bower (because, I  am using this package manager for the scores-service UI )
  • Git for the installation
  • Scores-service application source code.

I configure the execution of the download with RUN  and installation of Node.js and git.

RUN curl --silent --location https://rpm.nodesource.com/setup_8.x | bash -
RUN yum install -y nodejs
RUN yum install -y git

Defining the source code location and copying the source code into the container

Now I create the directories I need for my source code inside the image.
The folder public contains the scores-service UI and the app folder contains the scores-core-service.

# setup folder structure in centos
# service (node server)
RUN mkdir usr/app
# webapplication
RUN mkdir usr/app/public
RUN mkdir usr/app/public/lib

Then I COPY the source code from the local machine into the defined directories.
As you can see, I use more then needed copy statements, because I want to highlight some of the files inside the app folder for myself s.
The .env  file contains Cloudant access information for the scores-core-service.
I decided not to use ENV in the Dockerfile and refine all environment variables already defined in the .env file.

# Bundle app source
COPY ./public /usr/app/public
RUN ls
COPY ./server.js /usr/app
COPY ./.cfignore /usr/app
COPY ./highscore_view.json /usr/app
COPY ./sampledata.json /usr/app
COPY ./score_index.json /usr/app
COPY ./manifest.yml /usr/app
COPY ./.env /usr/app

Configuring a new user and group for a package manager

During the installation of bower modules, Bower uses the folder public/lib. Bower is not allowed be executed as root.  When you use the instruction RUN in a Dockerfile,  by default the root user is used.

Bower needs rights to create or change folders.

So, I need to add a user and  give him rights to the folders.
By the way, I install the needed Bower modules in the folder called lib and not to the default folder bower_components.

I add a user called bower and provide him specific rights to access folders . I found the easiest way to provide the rights was defining a user group and giving the group access to the needed folders.

# create group and user
RUN groupadd installer
RUN useradd -ms /bin/bash bower --group installer
# set user rights to allow the bower user to setup custom lib folder
RUN chown -R bower:installer usr
RUN chown -R bower:installer usr/app
RUN chown -R bower:installer usr/app/public
RUN chmod g+rwX usr/app/public
RUN chmod g+rwX usr/app
RUN chmod g+rwX usr

Setting up the score-service

To setup the scores-core-service I set the working directory to execute commands from the /usr/app with WORKDIR . Then I copy the npm package.json, and I install the modules for the scores-core-service with the npm package manager .

# Install app npm dependencies
WORKDIR /usr/app
COPY ./package.json /usr/app
RUN npm install

The setup of the scores-core-service is done. Only the scores-service UI setup is missing.

As you know, I am using bower package manager to setup the scores-service UI.
In the following steps, I install bower and copy the needed configuration files into the image. Then I change the USER and run bower install .

# Create app directory
WORKDIR /usr/app
# install bower
RUN npm install --global bower
# Install app bower dependencies
COPY ./bower.json /usr/app
COPY ./.bowerrc /usr/app
USER bower
RUN bower install

The few remaining steps are:

  • Defining the port which the container should  EXPOSE . I define my port inside the server.js file line 57 var port = process.env.PORT || 3000; .
  • Defining the default execution at the startup of the container. To start the node server at the startup of container I use the command CMD .

Dockerfile steps:

# Server listens on
EXPOSE 3000
CMD [ "npm", "start" ]

For now the score-core-service and score-service UI setup in the Dockerfile is done.
To access the Cloudant database the .env file I copied before, which contains the information for the  score-core-service

Note: The .env file is not a part of the git repository,  because normally I create the values with a bash script automatically and it contains keys, which should not be saved inside the github source code.

 

Here is a sample for the .env file.

# CF APP
SERVICE_USER=admin
SERVICE_PASSWORD=a12345678
BASE_PATH=/scores-service
# CLOUDANT
CLOUDANT_NAME=blue-cloud-mirror-scores-service-db
CLOUDANT_DES_SCORES=_d_scores
CLOUDANT_IDX_SCORES=_idx_scores
CLOUDANT_DES_HIGHSCORE=_d_highscores
CLOUDANT_IDX_HIGHSCORE=_v_highscores
CLOUDANT_USERNAME=XXXXX
CLOUDANT_PASSWORD=XXXXX
CLOUDANT_URL=https://XXXXX-bluemix.cloudantnosqldb.appdomain.cloud
CLOUDANT_PORT=443
SERVICE_URL=

Running the score-service container locally

The last remaining steps are building, running, and using this docker image locally.

  • Build it
  • Run it
  • Use it

Build a container with the tag v1.

docker build -t scores-service:v1 .

scores-service-docker

Now run the container exposing port 3000 to the local machine.

docker run -d -p 3000:3000 scores-service:v1

run-scores-service-on-docker

Now the scores-service is running the container is locally available on  http://localhost:3000 .

local-scores-service

I hope this was useful for you and let’s see what’s next?

Greetings,

Thomas

FYI: You can find the next step here: How to deploy a container to the IBM Cloud Kubernetes Service.

PS: By the way, you can use the IBM Cloud for free, if you simply create an IBM Lite account. Here you only need an e-mail address.

#BlueCloudMirror, #Docker #Container, #Bower, #IBMDeveloper

3 thoughts on “How to build a container

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 )

Google photo

You are commenting using your Google 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 )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.