This note came from one of those storage tasks that is easy to get wrong if you try to reconstruct it from memory later.

The goal was not to build a new Ceph cluster from scratch. The goal was to connect a Kubernetes cluster to an existing Ceph deployment and expose it through Rook as external storage for workloads.

1. Collect the Ceph Cluster Details

Start on a Ceph node and capture the monitor map and the FSID:

1
2
ceph mon dump
ceph fsid

What I cared about here was:

  • the Ceph FSID
  • the monitor endpoints
  • the pool names that Kubernetes would use later for RBD and CephFS

The original note contained real monitor names, IP addresses, and secrets, so those are omitted here.

2. Generate the External Cluster Resource Exports

Rook ships a helper script that can generate the environment values needed to import an external Ceph cluster.

1
2
3
4
5
6
7
8
curl -s https://raw.githubusercontent.com/rook/rook/release-1.16/deploy/examples/create-external-cluster-resources.py \
  > create-external-cluster-resources.py

python3 create-external-cluster-resources.py \
  --skip-monitoring-endpoint \
  --rbd-data-pool-name <rbd-pool-name> \
  --namespace rook-ceph-external \
  --format bash

That script prints a set of exported variables for:

  • the namespace
  • the Ceph FSID
  • the monitor endpoints
  • the RBD and CephFS pool names
  • the provisioner and node secrets

Do not paste those secrets into a public post. Treat that output like credentials.

3. Import the External Ceph Configuration into Kubernetes

On a machine that has working kubectl access to the target cluster:

1
2
3
4
5
curl -s https://raw.githubusercontent.com/rook/rook/release-1.16/deploy/examples/import-external-cluster.sh \
  > import-external-cluster.sh

chmod +x ./import-external-cluster.sh
./import-external-cluster.sh

If the import works, you should see the external namespace, monitor config map, secrets, and storage classes get created.

That part is important because it tells you the target cluster now has the credentials and metadata it needs to talk to the existing Ceph backend.

4. Install the Rook Operator and External Cluster Chart

Once the import step is done, install the operator and the external cluster chart:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
export operatorNamespace="rook-ceph"
export clusterNamespace="rook-ceph-external"

curl -s https://raw.githubusercontent.com/rook/rook/release-1.16/deploy/charts/rook-ceph/values.yaml > values.yaml
curl -s https://raw.githubusercontent.com/rook/rook/release-1.16/deploy/charts/rook-ceph-cluster/values-external.yaml > values-external.yaml

helm repo add rook-release https://charts.rook.io/release
helm repo update

helm install --create-namespace --namespace "$operatorNamespace" \
  rook-ceph rook-release/rook-ceph -f values.yaml

helm install --create-namespace --namespace "$clusterNamespace" \
  rook-ceph-cluster rook-release/rook-ceph-cluster \
  --set operatorNamespace="$operatorNamespace" \
  -f values-external.yaml

At this point I watched both the operator and the CephCluster resource:

1
2
kubectl --namespace rook-ceph get pods -l "app=rook-ceph-operator" -w
kubectl --namespace rook-ceph-external get cephcluster -w

5. Verify the External Cluster Connection

The state I wanted to reach was:

1
2
PHASE       MESSAGE
Connected   Cluster connected successfully

And then:

1
2
kubectl -n rook-ceph-external get cephcluster
kubectl get storageclass

In the original work log, the final result exposed both ceph-rbd and cephfs.

6. Set the Default StorageClass if Needed

If this Ceph-backed RBD class should become the cluster default, patch it explicitly:

1
2
kubectl patch storageclass ceph-rbd \
  -p '{"metadata":{"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

I like making this explicit instead of assuming the right default will be chosen automatically.

What This Guide Is Really About

The hard part here is not the Helm command. It is keeping the flow straight:

  1. collect the external Ceph details
  2. generate the importable resources
  3. import them into Kubernetes
  4. install the Rook operator and external cluster chart
  5. verify the connection and the resulting storage classes

That is the part worth writing down.