Deploying a Stateful Web Application on Kubernetes: A Hands-On Guide

Introduction

Kubernetes is a powerful container orchestration platform that allows developers to deploy, manage, and scale applications seamlessly. In this blog, we will walk through deploying a stateful web application on Kubernetes, covering essential concepts such as namespaces, ConfigMaps, Secrets, and StatefulSets. By the end of this guide, you'll have a practical understanding of how to use these features to manage and deploy your applications.

Table of Contents

  1. Namespaces

  2. ConfigMaps and Secrets

  3. StatefulSets

  4. Practice Project: Deploying a Stateful Web Application

  5. Conclusion

Namespaces

Namespaces in Kubernetes provide a way to partition cluster resources between multiple users. They are particularly useful for organizing environments like development, staging, and production within a single cluster. By using namespaces, you can apply policies and allocate resources in an isolated manner.

Example: Creating a Namespace

apiVersion: v1
kind: Namespace
metadata:
  name: webapp-namespace

To create the namespace, apply the configuration:

kubectl apply -f namespace.yaml

ConfigMaps and Secrets

ConfigMaps and Secrets are Kubernetes objects that allow you to decouple configuration and sensitive data from your application code.

  • ConfigMaps store non-confidential data in key-value pairs, such as configuration settings or environment variables.

Example: Creating a ConfigMap

apiVersion: v1
kind: ConfigMap
metadata:
  name: mysql-config
  namespace: webapp-namespace
data:
  MYSQL_DATABASE: webappdb
  MYSQL_USER: webappuser

Apply the ConfigMap:

kubectl apply -f mysql-configmap.yaml
  • Secrets store sensitive data like passwords, tokens, and SSH keys. Secrets ensure that sensitive information is stored securely, typically in base64 encoding.

Example: Creating a Secret

apiVersion: v1
kind: Secret
metadata:
  name: mysql-secret
  namespace: webapp-namespace
type: Opaque
data:
  MYSQL_ROOT_PASSWORD: dG9wU2VjcmV0Cg==
  MYSQL_PASSWORD: c2VjcmV0Cg==

Apply the Secret:

kubectl apply -f mysql-secret.yaml

StatefulSets

StatefulSets manage the deployment and scaling of a set of pods, providing guarantees about the ordering and uniqueness of these pods. They are particularly useful for stateful applications that require stable, persistent storage and consistent network identities, such as databases.

Key features of StatefulSets:

  • Stable, unique network identifiers

  • Stable, persistent storage

  • Ordered, graceful deployment and scaling

Example: Creating a StatefulSet for MySQL

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
  namespace: webapp-namespace
spec:
  selector:
    matchLabels:
      app: mysql
  serviceName: "mysql"
  replicas: 1
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:5.7
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: MYSQL_ROOT_PASSWORD
        - name: MYSQL_DATABASE
          valueFrom:
            configMapKeyRef:
              name: mysql-config
              key: MYSQL_DATABASE
        - name: MYSQL_USER
          valueFrom:
            configMapKeyRef:
              name: mysql-config
              key: MYSQL_USER
        - name: MYSQL_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: MYSQL_PASSWORD
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
  volumeClaimTemplates:
  - metadata:
      name: mysql-persistent-storage
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 1Gi

Apply the StatefulSet:

kubectl apply -f mysql-statefulset.yaml

Practice Project: Deploying a Stateful Web Application

Let's put everything together and deploy a simple web application with a MySQL backend.

  1. Set Up Kubernetes Namespace
apiVersion: v1
kind: Namespace
metadata:
  name: webapp-namespace

Apply the namespace:

kubectl apply -f namespace.yaml
  1. Create ConfigMaps and Secrets

ConfigMap for MySQL Configuration

apiVersion: v1
kind: ConfigMap
metadata:
  name: mysql-config
  namespace: webapp-namespace
data:
  MYSQL_DATABASE: webappdb
  MYSQL_USER: webappuser

Apply the ConfigMap:

kubectl apply -f mysql-configmap.yaml

Secret for MySQL Password

apiVersion: v1
kind: Secret
metadata:
  name: mysql-secret
  namespace: webapp-namespace
type: Opaque
data:
  MYSQL_ROOT_PASSWORD: dG9wU2VjcmV0Cg==  # base64 encoded "topSecret"
  MYSQL_PASSWORD: c2VjcmV0Cg==  # base64 encoded "secret"

Apply the Secret:

kubectl apply -f mysql-secret.yaml
  1. Deploy a MySQL StatefulSet
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
  namespace: webapp-namespace
spec:
  selector:
    matchLabels:
      app: mysql
  serviceName: "mysql"
  replicas: 1
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:5.7
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: MYSQL_ROOT_PASSWORD
        - name: MYSQL_DATABASE
          valueFrom:
            configMapKeyRef:
              name: mysql-config
              key: MYSQL_DATABASE
        - name: MYSQL_USER
          valueFrom:
            configMapKeyRef:
              name: mysql-config
              key: MYSQL_USER
        - name: MYSQL_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: MYSQL_PASSWORD
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
  volumeClaimTemplates:
  - metadata:
      name: mysql-persistent-storage
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 1Gi

Apply the StatefulSet:

kubectl apply -f mysql-statefulset.yaml
  1. Deploy a Web Application using Deployment

We will use the nginx image to simulate our web application.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp
  namespace: webapp-namespace
spec:
  replicas: 2
  selector:
    matchLabels:
      app: webapp
  template:
    metadata:
      labels:
        app: webapp
    spec:
      containers:
      - name: webapp
        image: nginx:latest  # Using the official Nginx image
        ports:
        - containerPort: 80

Apply the deployment:

kubectl apply -f webapp-deployment.yaml

Verify the Setup

  1. Check Namespaces
kubectl get namespaces
  1. Check ConfigMaps and Secrets
kubectl get configmaps -n webapp-namespace
kubectl get secrets -n webapp-namespace
  1. Check StatefulSet and Pods
kubectl get statefulsets -n webapp-namespace
kubectl get pods -n webapp-namespace
  1. Check Deployment and Pods
kubectl get deployments -n webapp-namespace
kubectl get pods -n webapp-namespace
  1. Check Services
kubectl get services -n webapp-namespace

By following this guide, you have deployed a stateful web application using Kubernetes, leveraging namespaces for resource isolation, ConfigMaps and Secrets for configuration management, and StatefulSets for stable storage and network identities.

Conclusion

In this blog, we explored how to deploy a stateful web application on Kubernetes. We covered essential concepts such as namespaces, ConfigMaps, Secrets, and StatefulSets, and applied them in a practical project. By mastering these concepts, you can efficiently manage and deploy complex applications on Kubernetes.

0
Subscribe to my newsletter

Read articles from Mohammed Yunus Shaikh directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Mohammed Yunus Shaikh
Mohammed Yunus Shaikh

I love to explore new technologies, excited to learn and grow everyday.