Put the UI in to Helm

Put the UI in to Helm

Spring Application Deployed with Kubernetes

Step by step building an application using Spring Boot and deployed via Docker on Kubernetes with Helm

full course
  1. Setup: IDE and New Project
  2. Create the Data Repository
  3. Building a Service Layer
  4. Create a REST Controller
  5. Logging, Tracing and Error Handling
  6. Documentation and Code Coverage
  7. Database as a Service
  8. Containerize the Service With Docker
  9. Docker Registry
  10. Automated Build Pipeline
  11. Helm for Deployment
  12. Setting up a Kubernetes Cluster
  13. Automating Deployment (for CICD)
  14. System Design
  15. Messaging and Event Driven Design
  16. Web UI with React
  17. Containerizing our UI
  18. UI Build Pipeline
  19. Put the UI in to Helm
  20. Creating an Ingress in Kubernetes
  21. Simplify Deployment
  22. Conclusion and Review

Lets take the docker image we just created and wrap it with helm so that we have an easy way to deploy our application.

Create Helm Chart Templates

We’ve created helm charts before, so lets create a helm directory at the frontend root. Then run helm create in that directory

helm create medium-customer-manager

That should build out more than we need. We really only need a few files:

templates/deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: "{{  .Chart.Name }}-deployment"
  labels:
    chart: '{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}'
spec:
  replicas: {{ .Values.replicaCount }}
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 0
      maxSurge: 1
  selector:
    matchLabels:
      app: "{{  .Chart.Name }}-selector"
      version: "current"
  template:
    metadata:
      labels:
        app: "{{  .Chart.Name }}-selector"
        version: "current"
    spec:
      imagePullSecrets:
        - name: regcred
      containers:
        - name: "{{  .Chart.Name  }}"
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          volumeMounts:
            - name: data
              mountPath: /data
            {{- if and (eq .Values.config.type "file") (hasKey .Values.config "content") }}
            - name: config-file
              mountPath: /usr/share/nginx/html/config.js
              subPath: config.js
            {{- end }}
          ports:
            - name: http
              containerPort: {{ .Values.containerPort }}
              protocol: TCP
          env:
            - name: PORT
              value : "{{ .Values.service.servicePort }}"
      volumes:
        - name: data
          emptyDir: {}
        {{- if and (eq .Values.config.type "file") (hasKey .Values.config "content") }}
        - name: config-file
          configMap:
            name: {{ .Chart.Name }}-config
        {{- end }}

template/service.yaml

apiVersion: v1
kind: Service
metadata:
  annotations:
    prometheus.io/scrape: 'true'
  name: "{{  .Chart.Name }}-service"
  labels:
    chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
spec:
  type: {{ .Values.service.type }}
  ports:
  - name: http
    port: {{ .Values.service.httpPort }}
    targetPort: http
  {{- if hasKey .Values.service "nodePort" }}
    nodePort: {{ .Values.service.nodePort }}
  {{- end }}
  selector:
    app: "{{  .Chart.Name }}-selector"

template/customer-manager-configmap.yaml

{{- if and ( eq .Values.config.type "file") (hasKey .Values.config "content") }}
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Chart.Name }}-config
  namespace: {{ .Release.Namespace | quote }}
data:
  config.js:
    {{ toYaml .Values.config.content | indent 4  }}
{{- end }}

Chart.yaml

apiVersion: v2
name: medium-customer-manager
description: A Helm chart for Kubernetes
type: application
version: 1.0.0

values.yaml

# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
replicaCount: 1
image:
  repository: r.cfcr.io/docketdynamics/medium-customer-manager
  tag: "5556008"
  pullPolicy: IfNotPresent
containerPort: 80
service:
  enabled: true
  httpPort: 80
  nodePort: 30002
  type: NodePort

config:
## Currently only supports file
type: file
## Contents of config in YAML
content: |-
    window.REACT_APP_CUSTOMER_HOST='http://172.18.51.90/:30001'

Again, you can see that we’re hardcoding in our customer host, which isn’t ideal, but it will get us moving forward. We’ll eventually replace that with an ingress.

The only interesting part is how we’re writing the configuration. We’re following a similar pattern to the spring app where we write a configmap and then use the configmap to write out a configuration file into the pod.

Which reminds me that we need to update our front end application to support that.

Create public/config.js

window.REACT_APP_CUSTOMER_HOST='HTTP://localhost:10000'

which is a placeholder file that will eventually be overwritten. Again, this isn’t how we’re going to solve our long term problem, but it will allow us to deploy and test.

Deploy and Test

Deploy our front end with

helm install cust-mgr helm/medium-customer-manager

Which should find our image we just build in the last section. We can hit our application at http://<minikube ip>:30002/

Helm Chart Packaging and Publishing

Lets add the automation to the pipeline to package the helm chart and publish to our chart registry. Add these steps to the pipeline:

stages:
...
- "helmpublish"
...
  HelmChartGetVersion:
    title: Get Helm Chart Version
    stage: helmpublish
    image: codefresh/cfstep-helm
    working_directory: '/codefresh/volume/medium-customer-manager'
    environment:
      - CHART_PATH=helm/medium-customer-manager
      - CHART_NAME=medium-customer-manager
    commands:
      - export ACTION=auth
      - source /opt/bin/release_chart
      - helm repo add default ${{CF_CTX_CF_HELM_DEFAULT_URL}}
      - yq .version ${CHART_PATH}/Chart.yaml
      - export CURRENT_CHART_VERSION=`helm search default/${CHART_NAME} | awk 'FNR==2{print $2}' || yq .version ${CHART_PATH}/Chart.yaml`
      - echo $CURRENT_CHART_VERSION
      - cf_export NEW_CHART_VERSION=`echo "${CURRENT_CHART_VERSION}" | awk -F. '{$NF = $NF + 1;} 1' | sed 's/ /./g'`
      - echo $NEW_CHART_VERSION
  HelmChartUpdate:
    title: Update Helm Chart Version
    stage: helmpublish
    image: gksoftware/yq
    working_directory: '/codefresh/volume/medium-customer-manager'
    environment:
      - CHART_PATH=helm/medium-customer-manager
      - YAML_PATH=image.tag
    commands: 
      - echo $NEW_CHART_VERSION
      - yq w -i ${CHART_PATH}/Chart.yaml version ${NEW_CHART_VERSION}
      - echo $CF_SHORT_REVISION
      - yq w -i ${CHART_PATH}/values.yaml ${YAML_PATH} '"${{CF_SHORT_REVISION}}"'
  HelmChartPush:
      title: Push Helm Chart to Chart Repository
      stage: helmpublish
      image: codefresh/cfstep-helm
      working_directory: '/codefresh/volume/medium-customer-manager'
      environment:
        - CHART_REF=helm/medium-customer-manager/
        - ACTION=push

Make sure to add the helm registry as and environment variable to your build so that the pipeline can publish the chart.

Commit

git checkout -b helm
git add .
git commit -m "helm chart"
git push
git checkout master
git merge helm
git push

0 comments on “Put the UI in to HelmAdd yours →

Leave a Reply

Your email address will not be published. Required fields are marked *