7.1 Refactor 1

Task 7.1.1: Make the Ingress resource more configurable

After cloning the repository and inspecting the templates already created for you, you will notice some potential for improvement. For example the hostname of the applications should not be hard-coded. When deploying to multiple environments you will run into conflicts.

Modify the consumer and producer ingress templates and extract following variables to make them configurable:

  • Extract .spec.rules.host as value
  • Extract .spec.tls.hosts[0] as value, use the same value as above

First let us define the new variables in our values.yaml file. Replace <username> with your username

producer:
  host: producer-<username>.labapp.acend.ch

consumer:
  tag: latest
  host: consumer-<username>.labapp.acend.ch

Next replace the hard coded values for the host value in our consumer-ingress.yaml file.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/tls-acme: "true"
  labels:
    app: {{ include "helm-basic-chart.fullname" . }}-consumer
  name: {{ include "helm-basic-chart.fullname" . }}-consumer
spec:
  rules:
    - host: {{ .Values.consumer.host }}
      http:
        paths:
          - backend:
              service:
                name: {{ include "helm-basic-chart.fullname" . }}-consumer
                port:
                  number: 8080
            path: /
            pathType: ImplementationSpecific
  tls:
    - hosts:
        - {{ .Values.consumer.host }}
      secretName: consumer-labapp-acend-ch

Replace the same value in our producer-ingress.yaml file.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/tls-acme: "true"
  labels:
    app: {{ include "helm-basic-chart.fullname" . }}-producer
  name: {{ include "helm-basic-chart.fullname" . }}-producer
spec:
  rules:
    - host: {{ .Values.producer.host }}
      http:
        paths:
          - backend:
              service:
                name: {{ include "helm-basic-chart.fullname" . }}-producer
                port:
                  number: 8080
            path: /
            pathType: ImplementationSpecific
  tls:
    - hosts:
        - {{ .Values.producer.host }}
      secretName: producer-labapp-acend-ch

Afterwards we can install our Helm Chart with following command.

helm upgrade -i myrelease --namespace $USER ./helm-basic-chart

Verify your deployment! Check if your pods are running and healthy!

kubectl get pods

This should return something like this:

kubectl get pods
NAME                             READY   STATUS    RESTARTS   AGE
data-consumer-7686976d88-2wbh5   1/1     Running   0          72s
data-producer-786d6bb688-qpg4c   1/1     Running   0          72s

Pay attention to the 1/1 status in the ready section! After checking if our pods are ready and therefore will accept traffic from the service, check if the application is running correctly:

Both applications (data-producer and data-consumer) you just deployed expose an endpoint /data which will return a random double data json. Try to verify if your deployment is running correctly by using curl.

Hint 1

If you are struggling with curl you can use the following syntax:

curl http(s)://HOST

When the problem will be a redirect or certificate problem, try the flags -L and -k to mitigate the error.

Solution

curl -kL $(kubectl get ingress <releasename>-consumer --template="{{(index .spec.rules 0).host}}")/data
{"data":0.15495350024595755}

If your application returns the data point when consuming the consumers /data endpoint, then both applications work.

Task 7.1.2: Make the deployments more configurable

Not just the ingresses could use some improvements. Also the deployments could be more configurable. In order to keep up to date with the current requirements your task is to adapt the following things:

Producer Deployment:

  • Extract the image tag from the .spec.containers[0].image on Line 22 field as value
  • Extract the .spec.containers[0].resources block from line 51 as value consumer.resources. Make use of the toYaml and the nindent function.
  • Extract the .spec.containers[0].env["QUARKUS_LOG_LEVEL"] on line 26 block as value

Consumer Deployment:

  • Extract the .spec.containers[0].resources block from line 51 as value producer.resources. Make use of the toYaml and the nindent function.
  • Extract the .spec.containers[0].env["QUARKUS_LOG_LEVEL"] on line 26 block as value producer.logLevel
Solution

producer-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: {{ include "helm-basic-chart.fullname" . }}-producer
  name: {{ include "helm-basic-chart.fullname" . }}-producer
spec:
  replicas: 1
  selector:
    matchLabels:
      deployment: {{ include "helm-basic-chart.fullname" . }}-producer
      app: {{ include "helm-basic-chart.fullname" . }}-producer
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        deployment: {{ include "helm-basic-chart.fullname" . }}-producer
        app: {{ include "helm-basic-chart.fullname" . }}-producer
    spec:
      containers:
        - image: quay.io/puzzle/quarkus-techlab-data-producer:{{ .Values.producer.tag }}
          imagePullPolicy: Always
          env:
          - name: QUARKUS_LOG_LEVEL
            value: {{ .Values.producer.logLevel }}
          livenessProbe:
            failureThreshold: 5
            httpGet:
              path: /health/live
              port: 8080
              scheme: HTTP
            initialDelaySeconds: 3
            periodSeconds: 20
            timeoutSeconds: 15
          readinessProbe:
            failureThreshold: 5
            httpGet:
              path: /health/ready
              port: 8080
              scheme: HTTP
            initialDelaySeconds: 3
            periodSeconds: 20
            timeoutSeconds: 15
          name: data-producer
          ports:
            - containerPort: 8080
              name: http
              protocol: TCP
          resources:
            {{- toYaml .Values.producer.resources | nindent 12 }}

