Skip to content

Cinder Operator ​

The Cinder operator runs the OpenStack block-storage service: the API under uWSGI, the scheduler, one cinder-volume process per attached CinderBackend, and cinder-backup while a CinderBackupBackend is attached. All three kinds live in cinder.openstack.c5c3.io/v1alpha1. Cinder describes the service, and the two satellites describe storage: a volume backend and the one backup driver. The volume backend and the backup backend each ship the NFS and the RBD drivers.

Storage attaches out-of-band, the inverted attachment GlanceBackend established: the backend points at the Cinder, so adding or removing storage never edits the Cinder CR.

Processes ​

Four long-running processes carry the service. The rendered [DEFAULT] host is the CR's name, and the three processes that hold a row in cinder's service registry key that row on an identity derived from it.

ProcessWorkloadIdentityWhat it does
uWSGI on cinder.wsgi.apithe {name} Deployment{name} (registers no row)The block-storage API on port 8776
cinder-schedulerthe {name}-scheduler Deployment{name}-schedulerPicks a backend for every volume request the API accepts
cinder-volumeone {name}-volume-{backend} Deployment per attached CinderBackend{name}@{backend}Creates and serves the volumes of its one backend
cinder-backupthe {name}-backup Deployment{name}-backupWrites and restores volume backups

A volume backend's identity is what the volumes it holds are keyed by, so it is derived from the CR and never from a pod: a Deployment roll, a rescheduled pod and a replaced node all keep it. The three non-API processes serve no HTTP port. Their readiness probe is cinder-amqp-ready, which reports whether a process of the container holds a socket established to the broker port (see Container Images).

The figure shows the four processes with what each mounts. A cinder-volume holds the export of its one backend, and the backup pod holds every volume export beside its own target.

The Cinder processes with their NFS mounts. One Cinder resource runs four processes: the API {cinder} on port 8776, the scheduler {cinder}-scheduler, one cinder-volume Deployment {cinder}-volume-{backend} per CinderBackend, and the backup Deployment {cinder}-backup, which exists only while a CinderBackupBackend is attached. All four hold a connection to RabbitMQ and to MariaDB: the API hands a volume request to the scheduler over the bus, the scheduler hands it to a cinder-volume, and backup jobs travel the same way. Each cinder-volume mounts the NFS export of its own backend at /var/lib/cinder/mnt/{md5}, where {md5} is the MD5 of server:path. The backup pod mounts every volume export at that same path and its backup target at /var/lib/cinder/backup_mount/{md5}. Every export in a Cinder pod is an inline CSI volume of the driver nfs.csi.k8s.io. On a hypervisor node nova-compute mounts the export itself when a volume attaches, at /var/lib/nova/mnt/{md5}, and mount propagation carries that mount to QEMU on the host. Locks are files inside each pod, and Memcached holds the token cache only.

Design decisions ​

