Overview

In this step, we will create Kubernetes manifests to deploy our FastAPI application locally using Minikube.

We'll configure various components, including namespaces, deployments, services, secrets, config maps, and ingress routes, to ensure our application runs smoothly within a Kubernetes environment.

Documentation provides basic but not comprehensive instruction. Kubernetes has a wide range of possibilities, resources and functionality.
For deeper information and possible configuration options, please refer to official documentation → https://kubernetes.io/docs/home/

Requirements:

Artifacts:

For the purpose of this tutorial we will be using this artifacts repository: https://gitlab.portaone.com:8949/read-only/tutorial-for-simple-application

Documentation Variables:

The documentation contains custom variables:

  • <application_name>
  • <application_version>
  • <personal dockerhub repository>

For details related to variables meaning, please refer => Guide to deploy application in Add-On Mart for third-party developers

1. Create Kubernetes Namespace

Purpose:
Namespaces in Kubernetes provide a way to logically partition a cluster, allowing for the isolation and management of resources.

Explanation:

  • apiVersion: v1: Specifies the Kubernetes API version for the resource.
  • kind: Namespace: Indicates that we are creating a namespace.
  • metadata: name: <application_name>-ns: Names the namespace <application_name>-ns.

1.1 Create Namespace Manifest:

Create a file named namespace.yaml in the Manifests_local directory with the following content:

apiVersion: v1
kind: Namespace
metadata:
  name: <application_name>-ns

1.2 Apply Namespace Manifest:

> kubectl apply -f ./Manifests_local/namespace.yaml

1.3 Verify Namespace Creation:

Check if the namespace was created:

> kubectl get namespaces | grep "<application_name>"
<application_name>-ns       Active   44s

2. Deploy Application

Purpose:
Deploying the application creates a running instance of your containerized application in the Kubernetes cluster.

This step defines how the application should run, including the number of replicas, container images, and ports.

Explanation:

  • apiVersion: apps/v1: Specifies the API version for deployment resources.
  • kind: Deployment: Indicates that we are creating a deployment resource.
  • metadata: name: <application_name>: Names the deployment <application_name>.
  • namespace: <application_name>-ns: Specifies the namespace for the deployment.
  • spec: replicas: 1: Defines the number of pod replicas.
  • template: spec: containers: Specifies the container image and ports.

2.1 Create Deployment Manifest:

Create a file named deployment.yaml in the Manifests_local directory with the following content:

Change <personal dockerhub repository> with appropriate repository name

./Manifests_local/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: <application_name>
  namespace: <application_name>-ns
spec:
  replicas: 1
  selector:
    matchLabels:
      app: <application_name>
  template:
    metadata:
      labels:
        app: <application_name>
    spec:
      containers:
      - name: <application_name>
        image: <personal dockerhub repository>/<application_name>:<application_version>
        ports:
        - name: http
          containerPort: 8000
          protocol: TCP

2.2 Apply Deployment Manifest:

Apply the manifest to deploy the application:

> kubectl apply -f ./Manifests_local/deployment.yaml
deployment.apps/<application_name> created

2.3 Verify Deployment:

Check if the deployment was created:

> kubectl get -n <application_name>-ns deployment
NAME       READY   UP-TO-DATE   AVAILABLE   AGE
<application_name>   1/1     1            1           17s

2.4 Verify Pod Status:

Check if the pod is running:

> kubectl get -n <application_name>-ns pod
NAME                        READY   STATUS    RESTARTS   AGE
<application_name>-7f6cf9c5cb-kpn52   1/1     Running   0          29s

3. Create Kubernetes Service

Purpose:
A Kubernetes Service enables network access to a set of pods. In this step, we create a service to expose the application and allow traffic to reach it

Explanation:

  • apiVersion: v1: Specifies the API version for the service.
  • kind: Service: Indicates that we are creating a service.
  • metadata: name: <application_name>: Names the service <application_name>.
  • spec: type: ClusterIP: Defines the service type as ClusterIP, making it accessible only within the cluster.
  • ports: port: 8888, targetPort: 8000: Maps port 8888 on the service to port 8000 on the pod.

