Ceph Upgrades

This guide will walk you through the manual steps to upgrade the software in a Rook cluster from one version to the next. Rook is a distributed software system and therefore there are multiple components to individually upgrade in the sequence defined in this guide. After each component is upgraded, it is important to verify that the cluster returns to a healthy and fully functional state.

With the release of Rook 0.9, significant progress has been made toward the goal of incorporating an automated upgrade solution into the Rook operator. While significant, this has merely lain the foundation for automated upgrade support, and we will continue to be open to community feedback for further improving and refining upgrade automation.

We welcome feedback and opening issues!

Supported Versions

The supported version for this upgrade guide is from a 0.8 release to a 0.9 release. Build-to-build upgrades are not guaranteed to work. This guide is to perform upgrades only between the official releases.

For a guide to upgrade previous versions of Rook, please refer to the version of documentation for those releases.

Patch Release Upgrades

One of the goals of the 0.9 release is that patch releases are able to be automated completely by the Rook operator. It is intended that upgrades from one patch release to another are as simple as updating the image of the Rook operator. For example, when Rook v0.9.3 is released, the process should be as simple as running the following:

kubectl -n rook-ceph-system set image deploy/rook-ceph-operator rook-ceph-operator=rook/ceph:v0.9.x


With this upgrade guide, there are a few notes to consider:

  • WARNING: Upgrading a Rook cluster is not without risk. There may be unexpected issues or obstacles that damage the integrity and health of your storage cluster, including data loss. Only proceed with this guide if you are comfortable with that.
  • The Rook cluster’s storage may be unavailable for short periods during the upgrade process for both Rook operator updates and for Ceph daemon updates.
  • Rook is able to handle a great deal of the upgrade on its own, but manual steps are still necessary. This is in part to reduce the Kubernetes privileges required by the Rook operator.
  • We recommend that you read this document in full before you undertake a Rook cluster upgrade.


We will do all our work in the Ceph example manifests directory.

cd $YOUR_ROOK_REPO/cluster/examples/kubernetes/ceph/

Unless your Rook cluster was created with customized namespaces, namespaces for Rook clusters created before v0.8 are likely to be rook-system and rook, and for Rook-Ceph clusters created with v0.8, rook-ceph-system and rook-ceph. With this guide, we do our best not to assume the namespaces in your cluster. To make things as easy as possible, modify and use the below snippet to configure your environment. We will use these environment variables throughout this document.

# Parameterize the environment
export ROOK_SYSTEM_NAMESPACE="rook-ceph-system"
export ROOK_NAMESPACE="rook-ceph"

We should start up the new toolbox pod before moving on, and this can be our first test of the namespace environment variables.

kubectl -n $ROOK_NAMESPACE delete pod rook-ceph-tools
kubectl -n $ROOK_NAMESPACE create -f toolbox.yaml

In order to successfully upgrade a Rook cluster, the following prerequisites must be met:

  • The cluster should be in a healthy state with full functionality. Review the health verification section in order to verify your cluster is in a good starting state.
  • All pods consuming Rook storage should be created, running, and in a steady state. No Rook persistent volumes should be in the act of being created or deleted.

The minimal sample v0.8 Cluster spec that will be used in this guide can be found below (note that the specific configuration may not be applicable to all environments):

apiVersion: v1
kind: Namespace
  name: rook
apiVersion: ceph.rook.io/v1
kind: CephCluster
  name: rook-ceph
  namespace: rook-ceph
  dataDirHostPath: /var/lib/rook
    useAllNodes: true
    useAllDevices: true
      storeType: bluestore
      databaseSizeMB: 1024
      journalSizeMB: 1024

Health Verification

Before we begin the upgrade process, let’s first review some ways that you can verify the health of your cluster, ensuring that the upgrade is going smoothly after each step. Most of the health verification checks for your cluster during the upgrade process can be performed with the Rook toolbox. For more information about how to run the toolbox, please visit the Rook toolbox readme.

Pods all Running

In a healthy Rook cluster, the operator, the agents and all Rook namespace pods should be in the Running state and have few, if any, pod restarts. To verify this, run the following commands:

kubectl -n $ROOK_SYSTEM_NAMESPACE get pods
kubectl -n $ROOK_NAMESPACE get pod

If pods aren’t running or are restarting due to crashes, you can get more information with and for the affected pods by trying the commands below.

  • kubectl -n <namespace> describe pod
  • kubectl -n <namespace> logs --previous

All Ceph daemon pods have a config-init init container which creates the config files for the daemon, and some daemons have other, specialized init containers, so you may need to look at logs for different containers within the pod.

  • kubectl -n <namespace> logs -c <container name>

