Skip to main content

Deploying Container Observability shared services

Container Observability (CO) deployment installs a set of northbound UI and analytics services together with southbound data collectors to give you end‑to‑end visibility into Kubernetes clusters and containerized workloads. Using Helm‑based charts, you deploy shared services such as Kafka, VictoriaMetrics, and metrics APIs, then layer on the CO frontend, backend, and south components that collect metrics, logs, traces, and events from your clusters. This architecture separates control‑plane functions from data‑plane collection so you can scale ingest independently, connect to cloud and on‑prem Kubernetes environments, and provide SREs and platform teams with a unified, topology‑aware view of application health and performance across hybrid infrastructure.

Prerequisites

Before you begin the installation, ensure that your environment meets the following basic requirements:

  • You have Helm installed and configured to access your Kubernetes cluster.

  • You have added the Virtana Helm repository to your Helm configuration.

  • You know the storage class names to use for Kafka and VictoriaMetrics.

  • You have Docker registry credentials if you need to pull images from a private registry.

Create the Shared Services values file

Create a new file named app-mon-shared-services-values.yaml in your terminal or default editor. This file defines the configuration for:

  • Global deployment parameters

  • Shared infrastructure services (co-config-events-service-shared)

  • Metrics service (cp-metrics-service)

  • VictoriaMetrics cluster (victoria-metrics-cluster)

Update the placeholder values according to your environment.

Deployment-wide settings

The global section sets values that apply across all shared-services components, including the Global View endpoint and the platform shared services that CO uses.

global:
  environment: "app"
  machine_type: "small" 
  secret_source: "valuesfile" 
  dockerRegistryCredentials: 
    DOCKER_SERVER: "https://index.docker.io/v2/"
    DOCKER_USERNAME: "username"
    DOCKER_PASSWORD: "password"

  controlplane:
    endpoint: <GV-HOSTNAME>
  envoy:
    enabled: false
  platform_shared_services:
    namespace: platform-shared-services
    cp_metric:
      service:
        enabled: true
    kafka:
      service:
        enabled: true
    configevent:
      service:
        enabled: true
    victoriametrics:
      service:
        enabled: true
    cassandra:
      service:
        enabled: true
    logs:
      service:
        enabled: true
    logs_data_receiver:
      service:
        enabled: true

The following table describes each field of above YAML file:

Table 37.

Field

Description

Default value

global.environment

Set this to identify the deployment environment, for example "app", "dev", or "prod".

"app"

global.machine_type

Controls resource sizing presets. Supported values: "small", "medium", "large".

"small"

global.secret_source

Docker credentials are provided directly in values file.

"valuesfile"

global.dockerRegistryCredentials

Credentials to pull container images from a Docker registry.

-

DOCKER_SERVER

Registry URL.

"https://index.docker.io/v2/"

DOCKER_USERNAME

Registry username.

"username"

DOCKER_PASSWORD

Registry password.

"password"

global.controlplane.endpoint

The Global View hostname. Enter the GLOBAL_VIEW_HOSTNAME value.

<GV-HOSTNAME>

global.envoy.enabled

Enables or disables Envoy Gateway routing across the shared services deployment.

false

global.platform_shared_services.namespace

The namespace of the platform shared services. Replace the sample value with your shared services namespace.

platform-shared-services

global.platform_shared_services.<service>.service.enabled

Enables each platform shared service. &lt;service&gt; is one of cp_metric, kafka, configevent, victoriametrics, cassandra, logs, or logs_data_receiver.

true



Shared infrastructure services configuration

Configure resource allocations, persistence, and scaling parameters for the core shared infrastructure components: Cassandra Shared, Platform Kafka Service, and Container Observability Configuration &amp; Events Service.

Add the following configuration block in your shared services values file:

cassandra-shared:
  replicaCount: 6
  persistence:
    enabled: true
    storageClass: ""  
    size: 100Gi
  resources:
    requests:
      cpu: 2
      memory: 16Gi
    limits:
      cpu: 2
      memory: 16Gi
  cassandra:
    heap_maxsize: "12G"
    heap_newsize: "2400M"

platform-kafka-service:
  controller:
    replicaCount: 3
    persistence:
      size: 50Gi
    resources:
      requests:
        cpu: 200m
        memory: 2Gi
      limits:
        cpu: 1
        memory: 2Gi
    kafka:
      listener:
        type: loadbalancer

