SynfraCore
Synfracore
Start Learning
Navigation

Academies

Platform

RoadmapsLabsCertificationsInterviewPYQsAI AssistantCareer
Start Learning Free🗺️ Learning Roadmaps

OpenShift (OCP)Advanced

Production patterns, performance, security hardening

✍️
Written by senior engineers. Reviewed for technical accuracy.· Updated 2025 · SynfraCore OpenShift (OCP) Team
Expert Content

OpenShift — Advanced

OCP Cluster Upgrades

OCP upgrades are managed by the Cluster Version Operator (CVO) — it's not a manual process like upgrading vanilla Kubernetes.

Upgrade Channels

ChannelPurpose

|---|---|

`stable-4.x`Production — most tested, recommended for enterprise
fast-4.xSlightly ahead of stable — early access to fixes
candidate-4.xPre-release — testing only
eus-4.xExtended Update Support — even versions only (4.12, 4.14, 4.16). Allows skipping odd versions

Golden rule: Always upgrade sequentially. 4.12 → 4.13 → 4.14 ✅. 4.12 → 4.14 ❌ (unless both are EUS).

Upgrade Process

bash
# Step 1: Verify cluster is healthy before starting
oc get co              # all AVAILABLE=True, PROGRESSING=False, DEGRADED=False
oc get nodes           # all Ready
oc get mcp             # all UPDATED=True, DEGRADED=False

# Step 2: Check what updates are available
oc adm upgrade
# Example output:
# Cluster version is 4.14.12
# Updates:
#   VERSION: 4.14.15   IMAGE: quay.io/openshift-release-dev/ocp-release@sha256:...
#   VERSION: 4.15.0    IMAGE: quay.io/openshift-release-dev/ocp-release@sha256:...

# Step 3: Review Red Hat release notes for target version
# https://docs.openshift.com/container-platform/4.15/release_notes/

# Step 4: Apply upgrade
oc adm upgrade --to-latest=true          # apply latest available
oc adm upgrade --to=4.14.15             # apply specific version

# Step 5: Monitor — this is critical (upgrade takes 1-3 hours)
watch oc get clusterversion              # shows overall progress
watch oc get co                          # operators upgrade sequentially
watch oc get nodes                       # workers drain+reboot via MachineConfigPool

# Step 6: Verify completion
oc get clusterversion
# DESIRED=4.14.15, CURRENT=4.14.15, AVAILABLE=True, PROGRESSING=False

What happens during upgrade:

1.CVO downloads new release payload
2.Control plane operators update first (one at a time)
3.Workers update via MachineConfigPool — each worker drains, reboots, comes back
4.Cluster Operators return to Available state

Best practice: Always upgrade non-prod first. Validate for 1-2 days. Then upgrade prod.

Monitoring Stack

OCP ships with a complete monitoring stack in openshift-monitoring:

Prometheus    → metrics collection (cluster + user workloads)
Alertmanager  → routes alerts (email, Slack, PagerDuty)
Thanos Querier → unified query across multiple Prometheus instances
Grafana       → dashboards (deprecated in 4.10+; use community operator)

Enabling User Workload Monitoring

By default, Prometheus only monitors OCP platform components. Enable it for your apps:

bash
# Edit the cluster monitoring configmap
oc edit configmap cluster-monitoring-config -n openshift-monitoring

# Add this under data:
data:
  config.yaml: |
    enableUserWorkload: true
    prometheusK8s:
      retention: 7d               # keep 7 days of metrics
      volumeClaimTemplate:
        spec:
          storageClassName: gp3
          resources:
            requests:
              storage: 40Gi

Now a separate Prometheus instance appears in openshift-user-workload-monitoring. Point your ServiceMonitor at it.

ServiceMonitor — Scrape Your App Metrics

yaml
# Your app must expose a /metrics endpoint (Prometheus format)
# Then create a ServiceMonitor:
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: myapp-monitor
  namespace: production
spec:
  selector:
    matchLabels:
      app: myapp             # selects the Service to scrape
  endpoints:
  - port: metrics            # port name on the Service
    path: /metrics
    interval: 30s

PrometheusRule — Custom Alerts

yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: myapp-alerts
  namespace: production
spec:
  groups:
  - name: myapp.rules
    rules:
    - alert: MyAppHighErrorRate
      expr: rate(http_requests_total{status=~"5.."}[5m]) > 0.1
      for: 5m
      labels:
        severity: critical
      annotations:
        summary: "High error rate on myapp"
        description: "Error rate is {{ $value }} requests/sec"

    - alert: MyAppPodRestarting
      expr: rate(kube_pod_container_status_restarts_total{namespace="production"}[15m]) > 0
      for: 10m
      labels:
        severity: warning
      annotations:
        summary: "Pod {{ $labels.pod }} is restarting frequently"

Configure Alertmanager

yaml
# Create secret with Alertmanager config
cat <<EOF | oc apply -f -
apiVersion: v1
kind: Secret
metadata:
  name: alertmanager-main
  namespace: openshift-monitoring
stringData:
  alertmanager.yaml: |
    global:
      smtp_smarthost: 'smtp.gmail.com:587'
      smtp_from: 'alerts@company.com'
    route:
      group_by: ['alertname', 'namespace']
      group_wait: 30s
      group_interval: 5m
      repeat_interval: 4h
      receiver: default
      routes:
      - match:
          severity: critical
        receiver: pagerduty
      - match:
          severity: warning
        receiver: slack
    receivers:
    - name: default
      email_configs:
      - to: 'ops@company.com'
    - name: pagerduty
      pagerduty_configs:
      - service_key: '<pagerduty-key>'
    - name: slack
      slack_configs:
      - api_url: 'https://hooks.slack.com/services/xxx/yyy/zzz'
        channel: '#alerts'
        text: '{{ .CommonAnnotations.summary }}'
EOF

OpenShift Virtualization (KubeVirt)

OpenShift Virtualization allows you to run virtual machines alongside containers on the same OCP cluster. It uses KubeVirt under the hood.

Why Run VMs on OCP?

Migrate legacy workloads that can't be containerised (Windows apps, licensed software)
Unified platform — same RBAC, networking, storage, monitoring for VMs and containers
Live migration of VMs between nodes — no downtime during node maintenance
Consolidate hypervisor + container platforms into one

Key Components

ComponentPurpose

|---|---|

**virt-api**Handles VM API requests
virt-controllerCreates and manages VirtualMachineInstance pods
virt-handlerNode-level agent — manages VMs on each node
virt-launcherPod that wraps each VM (one per VM)
CDI (Containerized Data Importer)Imports VM disk images into PVCs

Creating a Virtual Machine

bash
# Install OpenShift Virtualization operator first via OperatorHub
# Then create a HyperConverged CR to deploy all components

# Create a VM
cat <<EOF | oc apply -f -
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: rhel9-vm
  namespace: production
spec:
  running: true
  template:
    metadata:
      labels:
        kubevirt.io/vm: rhel9-vm
    spec:
      domain:
        cpu:
          cores: 2
        memory:
          guest: 4Gi
        devices:
          disks:
          - name: rootdisk
            disk:
              bus: virtio
          - name: cloudinitdisk
            disk:
              bus: virtio
          interfaces:
          - name: default
            masquerade: {}         # pod network
          - name: secondary
            bridge: {}             # Multus additional network
      networks:
      - name: default
        pod: {}
      - name: secondary
        multus:
          networkName: storage-network
      volumes:
      - name: rootdisk
        dataVolume:
          name: rhel9-dv
      - name: cloudinitdisk
        cloudInitNoCloud:
          userData: |
            #cloud-config
            user: cloud-user
            password: redhat
            chpasswd:
              expire: false
EOF

Live Migration

Live migration moves a running VM from one node to another with zero downtime — VM keeps running, memory is transferred incrementally.

bash
# Trigger live migration
cat <<EOF | oc apply -f -
apiVersion: kubevirt.io/v1
kind: VirtualMachineInstanceMigration
metadata:
  name: migrate-rhel9-vm
  namespace: production
spec:
  vmiName: rhel9-vm
EOF

# Check migration status
oc get vmim migrate-rhel9-vm -n production

# Monitor migration
oc describe vmim migrate-rhel9-vm -n production

