Data Plane Resilience
API7 Gateway data plane nodes cache configuration in memory and can continue processing traffic during brief control plane (CP) outages. However, for extended outages, such as a database failure, control plane upgrade, or disaster recovery scenario, nodes that restart without a CP connection cannot load configuration.
Use this guide after you have already planned for scaling and high availability of traffic-serving nodes:
- Scale Data Plane covers capacity growth.
- Data Plane High Availability covers multi-node deployments, load balancers, and health checks.
Fallback CP stores gateway configuration in AWS S3, S3-compatible storage, or Azure Blob Storage. During an outage, an operator can restart or redeploy a traffic node in fallback read mode so it loads the stored snapshot instead of connecting to the control plane.
Fallback CP does not switch a running node automatically when its control-plane connection fails. A node that remains running continues with its in-memory configuration. Use fallback read mode when a node must start while the control plane is unavailable, and restore its original deployment configuration after the control plane recovers.
How It Works
Fallback CP snapshots can be produced by either a backup gateway node or the scheduled Control Plane pusher. The backup gateway runs alongside your traffic-handling nodes but does not serve API traffic. Its sole purpose is to receive configuration from the control plane and export it to external storage on a schedule. The following diagram shows this option.
Normal Operation
During normal operation, every data plane node, including the backup node, watches the control plane's etcd-compatible API on mTLS port 7943. See Architecture for details on the pull/watch model. The backup node also writes the configuration it receives to external storage on a schedule.
Fallback Operation
When the control plane is unavailable, an operator redeploys or restarts a traffic node in fallback read mode. At startup, the node loads the resource and data plane configuration objects for its gateway-group short ID from external storage.
What Gets Exported
The backup node or Control Plane pusher exports two categories of data per gateway group:
| Category | Contents |
|---|---|
| Resource data | Routes, services, upstreams, consumers, credentials, SSL certificates, global rules, plugin metadata, plugin configs, stream routes, secrets, custom plugins, and protobuf definitions |
| Config data | Data plane configuration including keyring and service discovery settings |
Each gateway group's data is stored as a separate object, keyed by the gateway group's short ID. Recovery nodes must use the same API7_GATEWAY_GROUP_SHORT_ID as the snapshot they load.
The chart still creates a gateway Service and publishes its configured ports for a backup release. However, the gateway recognizes write mode at startup and omits its HTTP/HTTPS and stream traffic server blocks. Keep the backup Service out of load balancers, Ingress routes, DNS records, and client configuration. The backup node is not counted toward the license quota.
Prerequisites
- A running API7 Gateway deployment with at least one gateway group.
- An external storage backend:
- AWS S3 or S3-compatible storage: Two buckets (one for resource data, one for config data) with appropriate access permissions. For another S3-compatible service, prepare the custom endpoint URL.
- Azure Blob Storage: Two Blob containers (one for resource data, one for config data) with appropriate access credentials.
AWS S3 Permissions
The IAM policy for a backup node or Dashboard pusher must include:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:PutObject"],
"Resource": [
"arn:aws:s3:::fallback-cp-data/*",
"arn:aws:s3:::fallback-cp-config/*"
]
}
]
}
Traffic nodes in fallback mode need s3:GetObject on the same buckets.
For S3-compatible storage, grant equivalent object read/write permissions in your storage provider.
Azure Blob Storage Permissions
Grant Storage Blob Data Contributor on both containers to a backup gateway that uses Workload Identity. A recovery identity only needs Storage Blob Data Reader. The Control Plane pusher requires a storage account access key; an account access key authorizes access directly and is not assigned an Azure RBAC role.
Static Credentials
The Kubernetes static-key examples expect an existing Secret named fallback-storage-credentials in every namespace that contains a backup gateway, recovery gateway, or Dashboard pusher that consumes it.
| Provider | Required Secret keys |
|---|---|
| AWS S3 | aws-access-key-id, aws-secret-access-key |
| Azure Blob Storage | azure-storage-account-key |
Create and populate this Secret through your approved secret-management workflow before installing or upgrading a release. Kubernetes Secrets are namespace-scoped, so create the Secret separately when gateway and control-plane releases use different namespaces. The Docker examples expect the equivalent AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, or AZURE_STORAGE_ACCOUNT_KEY variables to contain non-empty values in the host environment or secret-injection system before the container starts.
Configure the Backup Node
The backup node is a gateway instance configured with mode: write under fallback_cp. It connects to the control plane like a regular data plane node but writes configuration to external storage instead of serving traffic.
- Kubernetes (Helm)
- Docker
Deploy one backup node per gateway group as a separate Helm release. Start with the values generated by the Dashboard for that gateway group. This preserves its DP Manager endpoints, mTLS Secret, gateway-group environment variable, image, and other connection settings. Add the fallback values below to that complete values file.
The chart reads fallback settings from the top-level deployment.fallback_cp value. In write mode, it keeps the DP Manager connection and renders node_listen, container ports, and gateway Service ports. It disables readiness and liveness probes and HTTP and stream access logs. At startup, the gateway reports itself as a backup node and omits the NGINX traffic server blocks. Keep the published gateway Service out of traffic paths so the release remains explicitly isolated.
- AWS S3
- Azure Blob Storage
Using IAM Roles for Service Accounts (IRSA):
apisix:
kind: Deployment
replicaCount: 1
deployment:
fallback_cp:
interval: 60
mode: write
aws_s3:
region: "us-east-1"
resource_bucket: "fallback-cp-data"
config_bucket: "fallback-cp-config"
serviceAccount:
create: true
annotations:
eks.amazonaws.com/role-arn: "arn:aws:iam::123456789012:role/fallback-cp-role"
❶ The interval (in seconds) between configuration exports.
❷ write mode enables storage export. The chart retains port declarations, while the gateway omits its traffic server blocks.
❸ The AWS region where the S3 buckets are located.
❹ ❺ Separate buckets for resource data and configuration data.
Using IAM Access Keys:
Keep the Dashboard-generated apisix.extraEnvVars entries and append the storage credentials to that list. The complete list must retain API7_GATEWAY_GROUP_SHORT_ID and any other generated entries:
apisix:
kind: Deployment
replicaCount: 1
extraEnvVars:
- name: API7_GATEWAY_GROUP_SHORT_ID
value: "YOUR_GATEWAY_GROUP_SHORT_ID"
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: fallback-storage-credentials
key: aws-access-key-id
- name: AWS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: fallback-storage-credentials
key: aws-secret-access-key
deployment:
fallback_cp:
interval: 60
mode: write
aws_s3:
access_key: '${{AWS_ACCESS_KEY_ID}}'
secret_key: '${{AWS_SECRET_ACCESS_KEY}}'
region: "us-east-1"
resource_bucket: "fallback-cp-data"
config_bucket: "fallback-cp-config"
For S3-compatible storage, use the provider's access key and secret key, and add endpoint to the aws_s3 block:
deployment:
fallback_cp:
aws_s3:
endpoint: "https://s3-compatible.example.com"
use_path_style: true
Enable use_path_style only when the storage provider requires path-style bucket URLs.
Using Workload Identity:
serviceAccount:
create: true
annotations:
azure.workload.identity/client-id: "<your-managed-identity-client-id>"
apisix:
kind: Deployment
replicaCount: 1
podLabels:
azure.workload.identity/use: "true"
deployment:
fallback_cp:
interval: 60
mode: write
azure_blob:
account_name: "youraccount"
resource_container: "fallback-cp-data"
config_container: "fallback-cp-config"
Using Storage Account Access Key:
Keep the Dashboard-generated apisix.extraEnvVars entries and append the storage credential to that list. The complete list must retain API7_GATEWAY_GROUP_SHORT_ID and any other generated entries:
apisix:
kind: Deployment
replicaCount: 1
extraEnvVars:
- name: API7_GATEWAY_GROUP_SHORT_ID
value: "YOUR_GATEWAY_GROUP_SHORT_ID"
- name: AZURE_STORAGE_ACCOUNT_KEY
valueFrom:
secretKeyRef:
name: fallback-storage-credentials
key: azure-storage-account-key
deployment:
fallback_cp:
interval: 60
mode: write
azure_blob:
account_name: "youraccount"
account_key: '${{AZURE_STORAGE_ACCOUNT_KEY}}'
resource_container: "fallback-cp-data"
config_container: "fallback-cp-config"
Start with the Docker command generated by the Dashboard for the gateway group. Keep every generated API7_DP_MANAGER_*, API7_CONTROL_PLANE_CA, and API7_GATEWAY_GROUP_SHORT_ID environment variable. The endpoint and certificate variables preserve the normal DP Manager connection; the short ID selects the object name in storage.
Populate the required storage variables through the host's approved secret-injection mechanism before running the generated command. A Docker option such as --env AWS_SECRET_ACCESS_KEY forwards an existing host variable; it does not assign a value.
- AWS S3
- Azure Blob Storage
deployment:
role: traditional
role_traditional:
config_provider: etcd
fallback_cp:
interval: 60
mode: write
aws_s3:
access_key: '${{AWS_ACCESS_KEY_ID}}'
secret_key: '${{AWS_SECRET_ACCESS_KEY}}'
region: "us-east-1"
resource_bucket: "fallback-cp-data"
config_bucket: "fallback-cp-config"
For S3-compatible storage, use the provider's access key and secret key, and add endpoint to the aws_s3 block:
deployment:
fallback_cp:
aws_s3:
endpoint: "https://s3-compatible.example.com"
use_path_style: true
Enable use_path_style only when the storage provider requires path-style bucket URLs.
Add these options to the generated command and keep its explicit gateway image version:
--env AWS_ACCESS_KEY_ID \
--env AWS_SECRET_ACCESS_KEY \
--mount type=bind,src="$(pwd)/config.yaml",dst=/usr/local/apisix/conf/config.yaml,readonly
deployment:
role: traditional
role_traditional:
config_provider: etcd
fallback_cp:
interval: 60
mode: write
azure_blob:
account_name: "youraccount"
account_key: '${{AZURE_STORAGE_ACCOUNT_KEY}}'
resource_container: "fallback-cp-data"
config_container: "fallback-cp-config"
Add these options to the generated command and keep its explicit gateway image version:
--env AZURE_STORAGE_ACCOUNT_KEY \
--mount type=bind,src="$(pwd)/config.yaml",dst=/usr/local/apisix/conf/config.yaml,readonly
Configure the Control Plane Pusher
As an alternative to a backup gateway, the Dashboard process can export every gateway group on a schedule. This path does not require one backup node per group, but it depends on a running Dashboard and database when each snapshot is created.
Helm
Configure the pusher under dashboard_configuration.fallback_cp. Merge the credential entries into the complete existing dashboard.extraEnvVars list. Helm replaces lists, so a credential-only overlay can remove required entries such as a Secret-backed database DSN.
For AWS S3:
dashboard:
extraEnvVars:
# Keep every existing Dashboard environment variable above or below these entries.
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: fallback-storage-credentials
key: aws-access-key-id
- name: AWS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: fallback-storage-credentials
key: aws-secret-access-key
dashboard_configuration:
fallback_cp:
cron_spec: "@every 1m"
aws_s3:
access_key: '${AWS_ACCESS_KEY_ID}'
secret_key: '${AWS_SECRET_ACCESS_KEY}'
region: "us-east-1"
resource_bucket: "fallback-cp-data"
config_bucket: "fallback-cp-config"
use_path_style: false
For S3-compatible storage, add custom_endpoint to the same block. Change use_path_style to true only when the provider requires path-style bucket URLs:
dashboard_configuration:
fallback_cp:
aws_s3:
custom_endpoint: "https://s3-compatible.example.com"
use_path_style: true
For Azure Blob Storage:
dashboard:
extraEnvVars:
# Keep every existing Dashboard environment variable above or below this entry.
- name: AZURE_STORAGE_ACCOUNT_KEY
valueFrom:
secretKeyRef:
name: fallback-storage-credentials
key: azure-storage-account-key
dashboard_configuration:
fallback_cp:
cron_spec: "@every 1m"
azure_blob:
account_name: "youraccount"
account_key: '${AZURE_STORAGE_ACCOUNT_KEY}'
resource_container: "fallback-cp-data"
config_container: "fallback-cp-config"
The Control Plane pusher requires explicit access keys. It does not use the gateway image's IAM or Workload Identity credential chain.
Docker or Packages
Configure the same producer in the Dashboard configuration file. Populate the referenced environment variables through the process supervisor or approved secret-injection mechanism before starting every Dashboard replica:
fallback_cp:
cron_spec: "@every 1m"
aws_s3:
access_key: "${AWS_ACCESS_KEY_ID}"
secret_key: "${AWS_SECRET_ACCESS_KEY}"
region: "us-east-1"
resource_bucket: "fallback-cp-data"
config_bucket: "fallback-cp-config"
use_path_style: false
azure_blob:
account_name: "youraccount"
account_key: "${AZURE_STORAGE_ACCOUNT_KEY}"
resource_container: "fallback-cp-data"
config_container: "fallback-cp-config"
❶ A schedule expression that controls how often the Dashboard pushes configuration. Common values include @every 1m and @every 5m.
❷ ❸ Configure one or both storage backends. The Dashboard pushes to every configured backend.
For S3-compatible storage, add custom_endpoint to the Dashboard-side aws_s3 block. Change use_path_style to true only when the provider requires path-style bucket URLs:
fallback_cp:
aws_s3:
custom_endpoint: "https://s3-compatible.example.com"
use_path_style: true
When multiple Dashboard instances are running, a distributed lock ensures that only one instance performs the push at any given time.
Recover Traffic Nodes from Fallback Storage
Before an outage, keep the complete normal deployment values or generated Docker command for every gateway group. Confirm that the selected backup method has written one object named with the gateway-group short ID to both the resource and configuration locations.
When the control plane is unavailable and a traffic node must restart, explicitly start that node in fallback read mode. The gateway loads the stored snapshot during startup and does not connect to DP Manager in this mode.
- Kubernetes (Helm)
- Docker
Create a small fallback values file and apply it together with the saved normal values for the release. Keep the Dashboard-generated API7_GATEWAY_GROUP_SHORT_ID environment variable and storage identity or credential configuration.
- AWS S3
- Azure Blob Storage
serviceAccount:
create: true
annotations:
eks.amazonaws.com/role-arn: "arn:aws:iam::123456789012:role/fallback-cp-reader-role"
deployment:
fallback_cp:
mode: read
aws_s3:
region: "us-east-1"
resource_bucket: "fallback-cp-data"
config_bucket: "fallback-cp-config"
For S3-compatible storage, add endpoint to the aws_s3 block. Set use_path_style to true only when the provider requires path-style bucket URLs:
deployment:
fallback_cp:
aws_s3:
endpoint: "https://s3-compatible.example.com"
use_path_style: true
serviceAccount:
create: true
annotations:
azure.workload.identity/client-id: "<your-reader-managed-identity-client-id>"
apisix:
podLabels:
azure.workload.identity/use: "true"
deployment:
fallback_cp:
mode: read
azure_blob:
account_name: "youraccount"
resource_container: "fallback-cp-data"
config_container: "fallback-cp-config"
The examples above create provider-specific service accounts for recovery. Grant the AWS role s3:GetObject on both buckets, or grant the Azure identity Storage Blob Data Reader on both containers. If your normal values already select a service account, merge the required annotations and Azure pod label into that existing identity instead of replacing it.
If traffic nodes use access keys, append the storage credential entries to the existing apisix.extraEnvVars list in normal-values.yaml and add the corresponding ${{...}} fields to fallback-read-values.yaml. Do not define a second apisix.extraEnvVars list in the fallback file: Helm replaces lists instead of appending them, which would remove generated entries such as API7_GATEWAY_GROUP_SHORT_ID.
Apply the fallback file over the complete saved values and use the same chart version as the normal release:
helm upgrade YOUR_GATEWAY_RELEASE api7/gateway \
--version YOUR_GATEWAY_CHART_VERSION \
-n YOUR_NAMESPACE \
-f normal-values.yaml \
-f fallback-read-values.yaml \
--wait
The chart changes role_data_plane.config_provider to json and restarts the pods. At startup, each pod uses the gateway-group short ID to fetch the resource and data plane configuration objects. Do not remove the generated short-ID environment variable from normal-values.yaml.
Stop the normal gateway container before starting a replacement in fallback mode. Use the same gateway-group short ID and image version as the normal container.
- AWS S3
- Azure Blob Storage
deployment:
role: data_plane
role_data_plane:
config_provider: json
fallback_cp:
aws_s3:
access_key: '${{AWS_ACCESS_KEY_ID}}'
secret_key: '${{AWS_SECRET_ACCESS_KEY}}'
region: "us-east-1"
resource_bucket: "fallback-cp-data"
config_bucket: "fallback-cp-config"
use_path_style: false
❶ Setting config_provider: json switches the gateway to standalone mode, where it reads configuration from external storage instead of connecting to the control plane.
For S3-compatible storage, add endpoint to the Docker recovery aws_s3 block. Change use_path_style to true only when the provider requires path-style bucket URLs:
deployment:
fallback_cp:
aws_s3:
endpoint: "https://s3-compatible.example.com"
use_path_style: true
Start the fallback container with the saved gateway-group short ID and storage credentials:
docker run -d --name api7-gateway-fallback \
-e API7_GATEWAY_GROUP_SHORT_ID="YOUR_GATEWAY_GROUP_SHORT_ID" \
-e AWS_ACCESS_KEY_ID \
-e AWS_SECRET_ACCESS_KEY \
-p 9080:9080 \
-p 9443:9443 \
--mount type=bind,src="$(pwd)/config.yaml",dst=/usr/local/apisix/conf/config.yaml,readonly \
api7/api7-ee-3-gateway:YOUR_GATEWAY_VERSION
deployment:
role: data_plane
role_data_plane:
config_provider: json
fallback_cp:
azure_blob:
account_name: "youraccount"
account_key: '${{AZURE_STORAGE_ACCOUNT_KEY}}'
resource_container: "fallback-cp-data"
config_container: "fallback-cp-config"
Start the fallback container with the saved gateway-group short ID and storage credential:
docker run -d --name api7-gateway-fallback \
-e API7_GATEWAY_GROUP_SHORT_ID="YOUR_GATEWAY_GROUP_SHORT_ID" \
-e AZURE_STORAGE_ACCOUNT_KEY \
-p 9080:9080 \
-p 9443:9443 \
--mount type=bind,src="$(pwd)/config.yaml",dst=/usr/local/apisix/conf/config.yaml,readonly \
api7/api7-ee-3-gateway:YOUR_GATEWAY_VERSION
Fallback mode serves the stored snapshot and does not receive later control-plane changes.
- For Helm, restore the release from
normal-values.yamlwithout the fallback overlay. Wait for the replacement pods to report Healthy, then verify current configuration and traffic. - For Docker, keep other HA nodes serving traffic, drain the fallback node from the load balancer, and remove the fallback container so it releases ports
9080and9443. Start the original pinned Dashboard-generated command, wait for the new instance to report Healthy, verify current configuration and traffic, then return the node to the load balancer.
Verify Backup and Recovery
Test the complete workflow in a non-production gateway group before relying on fallback storage:
- Create a distinctive test route and wait for the next backup interval or scheduled Dashboard run.
- Inspect the backup gateway or Dashboard logs and confirm that the resource object and data plane configuration object were both written successfully during the same run. Do not recover from a run where either write failed.
- Confirm that both storage locations contain an object named with the gateway-group short ID. The resource object should contain the test route; the configuration object should contain the data plane configuration for the same group. Compare their last-modified times or version IDs with the successful run. Enable object versioning where the storage provider supports it, and retain the matching pair needed for recovery.
- Save the normal deployment values or Docker command, then make the control plane unavailable to the test node.
- Start that node in fallback read mode and send a request directly to the test route. Confirm that authentication, plugins, upstreams, and service discovery used by the group behave as expected.
- Restore the normal deployment configuration after the control plane recovers. Wait for the instance to report Healthy, apply a small configuration change, and confirm that the node receives it before returning the node to production traffic.
Fallback objects contain gateway resources and data plane configuration, including credential-bearing plugin fields, private keys, and the gateway-group keyring in a form the gateway can consume. Encrypt the storage backend, restrict read and write access, audit access, and apply a retention policy appropriate for configuration backups.
Configuration Reference
Backup Node / Traffic Node (config.yaml)
| Field | Type | Description |
|---|---|---|
deployment.fallback_cp.mode | string | write for backup nodes or read for traffic nodes that start from fallback storage. The default is read. |
deployment.fallback_cp.interval | integer | Export interval in seconds (backup node only). |
deployment.fallback_cp.aws_s3.access_key | string | AWS access key ID. Not required when using IRSA. |
deployment.fallback_cp.aws_s3.secret_key | string | AWS secret access key. Not required when using IRSA. |
deployment.fallback_cp.aws_s3.region | string | AWS region for the S3 buckets. |
deployment.fallback_cp.aws_s3.resource_bucket | string | S3 bucket for resource data. |
deployment.fallback_cp.aws_s3.config_bucket | string | S3 bucket for configuration data. |
deployment.fallback_cp.aws_s3.endpoint | string | Custom S3 endpoint (for S3-compatible storage). |
deployment.fallback_cp.aws_s3.use_path_style | boolean | Whether to use path-style S3 bucket URLs. The default is false. |
deployment.fallback_cp.azure_blob.account_name | string | Azure storage account name. |
deployment.fallback_cp.azure_blob.account_key | string | Azure storage account key. Not required when using Workload Identity. |
deployment.fallback_cp.azure_blob.resource_container | string | Blob container for resource data. |
deployment.fallback_cp.azure_blob.config_container | string | Blob container for configuration data. |
deployment.fallback_cp.azure_blob.endpoint | string | Custom Azure Blob endpoint. Defaults to https://<account_name>.blob.core.windows.net. |
Dashboard (dashboard-config.yaml)
| Field | Type | Description |
|---|---|---|
fallback_cp.cron_spec | string | Schedule expression for configuration pushes (for example, @every 1m). |
fallback_cp.aws_s3.access_key | string | AWS access key ID. |
fallback_cp.aws_s3.secret_key | string | AWS secret access key. |
fallback_cp.aws_s3.region | string | AWS region for the S3 buckets. |
fallback_cp.aws_s3.resource_bucket | string | S3 bucket for resource data. |
fallback_cp.aws_s3.config_bucket | string | S3 bucket for configuration data. |
fallback_cp.aws_s3.custom_endpoint | string | Custom S3 endpoint for S3-compatible storage. In the API7 control plane Helm chart, configure this as dashboard_configuration.fallback_cp.aws_s3.custom_endpoint. |
fallback_cp.aws_s3.use_path_style | boolean | Whether to use path-style bucket URLs. The default is false; enable it only when the storage provider requires path-style URLs. In the API7 control plane Helm chart, configure this as dashboard_configuration.fallback_cp.aws_s3.use_path_style. |
fallback_cp.azure_blob.* | — | Same fields as the gateway-side azure_blob configuration. |
Next Steps
- Deploy for High Availability: Set up HA for both the control plane and data plane.
- Data Plane High Availability: Learn about health checks and multi-node DP architecture.
- Scale Data Plane: Add or remove traffic-serving nodes as traffic changes.
- Production Best Practices: Harden your deployment for production.