3.1 Create Service Manifest:

Create a file named service.yaml in the Manifests_local directory with the following content:

./Manifests_local/service.yaml
apiVersion: v1
kind: Service
metadata:
  namespace: <application_name>-ns
  name: <application_name>
spec:
  type: ClusterIP
  selector:
    app: <application_name>
  ports:
    - name: http
      protocol: TCP
      port: 8888
      targetPort: 8000

3.2 Apply Service Manifest:

Apply the manifest to create the service:

> kubectl apply -f ./Manifests_local/service.yaml
service/<application_name> created

3.3 Verify Service Creation:

Check if the service was created:

> kubectl get -n <application_name>-ns svc
NAME       TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
<application_name>   ClusterIP   10.99.87.35   <none>        8888/TCP   6s

4. Configure Environment Variables

Purpose:
Environment variables allow us to configure the application without changing the code. We can set variables like configuration paths, custom settings, and more.

Explanation:

  • env: Specifies environment variables to be used in the container.
  • name: CONFIG_PATH, value: /app/config.yaml: Sets the path to the configuration file.
  • name: BASE_PATH, value: /: Sets the base path for the application.
  • name: CUSTOM_ENV_VARIABLE, value: "deployed_env_value": Defines a custom environment variable.

4.1 Extend Deployment Manifest with Environment Variables:

Update the deployment.yaml file to include environment variables:

Change <personal dockerhub repository> with appropriate repository name

./Manifests_local/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: <application_name>
  namespace: <application_name>-ns
spec:
  replicas: 1
  selector:
    matchLabels:
      app: <application_name>
  template:
    metadata:
      labels:
        app: <application_name>
    spec:
      containers:
      - name: <application_name>
        image: <personal dockerhub repository>/<application_name>:<application_version>
        ports:
        - name: http
          containerPort: 8000
          protocol: TCP
        env:                                     # new code line 
          - name: CONFIG_PATH                    # new code line
            value: /app/config.yaml              # new code line
          - name: BASE_PATH					  # new code line
            value: /						     # new code line
          - name: CUSTOM_ENV_VARIABLE  		     # new code line
            value: "deployed_env_value"		     # new code line

4.2 Redeploy Application:

Apply the updated deployment manifest:

> kubectl apply -f ./Manifests_local/deployment.yaml

4.3 Enable port forwarding:

Open new terminal window (you will need to keep it open to keep forwarding in place) and forward port with following command:

The service we created in step 3 facilitates networking features for our application but is not exposed to traffic outside of the cluster yet. Later we will use Traefik to deliver outside connectivity, but for now we will use port forwarding.

> kubectl -n <application_name>-ns port-forward svc/<application_name> 8888:8888
Forwarding from 127.0.0.1:8888 -> 8000
Forwarding from [::1]:8888 -> 8000

4.4 Test environment variables:

Request
curl -X 'GET' 'http://127.0.0.1:8888/environment_variables' | jq . | grep -E "CONFIG_PATH|BASE_PATH|CUSTOM_ENV_VARIABLE"
Response
"BASE_PATH": "/",
"CUSTOM_ENV_VARIABLE": "deployed_env_value",
"CONFIG_PATH": "/app/config.yaml",

5. Create ConfigMap

Purpose:
A ConfigMap stores configuration data in key-value pairs. It allows us to decouple specific configurations from application code.

For our deployment, we will overwrite the config.yaml file in the image with a new version containing slightly different content.

To verify that the configuration file stored in the image has been successfully overwritten, we will introduce a new value for configuration parameters in the ConfigMap manifest.

5.1 Create ConfigMap Manifest:

Create a file named config-cm.yaml in the Manifests_local directory with the following content:

Explanation:

  • apiVersion: v1: Specifies the API version for the ConfigMap.
  • kind: ConfigMap: Indicates that we are creating a ConfigMap.
  • metadata: name: <application_name>-config: Names the ConfigMap <application_name>-config.
  • data: config-cm.yaml: Stores the configuration file as data within the ConfigMap.
./Manifests_local/config-cm.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: <application_name>-config
  namespace: <application_name>-ns
  labels:
