Create a Kubernetes cluster from the scratch (On CentOS 7 / RHEL 7) and Deploy an application on the cluster and Expose to Internet — Complete Example PART — 02 (Docker)

Hashith Karunarathne
5 min readJan 22, 2019

Content

  • Install Docker (Covered by previous story)
  • Create the cluster (on VM) (Covered by previous story)
  • Build Dockerized application — Covered on this story
  • Deploy the application on the cluster — Covered on this story

Previous story

TODO: Will cover on future stories.

  1. Expose the application to internet through an Ingress
  2. Install and configure Helm
  3. Deploy above application using Helm chart

Docker app source : https://github.com/el173/docker-node-app

Kubernetes deployment example : https://github.com/el173/kubernetes-examples

1.0 Build Dockerized application

Here I’m going to build a nodejs hello world app which is get app configurations as environment variables(Will explain later why we do this) on RHEL 7 (Same VM(s) which was used in my previous story PART-1)

First thing first

1.1 Install Node.js

  • Add Node.js Yum Repository
# yum install -y gcc-c++ make
# curl -sL https://rpm.nodesource.com/setup_10.x | sudo -E bash -
  • Install Node.js
# yum install nodejs
  • After installing node.js verify and check the installed version
# node -v
v10.15.0
# npm -v
6.4.1

1.2 Create the Node.js app

  • Create a new directory where all the files would live. And create a package.json file that describes app and its dependencies.
# mkdir nodeapp && touch package.json
  • And edit the file package.json
{ 
“name”: “docker_web_app”,
“version”: “1.0.0”,
“description”: “Node.js on Docker”,
“author”: “Hashith Karunarathne<hashithkarunarathne@gmail.com>”,
“main”: “server.js”,
“scripts”: {
“start”: “node server.js”
},
“dependencies”: {
“express”: “^4.16.1”
}
}
  • Then run npm install. If you are using npm version 5 or later, this will generate a package-lock.json file which will be copied into the Docker image.
  • After that, create a server.js file that specify the web app using the Express.js framework.
# touch server.js

Edit and add following code to server.js file

'use strict';  const express = require('express');  const PORT = 8080; 
const HOST = '0.0.0.0';
const DB_HOST = process.env.DB_HOST;

app = express();
app.get('/', (req, res) => {
res.send('Hello world\n DB HOST : '+DB_HOST+'\n');
});
app.listen(PORT, HOST);
console.log(`Running on http://${HOST}:${PORT}`);

1.3 Build a Docker image of the app

Note: Before move to the docker image creation, Create a Docker Hub account.

  • Create a empty file called Dockerfile
# touch Dockerfile
  • Edit and add below lines to Dockerfile
FROM node:8  
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 8080
CMD [ "npm", "start" ]
  • Create a .dockerignore file in the same directory and add following contents to it.
node_modules 
npm-debug.log

This will prevent your local modules and debug logs from being copied onto your Docker image.

  • Build myApp docker image

Run following command on same directory where the Dockerfile contains.

Note: Replace all the place where el173 with your docker hub user name.

# docker build -t el173/node-hello:v0.1 .

Your image will now be listed by Docker

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
el173/node-hello v0.1 683cf97e4468 14 seconds ago 895 MB
node 8 55b43107a63d 39 hours ago 893 MB

Then run the docker image

# docker run -d -p 12345:8080 -e DB_HOST=1.1.1.1 el173/node-hello:v0.1

Test the docker image

To verify container created successfully run the below command

# docker ps

Output should like below,

CONTAINER ID        IMAGE                   COMMAND             CREATED             STATUS              PORTS                     NAMES
39a41885f19e el173/node-hello:v0.1 "npm start" 3 minutes ago Up 2 minutes 0.0.0.0:12345->8080/tcp priceless_pare

To see the out put of the application

