Move documentation to MkDocs and add comprehensive guides
Reorganized documentation to be part of MkDocs site with three new
comprehensive guides covering API7 Gateway configuration.
Changes:
1. Documentation Structure:
- Moved SECRET-MANAGEMENT.md from helm/ to web/docs/
- Created service-discovery.md with complete guide
- Created ingress-routing.md with routing architecture
- Moved externalsecret examples to web/docs/examples/
2. New Documentation - Service Discovery:
- How service discovery works (architecture diagram)
- Benefits vs static configuration
- Configuration examples
- RBAC requirements
- Advanced use cases (auto-scaling, rolling updates)
- Load balancing algorithms
- Monitoring and troubleshooting
- Best practices
3. New Documentation - Ingress & Routing:
- Complete traffic flow architecture
- Ingress configuration explained
- Gateway routing rules and priority
- URI matching patterns (prefix, exact, regex)
- TLS/SSL with cert-manager
- Advanced routing scenarios:
* Multiple domains
* Path-based routing
* Header-based routing
* Method-based routing
- Configuration examples (microservices, WebSocket, canary)
- Monitoring and debugging
- Troubleshooting common issues
4. MkDocs Navigation:
- Updated mkdocs.yml with new pages in Configuration section
- Added: Ingress & Routing
- Added: Service Discovery
- Added: Secret Management
5. Examples Directory:
- Created web/docs/examples/ for configuration examples
- Moved ExternalSecret examples with multiple providers:
* AWS Secrets Manager
* HashiCorp Vault
* Azure Key Vault
* GCP Secret Manager
All documentation now integrated into MkDocs site with proper
navigation, cross-references, and Material theme styling.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
120
web/docs/examples/externalsecret-api7.yaml
Normal file
120
web/docs/examples/externalsecret-api7.yaml
Normal file
@@ -0,0 +1,120 @@
|
||||
# Example ExternalSecret for API7 Gateway credentials
|
||||
# This file demonstrates how to use External Secrets Operator with API7 Gateway
|
||||
#
|
||||
# Documentation: https://external-secrets.io/
|
||||
|
||||
apiVersion: external-secrets.io/v1beta1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: api7-gateway-credentials
|
||||
namespace: api7ee
|
||||
labels:
|
||||
app.kubernetes.io/name: api7ee-demo
|
||||
app.kubernetes.io/component: api7
|
||||
spec:
|
||||
# Refresh interval for fetching secrets from external provider
|
||||
refreshInterval: 1h
|
||||
|
||||
# Reference to SecretStore
|
||||
secretStoreRef:
|
||||
name: vault-backend # Name of your SecretStore
|
||||
kind: SecretStore # or ClusterSecretStore
|
||||
|
||||
# Target Secret configuration
|
||||
target:
|
||||
name: api7-credentials
|
||||
creationPolicy: Owner
|
||||
template:
|
||||
type: Opaque
|
||||
data:
|
||||
# Map external secret keys to Kubernetes secret keys
|
||||
admin-url: "{{ .adminUrl }}"
|
||||
admin-key: "{{ .adminKey }}"
|
||||
gateway-group: "{{ .group }}"
|
||||
|
||||
# Data to fetch from external provider
|
||||
data:
|
||||
- secretKey: adminUrl
|
||||
remoteRef:
|
||||
key: api7/gateway # Path in external secret store
|
||||
property: admin_url # Property name
|
||||
|
||||
- secretKey: adminKey
|
||||
remoteRef:
|
||||
key: api7/gateway
|
||||
property: admin_key
|
||||
|
||||
- secretKey: group
|
||||
remoteRef:
|
||||
key: api7/gateway
|
||||
property: gateway_group
|
||||
|
||||
---
|
||||
# Example SecretStore for AWS Secrets Manager
|
||||
apiVersion: external-secrets.io/v1beta1
|
||||
kind: SecretStore
|
||||
metadata:
|
||||
name: aws-secretsmanager
|
||||
namespace: api7ee
|
||||
spec:
|
||||
provider:
|
||||
aws:
|
||||
service: SecretsManager
|
||||
region: us-east-1
|
||||
auth:
|
||||
jwt:
|
||||
serviceAccountRef:
|
||||
name: external-secrets-sa
|
||||
|
||||
---
|
||||
# Example SecretStore for HashiCorp Vault
|
||||
apiVersion: external-secrets.io/v1beta1
|
||||
kind: SecretStore
|
||||
metadata:
|
||||
name: vault-backend
|
||||
namespace: api7ee
|
||||
spec:
|
||||
provider:
|
||||
vault:
|
||||
server: "https://vault.example.com"
|
||||
path: "secret"
|
||||
version: "v2"
|
||||
auth:
|
||||
kubernetes:
|
||||
mountPath: "kubernetes"
|
||||
role: "api7-role"
|
||||
serviceAccountRef:
|
||||
name: api7ee-demo-api7ee-demo-k8s
|
||||
|
||||
---
|
||||
# Example SecretStore for Azure Key Vault
|
||||
apiVersion: external-secrets.io/v1beta1
|
||||
kind: SecretStore
|
||||
metadata:
|
||||
name: azure-keyvault
|
||||
namespace: api7ee
|
||||
spec:
|
||||
provider:
|
||||
azurekv:
|
||||
vaultUrl: "https://my-vault.vault.azure.net"
|
||||
authType: WorkloadIdentity
|
||||
serviceAccountRef:
|
||||
name: api7ee-demo-api7ee-demo-k8s
|
||||
|
||||
---
|
||||
# Example SecretStore for GCP Secret Manager
|
||||
apiVersion: external-secrets.io/v1beta1
|
||||
kind: SecretStore
|
||||
metadata:
|
||||
name: gcp-secretmanager
|
||||
namespace: api7ee
|
||||
spec:
|
||||
provider:
|
||||
gcpsm:
|
||||
projectID: "my-project"
|
||||
auth:
|
||||
workloadIdentity:
|
||||
clusterLocation: us-central1
|
||||
clusterName: my-cluster
|
||||
serviceAccountRef:
|
||||
name: api7ee-demo-api7ee-demo-k8s
|
||||
616
web/docs/ingress-routing.md
Normal file
616
web/docs/ingress-routing.md
Normal file
@@ -0,0 +1,616 @@
|
||||
# Ingress and Gateway Routing
|
||||
|
||||
Learn how external traffic is routed through Kubernetes Ingress to the API7 Gateway, and then to backend services.
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
A[External User] -->|HTTPS| B[Ingress Controller]
|
||||
B -->|HTTP/HTTPS| C[API7 Gateway]
|
||||
C -->|Apply Plugins| C
|
||||
C -->|Route Traffic| D[Backend Service 1]
|
||||
C -->|Route Traffic| E[Backend Service 2]
|
||||
C -->|Route Traffic| F[Backend Service 3]
|
||||
|
||||
G[cert-manager] -->|TLS Cert| B
|
||||
H[ADC ConfigMap] -->|Routing Rules| C
|
||||
```
|
||||
|
||||
**Traffic Flow:**
|
||||
1. **External request** arrives at Ingress Controller (NGINX)
|
||||
2. **Ingress Controller** terminates TLS and forwards to API7 Gateway
|
||||
3. **API7 Gateway** applies policies (rate limiting, CORS, auth)
|
||||
4. **Gateway** routes to backend services based on ADC rules
|
||||
5. **Backend services** process request and return response
|
||||
|
||||
## Ingress Configuration
|
||||
|
||||
### Current Setup
|
||||
|
||||
The Helm chart configures Ingress to route **all traffic** through API7 Gateway:
|
||||
|
||||
```yaml
|
||||
# values.yaml
|
||||
ingress:
|
||||
enabled: true
|
||||
className: "nginx"
|
||||
|
||||
hosts:
|
||||
- host: commandware.it
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
gateway:
|
||||
serviceName: gateway-0-1759393614-gateway
|
||||
port: 80
|
||||
```
|
||||
|
||||
Generated Ingress resource:
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: api7ee-demo
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: cloudflare-acme-prod
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
tls:
|
||||
- hosts:
|
||||
- commandware.it
|
||||
secretName: api7ee-tls
|
||||
rules:
|
||||
- host: commandware.it
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: gateway-0-1759393614-gateway
|
||||
port:
|
||||
number: 80
|
||||
```
|
||||
|
||||
### Why Route Through Gateway?
|
||||
|
||||
**With API7 Gateway (Recommended):**
|
||||
```
|
||||
User → Ingress → API7 Gateway → Backend
|
||||
↓
|
||||
TLS, Basic Routing
|
||||
↓
|
||||
Advanced Features:
|
||||
- Dynamic routing
|
||||
- Rate limiting
|
||||
- CORS policies
|
||||
- Authentication
|
||||
- Request transformation
|
||||
- Metrics & logging
|
||||
```
|
||||
|
||||
**Direct to Service (Legacy):**
|
||||
```
|
||||
User → Ingress → Backend
|
||||
↓
|
||||
TLS, Basic Routing
|
||||
❌ No advanced features
|
||||
❌ No rate limiting
|
||||
❌ No CORS
|
||||
❌ No centralized auth
|
||||
```
|
||||
|
||||
## Gateway Routing Rules
|
||||
|
||||
### ADC Configuration
|
||||
|
||||
API7 Gateway uses **ADC (API Declarative Configuration)** to define routing rules:
|
||||
|
||||
```yaml
|
||||
# Managed by Helm chart in ConfigMap
|
||||
services:
|
||||
- name: web-service
|
||||
hosts:
|
||||
- commandware.it
|
||||
upstream:
|
||||
discovery_type: kubernetes
|
||||
service_name: my-web-app
|
||||
namespace_id: default
|
||||
routes:
|
||||
- name: web-route
|
||||
uris:
|
||||
- /*
|
||||
priority: 1
|
||||
plugins:
|
||||
cors: {...}
|
||||
redirect:
|
||||
http_to_https: true
|
||||
|
||||
- name: api-service
|
||||
hosts:
|
||||
- commandware.it
|
||||
upstream:
|
||||
discovery_type: kubernetes
|
||||
service_name: my-api
|
||||
namespace_id: default
|
||||
routes:
|
||||
- name: api-route
|
||||
uris:
|
||||
- /api
|
||||
- /api/*
|
||||
priority: 10
|
||||
plugins:
|
||||
limit-count: {...}
|
||||
cors: {...}
|
||||
```
|
||||
|
||||
### Route Priority
|
||||
|
||||
Routes are evaluated by **priority** (higher number = higher priority):
|
||||
|
||||
```yaml
|
||||
routes:
|
||||
# Evaluated FIRST (highest priority)
|
||||
- name: api-llm-route
|
||||
uris:
|
||||
- /api/llm/*
|
||||
priority: 20
|
||||
plugins:
|
||||
ai-rate-limiting: {...}
|
||||
|
||||
# Evaluated SECOND
|
||||
- name: api-route
|
||||
uris:
|
||||
- /api/*
|
||||
priority: 10
|
||||
plugins:
|
||||
limit-count: {...}
|
||||
|
||||
# Evaluated LAST (lowest priority)
|
||||
- name: web-route
|
||||
uris:
|
||||
- /*
|
||||
priority: 1
|
||||
```
|
||||
|
||||
**Example Request Matching:**
|
||||
- `GET /api/llm/chat` → Matches `api-llm-route` (priority 20)
|
||||
- `GET /api/users` → Matches `api-route` (priority 10)
|
||||
- `GET /about` → Matches `web-route` (priority 1)
|
||||
|
||||
### URI Matching Patterns
|
||||
|
||||
**Prefix matching:**
|
||||
```yaml
|
||||
uris:
|
||||
- /api/* # Matches /api/users, /api/v1/products, etc.
|
||||
- /admin/* # Matches /admin/dashboard, /admin/users, etc.
|
||||
```
|
||||
|
||||
**Exact matching:**
|
||||
```yaml
|
||||
uris:
|
||||
- /health # Matches only /health
|
||||
- /ready # Matches only /ready
|
||||
```
|
||||
|
||||
**Regex matching:**
|
||||
```yaml
|
||||
vars:
|
||||
- - uri
|
||||
- "~~"
|
||||
- "^(?!/api)" # Match all URIs NOT starting with /api
|
||||
```
|
||||
|
||||
## TLS/SSL Configuration
|
||||
|
||||
### Certificate Management
|
||||
|
||||
The setup uses **cert-manager** with Cloudflare ACME:
|
||||
|
||||
```yaml
|
||||
# values.yaml
|
||||
ingress:
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: cloudflare-acme-prod
|
||||
tls:
|
||||
- secretName: api7ee-tls
|
||||
hosts:
|
||||
- commandware.it
|
||||
```
|
||||
|
||||
Generated Certificate:
|
||||
|
||||
```yaml
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: Certificate
|
||||
metadata:
|
||||
name: api7ee-demo-tls
|
||||
spec:
|
||||
secretName: api7ee-tls
|
||||
issuerRef:
|
||||
name: cloudflare-acme-prod
|
||||
kind: ClusterIssuer
|
||||
dnsNames:
|
||||
- commandware.it
|
||||
duration: 2160h # 90 days
|
||||
renewBefore: 720h # Renew 30 days before expiry
|
||||
```
|
||||
|
||||
### HTTP to HTTPS Redirect
|
||||
|
||||
API7 Gateway handles HTTP→HTTPS redirect:
|
||||
|
||||
```yaml
|
||||
plugins:
|
||||
redirect:
|
||||
http_to_https: true
|
||||
```
|
||||
|
||||
**Request flow:**
|
||||
1. User visits `http://commandware.it/api`
|
||||
2. Gateway returns `301 Moved Permanently`
|
||||
3. Browser redirects to `https://commandware.it/api`
|
||||
|
||||
## Advanced Routing Scenarios
|
||||
|
||||
### Multiple Domains
|
||||
|
||||
Route different domains to different backends:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
- name: main-site
|
||||
hosts:
|
||||
- commandware.it
|
||||
upstream:
|
||||
service_name: main-web
|
||||
routes:
|
||||
- uris: ["/*"]
|
||||
|
||||
- name: api-site
|
||||
hosts:
|
||||
- api.commandware.it
|
||||
upstream:
|
||||
service_name: api-backend
|
||||
routes:
|
||||
- uris: ["/*"]
|
||||
```
|
||||
|
||||
### Path-Based Routing
|
||||
|
||||
Route based on URL paths:
|
||||
|
||||
```yaml
|
||||
routes:
|
||||
# Route 1: Frontend SPA
|
||||
- name: frontend
|
||||
uris:
|
||||
- /
|
||||
- /app/*
|
||||
- /assets/*
|
||||
upstream:
|
||||
service_name: frontend-app
|
||||
|
||||
# Route 2: API endpoints
|
||||
- name: backend-api
|
||||
uris:
|
||||
- /api/*
|
||||
upstream:
|
||||
service_name: backend-api
|
||||
|
||||
# Route 3: Admin panel
|
||||
- name: admin
|
||||
uris:
|
||||
- /admin/*
|
||||
upstream:
|
||||
service_name: admin-panel
|
||||
plugins:
|
||||
key-auth: {...} # Require authentication
|
||||
```
|
||||
|
||||
### Header-Based Routing
|
||||
|
||||
Route based on HTTP headers:
|
||||
|
||||
```yaml
|
||||
routes:
|
||||
# Route for API v2 clients
|
||||
- name: api-v2
|
||||
uris:
|
||||
- /api/*
|
||||
vars:
|
||||
- - http_x_api_version
|
||||
- "=="
|
||||
- "v2"
|
||||
upstream:
|
||||
service_name: api-v2
|
||||
|
||||
# Route for API v1 clients (default)
|
||||
- name: api-v1
|
||||
uris:
|
||||
- /api/*
|
||||
upstream:
|
||||
service_name: api-v1
|
||||
```
|
||||
|
||||
### Method-Based Routing
|
||||
|
||||
Route based on HTTP method:
|
||||
|
||||
```yaml
|
||||
routes:
|
||||
# Read operations → Read-only replica
|
||||
- name: read-ops
|
||||
uris:
|
||||
- /api/*
|
||||
methods:
|
||||
- GET
|
||||
- HEAD
|
||||
upstream:
|
||||
service_name: api-readonly
|
||||
|
||||
# Write operations → Primary backend
|
||||
- name: write-ops
|
||||
uris:
|
||||
- /api/*
|
||||
methods:
|
||||
- POST
|
||||
- PUT
|
||||
- DELETE
|
||||
- PATCH
|
||||
upstream:
|
||||
service_name: api-primary
|
||||
```
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
### Example 1: Microservices API
|
||||
|
||||
```yaml
|
||||
services:
|
||||
# User service
|
||||
- name: users-api
|
||||
hosts:
|
||||
- api.commandware.it
|
||||
upstream:
|
||||
discovery_type: kubernetes
|
||||
service_name: users-service
|
||||
routes:
|
||||
- uris: ["/users", "/users/*"]
|
||||
plugins:
|
||||
limit-count:
|
||||
count: 100
|
||||
time_window: 60
|
||||
|
||||
# Orders service
|
||||
- name: orders-api
|
||||
hosts:
|
||||
- api.commandware.it
|
||||
upstream:
|
||||
discovery_type: kubernetes
|
||||
service_name: orders-service
|
||||
routes:
|
||||
- uris: ["/orders", "/orders/*"]
|
||||
plugins:
|
||||
key-auth: {}
|
||||
|
||||
# Products service
|
||||
- name: products-api
|
||||
hosts:
|
||||
- api.commandware.it
|
||||
upstream:
|
||||
discovery_type: kubernetes
|
||||
service_name: products-service
|
||||
routes:
|
||||
- uris: ["/products", "/products/*"]
|
||||
```
|
||||
|
||||
### Example 2: API with WebSocket
|
||||
|
||||
```yaml
|
||||
services:
|
||||
- name: websocket-service
|
||||
hosts:
|
||||
- ws.commandware.it
|
||||
upstream:
|
||||
service_name: websocket-backend
|
||||
routes:
|
||||
# WebSocket endpoint
|
||||
- name: ws-route
|
||||
uris:
|
||||
- /ws
|
||||
enable_websocket: true
|
||||
|
||||
# HTTP fallback
|
||||
- name: http-route
|
||||
uris:
|
||||
- /*
|
||||
```
|
||||
|
||||
### Example 3: Canary Deployment
|
||||
|
||||
```yaml
|
||||
services:
|
||||
# 90% traffic to stable version
|
||||
- name: app-stable
|
||||
hosts:
|
||||
- app.commandware.it
|
||||
upstream:
|
||||
service_name: app-v1
|
||||
nodes:
|
||||
- weight: 90
|
||||
routes:
|
||||
- uris: ["/*"]
|
||||
|
||||
# 10% traffic to canary version
|
||||
- name: app-canary
|
||||
hosts:
|
||||
- app.commandware.it
|
||||
upstream:
|
||||
service_name: app-v2
|
||||
nodes:
|
||||
- weight: 10
|
||||
routes:
|
||||
- uris: ["/*"]
|
||||
```
|
||||
|
||||
## Monitoring and Debugging
|
||||
|
||||
### Check Ingress Status
|
||||
|
||||
```bash
|
||||
# Get Ingress resource
|
||||
kubectl get ingress -n api7ee
|
||||
|
||||
# Describe Ingress
|
||||
kubectl describe ingress api7ee-demo -n api7ee
|
||||
|
||||
# Check Ingress Controller logs
|
||||
kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx
|
||||
```
|
||||
|
||||
### Check Gateway Routing
|
||||
|
||||
```bash
|
||||
# View ADC configuration
|
||||
kubectl get configmap api7ee-demo-api7ee-demo-k8s-adc-config -n api7ee -o yaml
|
||||
|
||||
# Check Gateway logs
|
||||
kubectl logs -n api7ee -l app.kubernetes.io/name=gateway
|
||||
|
||||
# Test routing
|
||||
curl -v https://commandware.it/api/health
|
||||
```
|
||||
|
||||
### Verify TLS Certificate
|
||||
|
||||
```bash
|
||||
# Check certificate
|
||||
kubectl get certificate -n api7ee
|
||||
|
||||
# Describe certificate
|
||||
kubectl describe certificate api7ee-demo-tls -n api7ee
|
||||
|
||||
# View certificate secret
|
||||
kubectl get secret api7ee-tls -n api7ee -o yaml
|
||||
|
||||
# Test TLS connection
|
||||
openssl s_client -connect commandware.it:443 -servername commandware.it
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### 404 Not Found
|
||||
|
||||
**Cause:** No route matches the request
|
||||
|
||||
**Debug:**
|
||||
```bash
|
||||
# Check ADC routes
|
||||
kubectl get configmap -n api7ee api7ee-demo-adc-config -o yaml | grep -A 10 "routes:"
|
||||
|
||||
# Check Gateway logs
|
||||
kubectl logs -n api7ee -l app.kubernetes.io/name=gateway | grep 404
|
||||
```
|
||||
|
||||
### 502 Bad Gateway
|
||||
|
||||
**Cause:** Backend service is unavailable
|
||||
|
||||
**Debug:**
|
||||
```bash
|
||||
# Check backend service
|
||||
kubectl get svc my-backend -n api7ee
|
||||
|
||||
# Check backend Pods
|
||||
kubectl get pods -l app=my-backend -n api7ee
|
||||
|
||||
# Check service discovery
|
||||
kubectl get endpoints my-backend -n api7ee
|
||||
```
|
||||
|
||||
### TLS Certificate Issues
|
||||
|
||||
**Cause:** cert-manager failed to issue certificate
|
||||
|
||||
**Debug:**
|
||||
```bash
|
||||
# Check certificate status
|
||||
kubectl describe certificate api7ee-demo-tls -n api7ee
|
||||
|
||||
# Check cert-manager logs
|
||||
kubectl logs -n cert-manager -l app=cert-manager
|
||||
|
||||
# Check certificate request
|
||||
kubectl get certificaterequest -n api7ee
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Always Use Gateway for Production
|
||||
|
||||
✅ **Do:** Route through API7 Gateway for advanced features
|
||||
|
||||
❌ **Don't:** Route directly to backend services
|
||||
|
||||
### 2. Use Descriptive Route Names
|
||||
|
||||
```yaml
|
||||
# Good
|
||||
routes:
|
||||
- name: api-users-list
|
||||
- name: api-products-create
|
||||
- name: web-frontend-spa
|
||||
|
||||
# Bad
|
||||
routes:
|
||||
- name: route1
|
||||
- name: route2
|
||||
```
|
||||
|
||||
### 3. Set Appropriate Priorities
|
||||
|
||||
Higher priority for more specific routes:
|
||||
|
||||
```yaml
|
||||
# Specific route (high priority)
|
||||
- uris: ["/api/v2/users/*"]
|
||||
priority: 20
|
||||
|
||||
# General route (low priority)
|
||||
- uris: ["/api/*"]
|
||||
priority: 10
|
||||
```
|
||||
|
||||
### 4. Enable TLS Everywhere
|
||||
|
||||
Always use HTTPS in production:
|
||||
|
||||
```yaml
|
||||
plugins:
|
||||
redirect:
|
||||
http_to_https: true
|
||||
```
|
||||
|
||||
### 5. Monitor Gateway Metrics
|
||||
|
||||
Set up monitoring for:
|
||||
- Request latency
|
||||
- Error rates (4xx, 5xx)
|
||||
- Upstream health
|
||||
- TLS certificate expiry
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Configure Service Discovery](service-discovery.md)
|
||||
- [Manage Secrets Securely](secret-management.md)
|
||||
- [Set Up Rate Limiting](api7-configuration.md#rate-limiting)
|
||||
|
||||
## References
|
||||
|
||||
- [Kubernetes Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/)
|
||||
- [cert-manager Documentation](https://cert-manager.io/docs/)
|
||||
- [API7 Gateway Routing](https://docs.api7.ai/enterprise/key-concepts/routes/)
|
||||
233
web/docs/secret-management.md
Normal file
233
web/docs/secret-management.md
Normal file
@@ -0,0 +1,233 @@
|
||||
# Secret Management for API7 Gateway
|
||||
|
||||
This document explains how to manage API7 Gateway credentials securely.
|
||||
|
||||
## Overview
|
||||
|
||||
API7 Gateway requires the following credentials:
|
||||
- **Admin URL**: Dashboard admin API endpoint
|
||||
- **Admin Key**: Authentication token for admin API
|
||||
- **Gateway Group**: Logical grouping of gateway instances
|
||||
|
||||
## Configuration Options
|
||||
|
||||
### Option 1: Inline Configuration (Development Only)
|
||||
|
||||
**⚠️ NOT RECOMMENDED for production**
|
||||
|
||||
Credentials are stored directly in `values.yaml`:
|
||||
|
||||
```yaml
|
||||
api7:
|
||||
gateway:
|
||||
existingSecret: "" # Leave empty
|
||||
adminUrl: https://api7ee3-0-1759339083-dashboard:7443
|
||||
adminKey: "your-admin-key"
|
||||
group: default
|
||||
```
|
||||
|
||||
The chart will create a Kubernetes Secret automatically.
|
||||
|
||||
### Option 2: Existing Secret (Recommended)
|
||||
|
||||
**✅ RECOMMENDED for production**
|
||||
|
||||
Create a Secret manually or using a secret management tool, then reference it:
|
||||
|
||||
```yaml
|
||||
api7:
|
||||
gateway:
|
||||
existingSecret: "api7-credentials" # Name of your secret
|
||||
existingSecretKeys:
|
||||
adminUrl: admin-url
|
||||
adminKey: admin-key
|
||||
group: gateway-group
|
||||
```
|
||||
|
||||
#### Create Secret Manually
|
||||
|
||||
```bash
|
||||
kubectl create secret generic api7-credentials \
|
||||
--from-literal=admin-url=https://api7ee3-0-1759339083-dashboard:7443 \
|
||||
--from-literal=admin-key=YOUR_ADMIN_KEY \
|
||||
--from-literal=gateway-group=default \
|
||||
-n api7ee
|
||||
```
|
||||
|
||||
#### Get Admin Key from API7 Enterprise
|
||||
|
||||
```bash
|
||||
# Get admin key from API7 Enterprise installation
|
||||
kubectl get secret -n api7ee api7ee3-0-1759339083 \
|
||||
-o jsonpath='{.data.admin_key}' | base64 -d
|
||||
```
|
||||
|
||||
### Option 3: External Secrets Operator
|
||||
|
||||
**✅ RECOMMENDED for production with centralized secret management**
|
||||
|
||||
Use External Secrets Operator to sync secrets from external providers like:
|
||||
- AWS Secrets Manager
|
||||
- HashiCorp Vault
|
||||
- Azure Key Vault
|
||||
- GCP Secret Manager
|
||||
- And more...
|
||||
|
||||
#### Step 1: Install External Secrets Operator
|
||||
|
||||
```bash
|
||||
helm repo add external-secrets https://charts.external-secrets.io
|
||||
helm install external-secrets external-secrets/external-secrets -n external-secrets-system --create-namespace
|
||||
```
|
||||
|
||||
#### Step 2: Configure SecretStore
|
||||
|
||||
Example for HashiCorp Vault:
|
||||
|
||||
```yaml
|
||||
apiVersion: external-secrets.io/v1beta1
|
||||
kind: SecretStore
|
||||
metadata:
|
||||
name: vault-backend
|
||||
namespace: api7ee
|
||||
spec:
|
||||
provider:
|
||||
vault:
|
||||
server: "https://vault.example.com"
|
||||
path: "secret"
|
||||
version: "v2"
|
||||
auth:
|
||||
kubernetes:
|
||||
mountPath: "kubernetes"
|
||||
role: "api7-role"
|
||||
serviceAccountRef:
|
||||
name: api7ee-demo-api7ee-demo-k8s
|
||||
```
|
||||
|
||||
#### Step 3: Create ExternalSecret
|
||||
|
||||
See `templates/externalsecret-api7.yaml.example` for a complete example.
|
||||
|
||||
```yaml
|
||||
apiVersion: external-secrets.io/v1beta1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: api7-credentials-external
|
||||
namespace: api7ee
|
||||
spec:
|
||||
refreshInterval: 1h
|
||||
secretStoreRef:
|
||||
name: vault-backend
|
||||
kind: SecretStore
|
||||
target:
|
||||
name: api7-credentials
|
||||
creationPolicy: Owner
|
||||
data:
|
||||
- secretKey: admin-url
|
||||
remoteRef:
|
||||
key: api7/gateway
|
||||
property: admin_url
|
||||
- secretKey: admin-key
|
||||
remoteRef:
|
||||
key: api7/gateway
|
||||
property: admin_key
|
||||
- secretKey: gateway-group
|
||||
remoteRef:
|
||||
key: api7/gateway
|
||||
property: gateway_group
|
||||
```
|
||||
|
||||
#### Step 4: Configure Helm Values
|
||||
|
||||
```yaml
|
||||
api7:
|
||||
gateway:
|
||||
existingSecret: "api7-credentials" # Created by ExternalSecret
|
||||
```
|
||||
|
||||
## Secret Keys
|
||||
|
||||
The Secret must contain these keys (default names):
|
||||
|
||||
| Key | Description | Example |
|
||||
|-----|-------------|---------|
|
||||
| `admin-url` | Dashboard admin API URL | `https://api7ee3-0-1759339083-dashboard:7443` |
|
||||
| `admin-key` | Dashboard admin API key | `edd1c9f034335f136f87ad84b625c8f1` |
|
||||
| `gateway-group` | Gateway group name | `default` |
|
||||
|
||||
### Custom Key Names
|
||||
|
||||
If your Secret uses different key names, configure them:
|
||||
|
||||
```yaml
|
||||
api7:
|
||||
gateway:
|
||||
existingSecret: "my-custom-secret"
|
||||
existingSecretKeys:
|
||||
adminUrl: dashboard_url # Your custom key name
|
||||
adminKey: api_token # Your custom key name
|
||||
group: group_name # Your custom key name
|
||||
```
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
1. **Never commit secrets to Git**
|
||||
- Use `.gitignore` for values files containing secrets
|
||||
- Use secret management tools for production
|
||||
|
||||
2. **Use RBAC to restrict secret access**
|
||||
- Limit which ServiceAccounts can read secrets
|
||||
- Use namespace isolation
|
||||
|
||||
3. **Rotate credentials regularly**
|
||||
- Update admin keys periodically
|
||||
- Use External Secrets Operator for automatic rotation
|
||||
|
||||
4. **Enable audit logging**
|
||||
- Monitor secret access in Kubernetes audit logs
|
||||
- Alert on unauthorized access attempts
|
||||
|
||||
5. **Use encryption at rest**
|
||||
- Enable Kubernetes secret encryption
|
||||
- Use external KMS for additional security
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Secret not found
|
||||
|
||||
```bash
|
||||
# Check if secret exists
|
||||
kubectl get secret -n api7ee
|
||||
|
||||
# Describe the secret
|
||||
kubectl describe secret api7-credentials -n api7ee
|
||||
```
|
||||
|
||||
### Invalid credentials
|
||||
|
||||
```bash
|
||||
# View secret data (base64 encoded)
|
||||
kubectl get secret api7-credentials -n api7ee -o yaml
|
||||
|
||||
# Decode and verify values
|
||||
kubectl get secret api7-credentials -n api7ee \
|
||||
-o jsonpath='{.data.admin-key}' | base64 -d
|
||||
```
|
||||
|
||||
### ADC sync job fails
|
||||
|
||||
```bash
|
||||
# Check job logs
|
||||
kubectl logs -n api7ee job/api7ee-demo-api7ee-demo-k8s-adc-sync
|
||||
|
||||
# Common issues:
|
||||
# - Wrong admin URL (check DNS resolution)
|
||||
# - Invalid admin key (verify key is correct)
|
||||
# - TLS certificate issues (use tlsSkipVerify: true for self-signed)
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- [External Secrets Operator Documentation](https://external-secrets.io/)
|
||||
- [Kubernetes Secrets](https://kubernetes.io/docs/concepts/configuration/secret/)
|
||||
- [API7 Enterprise Documentation](https://docs.api7.ai/enterprise/)
|
||||
379
web/docs/service-discovery.md
Normal file
379
web/docs/service-discovery.md
Normal file
@@ -0,0 +1,379 @@
|
||||
# Service Discovery
|
||||
|
||||
Learn how API7 Gateway dynamically discovers backend services using Kubernetes service discovery.
|
||||
|
||||
## Overview
|
||||
|
||||
Service Discovery enables API7 Gateway to automatically discover and track backend Pod endpoints instead of using static upstream node configuration. This provides a dynamic, scalable, and resilient architecture.
|
||||
|
||||
## Why Use Service Discovery?
|
||||
|
||||
### Traditional Static Configuration
|
||||
|
||||
```yaml
|
||||
upstream:
|
||||
nodes:
|
||||
- host: 10.0.1.23
|
||||
port: 8080
|
||||
weight: 100
|
||||
- host: 10.0.1.24
|
||||
port: 8080
|
||||
weight: 100
|
||||
```
|
||||
|
||||
**Problems:**
|
||||
- ❌ Manual updates required when Pods scale
|
||||
- ❌ Stale Pod IPs after deployments
|
||||
- ❌ No automatic health checks
|
||||
- ❌ Downtime during updates
|
||||
|
||||
### With Kubernetes Service Discovery
|
||||
|
||||
```yaml
|
||||
upstream:
|
||||
discovery_type: kubernetes
|
||||
service_name: my-service
|
||||
namespace_id: default
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- ✅ Automatic Pod discovery
|
||||
- ✅ Real-time updates during scaling
|
||||
- ✅ Health checks built-in
|
||||
- ✅ Zero downtime deployments
|
||||
|
||||
## How It Works
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
A[API7 Gateway] -->|Query Endpoints| B[Kubernetes API]
|
||||
B -->|Return Pod IPs| A
|
||||
A -->|Route Traffic| C[Pod 1]
|
||||
A -->|Route Traffic| D[Pod 2]
|
||||
A -->|Route Traffic| E[Pod 3]
|
||||
|
||||
F[HPA/Deploy] -->|Scale/Update| B
|
||||
B -->|Notify| A
|
||||
```
|
||||
|
||||
1. **API7 Gateway** watches Kubernetes Endpoints API
|
||||
2. **Kubernetes API** returns list of healthy Pod IPs
|
||||
3. **Gateway** automatically adds/removes Pods from upstream
|
||||
4. **Traffic** is load-balanced across discovered Pods
|
||||
|
||||
## Configuration
|
||||
|
||||
### Enable in Helm Chart
|
||||
|
||||
Edit `values.yaml`:
|
||||
|
||||
```yaml
|
||||
api7:
|
||||
serviceDiscovery:
|
||||
enabled: true # Enable Kubernetes service discovery
|
||||
namespace: "" # Leave empty to use release namespace
|
||||
```
|
||||
|
||||
### ADC Configuration
|
||||
|
||||
The Helm chart automatically generates ADC configuration with service discovery:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
- name: my-service
|
||||
upstream:
|
||||
name: my-upstream
|
||||
type: roundrobin
|
||||
discovery_type: kubernetes
|
||||
service_name: my-service # Kubernetes Service name
|
||||
namespace_id: default # Kubernetes namespace
|
||||
```
|
||||
|
||||
### RBAC Requirements
|
||||
|
||||
Service Discovery requires permissions to watch Kubernetes resources. These are automatically configured in `rbac-adc.yaml`:
|
||||
|
||||
```yaml
|
||||
rules:
|
||||
# Allow reading services and endpoints for service discovery
|
||||
- apiGroups: [""]
|
||||
resources: ["services", "endpoints"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
```
|
||||
|
||||
## Use Cases
|
||||
|
||||
### 1. Auto-Scaling Applications
|
||||
|
||||
When your application scales:
|
||||
|
||||
```bash
|
||||
# Scale deployment
|
||||
kubectl scale deployment my-app --replicas=10
|
||||
|
||||
# API7 Gateway automatically discovers new Pods
|
||||
# No configuration changes needed!
|
||||
```
|
||||
|
||||
### 2. Rolling Updates
|
||||
|
||||
During deployments:
|
||||
|
||||
```bash
|
||||
# Start rolling update
|
||||
kubectl rollout restart deployment my-app
|
||||
|
||||
# Gateway automatically:
|
||||
# 1. Discovers new Pods
|
||||
# 2. Adds them to upstream
|
||||
# 3. Removes old Pods
|
||||
# 4. Zero downtime!
|
||||
```
|
||||
|
||||
### 3. Multi-Service Architecture
|
||||
|
||||
Discover multiple backend services:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
- name: web-frontend
|
||||
upstream:
|
||||
discovery_type: kubernetes
|
||||
service_name: web-frontend
|
||||
namespace_id: production
|
||||
|
||||
- name: api-backend
|
||||
upstream:
|
||||
discovery_type: kubernetes
|
||||
service_name: api-backend
|
||||
namespace_id: production
|
||||
|
||||
- name: admin-api
|
||||
upstream:
|
||||
discovery_type: kubernetes
|
||||
service_name: admin-api
|
||||
namespace_id: admin
|
||||
```
|
||||
|
||||
## Advanced Configuration
|
||||
|
||||
### Cross-Namespace Discovery
|
||||
|
||||
Discover services in different namespaces:
|
||||
|
||||
```yaml
|
||||
upstream:
|
||||
discovery_type: kubernetes
|
||||
service_name: shared-service
|
||||
namespace_id: shared-services # Different namespace
|
||||
```
|
||||
|
||||
!!! warning "RBAC Permissions"
|
||||
Ensure the ServiceAccount has permissions to watch Endpoints in the target namespace.
|
||||
|
||||
### Load Balancing Algorithms
|
||||
|
||||
Combine service discovery with load balancing:
|
||||
|
||||
```yaml
|
||||
upstream:
|
||||
discovery_type: kubernetes
|
||||
service_name: my-service
|
||||
namespace_id: default
|
||||
type: roundrobin # or chash, least_conn, ewma
|
||||
```
|
||||
|
||||
**Available algorithms:**
|
||||
- `roundrobin`: Distribute requests evenly (default)
|
||||
- `chash`: Consistent hashing (sticky sessions)
|
||||
- `least_conn`: Send to Pod with fewest connections
|
||||
- `ewma`: Exponentially weighted moving average
|
||||
|
||||
### Health Checks
|
||||
|
||||
API7 Gateway respects Kubernetes readiness probes:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: my-app
|
||||
spec:
|
||||
containers:
|
||||
- name: app
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8080
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 3
|
||||
```
|
||||
|
||||
Only Pods with passing readiness checks receive traffic.
|
||||
|
||||
## Monitoring
|
||||
|
||||
### Check Discovered Endpoints
|
||||
|
||||
View upstream nodes in API7 Dashboard:
|
||||
|
||||
```bash
|
||||
# Port-forward to dashboard
|
||||
kubectl port-forward -n api7ee svc/api7ee3-0-1759339083-dashboard 7443:7443
|
||||
|
||||
# Open browser
|
||||
open https://localhost:7443
|
||||
```
|
||||
|
||||
Navigate to: **Gateway Groups → Upstreams → View Nodes**
|
||||
|
||||
### Debug Service Discovery
|
||||
|
||||
Check ADC sync logs:
|
||||
|
||||
```bash
|
||||
# View ADC sync job logs
|
||||
kubectl logs -n api7ee job/api7ee-demo-api7ee-demo-k8s-adc-sync
|
||||
|
||||
# Look for service discovery messages
|
||||
# [INFO] Discovered 3 endpoints for service my-service
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### No Endpoints Discovered
|
||||
|
||||
**Symptoms:** Gateway shows 0 upstream nodes
|
||||
|
||||
**Causes:**
|
||||
1. Service doesn't exist
|
||||
2. No Pods match Service selector
|
||||
3. All Pods are not ready
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
# Check Service exists
|
||||
kubectl get service my-service -n default
|
||||
|
||||
# Check Endpoints
|
||||
kubectl get endpoints my-service -n default
|
||||
|
||||
# Check Pod readiness
|
||||
kubectl get pods -l app=my-service -n default
|
||||
```
|
||||
|
||||
### RBAC Permission Denied
|
||||
|
||||
**Error:** `forbidden: User "system:serviceaccount:..." cannot list endpoints`
|
||||
|
||||
**Solution:**
|
||||
Verify RBAC permissions:
|
||||
|
||||
```bash
|
||||
# Check Role binding
|
||||
kubectl get rolebinding -n api7ee | grep adc
|
||||
|
||||
# Describe permissions
|
||||
kubectl describe role api7ee-demo-api7ee-demo-k8s-adc -n api7ee
|
||||
```
|
||||
|
||||
### Stale Endpoints
|
||||
|
||||
**Symptoms:** Traffic sent to terminated Pods
|
||||
|
||||
**Causes:** Kubernetes API not updating fast enough
|
||||
|
||||
**Solution:**
|
||||
Check Kubernetes API health:
|
||||
|
||||
```bash
|
||||
# Verify API server is responsive
|
||||
kubectl get --raw /healthz
|
||||
|
||||
# Check endpoint update timestamps
|
||||
kubectl get endpoints my-service -o yaml | grep -i time
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Use Service Discovery for All Dynamic Workloads
|
||||
|
||||
✅ **Do:**
|
||||
```yaml
|
||||
upstream:
|
||||
discovery_type: kubernetes
|
||||
service_name: my-dynamic-app
|
||||
```
|
||||
|
||||
❌ **Don't:**
|
||||
```yaml
|
||||
upstream:
|
||||
nodes:
|
||||
- host: pod-ip # Brittle, breaks on restart
|
||||
```
|
||||
|
||||
### 2. Configure Readiness Probes
|
||||
|
||||
Always configure readiness probes on Pods:
|
||||
|
||||
```yaml
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /ready
|
||||
port: 8080
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 5
|
||||
```
|
||||
|
||||
### 3. Use Namespaces for Isolation
|
||||
|
||||
Separate environments by namespace:
|
||||
|
||||
```yaml
|
||||
# Production
|
||||
namespace_id: production
|
||||
|
||||
# Staging
|
||||
namespace_id: staging
|
||||
|
||||
# Development
|
||||
namespace_id: development
|
||||
```
|
||||
|
||||
### 4. Monitor Discovery Performance
|
||||
|
||||
Set up alerts for:
|
||||
- Number of discovered endpoints
|
||||
- Service discovery latency
|
||||
- RBAC permission errors
|
||||
|
||||
### 5. Test Failover Scenarios
|
||||
|
||||
Regularly test:
|
||||
- Pod termination
|
||||
- Rolling updates
|
||||
- Scale up/down events
|
||||
|
||||
## Comparison: Static vs Service Discovery
|
||||
|
||||
| Feature | Static Nodes | Service Discovery |
|
||||
|---------|--------------|-------------------|
|
||||
| Setup | Manual | Automatic |
|
||||
| Scaling | Manual updates | Automatic |
|
||||
| Health checks | Manual | Built-in |
|
||||
| Deployments | Downtime risk | Zero downtime |
|
||||
| Maintenance | High | Low |
|
||||
| Flexibility | Low | High |
|
||||
| Production-ready | ❌ | ✅ |
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Configure Secret Management](secret-management.md)
|
||||
- [Set up Ingress Routing](kubernetes-resources.md#ingress)
|
||||
- [Monitor Gateway Metrics](troubleshooting.md#monitoring)
|
||||
|
||||
## References
|
||||
|
||||
- [API7 Service Discovery Documentation](https://docs.api7.ai/enterprise/3.2.14.6/best-practice/service-discovery/)
|
||||
- [Kubernetes Endpoints API](https://kubernetes.io/docs/concepts/services-networking/service/#endpoints)
|
||||
- [Kubernetes Service Discovery](https://kubernetes.io/docs/concepts/services-networking/service/)
|
||||
@@ -41,6 +41,9 @@ nav:
|
||||
- Kubernetes Resources: kubernetes-resources.md
|
||||
- Configuration:
|
||||
- API7 Gateway: api7-configuration.md
|
||||
- Ingress & Routing: ingress-routing.md
|
||||
- Service Discovery: service-discovery.md
|
||||
- Secret Management: secret-management.md
|
||||
- CI/CD Pipeline: cicd-pipeline.md
|
||||
- Troubleshooting: troubleshooting.md
|
||||
|
||||
|
||||
Reference in New Issue
Block a user