data:
  config.yaml: |
    SERVER_URL: "https://jsonplaceholder.typicode.com/users"
    CONFIG_OPTION: "deployed config value"

5.2 Apply ConfigMap Manifest:

Apply the manifest to create the ConfigMap:

> kubectl apply -f ./Manifests_local/config-cm.yaml
configmap/<application_name>-config created

5.3 Verify ConfigMap Creation:

Check if the ConfigMap was created:

> kubectl get -n <application_name>-ns cm
NAME                DATA   AGE
<application_name>-config     1      18s

5.4 Mount ConfigMap to Deployment:

Update the deployment.yaml file to mount the ConfigMap:

Explanation:

  • volumeMounts: Mounts the ConfigMap as a volume in the container.
  • mountPath: /app/config.yaml: Specifies the path where the config file will be mounted.
  • subPath: config.yaml: Indicates the file name within the volume to mount a specific file (config.yaml) from the ConfigMap instead of the entire volume.
  • volumes: configMapDefines the volume available to the containers in the pod. Volume is sourced from configMap.
./Manifests_local/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: <application_name>
  namespace: <application_name>-ns
spec:
  replicas: 1
  selector:
    matchLabels:
      app: <application_name>
  template:
    metadata:
      labels:
        app: <application_name>
    spec:
      containers:
      - name: <application_name>
        image: <personal dockerhub repository>/<application_name>:<application_version>
        ports:
        - name: http
          containerPort: 8000
          protocol: TCP
        env:
          - name: CONFIG_PATH
            value: /app/config.yaml
          - name: BASE_PATH
            value: /
          - name: CUSTOM_ENV_VARIABLE
            value: "deployed_env_value"
        volumeMounts:							    # new code line
        - name: config-vol						    # new code line
          mountPath: /app/config.yaml			    # new code line
          subPath: config.yaml					    # new code line
      volumes:									    # new code line
        - name: config-vol						    # new code line
          configMap:							    # new code line
            name: <application_name>-config		  # new code line

5.5 Redeploy Application:

Apply the updated deployment manifest:

> kubectl apply -f ./Manifests_local/deployment.yaml

5.6 Test

Make sure  Port Forwarding command is still running

Trigger /config_values endpoint  

Request
curl -X 'GET' 'http://127.0.0.1:8888/config_values' | jq .
Response
{
  "SERVER_URL": "https://jsonplaceholder.typicode.com/users",
  "CONFIG_OPTION": "deployed config value"
}

6. Create Secret

Purpose:
Secrets in Kubernetes are used to store sensitive information such as passwords, tokens, or keys. By using secrets, we ensure that sensitive data is handled securely within the cluster.

6.1 Create Secret Manifest:

Create a file named secret.yaml in the Manifests_local directory with the following content:

Explanation:

  • apiVersion: v1: Specifies the API version for the secret.
  • kind: Secret: Indicates that we are creating a secret.
  • metadata: name: <application_name>-secret: Names the secret <application_name>-secret.
  • type: Opaque: Defines the secret type as opaque, which is a generic type for arbitrary user-defined data.
  • stringData: Allows you to provide secret data as plain strings (Kubernetes will handle the encoding).
  • data: Contains the base64-encoded data. Use this when data needs to be pre-encoded.
./Manifests_local/secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: <application_name>-secret
  namespace: <application_name>-ns
type: Opaque
stringData:
  SECRET_USERNAME: "username"
  SECRET_PASSWORD: "s_password"
data:
  SECRET_BASE_64_ENCODED: VGhpcyBzdHJpbmcgd2FzIGVuY29kZWQgdXNpbmcgYmFzZTY0

6.2 Apply Secret Manifest:

Apply the manifest to create the secret:

> kubectl apply -f ./Manifests_local/secret.yaml
secret/<application_name>-secret created

6.3 Verify Secret Creation:

Check if the secret was created:

> kubectl get -n <application_name>-ns secret
NAME                   TYPE     DATA   AGE
<application_name>-secret        Opaque   3      20s

6.4 Update Deployment to Use Secret:

Update the deployment.yaml file to include the secret:

Explanation:

  • envFrom: secretRef: Pulls environment variables from the specified secret.

