Deploy an AngularJs application on Kubernetes (Step by step Guide) - Beyond Coding !

 

Kubernetes Cluster

In this tutorial, we will learn how an angularjs application can be deployed to a Kubernetes cluster.


We will be discussing each step with code samples.


  • Create a sample angularJs app
  • Dockerization of the app
  • Build & analysis the compiled output
  • Dockerization
  • Use Nginx to handle requests inside the docker image
  • Running the app in a subfolder
  • Running docker image in local machine
  • Push docker image to the Docker registry
  • Create a Kubernetes manifest file for deployment
  • Connect to Kubernetes cluster
  • Deploy the app to the cluster
  • Set up the ingress controller to expose the app to the internet.


Prerequisites -

Before you getting started, let's take a look at the prerequisites.


Tools -

  1. NodeJs environment ( https://nodejs.org/en/download/ )
  2. Docker (  https://docs.docker.com/get-docker/ )
  3. Angularjs CLI ( https://cli.angular.io/ )
  4. Cloud Account with Kubernetes offering or MiniQube for testing purposes ( https://kubernetes.io/docs/tasks/tools/install-minikube/ )


Create a sample app -

Before you get started, install the node.js in your system, if you do not have it yet. You can download and run the installer from here https://nodejs.org/en/download/


Open your terminal on mac or command prompt in windows.


Install the Angular command-line tool using the command below. To know more, check https://cli.angular.io/


npm install -g @angular/cli


Now create a project using the ng command


ng new angular-k8s-app


You should see the output like below:




To check if the project is running properly on your local machine, navigate to the project


cd angular-k8s-app


Run the project using the command


npm start


Open http://localhost:4200 in your browser, you should see the app default template in the browser.




Here you have your app up & running on the development mode.


If you face any issue, please visit the official angular site for more detailed instructions (https://angular.io/start)



Build & Analyse the output -

To create the build you can run the command npm run build which executes the command ng build from package.json


But for optimized production build we want to run ng build — prod


For that, we will modify the package.json script section and add another script command


“build:prod”: “ng build — prod”


the script section should look like this :




Let’s run the build command and see the output by doing


npm run build:prod


You should see the output in the console similar to this :




The build output is generated under the folder /dist (by default)




You see the build has a parent folder with the same name as our project which is angular-k8s-app for this case.


The folder /dist/angular-k8s-app contains static files that are ready for the deployment to any web server.



Dockerize the app -


To deploy the app to a Kubernetes cluster, we need to dockerize the app first.


Create a file called ‘Dockerfile’ at the root of your project source.


We will add two stages to the docker build


One is to build the project and another is to serve the static build files using Nginx


I will be describing all steps below.


### STAGE 1: Build ###

FROM node:12.14-alpine AS build

WORKDIR /app

COPY package.json ./

RUN npm install

COPY . .

RUN npm run build:prod



stage #1


Here we are using node alpine for executing build commands. The rest of the commands are to install packages and create the build.


Now in stage #2, we will use Nginx to handle requests.


### STAGE 2: Run ###

FROM nginx:1.17.1-alpine

COPY --from=build /app/dist /usr/share/nginx/html

COPY nginx.conf /etc/nginx/nginx.conf


In the above script, we are copying the dist folder under the Nginx default serve path.


and copy a custom nginx.conf file to the image. see the next section to know about the custom nginx.conf in detail.


Custom nginx.conf -

create the custom Nginx.conf file at the root of the project. This is the same file we copied in step #STAGE 2 above.


nginx.conf


worker_processes 1;


events { worker_connections 1024; }


http {

    server {

        listen       80;

        server_name  localhost;

        include /etc/nginx/mime.types;


         location / {

                 root /usr/share/nginx/html/angular-k8s-app/;

                 try_files $uri $uri/ /index.html;

             }


    }

}



In the nginx.conf file we are handling all HTTP requests and forwarding the request to the index.html


Like most of the other static applications, we do not have different files or directories for different routes(URL). We have to forward all the requests to that index.html file which is located here /dist/angular-k8s-app/index.html The above nginx.onf file is doing the same for us.


Let's take a look at the final Docker file once -


Dockerfile


### STAGE 1: Build ###

FROM node:12.14-alpine AS build

WORKDIR /app

COPY package.json ./

RUN npm install

COPY . .

RUN npm run build:prod


### STAGE 2: Run ###

FROM nginx:1.17.1-alpine

COPY --from=build /app/dist /usr/share/nginx/html

COPY nginx.conf /etc/nginx/nginx.conf



we are done with the dockerize part here. next, we will run and test the docker image locally.


Run docker in local -


To create the docker image, we need to run the command


docker build -t demo-images/angular-k8-app .


When the image is created, let’s run the docker to check everything is working fine.


Run the docker image by doing this


docker run -p 80:80 -it demo-images/angular-k8-app:latest


the first 80 port is the port of the host machine that will be used in the browser to run the app, the second 80 port is the container’s port where Nginx is running and serving the project.




By opening the URL http://localhost on the browser, I see the app is up and running and the minified build files are executing.


We are good at the dockerize part here.


Running the app in a subfolder -


So often we see the app is hosted under a subfolder. Also in a cluster, we may have multiple applications hosted, there might be many micro-services as well.


Let’s make some adjustments to the project and build-process to make the app compatible to run in a subfolder.


In angular, if you add base href, this will run the app in the URL like this


http://localhost/demo-app-path


<base href="/demo-app-path/">

If you want to run your app without a base path for development and only add a base path for deployment, then need to modify the build command and add — base-href to it like this


"build:prod": "ng build --base-href /demo-app-path/ --prod",

and then modify the nginx.conf


worker_processes 1;

events { worker_connections 1024; }

http {

    server {

        listen       80;

        server_name  localhost;

        include /etc/nginx/mime.types;

         location / {

                 root /usr/share/nginx/html/angular-k8s-app/;

                 try_files $uri $uri/ /index.html;

             }

         location /demo-app-path {

            alias  /usr/share/nginx/html/angular-k8s-app/;

            try_files $uri$args $uri$args/ /angular-k8s-app/index.html;

          }

    }

}



Let’s build the image again for testing


docker build -t demo-images/angular-k8-app .


If your docker container is already running and port 80 is already taken, use this command to stop them all.


docker stop $(docker ps -a -q)


Now run the new container again


docker run -p 80:80 -it demo-images/angular-k8-app:latest




Upload the image to the Docker Registry -


To push your docker image, you need to tag that image first.


You can use your own (Private) registry or public docker registry which is set as default as you install the docker in your system


When you use IBM Cloud, you will have your private registry with limited space.


To tag your image for your registry run command


docker tag demo-images/angular-k8-app:latest <myregistryhosturl.com>/<demo-apps>/angular-k8-app:latest


then


docker push <myregistryhosturl.com>/<demo-apps>/angular-k8-app:latest




Deploy the app to the cluster -


In my demo, I am using IBM Cloud as a provider. To deploy the image to a cluster, first need to login to the account.


You can find the detail here about how to set up IBM Cloud CLI :

https://cloud.ibm.com/docs/containers?topic=containers-cs_cli_install


When you are logged in, choose the right account if you are a member of multiple accounts by using the interactive command-line tool.


List the available


ibmcloud ks cluster ls


Get the cluster config


ibmcloud ks cluster config — cluster <cluster_name_or_ID>


the console should output something like this


export KUBECONFIG=/Users/sanjitbauli/.bluemix/plugins/container-service/clusters/<account_name>/kube-config-dal10-XXX.yml


Copy and paste to the terminal so that you have the config to connect to the cluster.


If you want to create a new namespace run this command


ibmcloud cr namespace-add <namespace>


In my case, I already have a namespace. so I am setting the context to that namespace


kubectl config set-context — current — namespace=myexisting-namespace


Prepare Deployment YAML -


Now we need to create a deployment YAML file which will do two things,


#1 will deploy the app to multiple pods


#2 Create a service to connect the deployed app to ingress.


deployment.yaml


apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2

kind: Deployment

metadata:

  name: angular-k8-app-deploy

spec:

  selector:

    matchLabels:

      app: angular-k8-app

  replicas: 2

  template:

    metadata:

      labels:

        app: angular-k8-app

    spec:

      containers:

        - name: angular-k8-app

          image: <myregistryhosturl.com>/<demo-apps>/angular-k8-app:latest

          ports:

            - containerPort: 80

---

# See more here

https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service


kind: Service

apiVersion: v1

metadata:

  name: angular-k8-app-service

spec:

  selector:

    app: angular-k8-app

  ports:

    - protocol: TCP

      port: 80

      targetPort: 80

      nodePort: 80

  type: NodePort



Apply the YAML to deploy the app -


kubectl apply -f deployment.yaml


By opening the Kubernetes dashboard, I can see the deployment and service are up and running.




Ingress controller set up -


Now the app needs to be exposed to the internet.


To do that we need to set up the ingress to map the angular-k8-app-service.


If you already have an ingress, please modify the path array or you can create one like this


ingress.yaml


apiVersion: networking.k8s.io/v1beta1

kind: Ingress

metadata:

  name: test-ingress

  annotations:

    nginx.ingress.kubernetes.io/use-regex: "true"

spec:

  rules:

  - host: test.com

    http:

      paths:

      - path: /demo-app-path/.*

        backend:

          serviceName: angular-k8s-app-service

          servicePort: 80


Run this similarly as we did for deployment.yaml


kubectl apply -f ingress.yaml


Modify existing ingress from Kubernetes dashboard,


{

  "kind": "Ingress",

  "apiVersion": "extensions/v1beta1",

  "metadata": {

    ...

    "creationTimestamp": "2019-11-04T10:31:08Z",

    "annotations": {

      "nginx.ingress.kubernetes.io/use-regex": "..."

    }

  },

  "spec": {

    "tls": [

    {

      "hosts": [

        "test.com"

      ],

      "secretName": "xxx"

    }

    ],

    "rules": [

    {

      "host": "test.com",

      "http": {

        "paths": [

        {

          "path": "/other/app/url",

          "backend": {

            "serviceName": "other-app-svc",

            "servicePort": 80

          }

        },

        {

          "path": "/demo-app-path",

          "backend": {

            "serviceName": "angular-k8s-app-service",

            "servicePort": 80

          }

        },

        ]

      }

    }

    ]

  },

  "status": {

    "loadBalancer": {

      "ingress": [

      {

        "ip": "xx.xx.xxx.xxx"

      }

      ]

    }

  }

}


You should see the app on the web at http://test.com/demo-app-path


Conclusion

The angular app can be served on the server in several ways if the app is a static app and no server-side rendering is involved, the best way is to serve it using Nginx. you can easily serve the angular app using express but then there will be some execution on the server which may cost you a bit of performance which is very expensive nowadays.


If your app has some API proxy to avoid CORS, you can set a rewrite using your ingress.


Here’s the demo app repository with source code & configurations https://github.com/sanjitbauli/angular-k8-app


I hope you find this helpful while working with angularJs, docker, Nginx & Kubernetes.


Thanks For Reading :)

Comments