consumer-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: {{ include "helm-basic-chart.fullname" . }}-consumer
  name: {{ include "helm-basic-chart.fullname" . }}-consumer
spec:
  replicas: 1
  selector:
    matchLabels:
      deployment: {{ include "helm-basic-chart.fullname" . }}-consumer
      app: {{ include "helm-basic-chart.fullname" . }}-consumer
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        deployment: {{ include "helm-basic-chart.fullname" . }}-consumer
        app: {{ include "helm-basic-chart.fullname" . }}-consumer
    spec:
      containers:
        - image: quay.io/puzzle/quarkus-techlab-data-consumer:{{ .Values.consumer.tag }}
          imagePullPolicy: Always
          env:
          - name: QUARKUS_LOG_LEVEL
            value: {{ .Values.consumer.logLevel }}
          - name: DATA_PRODUCER_API_MP_REST_URL
            value: http://{{ include "helm-basic-chart.fullname" . }}-producer:8080
          livenessProbe:
            failureThreshold: 5
            httpGet:
              path: /health/live
              port: 8080
              scheme: HTTP
            initialDelaySeconds: 3
            periodSeconds: 20
            timeoutSeconds: 15
          readinessProbe:
            failureThreshold: 5
            httpGet:
              path: /health/ready
              port: 8080
              scheme: HTTP
            initialDelaySeconds: 3
            periodSeconds: 20
            timeoutSeconds: 15
          name: data-consumer
          ports:
            - containerPort: 8080
              name: http
              protocol: TCP
          resources:
            {{- toYaml .Values.consumer.resources | nindent 12 }}

values.yaml

producer:
  host: producer-<username>.labapp.acend.ch
  logLevel: DEBUG
  resources:
    limits:
      cpu: '1'
      memory: 500Mi
    requests:
      cpu: 50m
      memory: 100Mi
  tag: latest

consumer:
  logLevel: DEBUG
  host: consumer-<username>.labapp.acend.ch
  resources:
    limits:
      cpu: '1'
      memory: 500Mi
    requests:
      cpu: 50m
      memory: 100Mi
  tag: latest

Task 7.1.3: Upgrade the chart

Execute following command to update our helm release.

helm upgrade myrelease --namespace $USER ./helm-basic-chart

Finally, you can visit your application with the URL provided from the Route: https://consumer-<username>.training.cluster.acend.ch/data

Or you could access the data endpoint using curl:

curl -kL $(kubectl get ingress <releasename>-consumer --template="{{(index .spec.rules 0).host}}")/data

When you open the URL you should see the producers data

{"data":0.6681209742895893}

If you only see Your new Cloud-Native application is ready!, then you forgot to append the /datapath to the URL.

Task 7.1.4: Prepare another release

At this point we have a configurable Helm chart and a running release. Next we gonna use the cart for another release. We consider to release it into a production environment. therefore we have to adjust some values. First copy the existing values.yaml to values-production.yaml.

.
├── Readme.md
└── helm-basic-chart
    ├── Chart.yaml
    ├── templates
    │   ├── helpers.tpl
    │   ├── consumer-deployment.yaml
    │   ├── consumer-ingress.yaml
    │   ├── consumer-service.yaml
    │   ├── producer-deployment.yaml
    │   ├── producer-ingress.yaml
    │   ├── producer-service.yaml
    │   └── tests
    │       └── test-connection.yaml
    ├── values-production.yaml
    └── values.yaml

Open the values-production.yaml and change following values.

  • Debug log level is too high in a production environment, change it to INFO
  • The resource requirements are usually higher in a production environment than in a development environment. Increase the Memory Limits to 750Mi
  • To avoid DNS collisions we need to chang the host to, change it to producer-<username>-prod.training.cluster.acend.ch and consumer-<username>-prod.training.cluster.acend.ch
Solution

values-production.yaml

producer:
  host: producer-<username>-prod.labapp.acend.ch
  logLevel: INFO
  resources:
    limits:
      cpu: '1'
      memory: 750Mi
    requests:
      cpu: 50m
      memory: 100Mi
  tag: latest

consumer:
  logLevel: INFO
  host: consumer-<username>-prod.labapp.acend.ch
  resources:
    limits:
      cpu: '1'
      memory: 750Mi
    requests:
      cpu: 50m
      memory: 100Mi
  tag: latest

Task 7.1.6: Install and verify production release

Now we have prepared our values file for the production environment. Next we can install the chart again, but with a different name and different values. Execute the Helm install command and pass the new created production values as parameter.

helm upgrade -i myrelease-prod --values values-production.yaml --namespace $USER ./helm-basic-chart

Use the helm list command to list all releases in your namespace

helm ls --namespace $USER

You should see following output with de development and the production release

NAME            NAMESPACE       REVISION        UPDATED                                         STATUS          CHART                   APP VERSION
myrelease       default         1               2022-05-19 13:26:56.278026261 +0200 CEST        deployed        helm-basic-chart-0.1.0  1.16.0
myrelease-prod  default         1               2022-05-19 13:26:36.570013792 +0200 CEST        deployed        helm-basic-chart-0.1.0  1.16.0

Task 7.1.7: Cleanup

helm uninstall myrelease --namespace $USER
helm uninstall myrelease-prod --namespace $USER