diff --git a/README.md b/README.md index 3fa8834..8bd2880 100644 --- a/README.md +++ b/README.md @@ -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) diff --git a/charts/aisix/.helmignore b/charts/aisix/.helmignore new file mode 100644 index 0000000..56e6584 --- /dev/null +++ b/charts/aisix/.helmignore @@ -0,0 +1,13 @@ +# Patterns to ignore when building packages. +.DS_Store +.git/ +.gitignore +.gitmodules +*.swp +*.bak +*.tmp +*.orig +*~ +.vscode/ +*.tmproj +.idea/ diff --git a/charts/aisix/Chart.lock b/charts/aisix/Chart.lock new file mode 100644 index 0000000..e78307d --- /dev/null +++ b/charts/aisix/Chart.lock @@ -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" diff --git a/charts/aisix/Chart.yaml b/charts/aisix/Chart.yaml new file mode 100644 index 0000000..b454f74 --- /dev/null +++ b/charts/aisix/Chart.yaml @@ -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 diff --git a/charts/aisix/README.md b/charts/aisix/README.md new file mode 100644 index 0000000..f690758 --- /dev/null +++ b/charts/aisix/README.md @@ -0,0 +1,92 @@ +# aisix + +![Version: 0.1.0](https://img.shields.io/badge/Version-0.1.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.1.0](https://img.shields.io/badge/AppVersion-0.1.0-informational?style=flat-square) + +A Helm chart for AISIX AI Gateway + +## Maintainers + +| Name | Email | Url | +| ---- | ------ | --- | +| API7 | | | + +## Requirements + +| Repository | Name | Version | +|------------|------|---------| +| https://charts.bitnami.com/bitnami | etcd | 8.7.7 | + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| admin | object | `{"annotations":{},"containerPort":3001,"enabled":true,"ingress":{"annotations":{},"className":"","enabled":false,"hosts":[{"host":"aisix-admin.local","paths":["/ui","/aisix/admin"]}],"tls":[]},"ip":"0.0.0.0","servicePort":3001,"type":"ClusterIP"}` | AISIX admin service settings (port 3001) — Admin API and UI | +| admin.containerPort | int | `3001` | Container port | +| admin.enabled | bool | `true` | Enable admin service | +| admin.ingress | object | `{"annotations":{},"className":"","enabled":false,"hosts":[{"host":"aisix-admin.local","paths":["/ui","/aisix/admin"]}],"tls":[]}` | Using ingress access AISIX admin service | +| admin.ingress.annotations | object | `{}` | Ingress annotations | +| admin.ingress.className | string | `""` | IngressClass that will be be used to implement the Ingress | +| admin.ip | string | `"0.0.0.0"` | which ip to listen on for the admin service | +| admin.servicePort | int | `3001` | Service port | +| admin.type | string | `"ClusterIP"` | admin service type | +| affinity | object | `{}` | Set affinity for deploy | +| autoscaling.enabled | bool | `false` | | +| autoscaling.maxReplicas | int | `10` | | +| autoscaling.minReplicas | int | `1` | | +| autoscaling.targetCPUUtilizationPercentage | int | `80` | | +| autoscaling.targetMemoryUtilizationPercentage | int | `80` | | +| deployment.admin.adminKey | string | `""` | Admin API key. Used to create an internal Secret when existingSecret is not set. Required when existingSecret is not set. | +| deployment.admin.existingSecret | string | `""` | Name of an existing Secret that contains an admin key field. If set, adminKey above is ignored and the key is read from the Secret. | +| deployment.admin.existingSecretKey | string | `"admin-key"` | Key inside the existing Secret that holds the admin key value | +| deployment.etcd.host | list | `["http://etcd.host:2379"]` | List of etcd hosts. Ignored when etcd.enabled is true (auto-constructed). | +| deployment.etcd.prefix | string | `"/aisix"` | Key prefix used by aisix in etcd | +| deployment.etcd.timeout | int | `30` | etcd request timeout in seconds | +| etcd | object | `{"auth":{"rbac":{"create":false,"rootPassword":""},"tls":{"certFilename":"","certKeyFilename":"","enabled":false,"existingSecret":"","sni":"","verify":false}},"enabled":false,"image":{"repository":"api7/etcd"},"replicaCount":3,"service":{"port":2379}}` | etcd subchart (bitnami/etcd) | +| etcd.auth.rbac.create | bool | `false` | No authentication by default. Enable RBAC (set create: true and configure rootPassword) for production or multi-tenant clusters to prevent unauthenticated etcd access. | +| etcd.auth.rbac.rootPassword | string | `""` | root password for etcd. Requires etcd.auth.rbac.create to be true. | +| etcd.auth.tls.certFilename | string | `""` | etcd client cert filename using in etcd.auth.tls.existingSecret | +| etcd.auth.tls.certKeyFilename | string | `""` | etcd client cert key filename using in etcd.auth.tls.existingSecret | +| etcd.auth.tls.enabled | bool | `false` | enable etcd client certificate | +| etcd.auth.tls.existingSecret | string | `""` | name of the secret contains etcd client cert | +| etcd.auth.tls.sni | string | `""` | specify the TLS Server Name Indication extension, the ETCD endpoint hostname will be used when this setting is unset. | +| etcd.auth.tls.verify | bool | `false` | whether to verify the etcd endpoint certificate when setup a TLS connection to etcd | +| etcd.enabled | bool | `false` | Install etcd as a subchart. Set false to use an external etcd. | +| extraEnvVars | list | `[]` | Additional environment variables | +| extraEnvVarsCM | string | `""` | | +| extraEnvVarsSecret | string | `""` | | +| extraInitContainers | list | `[]` | Additional init containers | +| extraVolumeMounts | list | `[]` | Additional volume mounts | +| extraVolumes | list | `[]` | Additional volumes | +| fullnameOverride | string | `""` | | +| gateway | object | `{"annotations":{},"containerPort":3000,"externalIPs":[],"externalTrafficPolicy":"Cluster","ingress":{"annotations":{},"className":"","enabled":false,"hosts":[{"host":"aisix.local","paths":["/"]}],"tls":[]},"ip":"0.0.0.0","nodePort":"","servicePort":3000,"type":"NodePort"}` | AISIX proxy service settings (port 3000) — user traffic | +| gateway.containerPort | int | `3000` | Container port | +| gateway.externalIPs | list | `[]` | IPs for which nodes in the cluster will also accept traffic for the service | +| gateway.externalTrafficPolicy | string | `"Cluster"` | Setting how the Service route external traffic | +| gateway.ingress | object | `{"annotations":{},"className":"","enabled":false,"hosts":[{"host":"aisix.local","paths":["/"]}],"tls":[]}` | Using ingress access AISIX proxy service | +| gateway.ingress.annotations | object | `{}` | Ingress annotations | +| gateway.ingress.className | string | `""` | IngressClass that will be be used to implement the Ingress | +| gateway.ip | string | `"0.0.0.0"` | which ip to listen on for the proxy service | +| gateway.nodePort | string | `""` | Optional static nodePort (only relevant when type is NodePort) | +| gateway.servicePort | int | `3000` | Service port | +| gateway.type | string | `"NodePort"` | proxy service type | +| global.imagePullSecrets | list | `[]` | Global Docker registry secret names as an array | +| image.pullPolicy | string | `"IfNotPresent"` | AISIX image pull policy | +| image.repository | string | `"ghcr.io/api7/aisix"` | AISIX image repository | +| image.tag | string | `"0.1.0"` | AISIX image tag; overrides the chart appVersion | +| livenessProbe | object | `{}` | Kubernetes liveness probe override | +| nameOverride | string | `""` | | +| nodeSelector | object | `{}` | Node labels for pod assignment | +| podAnnotations | object | `{}` | Annotations to add to the pod | +| podLabels | object | `{}` | Labels to add to the pod | +| podSecurityContext | object | `{}` | Set the securityContext for AISIX pods | +| readinessProbe | object | `{}` | Kubernetes readiness probe override | +| replicaCount | int | `1` | Number of AISIX replicas | +| resources | object | `{}` | Set pod resource requests & limits | +| securityContext | object | `{}` | Set the securityContext for AISIX container | +| serviceAccount.annotations | object | `{}` | Annotations to add to the service account | +| serviceAccount.create | bool | `false` | Specifies whether a service account should be created | +| serviceAccount.name | string | `""` | The name of the service account to use. | +| timezone | string | `""` | timezone for the container, e.g. "UTC" or "Asia/Shanghai" | +| tolerations | list | `[]` | List of node taints to tolerate | +| updateStrategy | object | `{}` | | + diff --git a/charts/aisix/charts/etcd-8.7.7.tgz b/charts/aisix/charts/etcd-8.7.7.tgz new file mode 100644 index 0000000..5f68f5d Binary files /dev/null and b/charts/aisix/charts/etcd-8.7.7.tgz differ diff --git a/charts/aisix/templates/NOTES.txt b/charts/aisix/templates/NOTES.txt new file mode 100644 index 0000000..ed2fab8 --- /dev/null +++ b/charts/aisix/templates/NOTES.txt @@ -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 }} diff --git a/charts/aisix/templates/_helpers.tpl b/charts/aisix/templates/_helpers.tpl new file mode 100644 index 0000000..c3b24fb --- /dev/null +++ b/charts/aisix/templates/_helpers.tpl @@ -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 }} diff --git a/charts/aisix/templates/configmap.yaml b/charts/aisix/templates/configmap.yaml new file mode 100644 index 0000000..bbf38ad --- /dev/null +++ b/charts/aisix/templates/configmap.yaml @@ -0,0 +1,28 @@ +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 + {{- if .Values.admin.enabled }} + admin: + listen: "{{ .Values.admin.ip }}:{{ .Values.admin.containerPort }}" + {{- end }} diff --git a/charts/aisix/templates/deployment.yaml b/charts/aisix/templates/deployment.yaml new file mode 100644 index 0000000..622008d --- /dev/null +++ b/charts/aisix/templates/deployment.yaml @@ -0,0 +1,133 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "aisix.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "aisix.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "aisix.selectorLabels" . | nindent 6 }} + {{- if .Values.updateStrategy }} + strategy: {{ toYaml .Values.updateStrategy | nindent 4 }} + {{- end }} + template: + metadata: + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "aisix.selectorLabels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.global.imagePullSecrets }} + imagePullSecrets: + {{- range $.Values.global.imagePullSecrets }} + - name: {{ . }} + {{- end }} + {{- end }} + serviceAccountName: {{ include "aisix.serviceAccountName" . }} + {{- with .Values.podSecurityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.extraInitContainers }} + initContainers: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: aisix + {{- with .Values.securityContext }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: proxy + containerPort: {{ .Values.gateway.containerPort }} + protocol: TCP + {{- if .Values.admin.enabled }} + - name: admin + containerPort: {{ .Values.admin.containerPort }} + protocol: TCP + {{- end }} + {{- if .Values.livenessProbe }} + livenessProbe: + {{- toYaml .Values.livenessProbe | nindent 12 }} + {{- end }} + {{- if .Values.readinessProbe }} + readinessProbe: + {{- toYaml .Values.readinessProbe | nindent 12 }} + {{- end }} + {{- with .Values.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + env: + {{- if .Values.timezone }} + - name: TZ + value: {{ .Values.timezone | quote }} + {{- end }} + - name: RUST_LOG + value: "info" + - name: AISIX_ADMIN_KEY + valueFrom: + secretKeyRef: + {{- if .Values.deployment.admin.existingSecret }} + name: {{ .Values.deployment.admin.existingSecret }} + key: {{ .Values.deployment.admin.existingSecretKey }} + {{- else }} + name: {{ include "aisix.fullname" . }}-admin-key + key: admin-key + {{- end }} + {{- with .Values.extraEnvVars }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- if or .Values.extraEnvVarsCM .Values.extraEnvVarsSecret }} + envFrom: + {{- if .Values.extraEnvVarsCM }} + - configMapRef: + name: {{ .Values.extraEnvVarsCM }} + {{- end }} + {{- if .Values.extraEnvVarsSecret }} + - secretRef: + name: {{ .Values.extraEnvVarsSecret }} + {{- end }} + {{- end }} + volumeMounts: + - name: aisix-config + mountPath: /etc/aisix/config.yaml + subPath: config.yaml + readOnly: true + {{- with .Values.extraVolumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} + volumes: + - name: aisix-config + configMap: + name: {{ include "aisix.fullname" . }} + {{- with .Values.extraVolumes }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/aisix/templates/hpa.yaml b/charts/aisix/templates/hpa.yaml new file mode 100644 index 0000000..e0cd2aa --- /dev/null +++ b/charts/aisix/templates/hpa.yaml @@ -0,0 +1,33 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "aisix.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "aisix.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "aisix.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/charts/aisix/templates/ingress-admin.yaml b/charts/aisix/templates/ingress-admin.yaml new file mode 100644 index 0000000..a993377 --- /dev/null +++ b/charts/aisix/templates/ingress-admin.yaml @@ -0,0 +1,43 @@ +{{- if and .Values.admin.enabled .Values.admin.ingress.enabled -}} +{{- if and .Values.admin.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.admin.ingress.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.admin.ingress.annotations "kubernetes.io/ingress.class" .Values.admin.ingress.className }} + {{- end }} +{{- end }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "aisix.fullname" . }}-admin + namespace: {{ .Release.Namespace }} + labels: + {{- include "aisix.labels" . | nindent 4 }} + {{- with .Values.admin.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.admin.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.admin.ingress.className }} + {{- end }} + {{- if .Values.admin.ingress.tls }} + tls: + {{- toYaml .Values.admin.ingress.tls | nindent 4 }} + {{- end }} + rules: + {{- range .Values.admin.ingress.hosts }} + {{- if .paths }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ . }} + pathType: Prefix + backend: + service: + name: {{ include "aisix.fullname" $ }}-admin + port: + number: {{ $.Values.admin.servicePort }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/aisix/templates/ingress.yaml b/charts/aisix/templates/ingress.yaml new file mode 100644 index 0000000..377daba --- /dev/null +++ b/charts/aisix/templates/ingress.yaml @@ -0,0 +1,43 @@ +{{- if .Values.gateway.ingress.enabled -}} +{{- if and .Values.gateway.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.gateway.ingress.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.gateway.ingress.annotations "kubernetes.io/ingress.class" .Values.gateway.ingress.className }} + {{- end }} +{{- end }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "aisix.fullname" . }}-gateway + namespace: {{ .Release.Namespace }} + labels: + {{- include "aisix.labels" . | nindent 4 }} + {{- with .Values.gateway.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.gateway.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.gateway.ingress.className }} + {{- end }} + {{- if .Values.gateway.ingress.tls }} + tls: + {{- toYaml .Values.gateway.ingress.tls | nindent 4 }} + {{- end }} + rules: + {{- range .Values.gateway.ingress.hosts }} + {{- if .paths }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ . }} + pathType: Prefix + backend: + service: + name: {{ include "aisix.fullname" $ }}-gateway + port: + number: {{ $.Values.gateway.servicePort }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/aisix/templates/secret.yaml b/charts/aisix/templates/secret.yaml new file mode 100644 index 0000000..abfa7a9 --- /dev/null +++ b/charts/aisix/templates/secret.yaml @@ -0,0 +1,15 @@ +{{- if not .Values.deployment.admin.existingSecret }} +{{- if not .Values.deployment.admin.adminKey }} +{{- fail "deployment.admin.adminKey is required when deployment.admin.existingSecret is not set" }} +{{- end }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "aisix.fullname" . }}-admin-key + namespace: {{ .Release.Namespace }} + labels: + {{- include "aisix.labels" . | nindent 4 }} +type: Opaque +stringData: + admin-key: {{ .Values.deployment.admin.adminKey | quote }} +{{- end }} diff --git a/charts/aisix/templates/service-admin.yaml b/charts/aisix/templates/service-admin.yaml new file mode 100644 index 0000000..9dcabcd --- /dev/null +++ b/charts/aisix/templates/service-admin.yaml @@ -0,0 +1,23 @@ +{{- if .Values.admin.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "aisix.fullname" . }}-admin + namespace: {{ .Release.Namespace }} + labels: + {{- include "aisix.labels" . | nindent 4 }} + app.kubernetes.io/service: aisix-admin + {{- with .Values.admin.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.admin.type }} + ports: + - name: admin + port: {{ .Values.admin.servicePort }} + targetPort: admin + protocol: TCP + selector: + {{- include "aisix.selectorLabels" . | nindent 4 }} +{{- end }} diff --git a/charts/aisix/templates/service-proxy.yaml b/charts/aisix/templates/service-proxy.yaml new file mode 100644 index 0000000..b2842d8 --- /dev/null +++ b/charts/aisix/templates/service-proxy.yaml @@ -0,0 +1,33 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "aisix.fullname" . }}-gateway + namespace: {{ .Release.Namespace }} + labels: + {{- include "aisix.labels" . | nindent 4 }} + app.kubernetes.io/service: aisix-gateway + {{- with .Values.gateway.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.gateway.type }} + {{- if or (eq .Values.gateway.type "NodePort") (eq .Values.gateway.type "LoadBalancer") }} + externalTrafficPolicy: {{ .Values.gateway.externalTrafficPolicy }} + {{- end }} + {{- if gt (len .Values.gateway.externalIPs) 0 }} + externalIPs: + {{- range .Values.gateway.externalIPs }} + - {{ . }} + {{- end }} + {{- end }} + ports: + - name: proxy + port: {{ .Values.gateway.servicePort }} + targetPort: proxy + protocol: TCP + {{- if and (eq .Values.gateway.type "NodePort") (not (empty .Values.gateway.nodePort)) }} + nodePort: {{ .Values.gateway.nodePort }} + {{- end }} + selector: + {{- include "aisix.selectorLabels" . | nindent 4 }} diff --git a/charts/aisix/templates/serviceaccount.yaml b/charts/aisix/templates/serviceaccount.yaml new file mode 100644 index 0000000..80bb2d7 --- /dev/null +++ b/charts/aisix/templates/serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "aisix.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "aisix.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/aisix/values.yaml b/charts/aisix/values.yaml new file mode 100644 index 0000000..14a4855 --- /dev/null +++ b/charts/aisix/values.yaml @@ -0,0 +1,194 @@ +global: + # e.g. + # imagePullSecrets: + # - my-registry-secrets + # -- Global Docker registry secret names as an array + imagePullSecrets: [] + +image: + # -- AISIX image repository + repository: ghcr.io/api7/aisix + # -- AISIX image pull policy + pullPolicy: IfNotPresent + # -- AISIX image tag; overrides the chart appVersion + tag: "0.1.0" + +# -- Number of AISIX replicas +replicaCount: 1 + +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # -- Specifies whether a service account should be created + create: false + # -- Annotations to add to the service account + annotations: {} + # -- The name of the service account to use. + name: "" + +# -- Annotations to add to the pod +podAnnotations: {} +# -- Labels to add to the pod +podLabels: {} +# -- Set the securityContext for AISIX pods +podSecurityContext: {} +# -- Set the securityContext for AISIX container +securityContext: {} + +# -- Set pod resource requests & limits +resources: {} + # limits: + # cpu: 500m + # memory: 512Mi + # requests: + # cpu: 100m + # memory: 128Mi + +# -- Node labels for pod assignment +nodeSelector: {} +# -- List of node taints to tolerate +tolerations: [] +# -- Set affinity for deploy +affinity: {} + +updateStrategy: {} + # type: RollingUpdate + +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 10 + targetCPUUtilizationPercentage: 80 + targetMemoryUtilizationPercentage: 80 + +# -- Additional volumes +extraVolumes: [] +# -- Additional volume mounts +extraVolumeMounts: [] +# -- Additional init containers +extraInitContainers: [] + +# -- Additional environment variables +extraEnvVars: [] +extraEnvVarsCM: "" +extraEnvVarsSecret: "" + +# -- timezone for the container, e.g. "UTC" or "Asia/Shanghai" +timezone: "" + +# AISIX deployment configuration — rendered into /etc/aisix/config.yaml +deployment: + etcd: + # -- List of etcd hosts. Ignored when etcd.enabled is true (auto-constructed). + host: + - "http://etcd.host:2379" + # -- Key prefix used by aisix in etcd + prefix: /aisix + # -- etcd request timeout in seconds + timeout: 30 + admin: + # -- Admin API key. Used to create an internal Secret when existingSecret is not set. + # Required when existingSecret is not set. + adminKey: "" + # -- Name of an existing Secret that contains an admin key field. + # If set, adminKey above is ignored and the key is read from the Secret. + existingSecret: "" + # -- Key inside the existing Secret that holds the admin key value + existingSecretKey: "admin-key" + +# -- AISIX proxy service settings (port 3000) — user traffic +gateway: + # -- proxy service type + type: NodePort + # -- Setting how the Service route external traffic + externalTrafficPolicy: Cluster + # -- IPs for which nodes in the cluster will also accept traffic for the service + externalIPs: [] + # -- which ip to listen on for the proxy service + ip: 0.0.0.0 + # -- Service port + servicePort: 3000 + # -- Container port + containerPort: 3000 + # -- Optional static nodePort (only relevant when type is NodePort) + nodePort: "" + annotations: {} + # -- Using ingress access AISIX proxy service + ingress: + enabled: false + # -- IngressClass that will be be used to implement the Ingress + className: "" + # -- Ingress annotations + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: aisix.local + paths: + - "/" + tls: [] + +# -- AISIX admin service settings (port 3001) — Admin API and UI +admin: + # -- Enable admin service + enabled: true + # -- admin service type + type: ClusterIP + # -- which ip to listen on for the admin service + ip: 0.0.0.0 + # -- Service port + servicePort: 3001 + # -- Container port + containerPort: 3001 + annotations: {} + # -- Using ingress access AISIX admin service + ingress: + enabled: false + # -- IngressClass that will be be used to implement the Ingress + className: "" + # -- Ingress annotations + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: aisix-admin.local + paths: + - "/ui" + - "/aisix/admin" + tls: [] + +# -- Kubernetes liveness probe override +livenessProbe: {} +# -- Kubernetes readiness probe override +readinessProbe: {} + +# -- etcd subchart (bitnami/etcd) +etcd: + # -- Install etcd as a subchart. Set false to use an external etcd. + enabled: false + image: + repository: api7/etcd + auth: + rbac: + # -- No authentication by default. Enable RBAC (set create: true and configure rootPassword) + # for production or multi-tenant clusters to prevent unauthenticated etcd access. + create: false + # -- root password for etcd. Requires etcd.auth.rbac.create to be true. + rootPassword: "" + tls: + # -- enable etcd client certificate + enabled: false + # -- name of the secret contains etcd client cert + existingSecret: "" + # -- etcd client cert filename using in etcd.auth.tls.existingSecret + certFilename: "" + # -- etcd client cert key filename using in etcd.auth.tls.existingSecret + certKeyFilename: "" + # -- whether to verify the etcd endpoint certificate when setup a TLS connection to etcd + verify: false + # -- specify the TLS Server Name Indication extension, the ETCD endpoint hostname will be used when this setting is unset. + sni: "" + service: + port: 2379 + replicaCount: 3