Status Output

The Rook toolbox contains the Ceph tools that can give you status details of the cluster with the ceph status command. Let’s look at some sample output and review some of the details:

> TOOLS_POD=$(kubectl -n $ROOK_NAMESPACE get pod -l "app=rook-ceph-tools" -o jsonpath='{.items[0].metadata.name}')
> kubectl -n $ROOK_NAMESPACE exec -it $TOOLS_POD -- ceph status
    id:     fe7ae378-dc77-46a1-801b-de05286aa78e
    health: HEALTH_OK

    mon: 3 daemons, quorum rook-ceph-mon0,rook-ceph-mon1,rook-ceph-mon2
    mgr: rook-ceph-mgr0(active)
    osd: 1 osds: 1 up, 1 in

    pools:   1 pools, 100 pgs
    objects: 0 objects, 0 bytes
    usage:   2049 MB used, 15466 MB / 17516 MB avail
    pgs:     100 active+clean

In the output above, note the following indications that the cluster is in a healthy state:

  • Cluster health: The overall cluster status is HEALTH_OK and there are no warning or error status messages displayed.
  • Monitors (mon): All of the monitors are included in the quorum list.
  • OSDs (osd): All OSDs are up and in.
  • Manager (mgr): The Ceph manager is in the active state.
  • Placement groups (pgs): All PGs are in the active+clean state.

If your ceph status output has deviations from the general good health described above, there may be an issue that needs to be investigated further. There are other commands you may run for more details on the health of the system, such as ceph osd status.

Pod Version

The version of a specific pod in the Rook cluster can be verified in its pod spec output. For example for the monitor pod mon0, we can verify the version it is running with the below commands:

POD_NAME=$(kubectl -n $ROOK_NAMESPACE get pod -o custom-columns=name:.metadata.name --no-headers | grep rook-ceph-mon0)
kubectl -n $ROOK_NAMESPACE get pod ${POD_NAME} -o jsonpath='{.spec.containers[0].image}'

All Pods Status and Version

The status and version of all Rook pods can be collected all at once with the following commands:

kubectl -n $ROOK_SYSTEM_NAMESPACE get pod -o jsonpath='{range .items[*]}{.metadata.name}{"\n\t"}{.status.phase}{"\t"}{.spec.containers[0].image}{"\t"}{.spec.initContainers[0]}{"\n"}{end}'
kubectl -n $ROOK_NAMESPACE get pod -o jsonpath='{range .items[*]}{.metadata.name}{"\n\t"}{.status.phase}{"\t"}{.spec.containers[0].image}{"\t"}{.spec.initContainers[0]}{"\n"}{end}'

Rook Volume Health

Any pod that is using a Rook volume should also remain healthy:

  • The pod should be in the Running state with no restarts
  • There shouldn’t be any errors in its logs
  • The pod should still be able to read and write to the attached Rook volume.

Upgrade process

In this guide, we will be upgrading a live Rook cluster running v0.8.3 to the next available version of v0.9. We will further assume that your previous cluster was created using an earlier version of this guide and manifests.

If you have created custom manifests, these steps may not work as written. The git diff between the release-0.9 branch and the release-0.8 branch may give you a better idea of what you need to change for your from-scratch cluster: git diff release-0.8 release-0.9 -- cluster/examples/kubernetes/ceph/

Rook release from master are expressly unsupported. It is strongly recommended that you use official releases of Rook, as unreleased versions from the master branch are subject to changes and incompatibilities that will not be supported in the official releases. Builds from the master branch can have functionality changed and even removed at any time without compatibility support and without prior notice.

Let’s get started!

1. Configure manifests

IMPORTANT: Ensure that you are using the latest manifests from the release-0.9 branch. If you have custom configuration options set in your old manifests, you will need to also alter those values in the v0.9 manifests. It may be notable that the serviceAccount property has been removed from the CephCluster CRD; default values will now be used.

If your cluster does not use the rook-ceph-system and rook-ceph namespaces, you will need to replace all manifest references to these namespaces with references to those used by your cluster. We can use a few simple sed commands to do this for all manifests at once.

# Replace yaml file namespaces with sed (and make backups)
sed -i.bak -e "s/namespace: rook-ceph-system/namespace: $ROOK_SYSTEM_NAMESPACE/g" *.yaml
sed -i -e "s/namespace: rook-ceph/namespace: $ROOK_NAMESPACE/g" *.yaml
# Reduce clutter by moving the backups we just created
mkdir backups
mv *.bak backups/

