Dell Unity XT (iSCSI)¶
Dell CSI Driver for Unity XT | CSM Operator
This guide installs the Dell CSI driver for Unity XT via the Container Storage Modules (CSM) Operator on OpenShift 4.22. It uses CSM Operator v1.12.x (CSM 1.17.x) with the Unity driver configVersion: v2.15.0.
Step 1 — Array-Side Prep (Unisphere)¶
Before touching the cluster, configure the Unity XT array:
- Configure iSCSI interfaces on both SPs (SPA + SPB) on your storage VLAN
- Create a storage pool — note the pool name/ID
- Confirm the Unisphere management IP is reachable over IPv4 from the cluster nodes (the driver is IPv4-only)
- If running jumbo frames, MTU 9000 must match end-to-end (array ports, switches, node NICs)
Collect the array serial (apm00...) and pool name — both are required below.
Step 2 — Node Prep (MachineConfigs)¶
RHCOS does not ship with an iSCSI initiator name, and Unity requires multipath. Apply all three MachineConfigs, then wait for the worker nodes to reboot.
2a. Generate iSCSI InitiatorName¶
Creates /etc/iscsi/initiatorname.iscsi if missing:
cat << 'EOF' | oc apply -f -
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
metadata:
name: 99-worker-iscsi-initiatorname
labels:
machineconfiguration.openshift.io/role: worker
spec:
config:
ignition:
version: 3.5.0
storage:
files:
- path: /usr/local/bin/gen-initiatorname.sh
mode: 0755
overwrite: true
contents:
source: data:text/plain;base64,IyEvYmluL3NoCmlmIFsgISAtZiAvZXRjL2lzY3NpL2luaXRpYXRvcm5hbWUuaXNjc2kgXTsgdGhlbgogICAgZWNobyAiSW5pdGlhdG9yTmFtZT0kKC91c3Ivc2Jpbi9pc2NzaS1pbmFtZSkiID4gL2V0Yy9pc2NzaS9pbml0aWF0b3JuYW1lLmlzY3NpCmZpCg==
systemd:
units:
- name: custom-iscsi-initiatorname.service
enabled: true
contents: |
[Unit]
Description=Generate iSCSI InitiatorName if missing
Before=iscsid.service iscsi.service
ConditionPathExists=!/etc/iscsi/initiatorname.iscsi
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/bin/gen-initiatorname.sh
[Install]
WantedBy=multi-user.target
EOF
2b. Enable iscsid¶
cat << 'EOF' | oc apply -f -
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
metadata:
name: 99-worker-iscsid-enable
labels:
machineconfiguration.openshift.io/role: worker
spec:
config:
ignition:
version: 3.5.0
systemd:
units:
- name: iscsid.service
enabled: true
EOF
2c. Multipath Configuration¶
Enables multipathd with Dell Unity defaults:
cat << 'EOF' | oc apply -f -
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
metadata:
name: 99-worker-multipath
labels:
machineconfiguration.openshift.io/role: worker
spec:
config:
ignition:
version: 3.5.0
storage:
files:
- path: /etc/multipath.conf
mode: 0644
overwrite: true
contents:
source: data:text/plain;base64,ZGVmYXVsdHMgewogICAgdXNlcl9mcmllbmRseV9uYW1lcyB5ZXMKICAgIGZpbmRfbXVsdGlwYXRocyB5ZXMKICAgIHBvbGxpbmdfaW50ZXJ2YWwgNQp9CmJsYWNrbGlzdCB7Cn0K
systemd:
units:
- name: multipathd.service
enabled: true
EOF
Wait for Rollout¶
Workers reboot serially. Wait for the MachineConfigPool to finish:
All pools should show UPDATED=True, UPDATING=False, DEGRADED=False.
Spot-Check a Worker¶
W=$(oc get nodes -l node-role.kubernetes.io/worker -o name | head -1)
oc debug $W -- chroot /host cat /etc/iscsi/initiatorname.iscsi
oc debug $W -- chroot /host systemctl is-active iscsid multipathd
Order matters
Step 2 must fully complete before deploying the driver in Step 6. If node pods CrashLoop with initiator name errors, the MachineConfig rollout was not finished before the driver was deployed.
Step 3 — Namespaces¶
cat << 'EOF' | oc apply -f -
apiVersion: v1
kind: Namespace
metadata:
name: dell-csm-operator
labels:
pod-security.kubernetes.io/enforce: privileged
pod-security.kubernetes.io/audit: privileged
pod-security.kubernetes.io/warn: privileged
---
apiVersion: v1
kind: Namespace
metadata:
name: unity
labels:
pod-security.kubernetes.io/enforce: privileged
pod-security.kubernetes.io/audit: privileged
pod-security.kubernetes.io/warn: privileged
EOF
Step 4 — Install the CSM Operator¶
cat << 'EOF' | oc apply -f -
apiVersion: operators.coreos.com/v1
kind: OperatorGroup
metadata:
name: dell-csm-operator
namespace: dell-csm-operator
spec: {}
---
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
name: dell-csm-operator-certified
namespace: dell-csm-operator
spec:
channel: stable
name: dell-csm-operator-certified
source: certified-operators
sourceNamespace: openshift-marketplace
installPlanApproval: Manual
EOF
Approve the install plan and confirm the CSV:
oc get installplan -n dell-csm-operator
oc patch installplan <name> -n dell-csm-operator --type merge -p '{"spec":{"approved":true}}'
oc get csv -n dell-csm-operator # Phase: Succeeded
oc get crd containerstoragemodules.storage.dell.com # CRD exists
Step 5 — Credentials Secret¶
Replace the array serial, Unisphere endpoint (IPv4), and password:
cat << 'EOF' > /tmp/unity-creds.yaml
storageArrayList:
- arrayId: "apm00XXXXXXXXX"
username: "admin"
password: "YourPassword"
endpoint: "https://10.0.0.10/"
skipCertificateValidation: true
isDefault: true
EOF
oc create secret generic unity-creds -n unity --from-file=config=/tmp/unity-creds.yaml
rm -f /tmp/unity-creds.yaml
Step 6 — Deploy the Driver (ContainerStorageModule CR)¶
cat << 'EOF' | oc apply -f -
apiVersion: storage.dell.com/v1
kind: ContainerStorageModule
metadata:
name: unity
namespace: unity
spec:
driver:
csiDriverType: "unity"
configVersion: v2.15.0
replicas: 2
authSecret: unity-creds
common:
image: "quay.io/dell/container-storage-modules/csi-unity:v2.15.0"
imagePullPolicy: IfNotPresent
envs:
- name: X_CSI_UNITY_ALLOW_MULTI_POD_ACCESS
value: "false"
- name: X_CSI_HEALTH_MONITOR_ENABLED
value: "false"
- name: X_CSI_UNITY_AUTOPROBE
value: "true"
- name: X_CSI_UNITY_SKIP_CERTIFICATE_VALIDATION
value: "true"
- name: CERT_SECRET_COUNT
value: "0"
controller:
envs:
- name: X_CSI_HEALTH_MONITOR_ENABLED
value: "false"
node:
envs:
- name: X_CSI_HEALTH_MONITOR_ENABLED
value: "false"
EOF
Tip
If the operator rejects configVersion, check its logs for the version it validates: oc get csm unity -n unity -o yaml. Set both configVersion and the image tag to the version the operator expects.
Step 7 — StorageClass and VolumeSnapshotClass¶
Replace arrayId and storagepool with your values from Step 1.
ArrayID Must Be Lowercase
The arrayId value in the StorageClass must be lowercase. The Unity CSI driver labels worker nodes with a lowercase ArrayID in the topology key (e.g. csi-unity.dellemc.com/apx00xxxxxxxxx-iscsi=true). If the StorageClass specifies it in uppercase (e.g. APX00XXXXXXXXX), the topology constraint will not match and PVCs will stay stuck in Pending. Kubernetes topology labels are case-sensitive.
cat << 'EOF' | oc apply -f -
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: unity-iscsi
provisioner: csi-unity.dellemc.com
reclaimPolicy: Delete
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer
parameters:
protocol: iSCSI
arrayId: "apm00xxxxxxxxx"
storagepool: "pool_1"
thinProvisioned: "true"
isDataReductionEnabled: "false"
csi.storage.k8s.io/fstype: "ext4"
---
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotClass
metadata:
name: unity-snapclass
driver: csi-unity.dellemc.com
deletionPolicy: Delete
EOF
Step 8 — Verify¶
oc get csm -n unity unity -o wide # State: Succeeded
oc get pods -n unity # controller (x2) + node pods Running
oc get csinode -o wide # each worker lists csi-unity.dellemc.com
oc get sc unity-iscsi
Step 9 — Smoke Test¶
cat << 'EOF' | oc apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: unity-test
namespace: unity
spec:
accessModes: [ReadWriteOnce]
storageClassName: unity-iscsi
resources:
requests:
storage: 5Gi
---
apiVersion: v1
kind: Pod
metadata:
name: unity-test-pod
namespace: unity
spec:
containers:
- name: app
image: registry.redhat.io/ubi9/ubi-minimal
command: ["sh", "-c", "echo hello > /data/test && sleep 3600"]
volumeMounts:
- name: vol
mountPath: /data
volumes:
- name: vol
persistentVolumeClaim:
claimName: unity-test
EOF
Confirm the PVC binds and the pod can write:
oc get pvc -n unity unity-test -w # -> Bound
oc exec -n unity unity-test-pod -- cat /data/test # -> hello
Clean up:
Troubleshooting¶
| Symptom | Cause | Fix |
|---|---|---|
| Node pods CrashLoop with initiator errors | MachineConfig not finished before driver deployed | Wait for oc get mcp worker to show UPDATED=True, then delete the node pods to restart them |
| PVC stuck in Pending | Wrong arrayId or storagepool in StorageClass |
Check controller pod logs: oc logs -n unity -l app=unity-controller --tail=50 |
| PVC stuck in Pending with topology mismatch | arrayId in StorageClass is uppercase but the driver labels nodes with lowercase |
Change arrayId in the StorageClass to lowercase to match the node topology labels (e.g. apm00xxxxxxxxx not APM00XXXXXXXXX) |
configVersion rejected |
Operator/driver version mismatch | Check oc get csm unity -n unity -o yaml for the expected version |
| iSCSI login failures | Array iSCSI interfaces not on the same VLAN as nodes | Verify SPA/SPB iSCSI IPs are reachable from worker nodes |
PVC stuck in Pending, attach failures, or missing csi-unity.dellemc.com topology labels after a network outage |
Stale Unisphere API sessions or iSCSI logins in the driver pods | Restore connectivity, then restart all Unity driver pods (see below) |
Network interruption — restart driver pods¶
After a network outage between the cluster and the Unity array (Unisphere management or the iSCSI data path), the CSI controller and node pods can keep stale sessions. Provisioning and attach then fail until the pods restart and re-login.
Confirm the array is reachable again from a worker, then delete every pod in the unity namespace. The CSM operator recreates the controller Deployment and node DaemonSet:
Wait until both controller replicas and the node pods are Running:
Confirm each worker still lists the Unity CSI driver: