Deploy on Kubernetes
This guide walks you through deploying API7 Enterprise on Kubernetes using Helm charts. The deployment consists of two main components:
- Control Plane (CP): Dashboard, DP Manager, and PostgreSQL database
- Data Plane (DP): API7 Gateway instances that handle API traffic
Architecture Overview
Prerequisites
Before you begin, ensure you have:
- A Kubernetes cluster running version
1.25or later, such as EKS, GKE, AKS, or a self-managed cluster. kubectlversion1.25or later, configured to access your cluster.- Helm version
3.10or later. See Install Helm. - PostgreSQL version
12or later. An external database is recommended for production. - An API7 Enterprise license. See Get a trial license.
By default, PostgreSQL and Prometheus enable persistent storage. If your cluster does not have a StorageClass configured, you will see PVC binding errors. Either configure a StorageClass or disable persistence (not recommended for production).
Step 1: Add the API7 Helm Repository
helm repo add api7 https://charts.api7.ai
helm repo update
Verify the repository was added:
helm search repo api7/
Expected output includes api7/api7ee3 (Control Plane) and api7/gateway (Data Plane).
Step 2: Create a Namespace
Create a dedicated namespace for all API7 components:
kubectl create namespace api7
Step 3: Provision a PostgreSQL Database
For production deployments, use an external PostgreSQL database (e.g., Amazon RDS, Cloud SQL, Azure Database for PostgreSQL) for durability and high availability.
If you are evaluating API7 or running in a non-production environment, the Helm chart can deploy a built-in PostgreSQL instance. In that case, skip this step and set postgresql.builtin: true in your CP values file (Step 4).
For external PostgreSQL, create the database and user:
CREATE DATABASE api7ee;
CREATE USER api7ee WITH ENCRYPTED PASSWORD 'YOUR_DB_PASSWORD';
GRANT ALL PRIVILEGES ON DATABASE api7ee TO api7ee;
Step 4: Configure the Control Plane
To avoid storing a DSN containing the database password in Helm values and control plane ConfigMaps, first store the DSN in a Kubernetes Secret in the same namespace as the control plane:
read -rsp "Database DSN: " DATABASE_DSN && echo
kubectl create secret generic api7-database-dsn \
--from-literal=DATABASE_DSN="${DATABASE_DSN}" \
-n api7
unset DATABASE_DSN
Enter the complete PostgreSQL connection string, for example, postgres://api7ee:YOUR_DB_PASSWORD@YOUR_PG_HOST:5432/api7ee. This command does not write the actual DSN to your shell history.
Create a cp-values.yaml file:
# -- Disable the built-in PostgreSQL chart and point the dashboard to your external database.
postgresql:
builtin: false
dashboard_configuration:
database:
dsn: '${DATABASE_DSN}'
dp_manager_configuration:
database:
dsn: '${DATABASE_DSN}'
developer_portal_configuration:
database:
dsn: '${DATABASE_DSN}'
dashboard:
extraEnvVars:
- name: DATABASE_DSN
valueFrom:
secretKeyRef:
name: api7-database-dsn
key: DATABASE_DSN
dp_manager:
extraEnvVars:
- name: DATABASE_DSN
valueFrom:
secretKeyRef:
name: api7-database-dsn
key: DATABASE_DSN
developer_portal:
extraEnvVars:
- name: DATABASE_DSN
valueFrom:
secretKeyRef:
name: api7-database-dsn
key: DATABASE_DSN
dashboard_service:
type: ClusterIP
- Disable the built-in PostgreSQL chart when you use an external database.
- The Dashboard, DP Manager, and Developer Portal reference the environment variable from their configuration files using
${DATABASE_DSN}. The rendered ConfigMaps contain only this placeholder, not the actual DSN. - Each component injects the same Secret key as the
DATABASE_DSNenvironment variable usingvalueFrom.secretKeyRef. The Secret must be in the same namespace as the Helm release. If you disable the Developer Portal, you can omit thedeveloper_portal_configurationanddeveloper_portalsettings. - For initial setup,
ClusterIPis recommended. Usekubectl port-forwardto access the dashboard. Switch toLoadBalanceror use an Ingress controller for permanent access.
Kubernetes Secret data is Base64-encoded by default, not encrypted. In production, restrict RBAC access to Secrets and pod exec, enable encryption at rest for Kubernetes Secrets, and consider an external secret manager through a solution such as External Secrets Operator or Secrets Store CSI Driver. Do not commit a manifest containing the plaintext DSN to source control.
For a quick evaluation with the built-in PostgreSQL (not for production):
postgresql:
builtin: true
primary:
persistence:
enabled: true
size: 10Gi
dashboard_service:
type: ClusterIP
- Enable the built-in PostgreSQL chart for evaluation environments.
- Keep the dashboard service as
ClusterIPand access it withkubectl port-forward.
Step 5: Install the Control Plane
helm install api7ee3 api7/api7ee3 \
-f cp-values.yaml \
-n api7
Both the Helm release name and the chart name used here are api7ee3, matching the chart's own Chart.yaml. You can pick any release name you prefer, but if you change it, adjust the Helm selectors in the verification commands below accordingly.
Step 6: Verify Control Plane Pods
Wait for all CP pods to reach the Ready state:
kubectl -n api7 wait \
--for=condition=Ready pod \
-l app.kubernetes.io/name=api7ee3 \
--timeout=900s
You can also watch pod status while the images are being pulled:
kubectl get pods -n api7 -w
Expected output:
NAME READY STATUS RESTARTS AGE
api7ee3-dashboard-xxxxx-yyyyy 1/1 Running 0 2m
api7ee3-dp-manager-xxxxx-yyyyy 1/1 Running 0 2m
api7ee3-developer-portal-xxxxx-yyyyy 1/1 Running 0 2m
If using the built-in PostgreSQL, you should also see:
api7-postgresql-0 1/1 Running 0 2m
On a cold start, api7ee3-dp-manager or api7ee3-developer-portal may briefly restart while the built-in PostgreSQL image is still being pulled or initialized. If the pod logs show database connection refused errors and api7-postgresql-0 is not ready yet, wait for PostgreSQL to become ready and re-check the CP pods. This transient state should resolve without manual action once the database is available.
Step 7: Verify Control Plane Services
kubectl get svc -n api7 -l app.kubernetes.io/name=api7ee3 -o wide
Expected output:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
api7ee3-dashboard ClusterIP 10.100.25.236 <none> 7080/TCP,7443/TCP 3m
api7ee3-developer-portal ClusterIP 10.100.88.101 <none> 4321/TCP 3m
api7ee3-dp-manager ClusterIP 10.100.239.32 <none> 7900/TCP,7943/TCP 3m
Key services:
| Service | Port | Purpose |
|---|---|---|
api7ee3-dashboard | 7443 | Dashboard UI and Admin API |
api7ee3-dashboard | 7080 | Dashboard HTTP endpoint |
api7ee3-developer-portal | 4321 | Developer portal service |
api7ee3-dp-manager | 7900 | DP Manager HTTP endpoint |
api7ee3-dp-manager | 7943 | DP Manager mTLS endpoint (gateway connection) |
Step 8: Access the Dashboard
Forward the dashboard port to your local machine:
kubectl -n api7 port-forward svc/api7ee3-dashboard 7443:7443
Open https://localhost:7443 in your browser. Log in with the default credentials (admin / admin). On first login, the dashboard prompts you to reset the password. After that, the dashboard opens the Activate License screen, where you can upload and activate your license.
Step 9: Configure the DP Manager Address
In the API7 Dashboard, navigate to Gateway Settings and set DP Manager Address to the internal Kubernetes service DNS:
https://api7ee3-dp-manager:7943
This is the address that data plane instances will use to connect to the control plane.
Step 10: Add a Gateway Instance (Generate DP Certificates)
In the API7 Dashboard, select a gateway group such as default, navigate to Gateway Instances, and click Add Gateway Instance. Choose Kubernetes, fill in the target namespace, and generate the deployment script. The dashboard will generate:
- A TLS certificate (
tls.crt) for the data plane - A TLS private key (
tls.key) - A CA certificate (
ca.crt) for verifying the control plane - A
kubectl create secretcommand for the generated certificates - A complete Helm install command with all necessary parameters
Copy the generated script. It contains the certificates, the secret creation command, and the exact Helm command to install the data plane.
Step 11: Create the mTLS Secret
Extract the certificates from the generated script and create a Kubernetes secret:
# Save the certificates from the generated script to files,
# then create the secret:
kubectl create secret generic api7-ee-3-gateway-tls \
--from-file=tls.crt=/tmp/tls.crt \
--from-file=tls.key=/tmp/tls.key \
--from-file=ca.crt=/tmp/ca.crt \
-n api7
The certificates are unique per gateway group. If you have multiple gateway groups, each group needs its own set of certificates and a separate Kubernetes secret.
Step 12: Install the Data Plane
Use the Helm command generated by the dashboard, or put the dashboard-generated settings into a dp-values.yaml file and install the data plane with Helm.
etcd:
auth:
tls:
enabled: true
existingSecret: api7-ee-3-gateway-tls
certFilename: tls.crt
certKeyFilename: tls.key
verify: true
host:
- https://api7ee3-dp-manager:7943
gateway:
tls:
existingCASecret: api7-ee-3-gateway-tls
certCAFilename: ca.crt
apisix:
extraEnvVars:
- name: API7_GATEWAY_GROUP_SHORT_ID
value: default
replicaCount: 2
image:
repository: api7/api7-ee-3-gateway
tag: ${GATEWAY_VERSION}
❶ Point the data plane to the DP Manager mTLS service inside the cluster.
❷ Replace default with your gateway group's short ID if you are not using the default group.
❸ Set the replica count and ${GATEWAY_VERSION} based on your availability requirements and the control-plane-compatible gateway image version. Always pin an explicit version in production rather than using latest.
helm upgrade --install api7-ee-3-gateway api7/gateway \
-f dp-values.yaml \
-n api7
Step 13: Verify Data Plane Pods
kubectl get pods -n api7 -l app.kubernetes.io/name=gateway -w
Expected output:
NAME READY STATUS RESTARTS AGE
api7-ee-3-gateway-xxxxx-yyyyy 1/1 Running 0 1m
api7-ee-3-gateway-xxxxx-zzzzz 1/1 Running 0 1m
Step 14: Verify Data Plane Services
kubectl get svc -n api7 -l app.kubernetes.io/name=gateway
Expected output:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
api7-ee-3-gateway-gateway NodePort 10.100.50.100 <none> 80:31080/TCP,443:31443/TCP 1m