Add API7 ADC integration to Helm chart for automatic gateway configuration

- Added ADC (API7 Declarative CLI) post-install job for automatic gateway setup
- Created ConfigMap with complete API7 routing and service configuration
- Integrated cert-manager for automatic TLS certificate management
- Added support for Kubernetes service discovery
- Implemented auto-publish feature for routes after deployment
- Added comprehensive API7 plugin configurations (rate limiting, CORS, auth)
- Created RBAC resources for ADC job to access cluster resources
- Secured admin credentials using Kubernetes secrets
- Updated values.yaml with extensive API7 configuration options
- Enhanced documentation with API7 setup and troubleshooting guides
This commit is contained in:
d.viti
2025-10-03 02:04:35 +02:00
parent d818ee6600
commit fd832e9b42
7 changed files with 590 additions and 1 deletions

View File

@@ -0,0 +1,25 @@
{{- if and .Values.api7.enabled .Values.api7.tls.enabled .Values.api7.tls.certManager.enabled }}
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: {{ include "api7ee.fullname" . }}-tls
labels:
{{- include "api7ee.labels" . | nindent 4 }}
spec:
secretName: {{ .Values.api7.tls.secretName | default (printf "%s-tls" (include "api7ee.fullname" .)) }}
issuerRef:
name: {{ .Values.api7.tls.certManager.issuer }}
kind: {{ .Values.api7.tls.certManager.issuerKind | default "ClusterIssuer" }}
commonName: {{ first .Values.api7.hosts }}
dnsNames:
{{- range .Values.api7.hosts }}
- {{ . | quote }}
{{- end }}
usages:
- digital signature
- key encipherment
- server auth
- client auth
duration: 2160h # 90 days
renewBefore: 720h # 30 days before expiry
{{- end }}

View File