Change <personal dockerhub repository> with appropriate repository name

./Manifests_local/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: <application_name>
  namespace: <application_name>-ns
spec:
  replicas: 1
  selector:
    matchLabels:
      app: <application_name>
  template:
    metadata:
      labels:
        app: <application_name>
    spec:
      containers:
      - name: <application_name>
        image: <personal dockerhub repository>/<application_name>:<application_version>
        ports:
        - name: http
          containerPort: 8000
          protocol: TCP
        env:
          - name: CONFIG_PATH
            value: /app/config.yaml
          - name: BASE_PATH
            value: /
          - name: CUSTOM_ENV_VARIABLE
            value: "deployed_env_value"
        envFrom:										# new code line
          - secretRef:								    # new code line
              name: <application_name>-secret		      # new code line
        volumeMounts:
        - name: config-vol
          mountPath: /app/config.yaml
          subPath: config.yaml
      volumes:
        - name: config-vol
          configMap:
            name: <application_name>-config

6.5 Redeploy Application:

Apply the updated deployment manifest:

> kubectl apply -f ./Manifests_local/deployment.yaml
deployment.apps/<application_name> configured

6.7 Test:

Make sure  Port Forwarding command is still running

Trigger the secret endpoint:

Request
 curl -X 'GET' 'http://127.0.0.1:8888/environment_variables' | jq . | grep -E 'SECRET_BASE_64_ENCODED|SECRET_PASSWORD|SECRET_USERNAME'
Response
 
  "SECRET_BASE_64_ENCODED": "This string was encoded using base64",
  "SECRET_PASSWORD": "s_password",
  "SECRET_USERNAME": "username"

7. Configure Ingress with Traefik

Purpose:
Traefik is an ingress controller that manages external access to services within a Kubernetes cluster. In this step, we'll configure Traefik to route traffic to our application.

Add-On Mart infrastructure uses Traefik Ingress Controller. If you plan to deploy applications on Add-On Mart infrastructure, do not choose other providers.

7.1 Configure Traefik:

Follow instructions → Step 0: Pre-requisites - make sure you have Minikube and Traefik installed

7.2 Create IngressRoute Manifest for HTTP:

Create a file named ingressroute.yaml in the Manifests_local directory with the following content:

Explanation:

  • apiVersion: traefik.containo.us/v1alpha1: Specifies the API version for Traefik's custom resources.
  • kind: IngressRoute: Indicates that we are creating an IngressRoute resource.
  • metadata: name: <application_name>-http: Names the IngressRoute <application_name>-http.
  • entryPoints: web: Specifies the entry point for HTTP traffic.
  • routes: match: Defines the routing rule based on the host and path prefix.
  • services: name: <application_name>: Specifies the service to route traffic to.
./Manifests_local/ingressroute.yaml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: <application_name>-http
  namespace: <application_name>-ns
spec:
  entryPoints:
  - web
  routes:
  - match: Host(`local_application.com`) && PathPrefix(`/`)
    kind: Rule
    services:
    - name: <application_name>
      namespace: <application_name>-ns
      port: 8888

7.3 Apply IngressRoute Manifest:

Now, as we have Traefik handling forwarding from the local computer to the cluster's service, we don't need Port Forwarding anymore that has been running in another terminal window. You can stop it now if it is still active.

Apply the manifest to create the IngressRoute:

> kubectl apply -f ./Manifests_local/ingressroute.yaml
ingressroute.traefik.containo.us/<application_name>-http created

7.4 Verify IngressRoute:

Test the routing to ensure that the service is accessible via the domain name:

Request
curl -X 'GET' 'http://local_application.com/environment_variables' | jq . | grep -E 'SECRET_BASE_64_ENCODED|SECRET_PASSWORD|SECRET_USERNAME'
Response
  "SECRET_BASE_64_ENCODED": "This string was encoded using base64",
  "SECRET_PASSWORD": "s_password",
  "SECRET_USERNAME": "username"

8. Enable HTTPS with TLS

Purpose:
Enabling HTTPS provides secure communication by encrypting traffic between the client and server. We'll use a TLS certificate to achieve this.

