Upgrade

How to run helm upgrade on this chart, and the breaking changes chart 5.0.0 brings — the booster UI removal, the OAP 11 dashboard-template changes, and the new ui.config default.

Run the upgrade

helm upgrade skywalking oci://docker.io/apache/skywalking-helm \
  --version 5.0.0 -n skywalking \
  --set oap.image.tag=11.0.0 \
  --set oap.storageType=banyandb \
  --set ui.image.tag=horizon-1.0.0 \
  --set elasticsearch.enabled=false \
  --set banyandb.enabled=true \
  --set banyandb.image.tag=0.11.0 \
  --wait --wait-for-jobs

Three values have no defaults and must be present on every upgrade, not just the first install:

value example
oap.image.tag 11.0.0
oap.storageType elasticsearch, postgresql, banyandb
ui.image.tag horizon-1.0.0 (only when ui.enabled is true)

helm upgrade does not remember --set flags from the previous release, so either repeat them, pass a values file with -f, or add --reuse-values. --wait-for-jobs alongside --wait makes Helm report an init-Job failure directly instead of leaving you to guess why OAP never went Ready.

Chart 5.0.0 is a version set

OAP and BanyanDB are hard-coupled and must move together — that pair is the most common upgrade failure. Horizon releases independently of OAP (1.0.0 covers both OAP 10.4.0 and 11.x), so its tag is pinned separately, but it must be a horizon-* tag: the chart no longer supports booster UI.

component value version
chart --version 5.0.0
OAP oap.image.tag 11.0.0
Horizon UI ui.image.tag horizon-1.0.0
BanyanDB banyandb.image.tag 0.11.0

OAP ships the BanyanDB server API versions it accepts in SW_STORAGE_BANYANDB_COMPATIBLE_SERVER_API_VERSIONS. OAP 11.0.0 accepts API 0.11, which maps to BanyanDB release 0.11.x. The check is an exact string match with no lenient fallback, so OAP 11 against BanyanDB 0.10.x refuses to start with Incompatible BanyanDB server API version. The mapping is published at BanyanDB API versions; see also BanyanDB.

The bump from 4.9.0 to 5.0.0 is a major one because the UI image line, several values.yaml keys and the init Job’s identity all changed incompatibly. The rest of this page is that list.

Breaking: booster UI is gone

OAP 11 deleted apm-webapp — the Armeria reverse proxy behind the skywalking/ui image — along with the skywalking-ui git submodule and the docker.ui Maven target. The last booster image published to apache/skywalking-ui is 10.4.0; there is no 11.x tag and there will not be one. Only horizon-* tags are published going forward.

What to change when coming from a release that ran booster UI:

before (4.9.0) after (5.0.0)
image tag ui.image.tag=<oap-version> ui.image.tag=horizon-1.0.0
container port 8080 8081 (ui.service.internalPort; Service still fronts 80)
OAP admin port no oap.ports.admin key at all oap.ports.admin: 17128, required
login none — booster was unauthenticated must be configured — no fallback
/graphql on the UI proxied to OAP not proxied; call OAP directly
UI env ui.env (map); chart set SW_OAP_ADDRESS / SW_ZIPKIN_ADDRESS ui.extraEnv (list) and ui.envFromSecret; OAP URLs come from the horizon.yaml ConfigMap
Zipkin port keys oap.ports.zipkinreceiver / zipkinquery oap.ports.zipkin-receiver / zipkin-query

ui.env no longer exists — a values file that still sets it renders nothing and the BFF gets no extra environment. The Zipkin keys were renamed too: oap-deployment.yaml reads them as zipkin-receiver / zipkin-query, so a carried-over zipkinquery still opens a container port but no longer sets SW_QUERY_ZIPKIN / SW_QUERY_ZIPKIN_REST_PORT, and the UI’s oap.zipkinUrl is not derived.

Configure logins before you cut over. Horizon has no built-in admin/admin, and the BFF does not fail closed: with no users it boots, logs an error, serves the login page, and answers /api/auth/health with 200 — which is the chart’s own readiness probe. The pod goes Ready and nobody can sign in. See Set Up Logins.

