Custom Default Backend

Wir erstellen ein Default Backend für den gesamten Microk8s Cluster

Custom Default Backend Dockerfile

Docker Image für das Custom default Backend mit Certbot für Letsencypt


  FROM nginx:alpine

  RUN apk update
  RUN apk add certbot nano
  
  COPY ./html /usr/share/nginx/html
  
  COPY secret-patch-template.json /
  COPY deployment-patch-template.json /
  COPY entrypoint.sh /
  
  RUN chmod +x /entrypoint.sh
  
  #CMD ["sh","/entrypoint.sh"]

PHP 7.2 fpm App Dockerfile

Docker Image für PHP 7.2 mit Mysql und GD Extensions

FROM php:7.2-fpm

RUN apt-get update && apt-get install -y \
		libfreetype6-dev \
		libjpeg62-turbo-dev \
		libpng-dev \
	&& docker-php-ext-configure gd  \
	&& docker-php-ext-install -j$(nproc) gd

RUN docker-php-ext-install mysqli pdo pdo_mysql

RUN mkdir /app
COPY hello.php /app

Config Map

Configuration für den Nginx Server

  apiVersion: v1
  kind: ConfigMap
  metadata:
    annotations:
    name: nginx-config
    namespace: default
  data:
    default.conf: |
      map $http_upgrade $connection_upgrade {
        default upgrade;
        '' close;
      }
      # Add upstream for letsencrypt job
      #upstream letsencrypt {
      #  server letsencrypt:80 max_fails=0 fail_timeout=1s;
      #}
      server {
      listen 80 default_server;
      listen [::]:80 default_server;
  
      root /usr/share/nginx/html;
      index index.html index.php index.htm index.nginx-debian.html;
  
      server_name YOURDOMAIN.COM;
  
      location / {
          try_files $uri $uri/ =404;
      }
      location ~ \.php$ {
            include fastcgi_params;
            fastcgi_param REQUEST_METHOD $request_method;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_pass 127.0.0.1:9000;
      }
      # Redirect all traffic in /.well-known/ to letsencrypt
      location ^~ /.well-known/acme-challenge/ {
          try_files $uri $uri/ =404;
          #proxy_pass http://letsencrypt;
      }
      location /sensors/export/data {
       autoindex on;
      }
      }  

Persistent Storage Klasse

Das Custom Default Backend mit Persistentem Volume dient als Frontend für den gesamten Cluster

Persistent Storage Klassen sind global und könnenn in jedem Namespace benutzt werden

  apiVersion: storage.k8s.io/v1
  kind: StorageClass
  metadata:
    name: custom
  provisioner: kubernetes.io/no-provisioner
  volumeBindingMode: WaitForFirstConsumer  

Persistent Volume

Das persistente Storage erstellt einen bleibenden Datenspeicher, in diesem Falle ein Verzeichnis (/mnt/data/custom-default-backend) auf dem Cluster

Dieser Datenspeicher bleibt nach dem Löschen und erneuten Deployen erhalten.

Persistent Volumes sind global und können in jedem Namespace benutzt werden

  kind: PersistentVolume
  apiVersion: v1
  metadata:
    name: custom-default-backend
    labels:
      type: local
  spec:
    storageClassName: custom
    capacity:
     storage: 5Gi
    accessModes:
      - ReadWriteOnce
    hostPath:
      path: "/mnt/data/custom-default-backend"
      type: DirectoryOrCreate 

Persistent Volume Claim

Ein Persistent Volume Claim legt fest, welcher Datenspeicher von welchem Deploment benutzt wird

Persistent Volume Claims sind NICHT global und können von Deployments im gleichen Namespace benutzt werden

  apiVersion: v1
  kind: PersistentVolumeClaim
  metadata:
    name: custom-default-backend-pvc
  spec:
    accessModes:
    - ReadWriteOnce
    resources:
      requests:
        storage: 1Gi
    storageClassName: custom

Deployment

Dieses Deployment nutzt den persistenen Datenspeicher custom-default-backend-pv und bleibt erhalten

  apiVersion: apps/v1
  kind: Deployment
  metadata:
    name: custom-default-backend
    labels:
      app: custom-default-backend #Service Selector
  spec:
    replicas: 1
    selector:
      matchLabels:
        app: custom-default-backend
    template:
      metadata:
        labels:
          app: custom-default-backend
      spec:
        containers:
        - name: phpapp
          image: localhost:32000/my-php-app:1.0 #php 7.3 fpm im selben Container
          volumeMounts:
          - name: docroot
            mountPath: /usr/share/nginx/html
        - name: custom-default-backend
          image: localhost:32000/custom-default-backend:1.0
          imagePullPolicy: Always
          ports:
          - containerPort: 8080
          volumeMounts:
          - name: nginx-configs
            mountPath: /etc/nginx/conf.d
          - name: docroot
            mountPath: /usr/share/nginx/html
        # Load the configuration files for nginx
        volumes:
          - name: nginx-configs
            configMap:
              name: nginx-config
          - name: docroot
            persistentVolumeClaim:
              claimName: custom-default-backend-pvc
              readOnly: false