8.1 Generate TLS Certificate:

If you don't have a signed certificate, create a self-signed certificate for your domain name:

Generate a Private Key:

cd ./Certificate
openssl genrsa -out sec.demo.key 2048

Create a Simple Config for Certificate Generation:

Create a file named cert.conf with the following content:

./Certificate/cert.conf
[ req ]
default_bits       = 2048
prompt             = no
default_md         = sha256
distinguished_name = dn
req_extensions     = req_ext

[ dn ]
C  = US
ST = California
L  = San Francisco
O  = My Organization
OU = My Unit
CN = local_application.com

[ req_ext ]
subjectAltName = @alt_names

[ alt_names ]
DNS.1 = local_application.com
DNS.2 = www.local_application.com

Create a CSR (Certificate Signing Request):

openssl req -new -key sec.demo.key -out sec.demo.csr -config ./cert.conf

Generate a Self-Signed Certificate:

openssl x509 -req -days 365 -in sec.demo.csr -signkey sec.demo.key -out sec.demo.crt -extfile cert.conf

8.2 Create TLS Secret Manifest:

Convert the key and certificate into base64 format:

Convert Key:

Prepare base64 encoded value of the key for  "data.tls.key" attribute in the tls-secret.yaml  file below

cat sec.demo.key | base64 | tr -d '\n'


Convert Certificate:

Prepare base64 encoded value of the certificate for  "data.tls.crt" attribute in the tls-secret.yaml  file below

cat sec.demo.crt | base64 | tr -d '\n'

Using the base64-encoded data you obtained earlier, create the TLS secret manifest file. Below is the complete content of the file:

./Manifests_local/tls-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: <application_name>-secrets-tls
  namespace: <application_name>-ns
type: kubernetes.io/tls
data:
  tls.crt: <base64_certificate>
  tls.key: <base64_key>

8.3 Apply TLS Secret Manifest:

Move to the parant directory

> cd ../

Apply the TLS secret manifest to store the TLS certificate and key securely within Kubernetes:

> kubectl apply -f ./Manifests_local/tls-secret.yaml
secret/<application_name>-secrets-tls created

8.4 Verify Secret Creation:

Ensure that the TLS secret has been created successfully:

> kubectl -n <application_name>-ns get secret
NAME                   TYPE                DATA   AGE
<application_name>-secret        Opaque              3      57m
<application_name>-secrets-tls   kubernetes.io/tls   2      41s

8.5 Create HTTPS IngressRoute:

Extend the ingressroute.yaml file to include an HTTPS route using the TLS secret:

Explanation:

  • tls: Specifies the TLS configuration for the IngressRoute, using the secret created earlier.
  • secretName: <application_name>-secrets-tls: References the TLS secret for the HTTPS connection.
  • domains: main: local_application.com: Specifies the domain names covered by the certificate.
./Manifests_local/ingressroute.yaml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: <application_name>-http
  namespace: <application_name>-ns
spec:
  entryPoints:
  - web
  routes:
  - match: Host(`local_application.com`) && PathPrefix(`/`)
    kind: Rule
    services:
    - name: <application_name>
      namespace: <application_name>-ns
      port: 8888
---																	# new code line
apiVersion: traefik.containo.us/v1alpha1						    # new code line
kind: IngressRoute												    # new code line
metadata:														    # new code line
  name: <application_name>-https								      # new code line
  namespace: <application_name>-ns								  # new code line
spec:															    # new code line
  entryPoints:													    # new code line
  - websecure													    # new code line
  routes:														    # new code line
  - match: Host(`local_application.com`) && PathPrefix(`/`)		    # new code line
    kind: Rule													    # new code line
    services:                                                       # new code line
    - name: <application_name>									    # new code line
      namespace: <application_name>-ns                              # new code line
      port: 8888												       # new code line
  tls:															    # new code line
    secretName: <application_name>-secrets-tls					  # new code line
    domains:													    # new code line
    - main: local_application.com								    # new code line

8.6 Reapply IngressRoute Manifest:

Apply the updated ingress route manifest to enable access via HTTPS:

