Daniele Viti 741295150d
Some checks failed
Helm Chart Build / lint-only (push) Has been skipped
Helm Chart Build / build-helm (push) Successful in 10s
Build and Deploy / build-web (push) Failing after 24s
Build and Deploy / build-api (push) Failing after 26s
Update .gitea/workflows/helm-build.yml
2025-10-06 16:36:23 +02:00
2025-10-03 01:20:15 +02:00

API7 Demo - FastAPI Applications

Demo project showcasing two FastAPI applications deployed on Kubernetes through API7 Enterprise Gateway with automated CI/CD using Gitea.

📁 Project Structure

api7-demo/
├── web/                    # Web application
│   ├── main.py            # FastAPI web app with HTML UI
│   ├── Dockerfile         # Container image
│   └── requirements.txt   # Python dependencies
├── api/                    # API application
│   ├── main.py            # FastAPI REST API with Swagger
│   ├── Dockerfile         # Container image
│   └── requirements.txt   # Python dependencies
├── .gitea/
│   └── workflows/
│       └── build.yml      # CI/CD pipeline
└── README.md

🌐 Applications

Web Application (web/)

Modern web interface with:

  • Responsive HTML dashboard
  • System information display
  • Health check endpoints

Endpoints:

  • GET / - Main webpage
  • GET /health - Health check

Port: 8000

API Application (api/)

REST API with full documentation:

  • CRUD operations for Items and Users
  • Automatic Swagger/OpenAPI docs
  • Data validation with Pydantic

Key Endpoints:

  • GET /docs - Swagger UI
  • GET /items - List items
  • POST /items - Create item
  • GET /users - List users
  • GET /health - Health check

Port: 8001 (internally 8000)

🚀 Quick Start

Local Development

Web Application:

cd web
pip install -r requirements.txt
python main.py
# Access at http://localhost:8000

API Application:

cd api
pip install -r requirements.txt
python main.py
# Swagger at http://localhost:8000/docs

Docker

Build and run Web:

docker build -t web-app ./web
docker run -p 8000:8000 web-app

Build and run API:

docker build -t api-app ./api
docker run -p 8001:8000 api-app

🐳 CI/CD with Gitea

Automated Pipeline

The CI/CD workflows automatically:

.gitea/workflows/build.yml:

  1. Builds Docker images for both applications
  2. Pushes to Gitea container registry
  3. Tags images with branch name
  4. Implements layer caching for faster builds

.gitea/workflows/helm-build.yml:

  1. Packages Helm charts on every main branch push
  2. Uses version from Chart.yaml (single source of truth)
  3. Publishes charts to Gitea Helm registry
  4. Validates charts on pull requests (lint only)

Triggers:

  • Any branch push (Docker images)
  • Push to main branch (Helm chart)
  • Pull requests (Helm lint only)
  • Manual dispatch

Registry: git.commandware.com/demos/api7-demo

Docker Images:

  • git.commandware.com/demos/api7-demo/web:<branch-name>
  • git.commandware.com/demos/api7-demo/api:<branch-name>

Helm Repository:

  • https://git.commandware.com/api/packages/$OWNER/helm

Setup

  1. Create GITEA_TOKEN secret:

    • Repository Settings → Secrets → Add Secret
    • Name: GITEA_TOKEN
    • Generate token at: User Settings → Applications → Generate Token
    • Required scope: write:package
  2. Push to trigger build:

    git push origin main
    

☸️ Kubernetes Deployment

Prerequisites

  • Kubernetes cluster (v1.19+)
  • Helm 3.8.0+
  • API7 Enterprise Gateway installed
  • Namespace: api7ee

Deploy with Helm

The project includes a complete Helm chart for easy deployment of both web and API components.

Add Helm Repository

# Add the Gitea Helm repository
helm repo add api7ee https://git.commandware.com/api/packages/$OWNER/helm
helm repo update

Install the Chart

# Install with default values
helm install my-api7ee api7ee/api7ee-demo-k8s --namespace api7ee --create-namespace

