Deploying a Kubernetes App with Nginx Ingress and Cert-Manager/Let's Encrypt

Deploying a Web App in Azure Kubernetes Services (AKS) using Github CI/CD

Deploying applications in Kubernetes with proper networking and security is crucial in modern software development. In this tutorial, we’ll walk through deploying a sample “Hello World” application using Nginx Ingress for routing and Cert-Manager for automatic HTTPS certificates from Let’s Encrypt. Also, to deploy it we will use Github Actions.

Prerequisites

Before we start, make sure you have the following prerequisites:

  • A Kubernetes cluster (you can use Azure Kubernetes Service (AKS) for this tutorial)
  • A Docker Hub account (or any other Docker registry)
  • A GitHub repository for your application

Step 1: Create a Simple “Hello World” Rust App

For this tutorial, we’ll use a basic “Hello World” application in Rust. Create a file named main.rs with the following code:

use actix_web::{web, App, HttpServer, Responder};

async fn hello() -> impl Responder {
    "Hello, Kubernetes!"
}

#[actix_rt::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| App::new().route("/", web::get().to(hello)))
        .bind("0.0.0.0:8080")?
        .run()
        .await
}

Step 2: Dockerize and Push the Rust App to Docker Hub

To deploy our Rust app in Kubernetes, we need to containerize it and push it to a container registry. Follow these steps: 1 - Create the Dockerfile

FROM rust:1.55 AS builder
WORKDIR /app
COPY main.rs .
RUN cargo build --release

FROM debian:buster-slim
COPY --from=builder /app/target/release/app /app
CMD ["/app"]

2 - Build a Docker image for your Rust app:

docker build -t your-dockerhub-username/hello-kubernetes-rust:latest .

3 - Push the image to Docker Hub:

docker push your-dockerhub-username/hello-kubernetes-rust:latest

Step 3: Install the Ingress Controller:

Run the following command to install the Nginx Ingress controller:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.0.0/deploy/static/provider/cloud/deploy.yaml

Create an ingress.yaml file with the following content:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: hello-world-ingress
spec:
  rules:
    - host: your-app-domain.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: hello-world-service
                port:
                  number: 80

Step 4: Install Cert-Manager

Cert-Manager is a Kubernetes addon that automates the management and issuance of TLS certificates. To install it, follow these steps:

Run the following commands to install Cert-Manager:

kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.5.3/cert-manager.yaml

Create an issuer.yaml file with the following content:

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    email: your-email@example.com
    server: https://acme-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
      - http01:
          ingress:
            class: nginx

Here we are using the prod server of letsencrypt, you can use the staging one.

Step 5: Set Up Azure Service Principal

For secure deployments, we’ll use an Azure Service Principal to authenticate with AKS. 1 - Create a new Service Principal:

az ad sp create-for-rbac --name "YourAppServicePrincipal" --skip-assignment

2 - Note down the appId (Client ID) and password (Client Secret) from the output.

Step 6: Configure Secrets in GitHub

In your GitHub repository, navigate to “Settings” > “Secrets” and add the following secrets:

  • AZURE_SP_CLIENT_ID: The appId (Client ID) of your Service Principal.
  • AZURE_SP_CLIENT_SECRET: The password (Client Secret) of your Service Principal.

Step 7: Set Up GitHub CI/CD

Create a .github/workflows/deploy.yml file with the following content to set up the CI/CD pipeline

name: Deploy Kubernetes App

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - name: Set up Azure CLI
        uses: azure/setup-az-cli@v1
        with:
          install-zsh: true  # Install Azure CLI in the Zsh shell

      - name: Authenticate to Azure using Service Principal
        run: az login --service-principal -u $ -p $ --tenant $

      - name: Get AKS credentials
        run: az aks get-credentials --resource-group your-aks-resource-group --name your-aks-cluster-name

      - name: Configure kubectl
        run: echo "$KUBECONFIG" > $HOME/.kube/config

      - name: Deploy to Kubernetes
        run: |
          kubectl apply -f kubernetes/deployment.yaml
          kubectl apply -f kubernetes/service.yaml
          kubectl apply -f kubernetes/ingress.yaml

Here is the example of deployment.yaml :

# kubernetes/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-world-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hello-world
  template:
    metadata:
      labels:
        app: hello-world
    spec:
      containers:
        - name: hello-world
          image: your-dockerhub-username/hello-kubernetes-rust:latest
          ports:
            - containerPort: 8080

Your app should be now deserved in HTTPS using letsencrypt certificate. More configuration is needed for an environment prod-ready of course.

Conclusion

By combining Nginx Ingress, Cert-Manager, and GitHub Actions, you’ve successfully set up a CI/CD pipeline for deploying your Kubernetes application written in Rust. This approach enhances security and automates deployment.