Migrating to Runway v2
Runway v2 generates your service’s Helm chart with Fairway
and deploys it through GitLab CI components, replacing the hand-written v1
RunwayKubernetesService and RunwayKubernetesDeployment files. This guide walks
through converting an existing GKE service.
All new and existing GKE services should move to v2. v1 is effectively deprecated, except for EKS services, which remain on v1 until v2 EKS support lands.
What does not change
Section titled “What does not change”The provisioner side is untouched. Your workload inventory entry
(config/runtimes/gke/workloads.yml: runway_service_id, project_id, regions,
members, groups) stays as-is, as does any managed infrastructure you provision.
The repository prerequisites are also unchanged: infra-mgmt project access tokens,
your container image pipeline, the semantic-release job, the vX.Y.Z tag
requirement, the CI/CD job-token allowlist for your deployment project, and the
“merge a feat/fix commit → tag → deploy” trigger flow.
What changes at a glance
Section titled “What changes at a glance”| v1 | v2 |
|---|---|
.runway/<id>/default-values.yaml (RunwayKubernetesService) | .runway/fairway.yaml (FairwayManifest) |
.runway/<id>/gke-service.yaml (RunwayKubernetesDeployment) | .runway/deployment.yaml (RunwayManifest, runway/v2) |
runtime labels in gke-service.yaml metadata.labels | .runway/values.yaml under common.labels |
include: of runwayctl helm-chart.yml | release-platform component from common-ci-tasks |
New repository layout
Section titled “New repository layout”.runway/├── fairway.yaml # chart definition (was default-values.yaml)├── deployment.yaml # Runway v2 manifest (was gke-service.yaml)├── values.yaml # base Helm values, including labels├── values-staging.yaml # staging overrides (optional)└── values-production.yaml # production overrides (optional)Values in values-staging.yaml and values-production.yaml override the base
values.yaml for their environment. Empty override files may be omitted.
Step 1: Create the Fairway manifest
Section titled “Step 1: Create the Fairway manifest”Use your existing default-values.yaml as the starting point. The conversion is not a
straight rename: a few fields stay at the top level of spec, but most move under
spec.values, and several need reshaping.
v1 RunwayKubernetesService | Fairway manifest | Note |
|---|---|---|
spec.image (ends in :{{ .AppVersion }}) | spec.image | Remove the tag — Fairway rejects a tag and supplies Chart.AppVersion itself |
spec.command | spec.command | unchanged |
spec.container_port | spec.containerPort | camelCase |
spec.protocol | spec.protocol | unchanged |
spec.environment | spec.values.environment | moves under values |
spec.scalability.* | spec.values.scalability.* | min_instances → minInstances, etc. |
spec.resources.* | spec.values.resources.* | ephemeral-storage → ephemeralStorage |
spec.observability.scrape_targets | spec.metricPorts | port numbers only — see gotchas |
spec.startup_probe.path | spec.startupProbe.path | path stays at the top level |
spec.startup_probe.{timeout_seconds,…} | spec.values.startupProbe.* | tuning moves under values |
spec.liveness_probe / spec.readiness_probe | same split | path → spec.*Probe.path, tuning → spec.values.*Probe |
spec.configMapVolumes | spec.values.configMapVolumes | |
spec.initContainers | spec.values.initContainers | |
deployment.ingress | spec.values.ingress | |
deployment.httpRoute | spec.values.httpRoute |
A v1 default-values.yaml:
apiVersion: runway/v1kind: RunwayKubernetesServicemetadata: name: example-servicespec: image: "registry.gitlab.com/my-group/example-service:{{ .AppVersion }}" command: ["/bin/frontend"] container_port: 8080 scalability: min_instances: 1 max_instances: 20 cpu_utilization: 70 observability: scrape_targets: - "localhost:8082" resources: requests: cpu: "100m" memory: "128Mi" ephemeral-storage: "512Mi" limits: cpu: "200m" memory: "256Mi" ephemeral-storage: "1Gi" startup_probe: path: "/health?type=startup" timeout_seconds: 1 period_seconds: 10 failure_threshold: 10 liveness_probe: path: "/health?type=liveness" timeout_seconds: 2 period_seconds: 10 failure_threshold: 3becomes:
apiVersion: fairway/v1kind: FairwayManifestmetadata: name: example-servicespec: image: "registry.gitlab.com/my-group/example-service" command: ["/bin/frontend"] containerPort: 8080 metricPorts: [8082] startupProbe: path: "/health?type=startup" livenessProbe: path: "/health?type=liveness" values: scalability: minInstances: 1 maxInstances: 20 cpuUtilization: 70 resources: requests: cpu: "100m" memory: "128Mi" ephemeralStorage: "512Mi" limits: cpu: "200m" memory: "256Mi" ephemeralStorage: "1Gi" startupProbe: timeoutSeconds: 1 periodSeconds: 10 failureThreshold: 10 livenessProbe: timeoutSeconds: 2 periodSeconds: 10 failureThreshold: 3Step 2: Create the Runway v2 manifest
Section titled “Step 2: Create the Runway v2 manifest”Replace gke-service.yaml with a deployment.yaml. The v2 manifest drops
serviceMixins entirely — runtime-specific resources (the Gateway, backend policies,
and so on) are now injected by runwayctl kubernetes generate-flux --runtime gke. It
adds a required chartRef pointing at the chart Fairway publishes for you.
apiVersion: runway/v2kind: RunwayManifestmetadata: name: example-service-gkespec: chartRef: "oci://registry.gitlab.com/my-group/example-service/chart/example-service:{% .ChartVersion %}"The chart is published to your service project’s container registry under
/chart/<fairway-manifest-name>, where <fairway-manifest-name> is the
metadata.name from your Fairway manifest. Keep the literal {% .ChartVersion %}
suffix — Runway fills it in at deploy time. (Note the {% … %} delimiter; this is not
the {{ … }} Go-template syntax used by the v1 image tag.)
This is also where Runway-level configuration lives that used to be spread across the v1 service spec:
- Load balancing moves from the v1
spec.load_balancingtospec.loadBalancinghere (externalLoadBalancer,internalLoadBalancer,cloudflareSetting). - Provisioned infrastructure (managed Redis, Cloud SQL) is declared under
spec.infrastructure— see Memorystore for Redis. - Vault access tokens and workload secrets are declared under
spec.vaultAccessTokensandspec.workloadSecrets.
Step 3: Move labels into values.yaml
Section titled “Step 3: Move labels into values.yaml”The mandatory infrastructure labels that lived under metadata.labels in
gke-service.yaml move into a values.yaml file sitting next to the manifests, under
common.labels. Keep them out of the Fairway manifest’s defaults so the generated chart
stays free of GitLab-specific values.
common: labels: gitlab.com/department: eng-infra gitlab.com/department_group: eng-infra-scalability gitlab.com/owner_email_handle: fforster gitlab.com/product_category: scalabilityUse values-staging.yaml and values-production.yaml for per-environment overrides;
their values override the base values.yaml. See the
GitLab Infrastructure Standards
for valid label values.
Step 4: Switch CI to the release-platform component
Section titled “Step 4: Switch CI to the release-platform component”Replace the v1 runwayctl include with the release-platform component from
common-ci-tasks.
It bundles the Fairway chart-build component and the runwayctl deployment component, and
ships its own pinned fairway_version and runway_version, so you no longer pin those
yourself.
include: - project: 'gitlab-com/gl-infra/platform/runway/runwayctl' file: 'ci-tasks/service-project/helm-chart.yml' ref: v3.82.0 inputs: runway_service_id: example-service-gke runway_version: v3.82.0 runtime: gkeinclude: - component: $CI_SERVER_FQDN/gitlab-com/gl-infra/common-ci-tasks/release-platform@v4.19 inputs: runway_service_id: example-service-gke runtime: gkeUseful optional inputs:
runway_manual_production_deploy: true— gate the production deployment behind a manual play; staging still deploys automatically.release_platform_enabled: truepluscanonical_project_idandcanonical_registry_path— for security-mirror projects that sync artifacts to a canonical project. Leave these unset for ordinary services.
What has no v2 equivalent yet
Section titled “What has no v2 equivalent yet”A few v1 capabilities do not carry over. Account for these before migrating:
| v1 feature | Status in v2 |
|---|---|
load_balancing.logging.* (GCP LB access-log tuning) | Not configurable. generate-flux emits a GCPBackendPolicy that only sets the Cloudflare security policy; access logging falls back to GCP defaults. |
observability ServiceMonitor tunables (path, interval, scheme, serviceMonitor.enabled) | Superseded by metricPorts, which takes port numbers only. |
spec.strategy (RollingUpdate/Recreate, maxSurge, maxUnavailable) | Not a chart concern; moving to the Runway manifest in a later release. |
If your service depends on any of these, raise it in #g_runway before cutting over.
Verify and deploy
Section titled “Verify and deploy”Open a merge request with the new .runway/ files and CI change. The MR pipeline runs
the dry-run and validation jobs, which render the staging and production manifests so
you can confirm they load and template cleanly without deploying.
On merge, the usual flow applies: a feat/fix commit triggers semantic-release, the
new tag pipeline builds and publishes the Fairway chart, and the deployment pipeline is
triggered. Staging deploys automatically; production deploys automatically too unless you
set runway_manual_production_deploy: true.
Next steps
Section titled “Next steps”- New to Runway entirely? Start with Getting Started.
- Adding managed dependencies during the migration? See Memorystore for Redis and Cloud SQL for Postgres.
- Read the
release-platformcomponent docs for the full input list. - Ask the Runway team in
#g_runwayfor help with anything that does not map cleanly.