co-config-events-service-shared:
  solr:
    resources:
      requests:
        cpu: 500m
        memory: 2Gi
      limits:
        cpu: 2
        memory: 4Gi
    persistence:
      size: 50Gi
    zookeeper:
      persistence:
        size: 8Gi
      resources:
        requests:
          cpu: 250m
          memory: 512Mi
        limits:
          cpu: 500m
          memory: 2Gi

The following table describes each field of the above YAML file:

Field

Description

Default value

cassandra-shared.replicaCount

Number of Cassandra cluster nodes/replicas to deploy.

6

cassandra-shared.persistence.enabled

Enables persistent storage for Cassandra.

true

cassandra-shared.persistence.storageClass

Kubernetes storage class name. Leave empty "" to use the cluster's default storage class.

""

cassandra-shared.persistence.size

Disk storage capacity allocated per Cassandra node.

100Gi

cassandra-shared.resources.requests

Minimum CPU and memory guaranteed for each Cassandra pod.

cpu: 2, memory: 16Gi

cassandra-shared.resources.limits

Maximum CPU and memory limit for each Cassandra pod.

cpu: 2, memory: 16Gi

cassandra-shared.cassandra.heap_maxsize

Maximum JVM heap size for Cassandra.

"12G"

cassandra-shared.cassandra.heap_newsize

JVM young generation heap size for Cassandra.

"2400M"

platform-kafka-service.controller.replicaCount

Number of Kafka controller replicas.

3

platform-kafka-service.controller.persistence.size

Persistent disk storage allocated for each Kafka broker/controller.

50Gi

platform-kafka-service.controller.resources.requests

Minimum compute resources requested by Kafka controller pods.

cpu: 200m, memory: 2Gi

platform-kafka-service.controller.resources.limits

Maximum compute resource limits for Kafka controller pods.

cpu: 1, memory: 2Gi

platform-kafka-service.controller.kafka.listener.type

Service exposure type for Kafka listener.

loadbalancer

co-config-events-service-shared.solr.resources.requests

Minimum compute resources allocated to Solr pods.

cpu: 500m, memory: 2Gi

co-config-events-service-shared.solr.resources.limits

Maximum compute resource limits for Solr pods.

cpu: 2, memory: 4Gi

co-config-events-service-shared.solr.persistence.size

Persistent volume size allocated for Solr data storage.

50Gi

co-config-events-service-shared.solr.zookeeper.persistence.size

Persistent disk storage size for Solr's ZooKeeper ensemble.

8Gi

co-config-events-service-shared.solr.zookeeper.resources.requests

Minimum compute resources requested by ZooKeeper pods.

cpu: 250m, memory: 512Mi

co-config-events-service-shared.solr.zookeeper.resources.limits

Maximum compute resource limits for ZooKeeper pods.

cpu: 500m, memory: 2Gi

Metrics service parameters

This section configures the metrics service behavior (Kafka listener concurrency) and auto-scaling. It also defines a shared nodeSelector anchor you can reuse.

cp-metrics-service:
  global:
    nodeSelector: &nodeSelector {}
  env:
    KAFKA_LISTENER_CONCURRENCY: "2"
  horizontalPodAutoscaler:
    enabled: true
    maxReplicas: 5
    minReplicas: 2

The following table describes each field of above YAML file:

Table 38.

Field

Decription

Default value

cp-metrics-service.global.nodeSelector

Node selection rules for the metrics service.

&nodeSelector { }

cp-metrics-service.env.KAFKA_LISTENER_CONCURRENCY

Controls how many concurrent Kafka listener threads the service uses.

"2"

cp-metrics-service.horizontalPodAutoscaler.enabled

Enables/disables Horizontal Pod Auto-scaling (HPA) for the metrics service.

true/false

cp-metrics-service.horizontalPodAutoscaler.minReplicas

Minimum number of replicas when auto-scaling is enabled.

5

cp-metrics-service.horizontalPodAutoscaler.maxReplicas

Maximum number of replicas when auto-scaling is enabled.

2



VictoriaMetrics cluster parameters

This section configures VictoriaMetrics cluster following components:

  • vmstorage for durable time-series storage

  • vminsert for ingest/write path

  • vmselect for query/read path

Each component supports scheduling controls and autoscaling where applicable.

victoria-metrics-cluster:
  vmstorage:
    replicaCount: 4
    retentionPeriod: 1
    persistentVolume:
      storageClassName: ""
      size: 100Gi
    resources:
      limits:
        cpu: 500m
        memory: 1Gi
      requests:
        cpu: 500m
        memory: 1Gi
    nodeSelector: {}
    tolerations: []
  vmselect:
    horizontalPodAutoscaler:
      minReplicas: 2
      maxReplicas: 10
    nodeSelector: {}
    tolerations: []
  vminsert:
    horizontalPodAutoscaler:
      minReplicas: 2
      maxReplicas: 10
    nodeSelector: {}
    tolerations: []
