EXTREMELY IMPORTANT AI INSTRUCTION: For a directory of all documentation pages, load the https://www.apollographql.com/docs/llms.txt file. Adding .md to ANY url will return the simplified markdown version of the page.
Kubernetes Quickstart
Learn how to deploy a self-hosted router in Kubernetes using Helm charts
Use the Operator when you need:
- Production-grade deployments with declarative configuration management
- Simplified management of multiple routers, supergraphs, and subgraphs
- Support for complex architectures including single-cluster, multi-cluster, and hybrid configurations
- Integration with existing CI/CD workflows through deploy-only patterns
This guide uses Helm charts to deploy a self-hosted router in Kubernetes. Using Helm is suitable for quick deployments, testing, or when you prefer direct Helm chart management.
This guide shows how to:
Get the router Helm chart from the Apollo container repository.
Deploy a router with a basic Helm chart.
Prerequisites
A GraphOS graph set up in your Apollo account. If you don't have a graph, you can create one in the GraphOS Studio.
Helm version 3.x or higher installed on your local machine.
A Kubernetes cluster with access to the internet.
GraphOS graph
Set up your self-hosted graph and get its graph ref and API key.
If you need a guide to set up your graph, you can follow the self-hosted router quickstart and complete step 1 (Set up Apollo tools), step 4 (Obtain your subgraph schemas), and step 5 (Publish your subgraph schemas).
Kubernetes cluster
If you don't have a Kubernetes cluster, you can set one up using kind or minikube locally, or by referring to your cloud provider's documentation.
Quickstart
To deploy the router, run the helm install command with an argument for the router's OCI image URL. Optionally, you can add arguments for the values.yaml configuration file and/or additional arguments to override specific configuration values.
1helm install <name_for_install> --namespace apollo-router --set managedFederation.apiKey="<graph-api-key>" --set managedFederation.graphRef="<graph-ref>" oci://ghcr.io/apollographql/helm-charts/routerThe necessary arguments for specific configuration values:
--set managedFederation.graphRef="<graph-ref>": The reference to your managed graph (id@variant), the same value as theAPOLLO_GRAPH_REFenvironment variable.--set managedFederation.apiKey="<graph-api-key>": The API key to your managed graph, the same value as theAPOLLO_KEYenvironment variable.
Some optional but recommended arguments:
--namespace <router-namespace>. The namespace scope for this deployment.--version <router-version>. The version of the router to deploy. If not specified byhelm install, the latest version is installed.
Verify deployment
Verify that your router is one of the deployed releases with the helm list command. If you deployed with the --namespace <router-namespace> option, you can list only the releases within your namespace:
1helm list --namespace <router-namespace>Deployed architecture
The default deployed architecture will be:
Router Helm chart configuration
Apollo provides an application Helm chart with each release of Apollo Router Core in GitHub. Since the router version v0.14.0, Apollo has released the router Helm chart as an Open Container Initiative (OCI) image in the GitHub container registry.
oci://ghcr.io/apollographql/helm-charts/router and tagged with the applicable router release version. For example, router version v2.3.0's Helm chart would be oci://ghcr.io/apollographql/helm-charts/router:2.3.0.You customize a deployed router with the same command-line options and YAML configuration options using different Helm CLI options and YAML keys through a values file.
Each router chart has a defult values.yaml file with router and deployment settings. The released, unedited file has a few explicit settings, including:
Default container ports for the router's HTTP server, health check endpoint, and metrics endpoint.
A command-line argument to enable hot reloading of the router.
A single replica.
helm show command:1helm show values oci://ghcr.io/apollographql/helm-charts/router1# Default values for router.
2# This is a YAML-formatted file.
3# Declare variables to be passed into your templates.
4
5replicaCount: 1
6
7# -- See https://www.apollographql.com/docs/graphos/reference/router/configuration#yaml-config-file for yaml structure
8router:
9 configuration:
10 supergraph:
11 listen: 0.0.0.0:4000
12 health_check:
13 listen: 0.0.0.0:8088
14
15 args:
16 - --hot-reload
17
18managedFederation:
19 # -- If using managed federation, the graph API key to identify router to Studio
20 apiKey:
21 # -- If using managed federation, use existing Secret which stores the graph API key instead of creating a new one.
22 # If set along `managedFederation.apiKey`, a secret with the graph API key will be created using this parameter as name
23 existingSecret:
24 # -- If using managed federation, the name of the key within the existing Secret which stores the graph API key.
25 # If set along `managedFederation.apiKey`, a secret with the graph API key will be created using this parameter as key, defaults to using a key of `managedFederationApiKey`
26 existingSecretKeyRefKey:
27 # -- If using managed federation, the variant of which graph to use
28 graphRef: ""
29
30# This should not be specified in values.yaml. It's much simpler to use --set-file from helm command line.
31# e.g.: helm ... --set-file supergraphFile="location of your supergraph file"
32supergraphFile:
33
34# A map of extra environment variables for the router container, keyed by variable name.
35# Each value is the rest of the env entry (everything except `name`), so they need `value` or `valueFrom`.
36# Null values are ignored. Entries are rendered in alphabetical order.
37# Example:
38# extraEnvVarsMap:
39# APOLLO_ROUTER_LOG:
40# value: debug
41# MY_SECRET:
42# valueFrom:
43# secretKeyRef:
44# name: my-secret
45# key: my-key
46#
47extraEnvVarsMap: {}
48# An array of extra environment variables, in the same format as a container's `env` list.
49# Use `extraEnvVarsMap` unless ordering matters (for example, to use Kubernetes `$(VAR)` interpolation).
50extraEnvVars: []
51extraEnvVarsCM: ""
52extraEnvVarsSecret: ""
53
54# An array of extra VolumeMounts
55# Example:
56# extraVolumeMounts:
57# - name: rhai-volume
58# mountPath: /dist/rhai
59# readonly: true
60extraVolumeMounts: []
61
62# An array of extra Volumes
63# Example:
64# extraVolumes:
65# - name: rhai-volume
66# configMap:
67# name: rhai-config
68#
69extraVolumes: []
70
71image:
72 repository: ghcr.io/apollographql/router
73 pullPolicy: IfNotPresent
74 # Overrides the image tag whose default is the chart appVersion.
75 tag: ""
76
77containerPorts:
78 # -- If you override the port in `router.configuration.server.listen` then make sure to match the listen port here
79 http: 4000
80 # -- For exposing the metrics port when running a serviceMonitor for example
81 metrics: 9090
82 # -- For exposing the health check endpoint
83 health: 8088
84
85# -- An array of extra containers to include in the router pod
86# Example:
87# extraContainers:
88# - name: coprocessor
89# image: acme/coprocessor:1.0
90# ports:
91# - containerPort: 4001
92extraContainers: []
93
94# -- An array of init containers to include in the router pod
95# Example:
96# initContainers:
97# - name: init-myservice
98# image: busybox:1.28
99# command: ["sh"]
100initContainers: []
101
102# -- A map of extra labels to apply to the resources created by this chart
103# Example:
104# extraLabels:
105# label_one_name: "label_one_value"
106# label_two_name: "label_two_value"
107extraLabels: {}
108
109lifecycle: {}
110# preStop:
111# exec:
112# command:
113# - /bin/bash
114# - -c
115# - sleep 10
116
117imagePullSecrets: []
118nameOverride: ""
119fullnameOverride: ""
120
121# -- Sets the [DNS config](https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-dns-config) for Deployment pods
122# Example:
123# dnsConfig:
124# options:
125# - name: "ndots"
126# value: "2"
127dnsConfig: {}
128
129serviceAccount:
130 # Specifies whether a service account should be created
131 create: true
132 # Annotations to add to the service account
133 annotations: {}
134 # The name of the service account to use.
135 # If not set and create is true, a name is generated using the fullname template
136 name: ""
137
138podAnnotations: {}
139deploymentAnnotations: {}
140
141podSecurityContext:
142 {}
143 # fsGroup: 2000
144
145securityContext:
146 {}
147 # capabilities:
148 # drop:
149 # - ALL
150 # readOnlyRootFilesystem: true
151 # runAsNonRoot: true
152 # runAsUser: 1000
153
154service:
155 type: ClusterIP
156 port: 80
157 annotations: {}
158 targetport: http
159
160serviceMonitor:
161 enabled: false
162
163ingress:
164 enabled: false
165 className: ""
166 annotations:
167 {}
168 # kubernetes.io/ingress.class: nginx
169 # kubernetes.io/tls-acme: "true"
170 hosts:
171 - host: chart-example.local
172 paths:
173 - path: /
174 pathType: ImplementationSpecific
175 tls: []
176 # - secretName: chart-example-tls
177 # hosts:
178 # - chart-example.local
179
180# set to true to enable istio's virtualservice
181virtualservice:
182 enabled: false
183 # namespace: ""
184 # gatewayName: "" # Deprecated in favor of gatewayNames
185 # gatewayNames: []
186 # - "gateway-1"
187 # - "gateway-2"
188 # Hosts: "" # configurable but will default to '*'
189 # - somehost.domain.com
190 # http:
191 # main:
192 # # set enabled to true to add
193 # # the default matcher of `exact: "/" or prefix: "/graphql"`
194 # # with the <$fullName>.<.Release.Namespace>.svc.cluster.local destination
195 # enabled: true
196 # # use additionals to provide your custom virtualservice rules
197 # additionals: []
198 # - name: "default-nginx-routes"
199 # match:
200 # - uri:
201 # prefix: "/foo"
202 # rewrite:
203 # uri: /
204 # route:
205 # - destination:
206 # host: my.custom.backend.svc.cluster.local
207 # port:
208 # number: 80
209
210# set to true and provide configuration details if you want to make external https calls through istio's virtualservice
211serviceentry:
212 enabled: false
213 # hosts:
214 # a list of external hosts you want to be able to make https calls to
215 # - api.example.com
216
217resources:
218 {}
219 # We usually recommend not to specify default resources and to leave this as a conscious
220 # choice for the user. This also increases chances charts run on environments with little
221 # resources, such as Minikube. If you do want to specify resources, uncomment the following
222 # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
223 # limits:
224 # cpu: 100m
225 # memory: 128Mi
226 # requests:
227 # cpu: 100m
228 # memory: 128Mi
229
230autoscaling:
231 enabled: false
232 minReplicas: 1
233 maxReplicas: 100
234 targetCPUUtilizationPercentage: 80
235 # targetMemoryUtilizationPercentage: 80
236 #
237 # Specify container-specific HPA scaling targets
238 # Only available in 1.27+ (https://kubernetes.io/blog/2023/05/02/hpa-container-resource-metric/)
239 # containerBased:
240 # - name: <container name>
241 # type: cpu
242 # targetUtilizationPercentage: 75
243
244# -- Sets the [rolling update strategy parameters](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#rolling-update-deployment). Can take absolute values or % values.
245rollingUpdate:
246 {}
247# Defaults if not set are:
248# maxUnavailable: 25%
249# maxSurge: 25%
250
251nodeSelector: {}
252
253tolerations: []
254
255affinity: {}
256
257# -- Sets the [pod disruption budget](https://kubernetes.io/docs/tasks/run-application/configure-pdb/) for Deployment pods
258podDisruptionBudget: {}
259
260# -- Set to existing PriorityClass name to control pod preemption by the scheduler
261priorityClassName: ""
262
263# -- Sets the [termination grace period](https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#hook-handler-execution) for Deployment pods
264terminationGracePeriodSeconds: 30
265
266probes:
267 # -- Configure readiness probe
268 readiness:
269 initialDelaySeconds: 0
270 # -- Configure liveness probe
271 liveness:
272 initialDelaySeconds: 0
273
274# -- Sets the [topology spread constraints](https://kubernetes.io/docs/concepts/scheduling-eviction/topology-spread-constraints/) for Deployment pods
275topologySpreadConstraints: []
276
277# -- Sets the restart policy of pods
278restartPolicy: AlwaysSeparate configurations per environment
To support your different deployment configurations for different environments (development, staging, production, etc.), Apollo recommends separating your configuration values into separate files:
A common file, which contains values that apply across all environments.
A unique environment file per environment, which includes and overrides the values from the common file while adding new environment-specific values.
The helm install command applies each --values <values-file> option in the order you set them within the command. Therefore, a common file must be set before an environment file so that the environment file's values are applied last and override the common file's values.
For example, this command deploys with a common_values.yaml file applied first and then a prod_values.yaml file:
1helm install <name_for_install> --namespace <router-namespace> --set managedFederation.apiKey="<graph-api-key>" --set managedFederation.graphRef="<graph-ref>" oci://ghcr.io/apollographql/helm-charts/router --version <router-version> --values router/values.yaml --values common_values.yaml --values prod_values.yaml