Changed adminUrl from dp-manager:7900 to dashboard:7080 for API7 Enterprise backend. The dp-manager service is for APISIX, while API7EE requires the dashboard service which exposes the admin API. This fixes the 404 errors when ADC tries to fetch configuration: - GET /api/version - GET /api/gateway_groups - GET /api/schema/core 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
API7 Enterprise Edition Demo
A comprehensive demo platform showcasing API7 Enterprise Edition (API7EE) as an API Gateway with two FastAPI microservices: a Web frontend with embedded documentation and an API backend with LLM integration. Features automated CI/CD via Gitea Actions, Helm-based deployment, and advanced API7 Gateway configurations including AI rate limiting.
📋 Table of Contents
- Overview
- Architecture
- Project Structure
- Features
- Quick Start
- CI/CD Pipeline
- Kubernetes Deployment
- API7 Gateway Configuration
- Development
- Troubleshooting
- Resources
🎯 Overview
This project demonstrates enterprise-grade API Gateway patterns using API7 Enterprise Edition, showcasing:
- Microservices Architecture: Web frontend + API backend
- AI Integration: LLM endpoints with OpenAI-compatible API
- Advanced Rate Limiting: Token-based AI rate limiting + IP-based rate limiting
- Service Discovery: Kubernetes-native service discovery via API7
- Automated Deployment: Gitea Actions CI/CD + Helm charts
- Production-Ready: TLS, monitoring, autoscaling, and security policies
Live Demo: https://api7-demo.commandware.it
🏗️ Architecture
┌─────────────────────────────────────────────────────────────┐
│ Internet / Users │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ NGINX Ingress Controller (TLS) │
│ cert-manager (Let's Encrypt) │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ API7 Enterprise Gateway │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Routes & Plugins: │ │
│ │ • / → Web Service (Apache/Nginx) │ │
│ │ • /api → API Backend (Rate: 100 req/60s) │ │
│ │ • /api/llm → LLM Endpoints (Rate: 100 tokens/60s) │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
┌────────────┴────────────┐
▼ ▼
┌─────────────────────┐ ┌──────────────────────┐
│ Web Service │ │ API Service │
│ (apache/nginx) │ │ (nginx) │
│ │ │ │
│ • Frontend UI │ │ • REST API │
│ • Documentation │ │ • LLM Integration │
│ • API Proxy │ │ • Swagger Docs │
│ Replicas: 2-10 │ │ Replicas: 3-20 │
└─────────────────────┘ └──────────────────────┘
│
▼
┌──────────────────────┐
│ Open WebUI (LLM) │
│ OpenAI-Compatible │
└──────────────────────┘
Service Naming
Important: The Helm chart names services as apache-service and nginx-service for API7 routing:
- Web Service: Deployed as
apache-service(serves frontend and docs) - API Service: Deployed as
nginx-service(serves REST API and LLM endpoints)
This naming convention is used in ADC configuration for consistent routing.
📁 Project Structure
api7ee/
├── web/ # Web frontend application
│ ├── main.py # FastAPI app with templates & API proxy
│ ├── Dockerfile # Multi-stage build with MkDocs
│ ├── requirements.txt # Dependencies: fastapi, httpx, mkdocs
│ ├── templates/ # Jinja2 HTML templates
│ │ ├── base.html # Base template
│ │ ├── index.html # Dashboard
│ │ ├── items.html # Items page
│ │ ├── users.html # Users page
│ │ └── llm.html # LLM chat interface
│ ├── static/ # CSS and JavaScript assets
│ ├── docs/ # MkDocs documentation source
│ │ ├── index.md
│ │ ├── getting-started.md
│ │ ├── architecture.md
│ │ ├── api7-configuration.md
│ │ ├── kubernetes-resources.md
│ │ ├── cicd-pipeline.md
│ │ └── troubleshooting.md
│ └── mkdocs.yml # MkDocs configuration
├── api/ # API backend application
│ ├── main.py # FastAPI app with REST + LLM endpoints
│ ├── Dockerfile # Container image
│ ├── requirements.txt # Dependencies: fastapi, httpx, pydantic
│ └── db.json # Sample data file
├── helm/ # Helm chart for Kubernetes
│ └── api7ee-demo-k8s/
│ ├── Chart.yaml # Chart metadata (v0.1.0)
│ ├── values.yaml # Default configuration
│ ├── values-dev.yaml # Development overrides
│ ├── values-production.yaml # Production overrides
│ └── templates/ # Kubernetes manifests
│ ├── deployment-web.yaml
│ ├── deployment-api.yaml
│ ├── service-web.yaml
│ ├── service-api.yaml
│ ├── ingress.yaml
│ ├── configmap-adc.yaml # API7 ADC configuration
│ ├── job-adc-sync.yaml # ADC sync job
│ ├── certificate.yaml # cert-manager certificate
│ ├── hpa-web.yaml # Horizontal Pod Autoscaler
│ ├── hpa-api.yaml
│ └── ...
├── .gitea/
│ └── workflows/
│ ├── build.yml # Docker image builds
│ └── helm-build.yml # Helm chart packaging
├── adc.yaml # Standalone API7 ADC configuration
└── README.md # This file
✨ Features
Web Application (web/)
- Interactive Dashboard: Modern UI with real-time stats
- Embedded Documentation: MkDocs Material theme at
/docs - API Proxy: Proxies requests to API backend
- LLM Chat Interface: Chat with videogame expert AI
- Health Checks:
/healthendpoint - Static Assets: Custom CSS and JavaScript
API Application (api/)
- REST API: Items and Users CRUD operations
- LLM Integration: OpenAI-compatible chat endpoint
- Swagger Documentation: Auto-generated at
/docs - Data Validation: Pydantic models
- Health Endpoints:
/healthand/llm/health - Model Management:
/llm/modelsendpoint
API7 Gateway Features
- Advanced Rate Limiting:
- Standard: 100 requests/60s per IP for
/api/* - AI: 100 tokens/60s for
/api/llm/*(token-based)
- Standard: 100 requests/60s per IP for
- Service Discovery: Kubernetes-native discovery
- TLS/SSL: Automatic certificate management
- HTTP → HTTPS Redirect: Enforced on all routes
- Prometheus Metrics: Built-in monitoring
- Route Prioritization: LLM routes (priority 20) > API (10) > Web (1)
DevOps Features
- CI/CD: Gitea Actions for automated builds
- Helm Packaging: Automated chart publishing
- Horizontal Autoscaling: HPA for both services
- Pod Disruption Budgets: High availability
- Security: Non-root containers, read-only root filesystem
- Multi-Environment: Dev and production value files
🚀 Quick Start
Prerequisites
- Docker (for local development)
- Kubernetes cluster (v1.19+)
- Helm 3.8.0+
- API7 Enterprise Edition installed
- kubectl configured
Local Development
Run Web Application
cd web
pip install -r requirements.txt
# Set API backend URL (optional)
export API_BASE_URL="http://localhost:8001"
python main.py
Access:
- Dashboard: http://localhost:8000
- Documentation: http://localhost:8000/docs
Run API Application
cd api
pip install -r requirements.txt
# Configure LLM endpoint (optional)
export OPENAI_API_BASE="http://localhost:11434/api"
export OPENAI_API_KEY="your-api-key"
export DEFAULT_LLM_MODEL="videogame-expert"
python main.py
Access:
- API Docs: http://localhost:8001/docs
- Health: http://localhost:8001/health
Docker Development
# Build images
docker build -t web-app ./web
docker build -t api-app ./api
# Run containers
docker run -d -p 8000:8000 --name web web-app
docker run -d -p 8001:8001 --name api api-app
# With environment variables
docker run -d -p 8001:8001 \
-e OPENAI_API_BASE="http://host.docker.internal:11434/api" \
-e OPENAI_API_KEY="sk-xxx" \
--name api api-app
🔄 CI/CD Pipeline
Docker Image Builds
Workflow: .gitea/workflows/build.yml
Triggers:
- Push to any branch
- Pull requests
- Manual dispatch
Process:
- Checkout code
- Set up Docker Buildx
- Login to Gitea container registry
- Build and push images:
git.commandware.com/demos/api7-demo/web:<branch-name>git.commandware.com/demos/api7-demo/api:<branch-name>
Helm Chart Publishing
Workflow: .gitea/workflows/helm-build.yml
Triggers:
- Push to
mainbranch (publishes) - Pull requests (lint only)
- Manual dispatch
Process:
- Extract version from
Chart.yaml - Lint Helm chart
- Update image registries in values
- Package chart as
.tgz - Push to Gitea Helm registry:
https://git.commandware.com/api/packages/demos/helm
Chart Versioning: Version is defined in helm/api7ee-demo-k8s/Chart.yaml (single source of truth)
Setup CI/CD
-
Create Gitea Secrets:
Repository Settings → Secrets → Add Secret - Name: USERNAME - Value: your-gitea-username - Name: TOKEN - Value: <gitea-token-with-write:package> -
Generate Token:
- User Settings → Applications → Generate New Token
- Scopes:
write:package,read:package
-
Push to Trigger:
git push origin main
☸️ Kubernetes Deployment
Using Helm (Recommended)
Add Helm Repository
# Add the Helm repository
helm repo add api7ee https://git.commandware.com/api/packages/demos/helm
# Update repositories
helm repo update
# Search for available versions
helm search repo api7ee
Install
# Install with default values
helm install api7ee-demo api7ee/api7ee-demo-k8s \
--namespace api7ee \
--create-namespace
# Install with custom values
helm install api7ee-demo api7ee/api7ee-demo-k8s \
--namespace api7ee \
-f custom-values.yaml
# Install specific version with custom image tags
helm install api7ee-demo api7ee/api7ee-demo-k8s \
--version 0.1.0 \
--set web.image.tag=main \
--set api.image.tag=main \
--set api7.gateway.adminKey="your-admin-key" \
--namespace api7ee
Configuration
Key values to customize:
# Custom domain
api7:
hosts:
- your-domain.com
# API7 Gateway connection
api7:
gateway:
adminUrl: http://api7ee3-0-xxx-dp-manager.api7ee.svc.cluster.local:7900
adminKey: "your-admin-key"
gatewayService: gateway-0-xxx-gateway
# Image tags
web:
image:
tag: "v1.0.0"
api:
image:
tag: "v1.0.0"
# Scaling
web:
replicaCount: 3
api:
replicaCount: 5
autoscaling:
enabled: true
maxReplicas: 30
# TLS
api7:
tls:
certManager:
enabled: true
issuer: cloudflare-acme-prod
Manage Deployment
# Check status
helm list -n api7ee
kubectl get pods -n api7ee
# Upgrade
helm upgrade api7ee-demo api7ee/api7ee-demo-k8s \
--namespace api7ee \
--reuse-values \
--set api.replicaCount=5
# Rollback
helm rollback api7ee-demo -n api7ee
# Uninstall
helm uninstall api7ee-demo -n api7ee
Using Local Helm Chart
# Install from local directory
helm install api7ee-demo ./helm/api7ee-demo-k8s \
--namespace api7ee \
--create-namespace
# Use production values
helm install api7ee-demo ./helm/api7ee-demo-k8s \
-f ./helm/api7ee-demo-k8s/values-production.yaml \
--namespace api7ee
Environment-Specific Deployments
Development:
helm install api7ee-dev ./helm/api7ee-demo-k8s \
-f ./helm/api7ee-demo-k8s/values-dev.yaml \
--namespace api7ee-dev
Production:
helm install api7ee-prod ./helm/api7ee-demo-k8s \
-f ./helm/api7ee-demo-k8s/values-production.yaml \
--namespace api7ee-prod
🔌 API7 Gateway Configuration
ADC (API7 Declarative CLI) Configuration
The Helm chart automatically configures API7 Gateway using ADC. Configuration is in helm/api7ee-demo-k8s/templates/configmap-adc.yaml.
Route Structure
1. Web Route (Priority: 1)
- name: apache-route
uris: [/*]
vars:
- [uri, "~~", "^(?!/api)"] # Match all except /api/*
plugins:
redirect:
http_to_https: true
2. API Route (Priority: 10)
- name: nginx-api-route
uris: [/api, /api/*]
plugins:
redirect:
http_to_https: true
limit-count:
count: 100
time_window: 60
key_type: "var"
key: "remote_addr"
3. LLM Route (Priority: 20)
- name: nginx-api-llm-route
uris: [/api/llm, /api/llm/*]
plugins:
redirect:
http_to_https: true
ai-rate-limiting:
limit: 100
time_window: 60
limit_strategy: "total_tokens"
Manual ADC Sync
If you need to manually sync ADC configuration:
# Using standalone adc.yaml file
adc sync -f adc.yaml \
--backend api7ee \
--server https://api7-dashboard.commandware.it \
--token <YOUR_API7_TOKEN> \
--gateway-group default \
--tls-skip-verify
# Publish routes via Dashboard
# Navigate to: Services → Routes → Click "Publish" → Select "default" gateway group
Service Discovery
API7 automatically discovers Kubernetes services:
upstream:
type: roundrobin
discovery_type: kubernetes # Helm uses direct node configuration
nodes:
- host: apache-service.api7ee.svc.cluster.local
port: 80
weight: 100
When pods scale, API7 automatically updates the upstream nodes.
Rate Limiting Configuration
Standard Rate Limiting (IP-based):
- Plugin:
limit-count - Limit: 100 requests per 60 seconds per IP
- Applies to:
/api/*routes (excluding/api/llm/*)
AI Rate Limiting (Token-based):
- Plugin:
ai-rate-limiting - Limit: 100 tokens per 60 seconds
- Strategy:
total_tokens(counts input + output tokens) - Applies to:
/api/llm/*routes
TLS/SSL Configuration
Option 1: cert-manager (Recommended)
api7:
tls:
certManager:
enabled: true
issuer: cloudflare-acme-prod
issuerKind: ClusterIssuer
Option 2: Existing Secret
api7:
tls:
enabled: true
secretName: my-tls-secret
Option 3: Direct Certificates (Not recommended for production)
api7:
tls:
enabled: true
certificate: |
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
key: |
-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----
🛠️ Development
Environment Variables
Web Application:
API_BASE_URL=http://localhost:8001 # API backend URL
API Application:
OPENAI_API_BASE=http://localhost:11434/api # LLM API endpoint
OPENAI_API_KEY=your-api-key # LLM API key
DEFAULT_LLM_MODEL=videogame-expert # Default model
Testing Endpoints
# Web health
curl http://localhost:8000/health
# API health
curl http://localhost:8001/health
# LLM health
curl http://localhost:8001/llm/health
# Get items
curl http://localhost:8001/items
# LLM chat
curl -X POST http://localhost:8001/llm/chat \
-H "Content-Type: application/json" \
-d '{
"prompt": "What is Zelda?",
"max_tokens": 150,
"model": "videogame-expert"
}'
Building Documentation
cd web
# Serve documentation locally
mkdocs serve
# Build static site
mkdocs build -d site
🔧 Troubleshooting
Common Issues
1. Routes Return 404
Symptom: Routes synced but returning 404
Cause: Routes not published to gateway group
Solution:
# Check route status in API7 Dashboard
# Services → Select service → Routes → Check publication status
# Publish via Dashboard:
# Click "Publish" → Select "default" gateway group → Confirm
# Or enable autoPublish in Helm:
api7:
autoPublish: true
2. ADC Sync Job Fails
Symptom: ADC sync job shows error status
Check logs:
kubectl logs -n api7ee -l app.kubernetes.io/component=adc-sync
# Common issues:
# - Incorrect adminKey
# - Wrong adminUrl (should point to dp-manager service)
# - Network connectivity to API7 Gateway
Verify API7 connection:
# Test API7 admin API
kubectl run -it --rm debug --image=curlimages/curl --restart=Never -- \
curl -H "X-API-KEY: your-admin-key" \
http://api7ee3-0-xxx-dp-manager.api7ee.svc.cluster.local:7900/apisix/admin/routes
3. Service Discovery Not Working
Check:
# Verify service exists
kubectl get svc -n api7ee apache-service nginx-service
# Check service endpoints
kubectl get endpoints -n api7ee
# Verify service has named ports
kubectl get svc apache-service -n api7ee -o yaml | grep -A5 ports
Ensure ports are named:
spec:
ports:
- port: 80
targetPort: 8000
name: http # ← Name is required
4. LLM Endpoints Failing
Check API configuration:
# Verify environment variables
kubectl get deployment nginx-service -n api7ee -o yaml | grep -A10 env
# Check API logs
kubectl logs -n api7ee -l app=nginx-service --tail=50
# Test LLM backend directly
curl http://localhost:11434/api/chat/completions \
-H "Authorization: Bearer your-key" \
-d '{"model":"videogame-expert","messages":[{"role":"user","content":"test"}]}'
5. Image Pull Errors
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 Helm values
global:
imagePullSecrets:
- name: gitea-registry
6. Certificate Issues
Check cert-manager:
# Check certificate status
kubectl get certificate -n api7ee
# Check certificate details
kubectl describe certificate api7ee-tls -n api7ee
# Check cert-manager logs
kubectl logs -n cert-manager -l app=cert-manager --tail=50
# Check challenge status (for ACME)
kubectl get challenge -n api7ee
Getting Help
-
Check logs:
kubectl logs -n api7ee -l app.kubernetes.io/name=api7ee-demo-k8s --tail=100 -
Check events:
kubectl get events -n api7ee --sort-by='.lastTimestamp' -
Verify Helm installation:
helm status api7ee-demo -n api7ee helm get values api7ee-demo -n api7ee -
Test connectivity:
kubectl run -it --rm debug --image=nicolaka/netshoot --restart=Never -n api7ee -- bash # Inside pod: curl http://apache-service curl http://nginx-service
📚 Resources
Documentation
- API7 Enterprise: https://docs.api7.ai/
- APISIX: https://apisix.apache.org/docs/
- FastAPI: https://fastapi.tiangolo.com/
- Helm: https://helm.sh/docs/
- Gitea Actions: https://docs.gitea.com/usage/actions/overview
Project Links
- Repository: https://git.commandware.com/demos/api7-demo
- Helm Registry: https://git.commandware.com/api/packages/demos/helm
- Container Registry: https://git.commandware.com/demos/-/packages/container
- Live Demo: https://api7-demo.commandware.it
Support
📄 License
Demo project for API7 Enterprise Gateway evaluation.
Version: 0.1.0 | Last Updated: 2025-10-07