kubectl apply -f ./Manifests_local/ingressroute.yaml
ingressroute.traefik.containo.us/<application_name>-http unchanged
ingressroute.traefik.containo.us/<application_name>-https created

8.7 Test HTTPS Endpoint:

Verify that the HTTPS endpoint is working correctly:

Request
curl -k -X 'GET' 'https://local_application.com/health' | jq .
Response
{
  "status": "OK"
}

9. Adding Middleware to Ingress Controller

Purpose:

Middleware in Traefik enhances routing and security for your application. In this step, we will configure middleware for:

  1. Redirecting HTTP traffic to HTTPS to ensure secure communication.
  2. Stripping prefixes from URLs to provide clean and manageable paths.

Explanation

  • HTTP to HTTPS Redirection: Ensures all traffic is encrypted by redirecting HTTP requests to HTTPS.
  • Strip Prefix: Removes specified prefixes from the URL path, making it easier to manage and route traffic within your application in kubernetes cluster.

9.1 Create Middleware for HTTP to HTTPS Redirection:

We will add following code to create a Middleware manifest to redirect HTTP traffic to HTTPS.

apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: <application_name>-redirect-scheme
  namespace: <application_name>-ns
spec:
  redirectScheme:
    scheme: https
    permanent: true
    port: "443"

9.2 Create Middleware for Stripping Prefix:

We will add following code to create a Middleware manifest to strip the specified prefix from the URL path.

apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: <application_name>-strip-prefix
  namespace: <application_name>-ns
spec:
  stripPrefix:
    prefixes:
    - /

9.3 Update IngressRoute to Use Middleware:

Update  existing ingressroute.yaml to include the newly created middleware for both HTTP and HTTPS routes.

./Manifests_local/ingressroute.yaml
apiVersion: traefik.containo.us/v1alpha1                            # new code line
kind: Middleware												    # new code line
metadata:														    # new code line
  name: <application_name>-redirect-scheme						  # new code line
  namespace: <application_name>-ns								  # new code line
spec:															    # new code line
  redirectScheme:												    # new code line
    scheme: https												    # new code line
    permanent: true												    # new code line
    port: "443"													    # new code line
---																    # new code line
											
apiVersion: traefik.containo.us/v1alpha1						    # new code line
kind: Middleware												    # new code line
metadata:                                                           # new code line
  name: <application_name>-strip-prefix							   # new code line
  namespace: <application_name>-ns								  # new code line
spec:															    # new code line
  stripPrefix:													    # new code line
    prefixes:													    # new code line
    - /                                                             # new code line
---																    # new code line

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: <application_name>-http
  namespace: <application_name>-ns
spec:
  entryPoints:
  - web
  routes:
  - match: Host(`local_application.com`) && PathPrefix(`/`)
    kind: Rule
    services:
      - name: <application_name>
        namespace: <application_name>-ns
        port: 8888
    middlewares:												  	 # new code line
      - name: <application_name>-redirect-scheme				    	# new code line
      - name: <application_name>-strip-prefix					    	# new code line

---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: <application_name>-https
  namespace: <application_name>-ns
spec:
  entryPoints:
    - websecure
  routes:
    - match: Host(`local_application.com`) && PathPrefix(`/`)
      kind: Rule
      services:
        - name: <application_name>
          namespace: <application_name>-ns
          port: 8888
      middlewares:												    # new code line
        - name: <application_name>-strip-prefix					  # new code line
  tls:
    secretName: <application_name>-secrets-tls
    domains:
      - main: local_application.com

9.4 Apply Middleware and IngressRoute Manifests:

Apply the middleware and updated IngressRoute manifests to the cluster:

> kubectl apply -f ./Manifests_local/ingressroute.yaml

9.5 Test middleware:

Verify HTTP to HTTPS redirection.

The flag "-v" can be used in the curl command to display more information and ensure that the request was redirected from port 80 to port 443.

> curl -k -L -X 'GET' 'http://local_application.com/health' | jq .
{
  "status": "OK"
}

Verify "/" stripping.

> curl -k -X 'GET' 'https://local_application.com//health' | jq .
{
  "status": "OK"
}

10. Configure Startup and Liveness Probes