2. Update modifed/added resources

A number of custom resources have been modified and added in v0.9. To make updating these resources easy, special upgrade manifest has been created.

kubectl create -f upgrade-from-v0.8-create.yaml
kubectl replace -f upgrade-from-v0.8-replace.yaml

Pod Security Policies: If your cluster has pod security policies enabled and you used the RBAC documentation, you will need to add the new rook-ceph-osd service account to the subject of the rook-ceph-osd-psp role binding. Notice here that the new service account exists alongside the old service account so that the existing OSDs may still function during the upgrade.

kubectl -n $ROOK_NAMESPACE patch rolebinding rook-ceph-osd-psp -p "{\"subjects\": [ \
  {\"kind\": \"ServiceAccount\", \"name\": \"rook-ceph-cluster\", \"namespace\": \"$ROOK_NAMESPACE\"}, \
  {\"kind\": \"ServiceAccount\", \"name\": \"rook-ceph-osd\", \"namespace\": \"$ROOK_NAMESPACE\"}]}"

3. Update the Rook operator image

The largest portion of the upgrade is triggered when the operator’s image is updated to v0.9.3, and with the greatly-expanded automatic update features in the new version, this is all done automatically.

kubectl -n $ROOK_SYSTEM_NAMESPACE set image deploy/rook-ceph-operator rook-ceph-operator=rook/ceph:v0.9.3

Watch now in amazement as the Ceph MONs, MGR, OSDs, RGWs, and MDSes are terminated and replaced with updated versions in sequence. The cluster may be offline very briefly as MONs update, and the Ceph Filesystem may fall offline a few times while the MDSes are upgrading. This is normal. Continue on to the next upgrade step while the update is commencing.

4. Delete the old MGR replicaset

After the MONs have updated, the MGR will update, and because of the new MGR service account with fewer decreased privileges, the old MGR replica set must be deleted manually. Once you see two MGR replica sets, delete the old one using the Rook v0.8 image.

kubectl -n $ROOK_NAMESPACE get rs -l app=rook-ceph-mgr \
  -o custom-columns='name:.metadata.name,image:.spec.template.spec.containers[0].image'
# Sample output:
#  rook-ceph-mgr-a-deletethis   rook/ceph:v0.8.3
#  rook-ceph-mgr-a-dontdelete   ceph/ceph:v12.2.9-2018102
kubectl -n $ROOK_NAMESPACE delete rs 'rook-ceph-mgr-a-deletethis'  # edit name to match your output

5. Wait for the upgrade to complete

Before moving on, the cluster’s main components should be fully updated. A telltale indication that the upgrade is nearly finished is that all the osd pods will have been renamed slightly. An example of an OSD pod name from v0.8 is rook-ceph-osd-id-0-6795dff4bb-d7pz9. This will have changed to something like rook-ceph-osd-0-74fcfd9c5b-58gd8 after the upgrade where the id- has been dropped between osd and the OSD ID.

watch -c kubectl -n $ROOK_NAMESPACE get pods

The MDSes and RGWs are the last daemons to update. An easy check to see if the upgrade is totally finished is to check that there is only one version of rook/ceph and one version of ceph/ceph being used in the cluster.

kubectl -n $ROOK_NAMESPACE describe pods | grep "Image:.*" | sort | uniq
# This cluster is not yet finished:
#      Image:         ceph/ceph:v12.2.9-20181026
#      Image:         rook/ceph:v0.9.3
#      Image:         rook/ceph:v0.8.3
# This cluster is finished:
#      Image:         ceph/ceph:v12.2.9-20181026
#      Image:         rook/ceph:v0.9.3

6. Remove unused resources

Finally, resources present in v0.8 that are no longer used in v0.9 can be safely removed.

# old osd service account
kubectl -n $ROOK_NAMESPACE delete serviceaccount rook-ceph-cluster
kubectl -n $ROOK_NAMESPACE delete role           rook-ceph-cluster
kubectl -n $ROOK_NAMESPACE delete rolebinding    rook-ceph-cluster
# old CRDs
kubectl -n $ROOK_NAMESPACE delete crd clusters.ceph.rook.io
kubectl -n $ROOK_NAMESPACE delete crd filesystems.ceph.rook.io
kubectl -n $ROOK_NAMESPACE delete crd objectstores.ceph.rook.io
kubectl -n $ROOK_NAMESPACE delete crd pools.ceph.rook.io

Pod Security Policies: If your cluster uses pod security policies, you can now remove the old rook-ceph-cluster service account from the subject of the rook-ceph-osd-psp role binding.

