Deploy static front-end application to kubernetes cluster using Jenkins CD and minio with automatic https cert
Tags: kubernetes, minio, letsencrypt, jenkins
Published: 2018-11-03 06:59:21

---
title: Deploy static front-end application to kubernetes cluster using Jenkins CD and minio with automatic https cert
published: true
description: Deploy static web application to cluster using Jenkins CD and minio
tags: #kubernetes,#minio,#letsencrypt,#jenkins
cover_image: https://thepracticaldev.s3.amazonaws.com/i/ute71a9t5qcu3z4w3nmk.jpg
---
[nodeport]: https://thepracticaldev.s3.amazonaws.com/i/4bap9h7cq3epurxujqwh.png "NodePort"
[minioadd]: https://thepracticaldev.s3.amazonaws.com/i/yq1znp7iiyekx5e7ebm5.png "Add success"
[miniobucket]: https://thepracticaldev.s3.amazonaws.com/i/xwvg7gvps8dah6vwrodh.png "Empty bucket"
[reactlocal]: https://thepracticaldev.s3.amazonaws.com/i/9ri3pp9z2kk5wyd41ywp.png "React local"
[ingressyml]: https://thepracticaldev.s3.amazonaws.com/i/yjwrfn0ladvwtlz83vfy.png "ingress.yml"
[jenkinsfile]: https://thepracticaldev.s3.amazonaws.com/i/bzgr920qqiw7b88oetnu.png "Jenkinsfile"
[insidejenkins]: https://thepracticaldev.s3.amazonaws.com/i/qpbx9zegw7nvwhn3a6zz.png "CLI inside Jenkins"
[jenkins1]: https://thepracticaldev.s3.amazonaws.com/i/fhj5l8f5yqc2z89wgq5m.png "Create pipeline"
[jenkins2]: https://thepracticaldev.s3.amazonaws.com/i/cnh2c1qzayuknhz126yu.png "Git repo and credential"
[jenkinsbuild]: https://thepracticaldev.s3.amazonaws.com/i/0hzksadfi1pvceagfdwz.png "Jenkins build"
[secrettls]: https://thepracticaldev.s3.amazonaws.com/i/qrqxmg0ca9d0wkn5ts71.png "Secret result"
[https]: https://thepracticaldev.s3.amazonaws.com/i/1635katlu1g8nmizhdii.png "https result"

After we've setup kubernetes cluster on our VMs, we setup nginx ingress automatically apply for certificate with letsencrypt. This post we will deploy static web application using Jenkins CD and minio.

With Jenkins CD, we can define our build and deployment pipeline, and with the power of kubernetes and docker, our application infrastructure also defined along with our source code.

With minio, a file storage server, we can host static web site as a folder like we do with AWS S3 but within our own infrastructure.