# Install with custom values
helm install my-api7ee api7ee/api7ee-demo-k8s -f custom-values.yaml --namespace api7ee

# Install with specific image tags
helm install my-api7ee api7ee/api7ee-demo-k8s \
  --set web.image.tag=v1.0.0 \
  --set api.image.tag=v1.0.0 \
  --namespace api7ee

Configuration Options

Key Helm values:

Parameter Description Default
web.enabled Enable Web component true
web.replicaCount Number of Web replicas 2
api.enabled Enable API component true
api.replicaCount Number of API replicas 3
ingress.enabled Enable ingress true
ingress.hosts[0].host Ingress hostname demo.commandware.it

Upgrade/Uninstall

# Upgrade the release
helm upgrade my-api7ee api7ee/api7ee-demo-k8s --namespace api7ee

# Uninstall
helm uninstall my-api7ee --namespace api7ee

Manual Deployment (Alternative)

k8s-deployments.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
  namespace: api7ee
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
      - name: web
        image: git.commandware.com/demos/api7-demo/web:main
        ports:
        - containerPort: 8000
          name: http
        livenessProbe:
          httpGet:
            path: /health
            port: 8000
---
apiVersion: v1
kind: Service
metadata:
  name: web-service
  namespace: api7ee
spec:
  type: ClusterIP
  ports:
  - port: 80
    targetPort: 8000
    name: http
  selector:
    app: web
---
# Similar configuration for api deployment

Deploy

kubectl apply -f k8s-deployments.yaml
kubectl rollout status deployment/web -n api7ee
kubectl rollout status deployment/api -n api7ee

🔌 API7 Gateway Configuration

Route Configuration (ADC)

api7-routes.yaml:

services:
  - name: web-service
    upstream:
      name: web-upstream
      scheme: http
      type: roundrobin
      discovery_type: kubernetes
      service_name: api7ee/web-service:http
    routes:
      - name: web-route
        uris:
          - /*
        hosts:
          - demo.yourdomain.com
        plugins:
          redirect:
            http_to_https: true

  - name: api-service
    upstream:
      name: api-upstream
      scheme: http
      type: roundrobin
      discovery_type: kubernetes
      service_name: api7ee/api-service:http
    routes:
      - name: api-route
        priority: 10
        uris:
          - /api
          - /api/*
        hosts:
          - demo.yourdomain.com
        plugins:
          redirect:
            http_to_https: true
          proxy-rewrite:
            regex_uri:
              - ^/api/(.*)
              - /$1

ssls:
  - snis:
      - "*.yourdomain.com"
    certificates:
      - certificate: |
          -----BEGIN CERTIFICATE-----
          <YOUR_CERTIFICATE>
          -----END CERTIFICATE-----
        key: |
          -----BEGIN PRIVATE KEY-----
          <YOUR_KEY>
          -----END PRIVATE KEY-----

Sync Configuration

adc sync -f api7-routes.yaml \
  --backend api7ee \
  --server https://api7-dashboard.yourdomain.com \
  --token <YOUR_API7_TOKEN> \
  --gateway-group default \
  --tls-skip-verify

Publish Routes

Routes must be published via API7 Dashboard to become active:

  1. Navigate to Services → Select service
  2. Go to Routes tab
  3. Click "Publish" for each route
  4. Select gateway group: "default"
  5. Confirm

🧪 Testing

Test Endpoints

# Web application
curl https://demo.yourdomain.com

# API health check
curl https://demo.yourdomain.com/api/health

# API Swagger (if exposed)
curl https://demo.yourdomain.com/api/docs

# Verify HTTP → HTTPS redirect
curl -I http://demo.yourdomain.com

Verify Service Discovery

# Scale deployment
kubectl scale deployment web -n api7ee --replicas=5

# API7 automatically discovers new endpoints
kubectl get endpoints -n api7ee web-service

# Scale back
kubectl scale deployment web -n api7ee --replicas=2

📊 Architecture

Internet
   ↓
LoadBalancer (External IP)
   ↓
NGINX Ingress Controller
   ↓
TLS Termination (Let's Encrypt)
   ↓
API7 Gateway (ClusterIP)
   ↓
[Kubernetes Service Discovery]
   ↓
┌──────────────┬──────────────┐
│ Web Service  │ API Service  │
└──────────────┴──────────────┘

Traffic Routing

  • demo.yourdomain.com/api/* → API Service (priority 10, strips /api prefix)
  • demo.yourdomain.com/* → Web Service (default priority)

🔧 API7 Enterprise Setup Guide

Certificate Management

Using cert-manager with Cloudflare:

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: cloudflare-acme-prod
spec:
  acme:
    email: your-email@example.com
    server: https://acme-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: letsencrypt-prod-key
    solvers:
      - dns01:
          cloudflare:
            apiTokenSecretRef:
              name: cloudflare-api-token-secret
              key: api-token

Create Cloudflare secret:

kubectl create secret generic cloudflare-api-token-secret \
  -n cert-manager \
  --from-literal=api-token=YOUR_TOKEN

Kubernetes Service Discovery

Configure in API7 Dashboard:

  1. Settings → Service Registry → Add Service Registry
  2. Select: Kubernetes
  3. Configure:
    Name: kubernetes-cluster
    API Server: https://kubernetes.default.svc.cluster.local:443
    Token Path: /var/run/secrets/kubernetes.io/serviceaccount/token
    Namespace Filter: api7ee (optional)
    

Verify RBAC permissions:

kubectl create clusterrolebinding api7-gateway-discovery \
  --clusterrole=view \
  --serviceaccount=<API7_NAMESPACE>:default

Ingress Configuration

Example ingress for API7 Gateway:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api7-gateway-ingress
  namespace: api7ee
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - demo.yourdomain.com
      secretName: demo-tls
  rules:
    - host: demo.yourdomain.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: api7-gateway-service
                port:
                  number: 80

Note: Ingress backend points to API7 Gateway service, not application services.

🛠️ Troubleshooting

Routes Return 404

Problem: Routes synced but returning 404

Solution: Routes not published. Publish via API7 Dashboard.

Service Discovery Not Working

Problem: service registry not found error

Checklist:

  • Service registry configured in dashboard
  • Registry status shows "Connected"
  • RBAC permissions granted
  • Service ports have name field

Certificate Issues

Problem: Certificate not trusted

Solution:

# Check certificate status
kubectl get certificate -n api7ee
kubectl describe certificate -n api7ee <cert-name>

# Check cert-manager logs
kubectl logs -n cert-manager -l app.kubernetes.io/name=cert-manager --tail=50

Container Images Not Found

Problem: ImagePullBackOff in Kubernetes

Solution:

# Create registry secret
kubectl create secret docker-registry gitea-registry \
  --docker-server=git.commandware.com \
  --docker-username=<USERNAME> \
  --docker-password=<TOKEN> \
  -n api7ee

# Add to deployment
spec:
  template:
    spec:
      imagePullSecrets:
      - name: gitea-registry

📚 Resources

🔐 Best Practices

Security

  • Use TLS for all external traffic
  • Implement rate limiting on public endpoints
  • Store secrets in Kubernetes Secrets or external vault
  • Use least-privilege RBAC permissions

Performance

  • Enable service discovery for automatic scaling
  • Configure appropriate resource limits
  • Use Docker layer caching in CI/CD
  • Implement health checks and readiness probes

Monitoring

  • Monitor gateway metrics in API7 Dashboard
  • Track API usage and performance
  • Set up alerts for certificate expiration
  • Review application logs regularly

📝 License

Demo project for API7 Enterprise Gateway evaluation.


Repository: https://git.commandware.com/demos/api7-demo.git

Description
Demo for API7 on kubernetes with MetaLLB and Nginx-Ingress (community)
Readme 415 KiB
Languages
Python 40%
HTML 32.5%
CSS 16.1%
JavaScript 6.2%
Smarty 3.5%
Other 1.7%