platform-logs-service:
  loki:
    loki:
      limits_config:
        retention_period: 168h
    minio:
      persistence:
        enabled: true
        size: 250Gi

The following table describes each field of above YAML file:

Table 39.

Field

Description

Default value

victoria-metrics-cluster.vmstorage.replicaCount

Number of vmstorage replicas.

4

victoria-metrics-cluster.vmstorage.retentionPeriod

Data retention window.

Supported values 1w, 1d, number without measurement means month, for example 2 = 2month

victoria-metrics-cluster.vmstorage.persistentVolume.storageClassName

StorageClass for VictoriaMetrics PVCs.

" "

victoria-metrics-cluster.vmstorage.persistentVolume.size

PVC size per vmstorage replica.

100 Gib

victoria-metrics-cluster.vmstorage.resources.requests.* / limits.*

Requests reserve capacity and limits cap usage. Ensure resources match expected ingest and query load. Storage nodes often need stable CPU and memory.

-

victoria-metrics-cluster.vmstorage.nodeSelector and tolerations

Controls which nodes vmstorage can run on.

-

victoria-metrics-cluster.vmselect.horizontalPodAutoscaler.minReplicas

Minimum vmselect replicas.

2

victoria-metrics-cluster.vmselect.horizontalPodAutoscaler.maxReplicas

Maximum vmselect replicas.

10

victoria-metrics-cluster.vminsert.horizontalPodAutoscaler.minReplicas

Minimum vminsert replicas.

2

victoria-metrics-cluster.vminsert.horizontalPodAutoscaler.maxReplicas

Maximum vminsert replicas.

10



Loki Migration input file

To migrate existing log data from an earlier Loki deployment to the Platform Logs Service, the log reader requires explicit mapping between your tenant IDs and their corresponding Kubernetes namespaces. Configuring this file ensures that the platform-logs-service can locate, read, and attribute historical log streams correctly across tenants and environments during and after the migration.

Create a new file named loki-migration.yaml and add the following configuration, and replace the placeholder values with your actual environment details:

platform-logs-service:
  log_reader:
    loki:
      migration:
        tenants:
          # Env: <ENVIRONMENT_NAME> # Tenant alias: <TENANT_ALIAS>
          <TENANT_UUID>: 
            namespaces:
              self-monitoring: <SELF_MONITORING_NAMESPACE> 
              co-dev-01: <CO_NAMESPACE>                   

The following table describes each field of the above YAML file:

Field

Description

platform-logs-service.log_reader.loki.migration.tenants

Root mapping key for tenant-specific migration parameters.

<TENANT_UUID>

The unique identifier (UUID) for your Virtana tenant. Replace with your actual Tenant ID (e.g., 00000000-0000-0000-0000-000000000000)

namespaces.<source_namespace>

Maps the source/internal monitoring namespace (e.g., self-monitoring) to the target destination namespace (e.g., virtana-self-monitoring). Repeat for each monitored namespace associated with the tenant.

Deploy shared services

Deploy the CO shared services by using the virtana-co-controller Helm chart and the app-mon-shared-services-values.yaml file that you created. You can deploy the chart by using the Helm CLI, Argo CD, or Terraform.

Check the latest chart version

Update the Helm repository in your terminal and list available versions of the controller chart:

helm repo update
helm search repo virtana-repo/virtana-co-controller

To list all available chart versions instead of only the latest version, add the --versions flag to the helm search repo command. Choose the deployment tag for your release that enables the CO shared-services components, depending on the virtana-co-controller chart version that you deploy. Starting with release 2026.6.1, the tag changed from tags.oc_shared_services to tags.platform. The chart version is the same as the release number. Use --set tags.platform=true (with --skip-crds) in place of --set tags.oc_shared_services=true in the following deploy commands. Update any deployment that still uses the previous tag. For example, chart version 2026.6.1 belongs to release 2026.6.1.

The following table lists the deployment tag for each release:

Release (chart version)

Deployment tag

2026.6.1 and later

tags.platform=true

2026.4.1 and earlier

tags.oc_shared_services=true

This installs shared services into the oc-shared-services namespace and enables the shared-services tag.