Service

  apiVersion: v1
  kind: Service
  metadata:
    annotations:
    name: custom-default-backend-svc
  spec:
    type: ClusterIP
    selector: 
      app: custom-default-backend
    ports:
    - port: 8080
      targetPort: 80
      name: http

Der Ingress sieht wie folgt aus:

  apiVersion: networking.k8s.io/v1
  kind: Ingress
  metadata:
    annotations:
      kubernetes.io/ingress.class: public
      nginx.ingress.kubernetes.io/rewrite-target: /
    name: custom-default-backend-ingress
  spec:
    tls:
    - hosts:
        -  YOURDOMAIN.COM
      secretName: letsencrypt-tls
    defaultBackend:
      service:
        name: custom-default-backend-svc
        port:
          number: 80
    rules:
      - host: YOURDOMAIN.COM
        http:
          paths:
            - path: /
              pathType: Prefix
              backend:
                service:
                  name: custom-default-backend-svc
                  port: 
                   number: 80

secret-patch-template.json

  {
    "kind": "Secret",
    "apiVersion": "v1",
    "metadata": {
        "name": "NAME",
        "namespace": "NAMESPACE"
    },
    "data": {
       "tls.crt": "TLSCERT",
       "tls.key": "TLSKEY"
    }
}

deployment-patch-template.json

  {
    "kind": "Deployment",
    "apiVersion": "apps/v1",
    "metadata": {
        "name": "NAME",
        "namespace": "NAMESPACE"
    },
    "spec": {
        "template": {
            "metadata": {
                "annotations": {
                    "tlsUpdated": "TLSUPDATED"
                }
            }
        }
    }
  }

entrypoint.sh

  #!/bin/bash

  if [[ -z $EMAIL || -z $DOMAINS || -z $SECRET ]]; then
          echo "EMAIL, DOMAINS, and SECRET env vars required"
          env
          exit 1
  fi
  echo "Inputs:"
  echo " EMAIL: $EMAIL"
  echo " DOMAINS: $DOMAINS"
  echo " SECRET: $SECRET"
  
  DEPLOYMENT=custom-default-backend
  NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)
  echo "Current Kubernetes namespce: $NAMESPACE"
  
  
  echo "Starting certbot..."
  certbot certonly --webroot -w /usr/share/nginx/html -n --agree-tos --email ${EMAIL} --no-self-upgrade -d ${DOMAINS}
  echo "Certbot finished..."
  
  echo "Finiding certs. Exiting if certs are not found ..."
  CERTPATH=/etc/letsencrypt/live/$(echo $DOMAINS | cut -f1 -d',')
  ls $CERTPATH || exit 1
  
  echo "Creating update for secret..."
  cat /secret-patch-template.json | \
          sed "s/NAMESPACE/${NAMESPACE}/" | \
          sed "s/NAME/${SECRET}/" | \
          sed "s/TLSCERT/$(cat ${CERTPATH}/fullchain.pem | base64 | tr -d '\n')/" | \
          sed "s/TLSKEY/$(cat ${CERTPATH}/privkey.pem |  base64 | tr -d '\n')/" \
          > /secret-patch.json
  
  echo "Checking json file exists. Exiting if not found..."
  ls /secret-patch.json || exit 1
  
  # Update Secret
  echo "Updating secret..."
  curl \
    --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt \
    -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
    -XPATCH \
    -H "Accept: application/json, */*" \
    -H "Content-Type: application/strategic-merge-patch+json" \
    -d @/secret-patch.json https://kubernetes/api/v1/namespaces/${NAMESPACE}/secrets/${SECRET} \
    -k -v
  echo "Done"
  
  
  cat /deployment-patch-template.json | \
          sed "s/TLSUPDATED/$(date)/" | \
          sed "s/NAMESPACE/${NAMESPACE}/" | \
          sed "s/NAME/${DEPLOYMENT}/" \
          > /deployment-patch.json
  
  ls /deployment-patch.json || exit 1
  
  # update pod spec on ingress deployment to trigger redeploy
  curl -v --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" -k -v -XPATCH  -H "Accept: application/json, */*" -H "Content-Type: application/strategic-merge-patch+json" -d @/deployment-patch.json https://kubernetes/apis/apps/v1/namespaces/${NAMESPACE}/deployments/${DEPLOYMENT}