# Live migration requirements:
# - Shared storage (RWX) — both nodes must access same PVC simultaneously
# - Network connectivity between nodes on migration network
# - CPU compatibility between source and destination node

Common live migration failure reasons:

VM uses RWO storage — cannot be mounted on two nodes simultaneously (need RWX)
CPU model mismatch between nodes (use cpu.model: host-model for compatibility)
Insufficient memory on destination node
No live migration network defined in HyperConverged config

Block vs File Storage for VMs

Storage TypeWhen to UseExamples

|---|---|---|

**Block (RWO)**Single VM, best performance, like a real hard diskAWS EBS, Azure Disk, iSCSI, FC
File (RWX)Live migration, shared access, multiple pods/VMsNFS, CephFS, Azure Files
ObjectLarge unstructured data, CDI import sourceS3, Swift
For VMs: Use block storage (RWO) for best performance
For live migration: You NEED RWX — the VM disk must be accessible from both source and destination node simultaneously
For OCP DataVolumes: CephFS (ODF) is the recommended RWX solution in OCP

Logging Stack

Loki (OCP 4.12+) — Modern Logging

bash
# Install Loki Operator via OperatorHub
# Then create LokiStack CR:
cat <<EOF | oc apply -f -
apiVersion: loki.grafana.com/v1
kind: LokiStack
metadata:
  name: logging-loki
  namespace: openshift-logging
spec:
  size: 1x.small            # 1x.extra-small, 1x.small, 1x.medium
  storage:
    schemas:
    - version: v12
      effectiveDate: '2023-10-15'
    secret:
      name: logging-loki-s3  # S3 bucket credentials
      type: s3
  storageClassName: gp3
  tenants:
    mode: openshift-logging
EOF

# Install Cluster Logging Operator
# Create ClusterLogging CR to deploy Vector collector
cat <<EOF | oc apply -f -
apiVersion: logging.openshift.io/v1
kind: ClusterLogging
metadata:
  name: instance
  namespace: openshift-logging
spec:
  managementState: Managed
  logStore:
    type: lokistack
    lokistack:
      name: logging-loki
  collection:
    type: vector           # replaces Fluentd in newer OCP
EOF

OpenShift Pipelines (Tekton)

bash
# Install via OpenShift Pipelines operator

# Key objects:
# Task        — reusable unit of work (step: build, test, push)
# TaskRun     — one execution of a Task
# Pipeline    — chain of Tasks
# PipelineRun — one execution of a Pipeline
# Workspace   — shared storage between Tasks
# Trigger     — event-based pipeline execution

# Example Pipeline
cat <<EOF | oc apply -f -
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
  name: build-and-deploy
  namespace: myproject
spec:
  params:
  - name: image-url
    type: string
  workspaces:
  - name: source
  tasks:
  - name: clone
    taskRef:
      name: git-clone
      kind: ClusterTask
    workspaces:
    - name: output
      workspace: source
    params:
    - name: url
      value: https://github.com/org/myapp

  - name: build
    taskRef:
      name: buildah         # builds OCI image using Buildah
      kind: ClusterTask
    runAfter: [clone]
    workspaces:
    - name: source
      workspace: source
    params:
    - name: IMAGE
      value: $(params.image-url)

  - name: deploy
    taskRef:
      name: openshift-client
      kind: ClusterTask
    runAfter: [build]
    params:
    - name: SCRIPT
      value: oc rollout restart deployment/myapp -n production
EOF

# Trigger via tkn CLI
tkn pipeline start build-and-deploy \
  -p image-url=image-registry.openshift-image-registry.svc:5000/myproject/myapp:latest \
  -w name=source,claimName=pipeline-pvc \
  -n myproject

# Watch logs
tkn pipelinerun logs --last -f -n myproject
Share:
Join our Community
Daily tips, job alerts, interview help — join engineers learning together
Quick Check — OpenShift (OCP)
1 / 1

What is the first step when optimizing a production system?

Up Next
🗺️
OpenShift (OCP)Roadmap
Step-by-step structured learning path from zero to expert
Also Worth Exploring
← Back to all OpenShift (OCP) modules
IntermediateRoadmap