The Helm CLI method installs the CO shared services into the oc-shared-services namespace and enables the shared-services components with the deployment tag for your release. Run the command that matches the chart version that you deploy.

For release 2026.6.1 and later, run the following command. Replace <LATEST_VERSION> with the latest chart version that the helm search repo command returns:

helm upgrade --install opscruise-shared-services virtana-repo/virtana-co-controller \
  --namespace oc-shared-services --create-namespace \
  --set tags.platform=true -f app-mon-shared-services-values.yaml \
  --skip-crds \
  --version <LATEST_VERSION>

For release 2026.4.3 and earlier, run the following command. Replace <CHART_VERSION> with the chart version that you deploy, for example, 2026.4.3:

helm upgrade --install opscruise-shared-services virtana-repo/virtana-co-controller \
  --namespace oc-shared-services --create-namespace \
  --set tags.oc_shared_services=true -f app-mon-shared-services-values.yaml \
  --version <LATEST_VERSION>

This method deploys the same Helm chart via Argo CD GitOps and keeps it continuously reconciled.

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: opscruise-shared-services
  namespace: argocd
  finalizers:
    - resources-finalizer.argocd.argoproj.io
spec:
  destination:
    server: https://kubernetes.default.svc
    namespace: oc-shared-services
  source:
    chart: virtana-co-controller
    repoURL: https://virtana.gitlab.io/helm-charts
    targetRevision: <LATEST_VERSION> 
    helm:
      releaseName: opscruise-shared-services
      parameters:
        - name: "tags.oc_shared_services"
          value: "true"
      values: |
        <contents of app-mon-shared-services-values.yaml>
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
      - SkipDryRunOnMissingResource=true
Table 40.

Field

Description

Default value

metadata.name

Argo CD application name.

opscruise-shared-services

spec.destination.server

Target cluster API server.

https://kubernetes.default.svc

spec.destination.namespace

Target namespace.

oc-shared-services

spec.source.chart / repoURL / targetRevision

Chart coordinates and version. Set targetRevision to the chart version that you deploy.

-

spec.source.helm.releaseName

Helm release name that Argo CD will manage.

-

spec.source.helm.parameters

Sets the deployment tag that enables the CO shared-services components.

For release 2026.4.1 and earlier, set:

- name: "tags.oc_shared_services"

value: "true"

For release 2026.6.1 and later,set :

- name: "tags.platform"

value: "true"

spec.source.helm.values

Inline values.

Paste the full contents of app-mon-shared-services-values.yaml

syncPolicy.automated.prune

Removes resources not in the desired state.

true

syncPolicy.automated.selfHeal

Re-applies drifted resources automatically.

true

syncOptions.CreateNamespace

Creates namespace if missing.

true

syncOptions.SkipDryRunOnMissingResource

Skips the dry run for resources whose custom resource definitions (CRDs) don't exist in the cluster yet. Use this option for release 2026.6.1 and later.

true



This method installs the chart using Terraform’s Helm provider and allows you to inject credentials via variables.

resource "helm_release" "opscruise_shared_services" {
  name             = "opscruise-shared-services"
  create_namespace = true
  namespace        = "oc-shared-services"
  chart            = "virtana-co-controller"
  repository       = "https://virtana.gitlab.io/helm-charts"
  version          = var.helm_version
  timeout          = 600
  wait             = true
  skip_crds        = true

  values = [
    templatefile("${path.module}/../values/app-mon-shared-services-values.yaml", {
      docker_password = var.docker_password
      docker_username = var.docker_username
    })
  ]

  set {
    name  = "tags.oc_shared_services"
    value = "true"
  }
}
Table 41.

Field

Description

name = "opscruise-shared-services"

Helm release name.

create_namespace = true

Boolean flag to create the target namespace.

namespace = "oc-shared-services"

Kubernetes namespace where the release will be installed.

chart = "virtana-co-controller"

Helm chart name.

repository = "https://virtana.gitlab.io/helm-charts"

Helm chart repository URL.

version = var.helm_version

Chart version to deploy.

timeout = 600

Deployment timeout in seconds.

wait = true

Wait behavior flag.

skip_crds = true

Skips the installation of the custom resource definitions (CRDs) that are packaged in the chart. Use this setting for release 2026.6.1 and later.

values = [templatefile(...)]

Renders a values YAML from a template.

set { name = "tags.oc_shared_services" ... }

Enables the shared services tag. For release 2026.4.1 and earlier, use tags.oc_shared_services.

For release 2026.6.1 and later, use tags.platform.