kubectl -n $ROOK_NAMESPACE patch rolebinding rook-ceph-osd-psp -p "{\"subjects\": [ \
  {\"kind\": \"ServiceAccount\", \"name\": \"rook-ceph-osd\", \"namespace\": \"$ROOK_NAMESPACE\"}]}"

7. Verify the updated cluster

At this point, your Rook operator should be running version rook/ceph:v0.9.3, and the Ceph daemons should be running image ceph/ceph:v12.2.9-20181026. The Rook operator version and the Ceph version are no longer tied together, and we’ll cover how to upgrade Ceph later in this document.

Verify the Ceph cluster’s health using the health verification section.

8. Update optional components

In general, ancillary components of Rook can be updated updating the CRD, then replacing the resource.

kubectl -n $ROOK_SYSTEM replace -f my-manifest.yaml

File and object storage

There have been no significant changes to the file or object storage CRDs, so updating these should be unnecessary.

Ceph dashboard

The Ceph dashboard service from v0.8 (rook-ceph-mgr-dashboard-external) does not need updated at this time.

Ceph Daemon Upgrades

By default, an upgraded Rook cluster will be running Ceph Luminous (v12), the same Ceph version released with Rook v0.8. Now that the Rook and Ceph versions are independently controllable, you can choose to update Ceph at any time.

Ceph images

Official Ceph container images can be found on Docker Hub. These images are tagged in a few ways:

  • The most explicit form of tags are full-ceph-version-and-build tags (e.g., v13.2.4-20190109). These tags are recommended for production clusters, as there is no possibility for the cluster to be heterogeneous with respect to the version of Ceph running in containers.
  • Ceph major version tags (e.g., v13) are useful for development and test clusters so that the latest version of Ceph is always available.

Ceph containers other than the official images above will not be supported.

Example upgrade to Ceph Mimic

1. Update the main Ceph daemons

The majority of the upgrade will be handled by the Rook operator. Begin the upgrade by changing the Ceph image field in the cluster CRD (spec:cephVersion:image).

# sed -i.bak "s%image: .*%image: $NEW_CEPH_IMAGE%" cluster.yaml
# kubectl -n $ROOK_SYSTEM_NAMESPACE replace -f cluster.yaml
CLUSTER_NAME="$ROOK_NAMESPACE"  # change if your cluster name is not the Rook namespace
kubectl patch CephCluster $CLUSTER_NAME --type=merge \
  -p "{\"spec\": {\"cephVersion\": {\"image\": \"$NEW_CEPH_IMAGE\"}}}"

As with upgrading Rook, you must now wait for the upgrade to complete. Unlike with the Rook upgrade, there is no at-a-glance sign that the upgrade is complete. We suggest watching the cluster upgrade carefully, and it is likely safe to assume the upgrade is complete if there have been no pods terminated in over a minute.

watch -c kubectl -n $ROOK_NAMESPACE get pods

To verify the Ceph upgrade is complete, check that all the images Rook is using are the newest ones.

kubectl -n $ROOK_NAMESPACE describe pods | grep "Image:.*ceph/ceph" | sort | uniq
# This cluster is not yet finished:
#      Image:         ceph/ceph:v12.2.9-20181026
#      Image:         ceph/ceph:v13.2.4-20190109
#      Image:         rook/ceph:v0.9.3
# This cluster is finished:
#      Image:         ceph/ceph:v13.2.4-20190109
#      Image:         rook/ceph:v0.9.3

2. Update dashboard external service if applicable

There have been some changes to the Ceph dashboard in Mimic which affect Rook. In Ceph Luminous (ceph:v12), the dashboard uses HTTP on port 7000 by default, and the v0.8 dashboard service used this port. In Ceph Mimic (ceph:v13), the dashboard uses HTTPS on port 8443 by default. If you are upgrading from Ceph Luminous to Ceph Mimic, you must update the dashboard external service if you are using it.

To upgrade a dashboard external service created in v0.8, the old service must be deleted and the appropriate new service started. added.

kubectl -n $ROOK_NAMESPACE delete service rook-ceph-mgr-dashboard-external
kubectl -n $ROOK_NAMESPACE create -f dashboard-external-https.yaml  # for Ceph Mimic (v13)

For dashboard external services installed in v0.9, the HTTP service name has changed from the above, and a slight modification to these steps are needed.

kubectl -n $ROOK_NAMESPACE delete -f service rook-ceph-mgr-dashboard-external-http
kubectl -n $ROOK_NAMESPACE create -f dashboard-external-https.yaml  # for Ceph Mimic (v13)