@@ -0,0 +1,147 @@
{{- if .Values.api7.enabled }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "api7ee.fullname" . }}-adc-config
labels:
{{- include "api7ee.labels" . | nindent 4 }}
app.kubernetes.io/component: adc
data:
adc-config.yaml: |
services:
{{- if .Values.web.enabled }}
- name: web-service
upstream:
name: web-upstream
scheme: http
type: roundrobin
{{- if .Values.api7.serviceDiscovery.enabled }}
discovery_type: kubernetes
service_name: {{ .Release.Namespace }}/{{ include "api7ee.fullname" . }}-web:http
{{- else }}
nodes:
- host: {{ include "api7ee.fullname" . }}-web.{{ .Release.Namespace }}.svc.cluster.local
port: {{ .Values.web.service.port }}
weight: 100
{{- end }}
routes:
- name: web-route
uris:
- /*
hosts:
{{- range .Values.api7.hosts }}
- {{ . | quote }}
{{- end }}
priority: 0
plugins:
{{- if .Values.api7.tls.enabled }}
redirect:
http_to_https: true
{{- end }}
{{- if .Values.api7.plugins.rateLimit.enabled }}
limit-count:
count: {{ .Values.api7.plugins.rateLimit.count }}
time_window: {{ .Values.api7.plugins.rateLimit.timeWindow }}
rejected_code: 429
{{- end }}
{{- if .Values.api7.plugins.cors.enabled }}
cors:
allow_origins: {{ .Values.api7.plugins.cors.allowOrigins | toJson }}
allow_methods: {{ .Values.api7.plugins.cors.allowMethods | toJson }}
allow_headers: {{ .Values.api7.plugins.cors.allowHeaders | toJson }}
expose_headers: {{ .Values.api7.plugins.cors.exposeHeaders | toJson }}
max_age: {{ .Values.api7.plugins.cors.maxAge }}
allow_credentials: {{ .Values.api7.plugins.cors.allowCredentials }}
{{- end }}
{{- end }}
{{- if .Values.api.enabled }}
- name: api-service
upstream:
name: api-upstream
scheme: http
type: roundrobin
{{- if .Values.api7.serviceDiscovery.enabled }}
discovery_type: kubernetes
service_name: {{ .Release.Namespace }}/{{ include "api7ee.fullname" . }}-api:http
{{- else }}
nodes:
- host: {{ include "api7ee.fullname" . }}-api.{{ .Release.Namespace }}.svc.cluster.local
port: {{ .Values.api.service.port }}
weight: 100
{{- end }}
routes:
- name: api-route
uris:
- /api
- /api/*
hosts:
{{- range .Values.api7.hosts }}
- {{ . | quote }}
{{- end }}
priority: 10
plugins:
{{- if .Values.api7.tls.enabled }}
redirect:
http_to_https: true
{{- end }}
proxy-rewrite:
regex_uri:
- ^/api/(.*)
- /$1
{{- if .Values.api7.plugins.rateLimit.enabled }}
limit-count:
count: {{ .Values.api7.plugins.rateLimit.apiCount | default .Values.api7.plugins.rateLimit.count }}
time_window: {{ .Values.api7.plugins.rateLimit.timeWindow }}
rejected_code: 429
{{- end }}
{{- if .Values.api7.plugins.auth.enabled }}
key-auth:
header: {{ .Values.api7.plugins.auth.header | default "X-API-Key" }}
{{- end }}
{{- end }}
{{- if .Values.api7.tls.enabled }}
ssls:
- snis:
{{- range .Values.api7.hosts }}
- {{ . | quote }}
{{- end }}
certificates:
{{- if .Values.api7.tls.certManager.enabled }}
- certificate: /etc/ssl/certs/tls.crt
key: /etc/ssl/certs/tls.key
{{- else if .Values.api7.tls.certificate }}
- certificate: |
{{ .Values.api7.tls.certificate | nindent 14 }}
key: |
{{ .Values.api7.tls.key | nindent 14 }}
{{- end }}
{{- end }}
{{- if .Values.api7.plugins.auth.enabled }}
consumers:
{{- range .Values.api7.consumers }}
- username: {{ .username }}
plugins:
key-auth:
key: {{ .apiKey }}
{{- end }}
{{- end }}
global_rules:
{{- if .Values.api7.plugins.prometheus.enabled }}
- id: prometheus-metrics
plugins:
prometheus:
prefer_name: true
{{- end }}
{{- if .Values.api7.plugins.logging.enabled }}
- id: request-logging
plugins:
http-logger:
uri: {{ .Values.api7.plugins.logging.endpoint }}
batch_max_size: {{ .Values.api7.plugins.logging.batchMaxSize | default 1000 }}
inactive_timeout: {{ .Values.api7.plugins.logging.inactiveTimeout | default 5 }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,212 @@
{{- if .Values.api7.enabled }}
apiVersion: batch/v1
kind: Job
metadata:
name: {{ include "api7ee.fullname" . }}-adc-sync
labels:
{{- include "api7ee.labels" . | nindent 4 }}
app.kubernetes.io/component: adc-sync
annotations:
"helm.sh/hook": post-install,post-upgrade
"helm.sh/hook-weight": "10"
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
spec:
backoffLimit: 3
activeDeadlineSeconds: 300
template:
metadata:
labels:
{{- include "api7ee.selectorLabels" . | nindent 8 }}
app.kubernetes.io/component: adc-sync
spec:
restartPolicy: Never
serviceAccountName: {{ include "api7ee.serviceAccountName" . }}
{{- if .Values.api7.tls.certManager.enabled }}
initContainers:
- name: wait-for-certificate
image: busybox:1.35
command:
- sh
- -c
- |
echo "Waiting for TLS certificate to be ready..."
while [ ! -f /etc/ssl/certs/tls.crt ] || [ ! -f /etc/ssl/certs/tls.key ]; do
echo "Certificate not ready, waiting..."
sleep 5
done
echo "Certificate is ready!"
volumeMounts:
- name: tls-certs
mountPath: /etc/ssl/certs
readOnly: true
{{- end }}
containers:
- name: adc-sync
image: {{ .Values.api7.adc.image | default "ghcr.io/api7/adc:latest" }}
imagePullPolicy: {{ .Values.api7.adc.imagePullPolicy | default "IfNotPresent" }}
command:
- /bin/sh
- -c
- |
set -e
echo "Starting API7 ADC configuration sync..."
# Install jq if needed for auto-publish feature
{{- if .Values.api7.autoPublish }}
if ! command -v jq &> /dev/null; then
echo "Installing jq..."
apk add --no-cache jq curl || apt-get update && apt-get install -y jq curl || yum install -y jq curl
fi
{{- end }}
# Wait for API7 Gateway to be ready
echo "Waiting for API7 Gateway to be available..."
MAX_RETRIES=30
RETRY_COUNT=0
while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
if curl -s -o /dev/null -w "%{http_code}" ${API7_ADMIN_URL}/apisix/admin/routes \
-H "X-API-KEY: ${API7_ADMIN_KEY}" | grep -q "200\|401"; then
echo "API7 Gateway is ready!"
break
fi
echo "API7 Gateway not ready, retrying... ($RETRY_COUNT/$MAX_RETRIES)"
RETRY_COUNT=$((RETRY_COUNT + 1))
sleep 10
done
if [ $RETRY_COUNT -eq $MAX_RETRIES ]; then
echo "ERROR: API7 Gateway not ready after $MAX_RETRIES attempts"
exit 1
fi
{{- if .Values.api7.tls.certManager.enabled }}
# Copy certificates to config directory
cp /etc/ssl/certs/tls.crt /tmp/tls.crt
cp /etc/ssl/certs/tls.key /tmp/tls.key
# Update certificate paths in config
sed -i 's|/etc/ssl/certs/tls.crt|/tmp/tls.crt|g' /config/adc-config.yaml
sed -i 's|/etc/ssl/certs/tls.key|/tmp/tls.key|g' /config/adc-config.yaml
{{- end }}
# Validate configuration
echo "Validating ADC configuration..."
adc validate -f /config/adc-config.yaml || {
echo "ERROR: Configuration validation failed"
cat /config/adc-config.yaml
exit 1
}
# Sync configuration to API7
echo "Syncing configuration to API7 Gateway..."
adc sync -f /config/adc-config.yaml \
--backend {{ .Values.api7.backend | default "api7ee" }} \
--server ${API7_ADMIN_URL} \
--token ${API7_ADMIN_KEY} \
--gateway-group ${API7_GATEWAY_GROUP} \
{{- if .Values.api7.adc.tlsSkipVerify }}
--tls-skip-verify \
{{- end }}
--verbose || {
echo "ERROR: Failed to sync configuration"
exit 1
}
echo "✅ API7 configuration sync completed successfully!"
{{- if .Values.api7.autoPublish }}
# Auto-publish routes
echo "Auto-publishing routes..."
# Get list of services and routes
SERVICES=$(curl -s ${API7_ADMIN_URL}/apisix/admin/services \
-H "X-API-KEY: ${API7_ADMIN_KEY}" | jq -r '.list[].id' || echo "")
for SERVICE_ID in $SERVICES; do
echo "Publishing routes for service: $SERVICE_ID"
# Get routes for this service
ROUTES=$(curl -s ${API7_ADMIN_URL}/apisix/admin/services/${SERVICE_ID}/routes \
-H "X-API-KEY: ${API7_ADMIN_KEY}" | jq -r '.list[].id' || echo "")
for ROUTE_ID in $ROUTES; do
echo "Publishing route: $ROUTE_ID"
curl -X POST ${API7_ADMIN_URL}/apisix/admin/services/${SERVICE_ID}/routes/${ROUTE_ID}/publish \
-H "X-API-KEY: ${API7_ADMIN_KEY}" \
-H "Content-Type: application/json" \
-d "{\"gateway_group_id\": \"${API7_GATEWAY_GROUP}\"}" || {
echo "Warning: Failed to publish route $ROUTE_ID"
}
done
done
echo "✅ Routes published successfully!"
{{- end }}
# Display summary
echo ""
echo "=========================================="
echo "API7 Configuration Summary:"
echo "=========================================="
echo "Gateway URL: ${API7_ADMIN_URL}"
echo "Gateway Group: ${API7_GATEWAY_GROUP}"
echo "Hosts configured:"
{{- range .Values.api7.hosts }}
echo " - {{ . }}"
{{- end }}
{{- if .Values.api7.tls.enabled }}
echo "TLS: Enabled"
{{- end }}
{{- if .Values.api7.serviceDiscovery.enabled }}
echo "Service Discovery: Kubernetes"
{{- end }}
echo "=========================================="
echo ""
echo "Access your application at:"
{{- range .Values.api7.hosts }}
echo " {{ if $.Values.api7.tls.enabled }}https{{ else }}http{{ end }}://{{ . }}"
{{- end }}
env:
- name: ADC_VERBOSE
value: "{{ .Values.api7.adc.verbose | default true }}"
- name: API7_ADMIN_URL
valueFrom:
secretKeyRef:
name: {{ include "api7ee.fullname" . }}-api7-admin
key: admin-url
- name: API7_ADMIN_KEY
valueFrom:
secretKeyRef:
name: {{ include "api7ee.fullname" . }}-api7-admin
key: admin-key
- name: API7_GATEWAY_GROUP
valueFrom:
secretKeyRef:
name: {{ include "api7ee.fullname" . }}-api7-admin
key: gateway-group
volumeMounts:
- name: adc-config
mountPath: /config
readOnly: true
{{- if .Values.api7.tls.certManager.enabled }}
- name: tls-certs
mountPath: /etc/ssl/certs
readOnly: true
{{- end }}
resources:
limits:
cpu: 500m
memory: 256Mi
requests:
cpu: 100m
memory: 128Mi
volumes:
- name: adc-config
configMap:
name: {{ include "api7ee.fullname" . }}-adc-config
{{- if .Values.api7.tls.certManager.enabled }}
- name: tls-certs
secret:
secretName: {{ .Values.api7.tls.secretName | default (printf "%s-tls" (include "api7ee.fullname" .)) }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,36 @@
{{- if and .Values.api7.enabled .Values.serviceAccount.create }}
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: {{ include "api7ee.fullname" . }}-adc
labels:
{{- include "api7ee.labels" . | nindent 4 }}
rules:
# Allow reading secrets (for certificates)
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list"]
# Allow reading services and endpoints for service discovery
- apiGroups: [""]
resources: ["services", "endpoints"]
verbs: ["get", "list", "watch"]
# Allow reading pods for health checks
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: {{ include "api7ee.fullname" . }}-adc
labels:
{{- include "api7ee.labels" . | nindent 4 }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: {{ include "api7ee.fullname" . }}-adc
subjects:
- kind: ServiceAccount
name: {{ include "api7ee.serviceAccountName" . }}
namespace: {{ .Release.Namespace }}
{{- end }}

View File

@@ -0,0 +1,14 @@
{{- if .Values.api7.enabled }}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "api7ee.fullname" . }}-api7-admin
labels:
{{- include "api7ee.labels" . | nindent 4 }}
app.kubernetes.io/component: api7
type: Opaque
stringData:
admin-key: {{ .Values.api7.gateway.adminKey | quote }}
admin-url: {{ .Values.api7.gateway.adminUrl | quote }}
gateway-group: {{ .Values.api7.gateway.group | default "default" | quote }}
{{- end }}