From fc37e939e3281031e3ebaccb0994463f5ce5d4d5 Mon Sep 17 00:00:00 2001 From: Travis Nielsen Date: Fri, 31 Oct 2025 16:31:19 -0600 Subject: [PATCH 1/2] docs: example of application migration between clusters Applications can be migrated between clusters that are connecting to the same external Ceph cluster. This is done with a static PV that can be mounted by the application across the clusters. Signed-off-by: Travis Nielsen (cherry picked from commit dba69aab0a9f1d4c62f35062094afbd25dd5e773) --- .../Block-Storage-RBD/.pages | 2 + .../Block-Storage-RBD/app-migration.md | 90 ++++++++++++++++++ .../migration/app-migration.png | Bin 0 -> 48181 bytes deploy/examples/csi/rbd/pvc-static.yaml | 41 ++++++++ 4 files changed, 133 insertions(+) create mode 100644 Documentation/Storage-Configuration/Block-Storage-RBD/app-migration.md create mode 100644 Documentation/Storage-Configuration/Block-Storage-RBD/migration/app-migration.png create mode 100644 deploy/examples/csi/rbd/pvc-static.yaml diff --git a/Documentation/Storage-Configuration/Block-Storage-RBD/.pages b/Documentation/Storage-Configuration/Block-Storage-RBD/.pages index 8edb39c25..3174ebe69 100644 --- a/Documentation/Storage-Configuration/Block-Storage-RBD/.pages +++ b/Documentation/Storage-Configuration/Block-Storage-RBD/.pages @@ -2,4 +2,6 @@ title: Block Storage (RBD) nav: - block-storage.md - rbd-mirroring.md + - rbd-async-disaster-recovery-failover-failback.md + - app-migration.md - ... diff --git a/Documentation/Storage-Configuration/Block-Storage-RBD/app-migration.md b/Documentation/Storage-Configuration/Block-Storage-RBD/app-migration.md new file mode 100644 index 000000000..8e0f2d137 --- /dev/null +++ b/Documentation/Storage-Configuration/Block-Storage-RBD/app-migration.md @@ -0,0 +1,90 @@ +--- +title: Application Migration +--- + +When there are multiple Kubernetes clusters that are configured to connect +to the same external Ceph cluster, the applications running in each K8s cluster +will be storing the data in the same central Ceph cluster. +In this setup, applications can be migrated to another cluster without requiring any data movement. +For example, an application may need to migrate if one application cluster is becoming +overloaded or if there is an outage in a cluster. + +Consider the following diagram to illustrate two applications available for migration: + +- App A has an RBD RWO volume in Cluster 1 that can be migrated to Cluster 2 +- App B has a CephFS RXW volume in Cluster 1 that can be migrated to Cluster 2 + +The external Ceph cluster stores the data, thus no data movement is necessary when the applications +are migrated. + +![Application migration between clusters](migration/app-migration.png) + +### Defining Applications for Migration + +Configuring an application to migrate between clusters requires the following: + +- One external Ceph cluster that is accessible from the K8s application clusters. + The Ceph cluster could be configured by Rook with [host networking](../../CRDs/Cluster/network-providers.md#host-networking), + or configured with other tools such as cephadm. +- The application clusters must configure Rook to connect to the same + [external cluster](../../CRDs/Cluster/external-cluster/external-cluster.md), + with access to the same Ceph pool. +- For each application + - Create an RBD image in the external Ceph pool + - Create a static PV + - Create a PVC that binds to the static PV + +First, on the external Ceph cluster, create an RBD image with the command: + +```console +rbd create --size --pool +``` + +Parameters: + +- `name`: The name of the rbd image, which must be set as the `volumeHandle` in the PV created in the next step +- `size`: The size of the rbd image (with suffix M/G/T) +- `poolName`: The name of the Ceph pool where the rbd image is stored + +For example: + +```console +rbd create static-image-abc --size 100G --pool replicapool +``` + +Next, on the application cluster where the application is to be started, +create the application's PVC and the static PV. +See the example [pvc-static.yaml](https://github.com/rook/rook/blob/master/deploy/examples/csi/rbd/pvc-static.yaml). + +Take note of the settings: + +- The PVC defines an empty `storageClassName` +- The name of the rbd image created in the previous step must match the PV `volumeHandle` +- The pool name in the PV must match the pool where the rbd image was created +- The `clusterID` of the PV is the namespace where Rook is running +- The `csi.driver` prefix is the namespace where Rook is running +- `persistentVolumeReclaimPolicy` must be `Retain` + +### Migrating an Application + +When the application needs to be migrated to another cluster: + +1. Scale down the application in the first cluster. +2. Ensure the application is stopped and is not capable of accidentally connecting + to Ceph. RBD volumes have no protection against corruption from multiple instances + of an application accessing the same volume across clusters. Either confirm the + volume attachment has been removed in the original cluster, or block-list the + original cluster from connecting to the Ceph cluster. +3. Create the PVC and static PV in the new cluster. +4. Create or scale up the application in the new cluster. + +### RWX Applications + +Application migration can also be configured for CephFS RXW volumes. +This would allow multiple instances of the application to run +simultaneously across clusters. + +The configuration for CephFS RWX volumes is similar to the RBD RWO +static PV definition. See the +[Ceph-CSI Static PVC](https://github.com/ceph/ceph-csi/blob/04981f8b75b53e0dcf89a31625368eba3bbe9439/docs/static-pvc.md#cephfs-static-pvc) +topic for an example of using CephFS. diff --git a/Documentation/Storage-Configuration/Block-Storage-RBD/migration/app-migration.png b/Documentation/Storage-Configuration/Block-Storage-RBD/migration/app-migration.png new file mode 100644 index 0000000000000000000000000000000000000000..193bce1eb28c31e2546b23545a8d53ef606cec96 GIT binary patch literal 48181 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ℑU(u@bK&FYY(rMsIB;raQf%xADTMMR;`~-K0K_YrB%^3_ebuLr81-}$Y|dII)MTlJdgn@h6bJ~Umu8zWXM^U=~;k_2T=25 z!&_AbP`yiPtAh#+7lKAKusSUaXmL_J!N7NPLSul&k^l`*|K>o`#mkpx&zQj=d0?Rg z=<0+ESFg5$=dOAnTc4*bocik3t8*dY&huByIqp-sbzR>%qma$g=6M$~Ofs%3Fee!-A(0G2^#X@o)85t+$d@~B!+}Fn^EiDaE%fiO?sbWuR#!^sU z&gRbLgA0xA<*nSGT2|@De=98F`ubUzgXMI<*$SI^^XJP$CRc-kgD+pc?0VWY*txmA zyLxA)@$3y9xVu3Gi!^JigQ zecRYr&y5?OmF$|{>|BKs$aX$#6s{W|f4{4X z3*y{6dnzvy<4*;&Uy3hO-@R}gU3&%NJ&M_oM;#q$G7*@s-4U$*5&Oh zP*k_FYB;(`TGH~?t)ir4>8$MO>KZ22>#rO*@Zj0m*&sJHm_VlZJHn>CeEITNTictS zo`%Wlk|whzHXig;U;d+kA+M(9_fqc(Z7S-=*Z!)iOH6c)ii(Puv48dItt(gVTeoid z>TIu?n$*afH*VZGb#2kKX=2*i+8GxWm>s-~jEsbYgj_xydGR76Hui4onl&pf1h`x8 z7OtwgBCI}V&6*qY=4B=(9+mOS&U+`&&%XEbB(}f5xwx~>%{|@QYy0?p{iTZ+oBXa{ zy0XR0{JVXn(cHtDx|$C^|11j4ee~$jrAwC!Y;3G#nU<2WWaY}0 zA3i-@^5e&W;N^2>`Uop4Hz`OQJGO4ywjBTSOCCI!^WsGk-*Q9s=f|$DcG@v>#&N^A zxO>3?1-ja=y^@luDk^&B-`5luw=OPbuC0}omDMgT);Hh20<@p>TxdwhmoHz|gjf{X zojG$xLRz}Nzu&o=O_Jf#<5#buqN22-azR@LfBw03D@t$r>{Ab2=G(n}|M>Bv7bgtB z{k@CV(k^85UAs1qk1sJUjr~W=9zPCtc255D=f=EwdEdTmd-jY+s#k%dSy+9|nX{4S&b>Kspk>F7H*0j{ z`mbNQWMpHr=arVTr)THp&Bj|&Copc%c=h_Vtc;9H*U=j{B<7#rU-mYtveI(;XV-ju30v>6B%`}CeB{Na2jssu&|fcNW^HO> zVrpXY{>)76&dwhhXHF{ipZoLY;G?9E$zH2!Zl3Jo>iqul%z5$u3ZE|PA3O43{S*-y znOARRU%jopbn|BK$&zhbkJ>v%dv_~v92QoWP*dY8E7M7T-VnU}#=(OpJv}2MBV+Wo z@7lF%=gyhupZoj!YhQYqW&}DMJ(X-~$(L7z}pMU@I<;pb> z5EB(4(QKX2-?C%s)=T+-6BK}+78JhU@OCS{P1CBHhzYm@>&Ju<^En?O=jFi4AWYy%ip!Mw6L(Up8U+C>~K<$ ztF^JQ@!-LO6C7EL7^Y1C-K6s5C^^&>wM+201qBJYv^%gJC<+b_ zPftmiGH)KAqH;p2v-8T8D?_wIugzhQWYBJNP~hO<*|KFz$gQth4O5pcT6E~pAteO` zhG)VJJPlKq@7#Iw+_`fH4=&uYMMS8#;i;#jmZoN+(adezww*nD_5zzDTZ2qseEj=Y zue=st6cQ3j&|!?&wXyNXj|!>YXOA8Q#mDo%b2{>6)%k3UXLN%`^f=Uj`zL$_{ODJwIVtzwj9Slx!Q?DE#F zSulOJU5RjfG#R!NC90!O8A;muY>>P Y84hi!yTthH`ZSOhPgg&ebxsLQ0IiFDssI20 literal 0 HcmV?d00001 diff --git a/deploy/examples/csi/rbd/pvc-static.yaml b/deploy/examples/csi/rbd/pvc-static.yaml new file mode 100644 index 000000000..7308a9bdc --- /dev/null +++ b/deploy/examples/csi/rbd/pvc-static.yaml @@ -0,0 +1,41 @@ +# Before creating this PVC and PV, make sure to create a static RBD image in the Ceph cluster. +# rbd create static-image-abc --size 100G --pool replicapool +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: rbd-pvc-static +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 100Gi + storageClassName: "" + volumeName: rbd-static-pv-abc +--- +apiVersion: v1 +kind: PersistentVolume +metadata: + name: rbd-static-pv-abc +spec: + accessModes: + - ReadWriteOnce + capacity: + storage: 100Gi + csi: + driver: rook-ceph.rbd.csi.ceph.com # csi-driver-name + fsType: ext4 + nodeStageSecretRef: + name: rook-csi-rbd-node + namespace: rook-ceph # namespace:cluster + volumeAttributes: + "clusterID": "rook-ceph" + "pool": "replicapool" + "staticVolume": "true" + "imageFeatures": "layering" + + # volumeHandle should be same as the rbd image name created from the toolbox + volumeHandle: static-image-abc + persistentVolumeReclaimPolicy: Retain + volumeMode: Filesystem From 03d610a20a8ba6632111128a062e8e4cc7a3e7f7 Mon Sep 17 00:00:00 2001 From: Travis Nielsen Date: Tue, 4 Nov 2025 16:13:17 -0700 Subject: [PATCH 2/2] docs: example of application migration with dynamic pv Document how to migrate an application with a dynamic PV rather than a static PV, since static PVs have limitations such as not supporting snapshots and clones. Signed-off-by: Travis Nielsen (cherry picked from commit 4cd6416dabe5541424c484814342e189685a0bab) --- .../Block-Storage-RBD/app-migration.md | 76 ++++++++----------- deploy/examples/csi/rbd/pvc-static.yaml | 41 ---------- 2 files changed, 33 insertions(+), 84 deletions(-) delete mode 100644 deploy/examples/csi/rbd/pvc-static.yaml diff --git a/Documentation/Storage-Configuration/Block-Storage-RBD/app-migration.md b/Documentation/Storage-Configuration/Block-Storage-RBD/app-migration.md index 8e0f2d137..e2a925467 100644 --- a/Documentation/Storage-Configuration/Block-Storage-RBD/app-migration.md +++ b/Documentation/Storage-Configuration/Block-Storage-RBD/app-migration.md @@ -11,8 +11,8 @@ overloaded or if there is an outage in a cluster. Consider the following diagram to illustrate two applications available for migration: -- App A has an RBD RWO volume in Cluster 1 that can be migrated to Cluster 2 -- App B has a CephFS RXW volume in Cluster 1 that can be migrated to Cluster 2 +- App A has an RBD RWO PVC in Cluster 1 that can be migrated to Cluster 2 +- App B has a CephFS RWX PVC in Cluster 1 that can be migrated to Cluster 2 The external Ceph cluster stores the data, thus no data movement is necessary when the applications are migrated. @@ -28,63 +28,53 @@ Configuring an application to migrate between clusters requires the following: or configured with other tools such as cephadm. - The application clusters must configure Rook to connect to the same [external cluster](../../CRDs/Cluster/external-cluster/external-cluster.md), - with access to the same Ceph pool. + with access to the same Ceph pool, radosnamespace (RBD), and/or subvolumegroup (CephFS). - For each application - - Create an RBD image in the external Ceph pool - - Create a static PV - - Create a PVC that binds to the static PV + - Create the application and its PVC in the first cluster + - Backup the PV and modify the PV for creation in another cluster -First, on the external Ceph cluster, create an RBD image with the command: +After creating the application, there will be a PV that is bound to the application's PVC. +Find which PV is bound to the application's PVC. For example: -```console -rbd create --size --pool +```command +# replace "rbd-pvc" with the actual pvc name +$ kubectl get pvc rbd-pvc -o yaml | grep volumeName + + volumeName: pvc-2dc3e161-bda2-4b42-956a-42a69a717979 ``` -Parameters: +Retrieve the PV and save to a file: -- `name`: The name of the rbd image, which must be set as the `volumeHandle` in the PV created in the next step -- `size`: The size of the rbd image (with suffix M/G/T) -- `poolName`: The name of the Ceph pool where the rbd image is stored - -For example: - -```console -rbd create static-image-abc --size 100G --pool replicapool +```command +# This command removes the cluster-specific `uid` and `resourceVersion` fields +kubectl get pv pvc-2dc3e161-bda2-4b42-956a-42a69a717979 -o yaml | egrep -v " uid: | resourceVersion: " > application-pv.yaml ``` -Next, on the application cluster where the application is to be started, -create the application's PVC and the static PV. -See the example [pvc-static.yaml](https://github.com/rook/rook/blob/master/deploy/examples/csi/rbd/pvc-static.yaml). +Now the PV can be created in another cluster when the application needs to be migrated. -Take note of the settings: +!!! tip + The PV could be backed up with tools such as Velero. This doc is only attempting to show + how the application can be migrated without external tools. -- The PVC defines an empty `storageClassName` -- The name of the rbd image created in the previous step must match the PV `volumeHandle` -- The pool name in the PV must match the pool where the rbd image was created -- The `clusterID` of the PV is the namespace where Rook is running -- The `csi.driver` prefix is the namespace where Rook is running -- `persistentVolumeReclaimPolicy` must be `Retain` +!!! tip + Consider provisioning volmes from a storage class with `reclaimPolicy: Retain` to prevent + accidental deletion of a volume in one cluster while the other cluster is still consuming + the volume. ### Migrating an Application When the application needs to be migrated to another cluster: 1. Scale down the application in the first cluster. -2. Ensure the application is stopped and is not capable of accidentally connecting +2. If an RWO PVC, ensure the application is stopped and is not capable of accidentally connecting to Ceph. RBD volumes have no protection against corruption from multiple instances of an application accessing the same volume across clusters. Either confirm the volume attachment has been removed in the original cluster, or block-list the - original cluster from connecting to the Ceph cluster. -3. Create the PVC and static PV in the new cluster. -4. Create or scale up the application in the new cluster. - -### RWX Applications - -Application migration can also be configured for CephFS RXW volumes. -This would allow multiple instances of the application to run -simultaneously across clusters. - -The configuration for CephFS RWX volumes is similar to the RBD RWO -static PV definition. See the -[Ceph-CSI Static PVC](https://github.com/ceph/ceph-csi/blob/04981f8b75b53e0dcf89a31625368eba3bbe9439/docs/static-pvc.md#cephfs-static-pvc) -topic for an example of using CephFS. + original cluster from connecting to the Ceph cluster. This requirement + does not apply to CephFS RWX volumes, as CephFS allows multiple clients. +3. Create the PV that was prepared in the previous section. + - If the application will be created in a different namespace or with a different PVC + name from the original cluster, update the corresponding properties in the `claimRef`. + - `kubectl create -f application-pv.yaml` +4. Create or scale up the application and its PVC in the new cluster. +5. Confirm that the application PVC is bound to the PV created in step 3. diff --git a/deploy/examples/csi/rbd/pvc-static.yaml b/deploy/examples/csi/rbd/pvc-static.yaml deleted file mode 100644 index 7308a9bdc..000000000 --- a/deploy/examples/csi/rbd/pvc-static.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# Before creating this PVC and PV, make sure to create a static RBD image in the Ceph cluster. -# rbd create static-image-abc --size 100G --pool replicapool ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: rbd-pvc-static -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 100Gi - storageClassName: "" - volumeName: rbd-static-pv-abc ---- -apiVersion: v1 -kind: PersistentVolume -metadata: - name: rbd-static-pv-abc -spec: - accessModes: - - ReadWriteOnce - capacity: - storage: 100Gi - csi: - driver: rook-ceph.rbd.csi.ceph.com # csi-driver-name - fsType: ext4 - nodeStageSecretRef: - name: rook-csi-rbd-node - namespace: rook-ceph # namespace:cluster - volumeAttributes: - "clusterID": "rook-ceph" - "pool": "replicapool" - "staticVolume": "true" - "imageFeatures": "layering" - - # volumeHandle should be same as the rbd image name created from the toolbox - volumeHandle: static-image-abc - persistentVolumeReclaimPolicy: Retain - volumeMode: Filesystem