Strategia Migrazione OSSM 2/3 — caso reale
Caso reale di migrazione Red Hat OpenShift Service Mesh 2.6 → 3.0 sul cluster OCP COLL (OCP 4.18.5, OVN-Kubernetes). Ogni scelta è verificata sull’ambiente: control plane, ingress dietro F5, ~1500 risorse Istio (296 Gateway, VirtualService, AuthorizationPolicy, DestinationRule, PeerAuthentication).
As-is (dati certi)
| Elemento | Valore rilevato | Impatto |
|---|---|---|
| Piattaforma | OCP 4.18.5, OVN-Kubernetes | Supportata da OSSM 3. |
| Operator | servicemeshoperator.v2.6.17 — Succeeded | Prereq operator coperto (≥2.6.14). |
| Control plane | SMCP basic @ istio-system, spec.version v2.4 / chart 2.4.15 | Da portare a v2.6 (Fase 0). |
| Mode | ClusterWide | Guida cluster-wide, revision-label canary. |
| CA | secret cacerts (4 chiavi: ca-cert/ca-key/cert-chain/root-cert) = plugged CA | Root custom, no cert-manager. Verifica root su cacerts, non istio-ca-secret. |
| mTLS | dataPlane.mtls: true + PeerAuthentication/default STRICT | STRICT esplicito (API Istio) → invariato. |
| PA addon | disable-mtls-jaeger-collector (DISABLE), grafana-ports-mtls-disabled (PERMISSIVE) | Orfane dopo rimozione addon. |
| Ingress | 2 NodePort condivisi, su infra node | istio-ingressgateway 80→30001/443→30002/15021→32072 (pod-label istio: ingressgateway); backend-ingressgateway 80→30011/443→30012/15021→32082 (istio: backend-ingressgateway). |
| Egress | 0 riferimenti (nessun Gateway/VS lo instrada) | Da NON ricreare in OSSM 3. |
| Esposizione app | host VS = VIP F5 → uno dei 2 NodePort | nodePort fissi da preservare. |
| IOR | ~300 Route auto-generate in istio-system (IOR on, chart 2.4.x) | Vestigiali: le app entrano solo via F5→NodePort. Le uniche route “vive” sono quelle infra OCP (console/quay), estranee a OSSM. → disable IOR + delete. |
| Namespace | 312 con istio-injection=enabled (~157 prod / ~146 dev), pattern be/fe/mgw | Canary per namespace, a ondate. memberSelectors SMMR = istio-injection=enabled. |
| Gateway | 296: 229 istio: ingressgateway + 64 istio: backend-ingressgateway + 4 senza selettore (demo/hello) | Le CR selezionano il pod → invariate. |
| Secret TLS | tutti i gwc-* in istio-system, credentialName senza prefisso ns | I gateway injected devono restare in istio-system (SDS). Nessun <ns>/<name> da riscrivere. |
| VirtualService | gateway-bound (*.cariprpccoll.it, match URI/rewrite) + [mesh] interni + mgw SNI passthrough | Invariati (API Istio). |
| AuthorizationPolicy | allow-nothing/allow-from-ns/allow-istio-ingressgateway/allow-gateway-sa per ns | Referenziano il SA dell’ingress → SA da preservare. |
| DestinationRule | 78 | Invariate. |
| EnvoyFilter | solo stats-filter/tcp-stats-filter 1.13–1.16 di sistema | Generati dal CP 2.x, spariscono con esso. Zero custom. |
| WasmPlugin / Sidecar | nessuno | Nessuna remediation Envoy per Istio 1.24. |
| ServiceEntry | 1: d0-npf-be/auth-collaudo (res=DNS, MESH_EXTERNAL) | DNS capture da riabilitare in OSSM 3 (vedi Fase 3). |
Strategia in una riga
Cluster-wide, revision-label (canary), plugged CA condivisa via cacerts, gateway-injection dei soli 2 ingress con adozione dei Service NodePort → i due CP coesistono in istio-system, i namespace migrano a ondate senza disservizio, F5 non viene mai toccato.
Decisioni derivate dai dati reali:
- No cert-manager: CA = plugged
cacerts→ percorso “istio revision label”. - IOR vestigiale: disable + delete route generate, niente migrazione a route esplicite (traffico solo F5→NodePort).
- Egress escluso: 0 utilizzi → non ricreato.
- mTLS invariato: STRICT già
PeerAuthenticationesplicita. - DNS capture: 1 ServiceEntry
res=DNS→proxyMetadataobbligatorio nella CR Istio. - Nessun rischio Envoy 1.24: zero EnvoyFilter/WasmPlugin/Sidecar custom.
Fase 0 — Control plane a v2.6
Operator già 2.6.17. Il control plane è ancora v2.4 (chart 2.4.15) → va portato a v2.6 (che diventa 2.6.17 ≥ 2.6.14). Congela prima gli update.
oc patch subscription servicemeshoperator -n openshift-operators \ --type merge -p '{"spec":{"installPlanApproval":"Manual"}}'
# upgrade incrementale, una minor alla volta (matrice RH)oc patch smcp basic -n istio-system --type merge -p '{"spec":{"version":"v2.5"}}'oc rollout status deploy/istiod-basic -n istio-systemoc patch smcp basic -n istio-system --type merge -p '{"spec":{"version":"v2.6"}}'oc rollout status deploy/istiod-basic -n istio-systemoc get smcp basic -n istio-system -o jsonpath='spec={.spec.version} chart={.status.chartVersion}{"\n"}' # atteso 2.6.17Fase 1 — Premigration checklist
1.1 Dismetti IOR (route vestigiali)
Le app entrano via F5→NodePort: le route IOR in istio-system non servono e OSSM 3 non le gestisce. Disabilita IOR sul CP 2.6 ed eliminale.
# stop reconciliation IORoc patch smcp basic -n istio-system --type merge -p '{"spec":{"gateways":{"openshiftRoute":{"enabled":false}}}}'
# censisci le route generate (naming <ns>-<gateway>-<hash>, target *ingressgateway)oc get route -n istio-system -o json \ | jq -r '.items[] | select(.spec.to.name|test("ingressgateway")) | .metadata.name'# elimina dopo verifica (F5 non le usa). Esempio mirato:# oc delete route -n istio-system <name> ...1.2 ServiceEntry pre-check
Istio 1.24 rifiuta ServiceEntry >256 host o senza porte.
oc get serviceentry -A -o json | jq -r '.items[] | select(.spec.hosts|length>256) | "\(.metadata.namespace)/\(.metadata.name)"'oc get serviceentry -A -o json | jq -r '.items[] | select(.spec.ports==null or (.spec.ports|length==0)) | "\(.metadata.namespace)/\(.metadata.name)"'L’unico ServiceEntry (d0-npf-be/auth-collaudo) è res=DNS → richiede DNS capture (Fase 3), non un fix qui.
1.3 Disabilita addon e configura i sostituti
Addon tutti attivi (grafana, jaeger Memory, kiali, prometheus). In OSSM 3 non esistono più nell’SMCP.
oc patch smcp basic -n istio-system --type merge -p '{ "spec":{ "addons":{"grafana":{"enabled":false},"kiali":{"enabled":false},"prometheus":{"enabled":false}}, "tracing":{"type":"None"}, "security":{"manageNetworkPolicy":false} }}'Sostituti (validi anche in 3.0): metriche → User Workload Monitoring (extensionProvider prometheus); tracing → Tempo + OTel Collector (il Jaeger Memory a sampling 100% non è portabile); Kiali → CR Kiali standalone (Grafana off).
apiVersion: telemetry.istio.io/v1kind: Telemetrymetadata: name: mesh-default namespace: istio-systemspec: metrics: [{ providers: [{ name: prometheus }] }] tracing: [{ providers: [{ name: otel }] }]apiVersion: kiali.io/v1alpha1kind: Kialimetadata: name: kiali namespace: istio-systemspec: version: default external_services: prometheus: auth: { type: bearer, use_kiali_token: true } thanos_proxy: { enabled: true } url: https://thanos-querier.openshift-monitoring.svc.cluster.local:9091 tracing: enabled: true provider: tempo use_grpc: false internal_url: http://tempo-<stack>-query-frontend.tempo:3200 external_url: https://<tempo-route> grafana: { enabled: false }1.4 NetworkPolicy
manageNetworkPolicy messo a false sopra. In banking ricrea le NP a mano (Fase 4), con accesso a entrambi i CP, prima di migrare i workload.
Fase 2 — Gateway injection dei 2 ingress (F5-safe)
I VIP F5 bilanciano su node:nodePort fissi. Adotta i Service esistenti come standalone prima di sganciarli dall’SMCP → i nodePort non cambiano mai. Solo 2 ingress (l’egress è escluso: 0 utilizzi).
2.1 SA (verificati)
| Gateway | pod-label (istio:) | ServiceAccount |
|---|---|---|
istio-ingressgateway | ingressgateway | istio-ingressgateway-service-account |
backend-ingressgateway | backend-ingressgateway | backend-ingressgateway-service-account |
2.2 Adotta i Service NodePort (rimuovi ownerReferences SMCP)
for svc in istio-ingressgateway backend-ingressgateway; do oc get svc $svc -n istio-system -o yaml \ | yq 'del(.metadata.ownerReferences,.metadata.resourceVersion,.metadata.uid,.metadata.creationTimestamp,.status)' \ | oc apply -f -done2.3 Deploy gateway injected (revision 2.6) dietro lo stesso Service
Attenzione alla pod-label: default ingress = istio: ingressgateway (229 Gateway lo selezionano), backend = istio: backend-ingressgateway (64). Sbagliarla = host F5 a vuoto.
# DEFAULT ingress — pod-label istio: ingressgatewayapiVersion: apps/v1kind: Deploymentmetadata: name: istio-ingressgateway-inj namespace: istio-systemspec: selector: matchLabels: { istio: ingressgateway } template: metadata: annotations: { inject.istio.io/templates: gateway } labels: istio: ingressgateway # match del Service NodePort adottato (229 Gateway) sidecar.istio.io/inject: "true" istio.io/rev: basic # revision 2.6 corrente spec: serviceAccountName: istio-ingressgateway-service-account nodeSelector: { node-role.kubernetes.io/infra: "" } tolerations: - { key: node-role.kubernetes.io/infra, effect: NoSchedule } - { key: node-role.kubernetes.io/infra, effect: NoExecute } - { key: node.ocs.openshift.io/storage, effect: NoSchedule } containers: - { name: istio-proxy, image: auto }---# BACKEND ingress — pod-label istio: backend-ingressgatewayapiVersion: apps/v1kind: Deploymentmetadata: name: backend-ingressgateway-inj namespace: istio-systemspec: selector: matchLabels: { istio: backend-ingressgateway } template: metadata: annotations: { inject.istio.io/templates: gateway } labels: istio: backend-ingressgateway # 64 Gateway sidecar.istio.io/inject: "true" istio.io/rev: basic spec: serviceAccountName: backend-ingressgateway-service-account nodeSelector: { node-role.kubernetes.io/infra: "" } tolerations: - { key: node-role.kubernetes.io/infra, effect: NoSchedule } - { key: node-role.kubernetes.io/infra, effect: NoExecute } - { key: node.ocs.openshift.io/storage, effect: NoSchedule } containers: - { name: istio-proxy, image: auto }2.4 Sgancia i gateway dall’SMCP
Con i pod injected Ready dietro i Service adottati, svuota spec.gateways dell’SMCP (default ingress + additionalIngress.backend-ingressgateway + egress). L’SMCP elimina solo i propri Deployment; Service standalone e pod injected restano.
istioctl ps -n istio-system | grep -E 'ingressgateway'oc edit smcp basic -n istio-system # svuota spec.gateways.*# conferma che i VIP F5 rispondono ancora (SIMPLE + mgw SNI)Fase 3 — Installa OSSM 3, IstioCNI e control plane 3.0
Operator OSSM 3 (Sail) → IstioCNI → risorsa Istio nello stesso istio-system per condividere la plugged CA (cacerts).
apiVersion: sailoperator.io/v1kind: IstioCNImetadata: { name: default }spec: namespace: istio-cni version: v1.24-latestapiVersion: sailoperator.io/v1kind: Istiometadata: name: ossm-3spec: namespace: istio-system # stesso ns del 2.6 → cacerts condiviso updateStrategy: { type: RevisionBased } version: v1.24-latest values: meshConfig: # cluster-wide: nessun discoverySelector → guarda tutti i namespace (come l'as-is) defaultConfig: proxyMetadata: # DNS capture per il ServiceEntry res=DNS (d0-npf-be/auth-collaudo) ISTIO_META_DNS_CAPTURE: "true" ISTIO_META_DNS_AUTO_ALLOCATE: "true" extensionProviders: - { name: prometheus, prometheus: {} } - name: otel opentelemetry: { port: 4317, service: otel-collector.<otel-ns>.svc.cluster.local } pilot: traceSampling: 100 # SMCP tracing.sampling:10000 = 100% nodeSelector: { node-role.kubernetes.io/infra: "" } tolerations: - { key: node-role.kubernetes.io/infra, effect: NoSchedule } - { key: node-role.kubernetes.io/infra, effect: NoExecute } - { key: node.ocs.openshift.io/storage, effect: NoSchedule } global: defaultNodeSelector: { node-role.kubernetes.io/infra: "" } defaultTolerations: - { key: node-role.kubernetes.io/infra, effect: NoSchedule } - { key: node-role.kubernetes.io/infra, effect: NoExecute } - { key: node.ocs.openshift.io/storage, effect: NoSchedule }oc apply -f istiocni.yaml -f istio-ossm3.yaml# Verifica CHIAVE: il nuovo istiod carica la plugged CA ESISTENTE (cacerts), non genera una root nuovaoc logs deploy/istiod-ossm-3-v1-24-<patch> -n istio-system | grep -i 'existing secret'oc get istios ossm-3 # ACTIVE REVISION es. ossm-3-v1-24-<patch>Fase 4 — NetworkPolicy durante la migrazione
Entrambi i CP devono raggiungere tutti i workload e viceversa.
for ns in $(oc get smmr default -n istio-system -o jsonpath='{.status.members[*]}'); do oc label ns "$ns" service-mesh=enabled --overwritedone# istiod NP rev 3.0: podSelector app=istiod, istio.io/rev=<ACTIVE REVISION 3.0>Fase 5 — Migrazione workload (canary, per namespace)
REV=$(oc get istios ossm-3 -o jsonpath='{.status.activeRevisionName}') # es. ossm-3-v1-24-x
oc label ns <ns> istio.io/rev=$REV maistra.io/ignore-namespace=true istio-injection- --overwrite=trueoc rollout restart deploy -n <ns>oc rollout status deploy -n <ns>istioctl ps -n <ns> # atteso: ISTIOD istiod-ossm-3-... VERSION 1.24.x- rimuove
istio-injection(ha precedenza suistio.io/rev), aggiungeistio.io/rev=$REV(proxy 3.0) emaistra.io/ignore-namespace=true(ferma l’injector 2.6 → evita il doppio-CNI che blocca il sidecar).
Fase 6 — Migrazione gateway (canary)
I 2 ingress sono già injected (Fase 2). Ruota i pod da rev basic a rev 3.0 sullo stesso Service NodePort → F5 intatto.
REV=$(oc get istios ossm-3 -o jsonpath='{.status.activeRevisionName}')
# clone del deployment injected con istio.io/rev=$REV, STESSA pod-label (ingressgateway / backend-ingressgateway)oc scale deploy/istio-ingressgateway-3 -n istio-system --replicas=<n+1>oc scale deploy/istio-ingressgateway-inj -n istio-system --replicas=<n-1>istioctl ps -n istio-system | grep ingressgateway # verifica rev 1.24.xRipeti per backend-ingressgateway. Per gateway a bassa criticità: in-place (relabel ns + rollout restart).
Fase 7 — mTLS / PeerAuthentication
PeerAuthentication/default STRICT è API Istio → resta valida in 3.0. Nessuna traduzione di dataPlane.mtls.
- Mantieni
PeerAuthentication/defaultSTRICT. - Rimuovi
disable-mtls-jaeger-collectoregrafana-ports-mtls-disableddopo la dismissione addon. - 78 DestinationRule e le AuthorizationPolicy restano invariate (dipendono dai SA preservati in Fase 2).
Fase 8 — Completamento
8.1 (Opzionale) default revision tag
Dopo aver migrato tutti ns e gateway, torna a istio-injection=enabled col tag di default → i futuri update 3.x non richiedono re-label dei ~300 ns.
apiVersion: sailoperator.io/v1kind: IstioRevisionTagmetadata: { name: default }spec: targetRef: { kind: IstioRevision, name: <ACTIVE REVISION 3.0> }oc apply -f rev-tag.yamloc get istiorevisiontags # default → Healthy / IN USE True dopo relabel# per ns: oc label ns <ns> istio-injection=enabled istio.io/rev- ; oc rollout restart deploy -n <ns>8.2 Rimozione OSSM 2.6
oc get smcp,smm,smmr -Aoc delete smcp --all -A ; oc delete smmr --all -A ; oc delete smm --all -A
csv=$(oc get subscription servicemeshoperator -n openshift-operators -o jsonpath='{.status.currentCSV}')oc delete subscription servicemeshoperator -n openshift-operatorsoc delete clusterserviceversion "$csv" -n openshift-operatorsoc get crds -o name | grep '\.maistra\.io$' | xargs -r -n1 oc delete
# label residue SOLO dopo la disinstallazione del CP 2.6oc get ns -l maistra.io/ignore-namespace=true -o name | xargs -r -n1 -I{} oc label {} maistra.io/ignore-namespace-Reference — mapping SMCP → Istio (campi in uso)
SMCP 2.6 (basic) | Istio 3.0 (ossm-3) | Nota |
|---|---|---|
mode: ClusterWide | (default) — no discoverySelectors | 3.0 cluster-wide di default. |
policy.type: Istiod | (default) | Mixer rimosso. |
tracing.sampling: 10000 | values.pilot.traceSampling: 100 | 10000 = 100%. |
tracing.type: Jaeger | Telemetry + extensionProvider otel → Tempo | Jaeger Memory non portabile. |
addons.* | Operator separati (UWM, Kiali, Tempo) | Grafana non supportata. |
security.dataPlane.mtls: true | PeerAuthentication/default STRICT | Già presente → invariata. |
security.certificateAuthority.istiod + cacerts | secret cacerts in istio-system | Plugged CA condivisa, no cert-manager. |
gateways.openshiftRoute (IOR) | — | Disabilitato + route eliminate (F5→NodePort). |
gateways.{ingress,additionalIngress} | Gateway injection (Deployment + Service self-managed) | Solo 2 ingress; egress escluso. |
runtime…nodeSelector/tolerations (infra) | values.pilot.* + values.global.default* | Placement infra preservato. |
ServiceEntry res=DNS | meshConfig.defaultConfig.proxyMetadata DNS_CAPTURE+AUTO_ALLOCATE | Evita Name or service not known. |
Non supportati in 3.0 e presenti in questo SMCP: addons.*, policy.*, telemetry.*, gateways.openshiftRoute, security.certificateAuthority.istiod.privateKey.rootCADir (root via cacerts).
Check residui (non bloccanti)
- I 4 Gateway senza selettore (
istio-system-hello-*,ossm-bookinfo-*,4296-demo-*): demo/test → verifica e rimuovi, o escludi dalla migrazione. - Conferma il mode dei Gateway mgw (PASSTHROUGH, porta 443, selettore su uno dei 2 ingress): SNI-routing gestito dai VS mgw, TLS terminato a valle.
4b-corporatebanking: presenti Gateway con nomi non allineati al namespace (corporatebanking-gateway) → verifica il binding VS↔Gateway prima di migrare quel gruppo.