Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ Detailed instructions are enrolled in the README of each chart.
* [api7-control-plane](./charts/api7/README.md)
* [api7-gateway](./charts/gateway/README.md)
* [api7-ingress-controller](./charts/ingress-controller/README.md)
* [aisix](./charts/aisix/README.md)
13 changes: 13 additions & 0 deletions charts/aisix/.helmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Patterns to ignore when building packages.
.DS_Store
.git/
.gitignore
.gitmodules
*.swp
*.bak
*.tmp
*.orig
*~
.vscode/
*.tmproj
.idea/
6 changes: 6 additions & 0 deletions charts/aisix/Chart.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
dependencies:
- name: etcd
repository: https://charts.bitnami.com/bitnami
version: 8.7.7
digest: sha256:c03ff5323e855335d94ce6cfce35745b84d03538dbb197e1a27520a7d69ea3ef
generated: "2026-04-15T17:14:56.064889296+08:00"
20 changes: 20 additions & 0 deletions charts/aisix/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
apiVersion: v2
name: aisix
description: A Helm chart for AISIX AI Gateway

type: application

version: 0.1.0

appVersion: "0.1.0"

maintainers:
- name: API7
email: support@api7.ai
url: https://api7.ai

dependencies:
- name: etcd
version: 8.7.7
repository: https://charts.bitnami.com/bitnami
condition: etcd.enabled
70 changes: 70 additions & 0 deletions charts/aisix/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# AISIX Helm Chart