# curl -i localhost:12345
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/html; charset=utf-8
Content-Length: 19
ETag: W/"13-VpSJg61R7DJwwGMhbMUNqUoKJcQ"
Date: Thu, 10 Jan 2019 18:15:27 GMT
Connection: keep-alive

Hello world
1.1.1.1

Now all good docker image of our app has been build successfully.

1.4 Push docker image to docker repository (This make easy the app deployment on Kubernetes)

First all, we need to login to our docker account on our app building environment.

# docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.

Then push your docker image to your Docker Hub repository.

# docker push el173/node-hello:v0.1

You can find the above example source code form this link

https://github.com/el173/docker-node-app

Now all ready to deploy our app on Kubernetes cluster (Which was created on my PART-1)

2.0 Deploy the application on the cluster

Before moving to the deployment please read this Understanding Kubernetes Objects

First create a separate namespace for our deployment. (It will easy to manage our app)

  • namespace.yaml file
apiVersion: v1
kind: Namespace
metadata:
name: node-app

Create namespace

# kubectl create -f https://raw.githubusercontent.com/el173/kubernetes-examples/master/simple-node-app/namespace.yaml

Why we use configmap — It is the most convenient way to store our application configurations in kubernetes cluster.

Read more : https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/

  • configmap.yaml file
apiVersion: v1
kind: ConfigMap
metadata:
name: node-app-config
namespace: node-app
data:
DB_HOST: "1.1.1.1"

Create config map

# kubectl create -f https://raw.githubusercontent.com/el173/kubernetes-examples/master/simple-node-app/configmap.yaml

Now all good to deploy our application on the kubernetes cluster.

MUST: Read before do the deployment — https://kubernetes.io/docs/concepts/workloads/controllers/deployment/

  • deployment.yaml file
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: node-app-deployment
namespace: node-app
labels:
app: node-app
spec:
selector:
matchLabels:
app: node-app
tier: node-app-tier
replicas: 2
template:
metadata:
labels:
app: node-app
tier: node-app-tier
spec:
containers:
- name: node-app-container
image: el173/node-hello
ports:
- name: http
containerPort: 80
envFrom:
- configMapRef:
name: node-app-config

Make the deployment

# kubectl create -f https://raw.githubusercontent.com/el173/kubernetes-examples/master/simple-node-app/deployment.yaml

Okay, we have successfully deployed our app on the cluster. Now we need to create a service to access our app.

MUST: Read before create the service — https://kubernetes.io/docs/concepts/services-networking/service/

service.yaml

apiVersion: v1
kind: Service
metadata:
name: node-app-service
namespace: node-app
labels:
app: node-app
tier: node-app-tier
spec:
type: NodePort
ports:
- port: 8080
selector:
app: node-app
tier: node-app-tier
# kubectl create -f https://raw.githubusercontent.com/el173/kubernetes-examples/master/simple-node-app/service.yaml

Once you created service. Retrieve all of your resources under node-app namespace, It should like below.

# kubectl get all -n node-app
NAME READY STATUS RESTARTS AGE
pod/node-app-deployment-556b878859-v57f2 1/1 Running 0 40h
pod/node-app-deployment-556b878859-wqk2p 1/1 Running 0 40h

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/node-app-service NodePort 10.103.112.204 <none> 8080:30814/TCP 40h

NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/node-app-deployment 2/2 2 2 40h

NAME DESIRED CURRENT READY AGE
replicaset.apps/node-app-deployment-556b878859 2 2 2 40h

And now all good, You can check whether service is running.

Get service ip (cluster ip only available within the cluster)

# kubectl get svc node-app-service -o yaml -n node-app | grep clusterIP
clusterIP: 10.103.112.204

Get service port

# kubectl get svc node-app-service -o yaml -n node-app | grep port
ports:
port: 8080

Then curl and see your application output:

# curl 10.103.112.204:8080
Hello world
1.1.1.1

On next story we will look on kubernetes Ingress.

References:

--

--

Hashith Karunarathne

Full Stack | Mobile | Cloud | Microservice | Micro Frontend