A FastAPI web application that accepts incoming HTTP requests, displays the caller’s IP in reverse order, and stores the record in a PostgreSQL database. The project is containerized with Docker, deployed on a DigitalOcean Kubernetes cluster using Helm, and its infrastructure is provisioned with Terraform. CI/CD is managed via GitHub Actions.
- Project Overview
- Architecture
- Prerequisites
- Local Development Setup
- Building and Pushing the Docker Image
- Infrastructure Provisioning with Terraform
- Deploying the Application with Helm
- Accessing the Application
- CI/CD Pipeline using GitHub Actions
- Troubleshooting CrashLoopBackOff Error
This project provides a simple but scalable solution for displaying and storing reversed IP addresses:
- Backend: FastAPI (Python) with Uvicorn.
- Database: PostgreSQL (managed on DigitalOcean).
- Containerization: Docker.
- Deployment: Kubernetes on DigitalOcean, deployed via Helm.
- Infrastructure as Code: Terraform (using DigitalOcean Spaces as an S3‑compatible backend for state).
- CI/CD: GitHub Actions.
-
FastAPI Application:
- Listens on port
8088and returns the reversed IP address. - Uses SQLAlchemy to connect to a PostgreSQL database.
- Environment variable
DATABASE_URLis used to specify the database connection string.
- Listens on port
-
Docker Container:
- Built from a lightweight Python Alpine image.
- Includes necessary dependencies (installed via
requirements.txt).
-
Kubernetes Deployment:
- Deployed on a DigitalOcean Kubernetes cluster.
- Managed by Helm charts for configuration and lifecycle management.
- Service exposed via a LoadBalancer to allow external access.
-
Infrastructure Provisioning:
- Terraform provisions the Kubernetes cluster and manages state using DigitalOcean Spaces.
- Backend configuration uses S3‑compatible settings.
-
CI/CD Pipeline:
- GitHub Actions automates the build, push, and deployment processes.
- Docker
- Kubernetes CLI (kubectl)
- Helm
- Terraform (v1.6.3 or later)
- DigitalOcean Account
- GitHub Account with repository secrets configured for:
DIGITALOCEAN_TOKENAWS_ACCESS_KEY_IDandAWS_SECRET_ACCESS_KEY(for DigitalOcean Spaces)
- Basic knowledge of YAML, shell scripting, and cloud deployments.
-
Clone the Repository:
git clone https://github.com/ogdmerlin/IpReverser-K8s.git cd IpReverser-K8s -
Run Locally with Docker Compose (Optional):
If you want to run the app and a local PostgreSQL instance for development:
# docker-compose.yml version: '3.8' services: web: build: . ports: - "8088:8088" environment: - DATABASE_URL=postgresql://postgres:postgres@db:5432/mydatabase db: image: postgres:15-alpine environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres POSTGRES_DB: mydatabase ports: - "5432:5432"
Then run:
docker-compose up -d
-
Test the FastAPI Application:
Visit http://localhost:8088 in your browser. You should see the page displaying your original IP and the reversed IP.
-
Access the Database:
You can access the PostgreSQL database using
psql:psql -h localhost -U postgres -d mydatabase
-
Build the Docker Image:
docker build -t ogdmerlin/reverse-ip:v1 . -
Tag the Image:
docker tag reverse-ip ogdmerlin/reverse-ip:v1
-
Push the Image to Docker Hub:
docker push ogdmerlin/reverse-ip:v1
Important
You must be logged in to Docker Hub to push the image, and you can replace ogdmerlin with your Docker Hub username.
Login to Docker Hub:
```bash
docker login
```
Create a backend.tf (or include in your main Terraform file):
terraform {
required_version = ">= 1.6.3"
backend "s3" {
endpoints = {
s3 = "https://sfo3.digitaloceanspaces.com"
}
bucket = "reverseip-statefile"
key = "terraform.tfstate"
# Disable AWS-specific validations
skip_credentials_validation = true
skip_requesting_account_id = true
skip_metadata_api_check = true
skip_region_validation = true
skip_s3_checksum = true
region = "us-east-1" # Arbitrary; required by Terraform but not used by Spaces
}
}Create your Terraform configuration (e.g., main.tf, database.tf, variables.tf) similar to:
# main.tf
provider "digitalocean" {
token = var.do_token
}
resource "digitalocean_kubernetes_cluster" "k8s_cluster" {
name = "ip-reverse-cluster"
region = "nyc3"
version = "1.26.3-do.0"
node_pool {
name = "default-pool"
size = "s-2vcpu-2gb"
node_count = 2
}
}
output "kubeconfig" {
value = digitalocean_kubernetes_cluster.k8s_cluster.kube_config[0].raw_config
sensitive = true
}# database.tf (DigitalOcean Managed PostgreSQL)
locals {
database_cluster_name = "reverseapp-db"
}
resource "digitalocean_database_db" "db" {
cluster_id = digitalocean_database_cluster.db_cluster.id
name = "reverseip"
}
resource "digitalocean_database_cluster" "db_cluster" {
name = local.database_cluster_name
engine = "pg"
version = "17"
size = "db-s-1vcpu-1gb"
region = "sfo3"
node_count = 1
# private_network_uuid = "default-sfo3"
tags = ["reverseip"]
}
resource "digitalocean_database_user" "db_user" {
cluster_id = digitalocean_database_cluster.db_cluster.id
name = "user"
# password = random_string.db_password.result
}# variables.tf
variable "digitalocean_token" {
description = "DigitalOcean API token"
type = string
sensitive = true
}Initialize Terraform and apply the configuration:
cd ./K8s_Infra
terraform init
terraform applyAfter applying, extract the kubeconfig:
terraform output -raw kubeconfig > do-kubeconfig.yaml
export KUBECONFIG=$(pwd)/do-kubeconfig.yamlVerify the cluster:
kubectl get nodes-
Add the Helm Repository:
helm install reverse-ip
Tip
You can customize the Helm chart values in ./reverse-ip/values.yaml before deploying.
-
Update Deployment Template (templates/deployment.yaml):
Ensure the environment variable is injected:
env: - name: DATABASE_URL valueFrom: secretKeyRef: name: db-credentials key: DATABASE_URL
-
Create or Update the Kubernetes Secret:
kubectl create secret generic db-credentials --from-literal=DATABASE_URL=postgresql://user:password@host:port/dbname
Caution
Replace the connection string with your PostgreSQL credentials.
-
Deploy the Application with helm:
helm install reverse-ip . -f values.yaml # For updates helm upgrade reverse-ip . -f values.yaml
-
Verify the Deployment:
kubectl get pods kubectl get svc
Important
The kubectl get svc show an external IP address that let us access our application from the browser.
It may take a few minutes for the LoadBalancer IP to be provisioned, Once the external IP is assigned, access your app at: http://<EXTERNAL_IP>:8088.

Troubleshooting CrashLoopBackOff Error:
Warning
I experience an issue with the pods not starting due to the CrashLoopBackOff error.
I resolved it by checking the logs with kubectl logs <pod-name> and after spending some time, I found out that the issue was with the livenessProbe, and readinessProbe was failing. I had to comment out the livenessProbe and readinessProbe in the deployment.yaml file.
Our GitHub Actions workflow (.github/workflows/ci-cd.yaml) builds the Docker image, pushes it to Docker Hub, and deploys via Helm.
Tip
Terraform Backend Issues in CI/CD:
Make sure AWS/Spaces credentials are set at the job level in GitHub Actions as shown above
This project demonstrates a complete workflow from local development to production deployment using modern tools and practices. The combination of FastAPI, Docker, Kubernetes, Terraform, and GitHub Actions provides a robust foundation for building scalable web applications. Feel free to explore, modify, and extend the application as needed. Contributions and feedback are welcome!