Then with nginx ingress that we setup from [previous post](https://dev.to/pongsatt/set-up-nginx-ingress-with-letsencrypt-certificate-on-vms-or-bare-metal-kubernetes-cluster-j25), we can point website URL to minio file serving.

**Note:**
> This post assume that you follow this [series](https://dev.to/pongsatt/setup-your-own-kubernetes-cluster-on-vms-5ln) of posts
> If you follow this [series](https://dev.to/pongsatt/setup-your-own-kubernetes-cluster-on-vms-5ln), you need to be on master node to follow this post

##Prerequisite:##
- A running kubernetes cluster
- helm installed
- Jenkins server with pipeline support

#Setup minio#

**Note:**
> minio requires access key and secret. Please replace "myaccesskey" and "mysecret" with you own values

###1. Install minio using helm###

This run will install minio server in "minio" namespace

```
helm install --name minio --namespace minio stable/minio \
--set accessKey=myaccesskey,secretKey=mysecret \
--set service.type=NodePort

```

###2. Install minio web client###

Install mc cli using command below (need root password).
```
wget https://dl.minio.io/client/mc/release/linux-amd64/mc && chmod +x mc && sudo mv mc /usr/local/bin/mc

```

###3. Configure minio pointing to the server###

Run `kubectl get service -n minio` to find NodePort.

![][nodeport]


Run command to add minio configuration folder.

**Note:**
> Replace <Master Node IP> with your real master node IP address
> Replace <NodePort> with real node port from above step
> Replace "myaccesskey" and "mysecret" with your own values

```
mc config host add myminio http://<Master Node IP>:<NodePort> myaccesskey mysecret
```

Result should look like this.

![][minioadd]


###4. Create minio folder to host static files###

In this example, we will create a bucket name "public" to host all static folders.

```
mc mb -p myminio/public
mc policy download myminio/public
```

Run `mc ls myminio` and you should see an empty bucket.

![][miniobucket]

#Setup DNS record#

In order to apply for https domain certificate, you need to set your DNS record "simpleapp.yourdomain.com" to your ingress service IP. You can see my example from [previous post](https://dev.to/pongsatt/set-up-nginx-ingress-with-letsencrypt-certificate-on-vms-or-bare-metal-kubernetes-cluster-j25).


#Build a static website#

We will use react application as our sample static website. Let's build it.

###1. Initialize application###

Note: you will need nodejs installed on your machine.

```
npx create-react-app simpleapp
cd simpleapp
npm start
```

Open "http://localhost:3000" and you should see.

![][reactlocal]


###2. Add kubernetes ingress configuration###

Add "ingress.yml" under "k8s" folder at the root folder.

![][ingressyml]


Content:

**Note:**
> Replace "simpleapp.yourdomain.com" with real domain
> This example use "dns01" protocol to acquire letsencrypt certificate. You can change it to "http01" by comment/uncomment

```
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: simpleapp-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"

    # use http01 protocol. uncomment line below to use http01
    # kubernetes.io/tls-acme: "true"

    # use dns01 protocol. comment 2 lines below if use http01
    certmanager.k8s.io/acme-challenge-type: "dns01"
    certmanager.k8s.io/acme-dns01-provider: "aws-route53"

    nginx.ingress.kubernetes.io/rewrite-target: "/public/simpleapp"
    nginx.ingress.kubernetes.io/configuration-snippet: |
      rewrite ^/?$ /public/simpleapp/index.html break;
spec:
  tls:
  - hosts:
    - simpleapp.yourdomain.com
    secretName: simpleapp-tls
  rules:
  # The host must be identical to the above one
  - host: simpleapp.yourdomain.com
    http:
      paths:
      - path: /
        backend:
          # The name of your service
          serviceName: minio
          servicePort: 9000

```

This configuration will point "simpleapp.yourdomain.com" to a folder under "public" bucket on minio to a folder name "simpleapp". Also support redirect from "/" to "/index.html"


###3. Add Jenkinsfile pipeline###

Create file name "Jenkinsfile" at the root folder.

![][jenkinsfile]


Content:

```
pipeline {
  environment {
    ENV = "minio"
    APP = "simpleapp"
  }
  agent { label 'docker' }

  stages {
    stage('build') {
      steps {
        withDockerContainer('node:8.4.0-alpine') { 
            sh 'yarn install'
            sh 'yarn build'
        }
      }
    }

    stage('publish to minio') {
      steps {
        sh "mc cp -r build/ myminio/public/${APP}"
      }
    }

    stage('deploy ingress to kubernetes') {
        steps {
            sh("kubectl --namespace=${ENV} apply -f k8s/ingress.yml")
        }
    }

  }

}
```

From the configuration, I have a Jenkins build agent with label "docker" that contains "kubernetes" and "mc" cli.

There are 3 stages.
1. build: react project to "build" folder
2. publish to minio: copy folder "build" to minio "public/simpleapp"
3. deploy ingress to kubernetes: deploy "k8s/ingress.yml" to cluster


###4. Publish to git repo###

You can publish your project to any git repository.


#Prepare Jenkins environment#

In this example, your jenkins needs to support below cli.

- kubectl : with ".kube" configuration folder that point to our kubernetes server
- mc : with ".mc" configuration folder that point to our minio instance

**Note:**
> Install these tools will depend on your jenkins environment

###1. kubectl configuration###

You can just copy "~/.kube/config" from master node to "/home/jenkins/.kube/config".

###2. mc configuration###

You can just copy "~/.mc/config.json" from master node to "/home/jenkins/.mc/config.json"

If all the configurations is ok, you should be able to run command below inside Jenkins agent.

![][insidejenkins]


#Build Jenkins pipeline#

In this example, we will create Jenkins pipeline that point to Jenkinsfile in the repository.

###1. Create Jenkins pipeline project###

Create "simpleapp" project.

![][jenkins1]

Enter your git repo url and credential.

![][jenkins2]


###2. Build pipeline###

Normally, pipeline build should be automatically triggered when the source code is update. This example will use manual trigger.

Build result.

![][jenkinsbuild]


#Test your application#

Wait until `kubectl get secret -n minio` return secret name "simpleapp-tls".

![][secrettls]

If everything is ok, you should be able to open URL "https://simpleapp.yourdomain.com" and see result as below.

![][https]

#Summary#

We build static website with Jenkins CD, then deploy to minio file server and kubernetes with automatic letsencrpyt certified. [Next](https://dev.to/pongsatt/deploy-back-end-api-application-with-database-to-the-kubernetes-cluster-with-jenkins-cd-51j7), we will do CD with backend code and kubernetes cluster.