Expose the OAP admin port. OAP 11 serves /status/* and /debugging/* on the admin REST port only, and Horizon’s BFF reads inspect, DSL debugging, runtime rules and (in the default templates.mode: live) the dashboard template store from it. oap.ports.admin defaults to 17128; set it to null on any OAP 10.x release — the admin server is an OAP 11 addition.

Retarget swctl and any other GraphQL caller. The BFF does not pass /graphql through to OAP, so anything that used to query the UI must address the OAP Service:

# before
swctl --base-url=http://skywalking-skywalking-helm-ui/graphql service ls

# after — OAP directly, on oap.ports.rest
swctl --display yaml \
  --base-url=http://skywalking-skywalking-helm-oap:12800/graphql \
  service ls

Point it at the OAP Service on 12800; copy the form from there if you need the in-cluster hostname pattern.

Upgrading the UI first

Horizon 1.0.0 runs against OAP 10.4.0 as well as OAP 11.x, so you can split the move in two: swap the UI while still on OAP 10, then upgrade OAP. On OAP 10 add one setting, because OAP 10 does not serve the /ui-management REST API Horizon reads templates from:

--set ui.config.templates.mode=readonly

That renders the templates bundled in the image and makes the configuration surface display-only. Dashboards, traces, logs, topology, alarms and profiling all work. Remove it once OAP is on 11. The mode is read at boot, so it needs a BFF restart — the UI Deployment’s checksum/config annotation rolls the pod for you whenever the ConfigMap changes.

Breaking: OAP 11 removed the UI template seeds

These OAP-side surfaces went with the bundled UI. If your values still set them, they are read by nothing — delete them:

removed where it used to live
ui-initialized-templates a key under oap.config, seeding on-disk dashboard JSON
SW_ENABLE_UPDATE_UI_TEMPLATE an env var under oap.env
sidebar menu storage OAP storage
UIConfigurationManagement GraphQL queries and mutations OAP query API

The on-disk dashboard seed files were deleted along with UITemplateInitializer. Horizon ships its own dashboard library and manages templates over the admin REST port instead — that is what oap.ports.admin and ui.config.templates.mode are for.

Breaking: ui.config is empty by default

The interim Horizon work on main mounted a ConfigMap of literal values over /app/horizon.yaml. As of 5.0.0 ui.config defaults to {} and the ConfigMap carries only the fields the chart has to compute:

field derived from
oap.queryUrl the in-cluster OAP Service and oap.ports.rest
oap.adminUrl the in-cluster OAP Service and oap.ports.admin
oap.zipkinUrl the OAP Service and oap.ports.zipkin-query, only when that port is set
server.publicUrl the first ui.ingress.hosts entry, only when ui.ingress.enabled and ui.ingress.hosts are both set (https when ui.ingress.tls is non-empty)
server.port ui.service.internalPort, so the BFF binds the port the container exposes

The four URLs are written as ${VAR:default} tokens, not literals, so the in-cluster value is only the default and the matching HORIZON_* variable still wins. server.port is the deliberate exception — the chart writes it as a plain number, because the container port and both probes are derived from ui.service.internalPort and the BFF has to bind that same port.

This matters because Horizon expands ${...} over the raw text of the config file before parsing it. A field written as a literal makes its HORIZON_* environment variable silently inert, and a field the file omits falls back to a schema default that consults the environment for only a fraction of the image’s variables. A config file full of literals therefore does not merely duplicate defaults — it disables most of the image’s configuration surface.

If you are carrying a full ui.config block forward — from the pre-release main values, not from 4.x, which had no ui.config at all — drop every field that only restates what the image already sets (server.host, oap.timeoutMs, auth.backend, rbac.enabled, session.* and templates.mode all did), and move the rest to ui.extraEnv or ui.envFromSecret:

config field how to set it now
templates.mode HORIZON_TEMPLATES_MODE — works as a bare env var
session.cookieSecure keep in ui.config, optionally as ${HORIZON_SESSION_COOKIE_SECURE:false}
server.trustProxy keep in ui.config, optionally as ${HORIZON_TRUST_PROXY:false}
auth.local.users keep in ui.config as ${HORIZON_AUTH_LOCAL_USERS:[]} + ui.envFromSecret
oap.auth keep in ui.config as ${HORIZON_OAP_AUTH:null} + ui.envFromSecret

Only the first row works from a bare environment variable. The other four have literal schema defaults, so their HORIZON_* variables are reachable only through a ${...} token in the mounted file — set the variable without the token and nothing happens, with no error. See Configure Horizon.

ui.config is still there for pinning a field regardless of the environment, and ${VAR} tokens you write in it do expand — that is how the Secret pattern works. See Configure Horizon.

The init Job re-runs on every upgrade that changes a value

The storage schema is created by a one-shot *-oap-init-* Job that runs OAP with -Dmode=init; the main Deployment runs -Dmode=no-init and blocks until the schema exists. The Job name carries a sha256 of the chart values, so any helm upgrade that changes a value produces a new Job name and re-runs init automatically, with Helm pruning the previous one. An upgrade that changes nothing reuses the existing Job.

Before 5.0.0 this Job was a post-install,post-upgrade,post-rollback Helm hook with a fixed name — the OAP Service name plus -init, e.g. skywalking-skywalking-helm-oap-init. Helm does not own hook resources, so an upgrade from 4.9.0 leaves that completed Job behind in the namespace. It is inert; delete it by hand.

To force a rerun without changing a value, delete the Job and upgrade again:

kubectl delete job -n skywalking -l release=skywalking
helm upgrade skywalking oci://docker.io/apache/skywalking-helm \
  --version 5.0.0 -n skywalking --reuse-values

More detail in The OAP Init Job.

Rolling back

helm rollback restores the previous release’s manifests, so image tags and configuration revert. It does not revert anything the init Job wrote to storage — the chart has no downgrade path for the storage schema. Before an OAP major upgrade, make sure the storage backend is one you can restore independently.

If the UI comes back Ready but unusable after an upgrade, start at UI and Login Problems; if OAP or the init Job fails, see Install and Startup Failures.