The decision record lives in meta issue #979. These are the entries this operator implements, together with the choices the CRD carries.

  • The message bus is required. spec.messaging has no optional form: the API hands every volume request to the scheduler over the bus, the scheduler hands it to a cinder-volume, and backup jobs travel the same way. The URL reaches all four processes and every migration Job as the OS_DEFAULT__TRANSPORT_URL environment override sourced from the derived {name}-transport-url Secret, so the broker password stays out of the rendered configuration. Volume lifecycle notifications are dropped at the source ([oslo_messaging_notifications] driver = noop), because nothing in this deployment consumes them.
  • No default backend. A volume type selects its backend by name, so the backends a Cinder serves are peers, and an empty set is a valid state rather than a violated invariant: BackendsReady is then True under the reason NoBackends. That is the one place the satellite shape departs from GlanceBackend, which elects exactly one default store.
  • One immutable Secret per backend. Each backend renders into its own content-hashed {name}-backend-{backend}-<hash> Secret, which only that backend's cinder-volume Deployment mounts, so attaching a second backend leaves the first one's pods untouched.
  • Inline CSI volumes for every share. A backend's export is mounted through an inline nfs.csi.k8s.io volume at /var/lib/cinder/mnt/<md5 of server:path>, the path os-brick's remotefs driver derives and cinder resolves every volume's provider location to. No PersistentVolume is bound and no cluster-scoped RBAC is needed, and a detaching backend leaves nothing to reclaim. The kind stack has to enable the driver's inline mode, which the CI wiring of #988 owns.
  • Detaching a backend runs a Job. A deleted CinderBackend is held by the cinder.openstack.c5c3.io/service-remove finalizer until its volume service is stopped and a {name}-{backend}-service-remove Job has run cinder-manage service remove cinder-volume {name}@{backend} against the database. Exit code 2 ("host not found") counts as success: a backend whose cinder-volume never registered has no row to remove and must still detach.
  • The privsep posture is unprivileged (decision D3). Both privsep contexts, [cinder_sys_admin] and [privsep_osbrick], are rendered with an empty capabilities value, because the pod's security context grants none, and nas_secure_file_operations = true is written explicitly so the driver runs its file operations as the service user instead of through a root helper the image has no sudoers entry for.
  • Configuration reaches the processes as directories. Every process is launched with --config-dir /etc/cinder/cinder.conf.d, which holds a file named cinder.conf, plus the directories that carry its own overlay: the scheduler reads scheduler.conf.d, a volume service reads backends.conf.d and volume.conf.d, the backup service reads backup.conf.d. oslo.config reads every file in a directory, so the split is what keeps one process from registering under another's identity.
  • A release bump rolls the processes in pipeline order: scheduler, volume, backup, then API. After the contract phase the three non-API Deployments roll once more, because the cinder.c5c3.io/installed-release pod annotation changes with status.installedRelease. Each of them caches the RPC version its peers announced at startup, and that cache pins the wire format for the life of the process.

Owned resources ​

The figure under Owned Resources of the Keystone operator draws the baseline this list follows: serving objects, config and Secrets, Jobs and CronJobs.

For a Cinder named {name}, with {backend} and {backupBackend} the names of the attached satellites:

ResourceNamePurpose
Deployment{name}The API pods, uWSGI on port 8776
Service{name}ClusterIP in front of the API pods on port 8776
PodDisruptionBudget{name}minAvailable: 1 above a lower replica bound of one, maxUnavailable: 1 at one (the bound is the HPA's minReplicas while spec.autoscaling is set); selects the API component and excludes Job pods
HorizontalPodAutoscaler{name}Only while spec.autoscaling is set; the API is the only autoscaled Deployment
NetworkPolicy{name}Only while spec.networkPolicy is set; one policy covers every workload and the Job pods
HTTPRoute{name}Only while spec.gateway is set
Deployment{name}-schedulercinder-scheduler
Deployment{name}-volume-{backend}The cinder-volume of one attached backend
Deployment{name}-backupcinder-backup, only while a backup backend is projected
ConfigMap{name}-config-<hash>Immutable, content-addressed cinder.conf and scheduler.conf, plus logging.ini and policy.yaml when applicable; 3 historical retained
Secret{name}-backend-{backend}-<hash>Immutable, content-addressed backend.conf, shares and volume.conf of one backend; 3 historical retained
Secret{name}-backup-{backupBackend}-<hash>Immutable, content-addressed backup.conf; 3 historical retained
Secret{name}-db-connectionThe derived pymysql DSN, consumed through OS_DATABASE__CONNECTION
Secret{name}-transport-urlThe derived rabbit:// URL, consumed through OS_DEFAULT__TRANSPORT_URL
Job{name}-db-synccinder-manage db sync
Job{name}-db-expand, {name}-db-migrate, {name}-db-contractThe three release-upgrade phases
CronJob{name}-db-purgeThe recurring cinder-manage db purge
Job{name}-{backend}-service-removeUnregisters one detaching backend's volume service
MariaDB Database / User / Grant{name}Managed mode only (spec.database.clusterRef); a brownfield database is left alone

Reference pages ​