Purpose:
Kubernetes health probes help ensure that your application is running correctly and can automatically restart the application if it becomes unhealthy.

Explanation:

  • startupProbe: This probe checks whether the application is started and ready. It prevents the application from being killed before it's ready to accept traffic.

    • httpGet: path: "/health": Specifies the endpoint used for the health check.
    • port: http: Specifies the port for the health check.
    • periodSeconds: 5: Indicates how often to perform the probe.
    • initialDelaySeconds: 5: Specifies the initial delay before starting the probes.
  • livenessProbe: This probe checks whether the application is running and healthy. If it fails, Kubernetes will restart the container.

    • httpGet: path: "/health": Specifies the endpoint used for the health check.
    • port: http: Specifies the port for the health check.
    • initialDelaySeconds: 5: Specifies the initial delay before starting the probes.
    • periodSeconds: 60: Indicates how often to perform the probe.

10.1 Update Deployment Manifest with Probes:

Modify the deployment.yaml file to include startup and liveness probes:

Change <personal dockerhub repository> with appropriate repository name

./Manifests_local/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: <application_name>
  namespace: <application_name>-ns
spec:
  replicas: 1
  selector:
    matchLabels:
      app: <application_name>
  template:
    metadata:
      labels:
        app: <application_name>
    spec:
      containers:
      - name: <application_name>
        image: <personal dockerhub repository>/<application_name>:<application_version>
        ports:
        - name: http
          containerPort: 8000
          protocol: TCP
        env:
          - name: CONFIG_PATH
            value: /app/config.yaml
          - name: BASE_PATH
            value: /
          - name: CUSTOM_ENV_VARIABLE
            value: "deployed_env_value"
        envFrom:
          - secretRef:
              name: <application_name>-secret
        startupProbe:								    # new code line
          httpGet:									    # new code line
            path: "/health"							    # new code line
            port: http								    # new code line
          periodSeconds: 5							    # new code line
          initialDelaySeconds: 5					    # new code line
        livenessProbe:								    # new code line
          httpGet:									    # new code line
            path: "/health"							    # new code line
            port: http								    # new code line
          initialDelaySeconds: 5					    # new code line
          periodSeconds: 60							    # new code line
        volumeMounts:
        - name: config-vol
          mountPath: /app/config.yaml
          subPath: config.yaml
      volumes:
        - name: config-vol
          configMap:
            name: <application_name>-config

10.2 Redeploy Application:

Apply the updated deployment manifest:

> kubectl apply -f ./Manifests_local/deployment.yaml
deployment.apps/<application_name> configured

11. Test deployed application

11.1 Test /health endpoint 

Request
 > curl -k  -X 'GET' 'https://local_application.com/health' | jq .
Response
 {
  "status": "OK"
}

11.2 Test /config_values endpoint

Request
 > curl -k  -X 'GET' 'https://local_application.com/config_values' | jq .
Response
 {
  "SERVER_URL": "https://jsonplaceholder.typicode.com/users",
  "CONFIG_OPTION": "deployed config value"
}

11.3  Test /environment_variables endpoint with secrets

Request
 > curl -k  -X 'GET' 'https://local_application.com/environment_variables' | jq . | grep -E 'SECRET_BASE_64_ENCODED|SECRET_PASSWORD|SECRET_USERNAME'
Response
 
  "SECRET_BASE_64_ENCODED": "This string was encoded using base64",
  "SECRET_PASSWORD": "s_password",
  "SECRET_USERNAME": "username"

12. Clean-up procedures

If you no longer need the application deployed in the local cluster, you can initiate the clean-up procedure.

To clean up all the applied manifests with a single command, use the kubectl delete command with the -f option, specifying the directory where all the manifests are located. This will delete all the resources defined in the files within that directory.

Response
> kubectl delete -f ./Manifests_local/

Summary:

In this step, we've successfully prepared Kubernetes manifests to deploy our FastAPI application locally using Minikube.

We've covered the setup of namespaces, deployments, services, environment variables, ConfigMaps, secrets, ingress routes, and health probes.

 These components provide a robust foundation for deploying, managing, and testing your application in a local Kubernetes environment.