Shared service deployment optional settings

Use these optional settings when your environment requires a private image registry or when you deploy shared services on Red Hat OpenShift with namespace-specific security constraints.

Use a private image registry (optional)

You can add this as an optional setting in your terminal if your cluster cannot pull images from the default public registry locations.

Add the following command to app-mon-shared-services-values.yaml and replace the example.io with your registry:

cp-metrics-service:
  image:
    registry: example.io

oc-shared-kafka:
  image:
    registry: example.io
    repository: kafka

victoria-metrics-cluster:
  vminsert:
    image:
      repository: example.io/vminsert
  vmselect:
    image:
      repository: example.io/vmselect
  vmstorage:
    image:
      repository: example.io/vmstorage
Table 42.

Field

Description

Default value

cp-metrics-service.image.registry

Sets the container image registry host for the cp-metrics-service image.

example.io

oc-shared-kafka.image.registry

Defines the registry host from which the Kafka image is pulled.

example.io

oc-shared-kafka.image.repository

Defines the image repository within the registry.

kafka

victoria-metrics-cluster.vminsert.image.repository

Sets the full image repository path for the vminsert component.

example.io/vminsert

victoria-metrics-cluster.vmselect.image.repository

Sets the full repository path for the vmselect image.

example.io/vmselect

victoria-metrics-cluster.vmstorage.image.repository

Sets the full repository path for the vmstorage image.

example.io/vmstorage



Deploy shared services on OpenShift

On Red Hat OpenShift, set the security contexts for the shared-services components so that they run within the UID, GID, and fsGroup range that OpenShift allows for the namespace. Create a file named app-mon-shared-services-scc.yaml with the security contexts, and add it to the Helm deploy command.

First, find the allowed UID, GID, and supplemental-group range for the namespace:

oc describe ns oc-shared-services | egrep "uid-range|supplemental-groups"

The runAsUser, runAsGroup, and fsGroup values you set must fall within the range that this command reports. Set the security contexts in app-mon-shared-services-scc.yaml:

cassandra-shared:
  securityContext:
    pod:
      runAsUser: <user_id>
      runAsGroup: <group_id>
      fsGroup: <fsgroup_id>

platform-kafka-service:
  podSecurityContext:
    fsGroup: <fsgroup_id>
  securityContext:
    runAsUser: <user_id>
    runAsGroup: <group_id>
  strimzi-kafka-operator:
    podSecurityContext:
      fsGroup: <fsgroup_id>
    securityContext:
      runAsGroup: <group_id>
      runAsUser: <user_id>

co-config-events-service-shared:
    podSecurityContext:
      fsGroup: <fsgroup_id>
    securityContext:
      runAsGroup: <group_id>
      runAsUser: <user_id>
    zookeeper:
      podSecurityContext:
        fsGroup: <fsgroup_id>
      securityContext:
        runAsGroup: <group_id>
        runAsUser: <user_id>

The Helm chart overrides assign a Kubernetes security context to each platform service and its sub-components. The same set of parameters recurs across the services, applied at either the pod level or the container level. The following table describes each parameter, the level at which it applies, and the value it takes.

Table 43.

Parameter

Description

podSecurityContext

Defines the security settings that apply to every container in the pod. These settings also govern the group ownership of mounted volumes, so pod-level fields such as fsGroup belong here.

securityContext

Defines the security settings for a single container. When a chart lists securityContext alongside a separate podSecurityContext, the values set here apply only to the container and override the equivalent pod-level settings.

securityContext.pod

Applies the security settings at the pod level through the pod sub-key. The cassandra-shared chart uses this nesting to express the same intent as podSecurityContext in the other charts.

runAsUser

Sets the numeric user ID (UID) that the container process runs as. This value overrides any user defined in the container image and is the primary control for running a service as a non-root user.

runAsGroup

Sets the numeric primary group ID (GID) for the container process. Files that the process creates are owned by this group.

fsGroup

Sets a supplemental group ID that Kubernetes applies to the pod's mounted volumes. Kubernetes changes the group ownership of the files in these volumes to this GID and adds the GID to each container's supplementary groups, so the process can read and write persistent data. This field is valid only at the pod level.



Note

Replace the placeholders <user_id>, <group_id>, and <fsgroup_id> with concrete integers before you deploy. In most deployments, you set the same non-root values across all services to keep permissions consistent on shared persistent volumes.

Note

Add the -f app-mon-shared-services-scc.yaml \ flag to the Helm deploy commands for OpenShift-based deployments.