A Helm chart for [AISIX](https://github.com/api7/aisix) — an open-source, high-performance AI Gateway and LLM proxy built in Rust.

## Prerequisites

- Kubernetes 1.21+
- Helm 3.7+

## Installing the Chart

```bash
helm repo add api7 https://charts.api7.ai
helm repo update

# Recommended: use an existing Secret for the admin key
kubectl create secret generic aisix-admin-secret \
--from-literal=admin-key=<your-strong-key>

helm install my-aisix api7/aisix \
--set deployment.admin.existingSecret=aisix-admin-secret
```

## Uninstalling the Chart

```bash
helm uninstall my-aisix
```

## Configuration

The following table lists the key configurable parameters. See `values.yaml` for the full list.

| Parameter | Description | Default |
|-----------|-------------|---------|
| `image.repository` | AISIX image repository | `ghcr.io/api7/aisix` |
Comment on lines +34 to +36
| `image.tag` | AISIX image tag | `0.1.0` |
| `replicaCount` | Number of replicas | `1` |
Comment on lines +34 to +38
| `deployment.admin.adminKey` | Admin API key (used to create an internal Secret) | `[{key: "changeme"}]` |
| `deployment.admin.existingSecret` | Existing Secret for admin key (overrides adminKey) | `""` |
| `deployment.etcd.host` | External etcd hosts (when `etcd.enabled=false`) | `["http://etcd.host:2379"]` |
| `deployment.etcd.prefix` | etcd key prefix | `/aisix` |
| `gateway.type` | Proxy Service type | `NodePort` |
| `gateway.servicePort` | Proxy Service port | `3000` |
| `gateway.ingress.enabled` | Enable Ingress for proxy | `false` |
| `admin.enabled` | Enable admin Service and port | `true` |
| `admin.type` | Admin Service type | `ClusterIP` |
| `admin.servicePort` | Admin Service port | `3001` |
| `admin.ingress.enabled` | Enable Ingress for admin | `false` |
| `etcd.enabled` | Install bundled etcd | `false` |
| `autoscaling.enabled` | Enable HPA | `false` |

## Using an Existing Secret for the Admin Key

```bash
kubectl create secret generic aisix-admin-secret \
--from-literal=admin-key=<your-strong-key>

helm install my-aisix api7/aisix \
--set deployment.admin.existingSecret=aisix-admin-secret
```

## Using an External etcd

```bash
helm install my-aisix api7/aisix \
--set etcd.enabled=false \
--set "deployment.etcd.host[0]=http://my-etcd:2379" \
--set deployment.admin.existingSecret=aisix-admin-secret
```
Binary file added charts/aisix/charts/etcd-8.7.7.tgz
Binary file not shown.
37 changes: 37 additions & 0 deletions charts/aisix/templates/NOTES.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
AISIX has been installed. Check its status by running:
kubectl --namespace {{ .Release.Namespace }} get pods -l "app.kubernetes.io/name={{ include "aisix.name" . }}"

1. Get the Proxy API URL:
{{- if .Values.gateway.ingress.enabled }}
{{- range .Values.gateway.ingress.hosts }}
http{{ if $.Values.gateway.ingress.tls }}s{{ end }}://{{ .host }}
{{- end }}
{{- else if eq .Values.gateway.type "NodePort" }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "aisix.fullname" . }}-gateway)
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo "Proxy API: http://$NODE_IP:$NODE_PORT"
{{- else if eq .Values.gateway.type "LoadBalancer" }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "aisix.fullname" . }}-gateway --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
echo "Proxy API: http://$SERVICE_IP:{{ .Values.gateway.servicePort }}"
{{- else }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "aisix.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 3000:{{ .Values.gateway.containerPort }}
echo "Proxy API: http://127.0.0.1:3000"
{{- end }}

2. Get the Admin UI URL:
{{- if .Values.admin.enabled }}
{{- if .Values.admin.ingress.enabled }}
{{- range .Values.admin.ingress.hosts }}
http{{ if $.Values.admin.ingress.tls }}s{{ end }}://{{ .host }}/ui
{{- end }}
{{- else }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "aisix.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 3001:{{ .Values.admin.containerPort }}
echo "Admin UI: http://127.0.0.1:3001/ui"
echo "Admin API: http://127.0.0.1:3001/aisix/admin"
{{- end }}
{{- else }}
Admin service is disabled. Enable it with --set admin.enabled=true
{{- end }}
92 changes: 92 additions & 0 deletions charts/aisix/templates/_helpers.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "aisix.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "aisix.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}

{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "aisix.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Common labels
*/}}
{{- define "aisix.labels" -}}
helm.sh/chart: {{ include "aisix.chart" . }}
{{ include "aisix.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{/*
Selector labels
*/}}
{{- define "aisix.selectorLabels" -}}
app.kubernetes.io/name: {{ include "aisix.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

{{/*
Create the name of the service account to use
*/}}
{{- define "aisix.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "aisix.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}

{{/*
Scheme to use while connecting etcd
*/}}
{{- define "aisix.etcd.scheme" -}}
{{- if .Values.etcd.auth.tls.enabled }}
{{- "https" }}
{{- else }}
{{- "http" }}
{{- end }}
{{- end }}

{{/*
Etcd host URL(s) to inject into config.yaml.
When etcd subchart is enabled, construct the in-cluster FQDN automatically.
When disabled, use the user-supplied deployment.etcd.host list.
*/}}
{{- define "aisix.etcd.hosts" -}}
{{- if .Values.etcd.enabled }}
{{- $scheme := include "aisix.etcd.scheme" . }}
{{- if .Values.etcd.fullnameOverride }}
- "{{ $scheme }}://{{ .Values.etcd.fullnameOverride }}:{{ .Values.etcd.service.port }}"
{{- else }}
- "{{ $scheme }}://{{ .Release.Name }}-etcd.{{ .Release.Namespace }}.svc.cluster.local:{{ .Values.etcd.service.port }}"
{{- end }}
{{- else }}
{{- toYaml .Values.deployment.etcd.host }}
{{- end }}
{{- end }}
26 changes: 26 additions & 0 deletions charts/aisix/templates/configmap.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "aisix.fullname" . }}
namespace: {{ .Release.Namespace }}
labels:
{{- include "aisix.labels" . | nindent 4 }}
data:
config.yaml: |-
deployment:
etcd:
host:
{{- include "aisix.etcd.hosts" . | nindent 10 }}
prefix: {{ .Values.deployment.etcd.prefix | quote }}
timeout: {{ .Values.deployment.etcd.timeout }}
admin:
admin_key:
- key: "{{"{{"}}AISIX_ADMIN_KEY{{"}}"}}"

server:
proxy:
listen: "{{ .Values.gateway.ip }}:{{ .Values.gateway.containerPort }}"
tls:
enabled: false
admin:
listen: "{{ .Values.admin.ip }}:{{ .Values.admin.containerPort }}"
Comment on lines +25 to +26
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, examine the ConfigMap template
find . -type f -name "configmap.yaml" | head -5

Repository: api7/api7-helm-chart

Length of output: 198


🏁 Script executed:

# Get the full ConfigMap template to understand context
cat -n charts/aisix/templates/configmap.yaml | head -60

Repository: api7/api7-helm-chart

Length of output: 1180


🏁 Script executed:

# Search for how admin.enabled is used in other templates
rg "admin\.enabled" charts/aisix/templates/ -A 2 -B 2

Repository: api7/api7-helm-chart

Length of output: 1462


🏁 Script executed:

# Check values schema or defaults for admin configuration
cat -n charts/aisix/values.yaml 2>/dev/null | grep -A 10 "admin:"

Repository: api7/api7-helm-chart

Length of output: 914


🏁 Script executed:

# Search for AISIX documentation or references in the repo
find . -type f -name "*.md" | xargs grep -l "admin" | head -5

Repository: api7/api7-helm-chart

Length of output: 115


🏁 Script executed:

# Check if there are other Helm charts or configurations that show admin as optional
rg "server.*admin" charts/ -B 2 -A 2

Repository: api7/api7-helm-chart

Length of output: 493


🏁 Script executed:

# Look at the deployment template to understand how the config is used
cat -n charts/aisix/templates/deployment.yaml | grep -A 20 -B 5 "config.yaml"

Repository: api7/api7-helm-chart

Length of output: 1101


🏁 Script executed:

# Search for any documentation about AISIX configuration schema
find . -type f \( -name "*.yaml" -o -name "*.yml" -o -name "*.md" \) | xargs grep -l "server\.admin" 2>/dev/null

Repository: api7/api7-helm-chart

Length of output: 88


🏁 Script executed:

# Check if there are any existing patterns of conditional config blocks in the configmap
cat -n charts/aisix/templates/configmap.yaml

Repository: api7/api7-helm-chart

Length of output: 1180


🏁 Script executed:

# Search for AISIX documentation or test files that might show config structure
find . -type f -name "*.md" -o -name "*.txt" | xargs grep -l "server\.admin\|aisix.*config" 2>/dev/null | head -10

Repository: api7/api7-helm-chart

Length of output: 88


🏁 Script executed:

# Look for any AISIX references or upstream references
rg "github.com.*aisix\|api7.*aisix" . -t yaml -t md | head -5

Repository: api7/api7-helm-chart

Length of output: 46


🏁 Script executed:

# Check the complete values.yaml to see if admin can actually be disabled
cat -n charts/aisix/values.yaml | grep -A 15 "^admin:"

Repository: api7/api7-helm-chart

Length of output: 46


🏁 Script executed:

# Look for any AISIX source code or examples in the repo
find . -type f -name "*.go" -o -name "*.js" -o -name "*.py" | xargs grep -l "server\.admin\|AISIX" 2>/dev/null | head -5

Repository: api7/api7-helm-chart

Length of output: 46


🏁 Script executed:

# Check if there are any test files or examples that show AISIX config without admin
find . -type f -name "*.yaml" -o -name "*.yml" | xargs grep -l "AISIX\|aisix" 2>/dev/null | grep -E "(test|example|spec)" | head -10

Repository: api7/api7-helm-chart

Length of output: 46


🏁 Script executed:

# Look at how the chart handles other optional server blocks (if any)
cat -n charts/aisix/templates/configmap.yaml | grep -E "({{-\s*if|{{-\s*end)"

Repository: api7/api7-helm-chart

Length of output: 158


🏁 Script executed:

# Check if there's any documentation on AISIX config schema or if server.admin is optional
find . -type f -name "*.md" | xargs cat | grep -A 10 -B 5 "server\.admin\|admin.*listen" 2>/dev/null | head -50

Repository: api7/api7-helm-chart

Length of output: 2909


Conditionally render admin config block to match admin.enabled flag.

The server.admin.listen configuration is always included in the ConfigMap, even when .Values.admin.enabled is false. This creates an inconsistency: the Service, Ingress, and container port are properly gated by the admin.enabled flag elsewhere in the chart (as seen in service-admin.yaml, ingress-admin.yaml, and deployment.yaml), but the configuration block itself is not. To maintain consistency and avoid potential configuration validation issues in AISIX, wrap the admin block conditionally:

     server:
       proxy:
         listen: "{{ .Values.gateway.ip }}:{{ .Values.gateway.containerPort }}"
         tls:
           enabled: false
+      {{- if .Values.admin.enabled }}
       admin:
         listen: "{{ .Values.admin.ip }}:{{ .Values.admin.containerPort }}"
+      {{- end }}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@charts/aisix/templates/configmap.yaml` around lines 29 - 30, The admin listen
line (server.admin.listen: "{{ .Values.admin.ip }}:{{
.Values.admin.containerPort }}") is always rendered even when
.Values.admin.enabled is false; wrap the entire admin block (the "admin:" key
plus the listen line) in a Helm conditional using .Values.admin.enabled (e.g.,
{{- if .Values.admin.enabled }} ... {{- end }}), preserving YAML indentation so
the block is omitted when admin.enabled is false and included when true.

Loading
Loading