Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(migration): adding support to migrate the PV to a new node #304

Merged
merged 7 commits into from
May 1, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
making migration user friendly
Signed-off-by: Pawan <pawan@mayadata.io>
  • Loading branch information
pawanpraka1 committed Apr 26, 2021
commit dce4b0c6e3f9aca5c69df863099bc9db803e70f9
4 changes: 0 additions & 4 deletions deploy/yamls/zfs-driver.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -805,8 +805,6 @@ spec:
value: "zfs-operator"
- name: OPENEBS_IO_ENABLE_ANALYTICS
value: "true"
- name: NODE_AFFINITY_KEY
value: kubernetes.io/hostname
args :
- "--endpoint=$(OPENEBS_CSI_ENDPOINT)"
- "--plugin=$(OPENEBS_CONTROLLER_DRIVER)"
Expand Down Expand Up @@ -1013,8 +1011,6 @@ spec:
value: agent
- name: OPENEBS_NAMESPACE
value: openebs
- name: NODE_AFFINITY_KEY
value: kubernetes.io/hostname
volumeMounts:
- name: plugin-dir
mountPath: /plugin
Expand Down
4 changes: 0 additions & 4 deletions deploy/zfs-operator.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2012,8 +2012,6 @@ spec:
value: "zfs-operator"
- name: OPENEBS_IO_ENABLE_ANALYTICS
value: "true"
- name: NODE_AFFINITY_KEY
value: kubernetes.io/hostname
args :
- "--endpoint=$(OPENEBS_CSI_ENDPOINT)"
- "--plugin=$(OPENEBS_CONTROLLER_DRIVER)"
Expand Down Expand Up @@ -2220,8 +2218,6 @@ spec:
value: agent
- name: OPENEBS_NAMESPACE
value: openebs
- name: NODE_AFFINITY_KEY
value: kubernetes.io/hostname
volumeMounts:
- name: plugin-dir
mountPath: /plugin
Expand Down
23 changes: 12 additions & 11 deletions docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,31 +226,32 @@ PVC size as zero in not a valid capacity. The minimum allocatable size for the Z

### 8. How to migrate PVs to the new node in case old node is not accessible

The ZFS-LocalPV driver will set affinity on the PV to make the volume stick to the node so that pod gets scheduled to that node only where the volume is present. Now the problem here is when that node is not accesible due to some reason and we moved the disks to a new node and imported the pool there, the pods will not be scheduled to this node as k8s scheduler will be looking for that node only to schedule the pod.
The ZFS-LocalPV driver will set affinity on the PV to make the volume stick to the node so that pod gets scheduled to that node only where the volume is present. Now, the problem here is, when that node is not accesible due to some reason and we move the disks to a new node and import the pool there, the pods will not be scheduled to this node as k8s scheduler will be looking for that node only to schedule the pod.

Now with the release of 1.7.0, ZFS-LocalPV driver has the ability to pass the affinity key at the deployment time. So, now the driver will use the provided key(default kubernetes.io/hostname) to set the affinity on the PV.

While deploying the ZFS-LocalPV driver, we should label the node first using some custom key and some unique value
Now, with the release of 1.7.0, ZFS-LocalPV driver has the ability to use the user defined affinity for creating the PV. While deploying the ZFS-LocalPV driver, we should label all the nodes first using the key `openebs.io/nodeid` with some unique value
pawanpraka1 marked this conversation as resolved.
Show resolved Hide resolved
```
$ kubectl label node node-1 custom.openebs.io/nodeid=custom-node-1
$ kubectl label node node-1 openebs.io/nodeid=custom-value-1
```

In the above command the custom key is `custom.openebs.io/nodeid` and value is `custom-node-1`. You can pick your own key and value, just make sure that the value is unique for each node. We have to label all the nodes in the cluster with the unique value. For example node-2 and node-3 can be labelled as below:
In the above command, we have labelled the node `node-1` using the key `openebs.io/nodeid` and the value we have used here is `custom-value-1`. You can pick your own value, just make sure that the value is unique for all the nodes. We have to label all the nodes in the cluster with the unique value. For example, `node-2` and `node-3` can be labelled as below:

```
$ kubectl label node node-2 custom.openebs.io/nodeid=custom-node-2
$ kubectl label node node-3 custom.openebs.io/nodeid=custom-node-3
$ kubectl label node node-2 openebs.io/nodeid=custom-value-2
$ kubectl label node node-3 openebs.io/nodeid=custom-value-3
```

Now, we need to pass the above custom key to ZFS-LocalPV driver, we can update the `NODE_AFFINITY_KEY` env in the zfs-operator yaml (total 2 places, controller and agent both needs this info) with the above key. By default, the driver uses `kubernetes.io/hostname` as the affinity key.

Now, the Driver will use `openebs.io/nodeid` as the key and the corresponding value to set the affinity on the PV and k8s scheduler will consider this affinity label while scheduling the pods.

Now, when a node is not accesible, we need to do below steps

1. remove the old node from the cluster or we can just remove the above node label from the node which we want to remove.
2. add a new node in the cluster
3. move the disks to this new node
4. import the zfs pools on the new nodes
5. label the new node with same custom key and value.
5. label the new node with same key and value. For example, if we have removed the node-3 from the cluster and added node-4 as new node, we have to label the node `node-4` and set the value to `custom-value-3` as shown below

```
$ kubectl label node node-4 openebs.io/nodeid=custom-value-3
```

Once the above steps are done, the pod should be able to run on this new node with all the data it has on the old node. Here, there is one limitation that we can only move the PVs to the new node, we can not move the PVs to the node which was already used in the cluster as there is only one allowed value for the custom key for setting the node label.
pawanpraka1 marked this conversation as resolved.
Show resolved Hide resolved
6 changes: 4 additions & 2 deletions pkg/driver/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,8 +229,10 @@ func (ns *node) NodeGetInfo(
// support all the keys that node has
topology := node.Labels

// add driver's topology key
topology[zfs.ZFSTopologyKey] = ns.driver.config.Nodename
// add driver's topology key if not labelled already
if _, ok := topology[zfs.ZFSTopologyKey]; !ok {
topology[zfs.ZFSTopologyKey] = ns.driver.config.Nodename
}

return &csi.NodeGetInfoResponse{
NodeId: ns.driver.config.Nodename,
Expand Down
2 changes: 1 addition & 1 deletion pkg/driver/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ func (cs *controller) CreateVolume(
return nil, status.Errorf(codes.Internal, "GetNodeID failed : %s", err.Error())
}

topology := map[string]string{zfs.ZFSAffinityKey: nodeid}
topology := map[string]string{zfs.ZFSTopologyKey: nodeid}
cntx := map[string]string{zfs.PoolNameKey: pool}

return csipayload.NewCreateVolumeResponseBuilder().
Expand Down
29 changes: 7 additions & 22 deletions pkg/zfs/volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const (
// ZFSNodeKey will be used to insert Label in ZfsVolume CR
ZFSNodeKey string = "kubernetes.io/nodename"
// ZFSTopologyKey is supported topology key for the zfs driver
ZFSTopologyKey string = "openebs.io/nodename"
ZFSTopologyKey string = "openebs.io/nodeid"
// ZFSStatusPending shows object has not handled yet
ZFSStatusPending string = "Pending"
// ZFSStatusFailed shows object operation has failed
Expand All @@ -66,9 +66,6 @@ var (
// NodeID is the NodeID of the node on which the pod is present
NodeID string

// ZFSAffinityKey is the key for setting the node affinity on the PV
ZFSAffinityKey string

// GoogleAnalyticsEnabled should send google analytics or not
GoogleAnalyticsEnabled string
)
Expand All @@ -77,7 +74,6 @@ func init() {
var err error

OpenEBSNamespace = os.Getenv(OpenEBSNamespaceKey)
ZFSAffinityKey = os.Getenv("NODE_AFFINITY_KEY")

if os.Getenv("OPENEBS_NODE_DRIVER") != "" {
if OpenEBSNamespace == "" {
Expand All @@ -87,26 +83,14 @@ func init() {
if nodename == "" {
klog.Fatalf("OPENEBS_NODE_NAME environment variable not set")
}
if len(ZFSAffinityKey) > 0 {
// if affinity key is provided, the node should be labelled with that key
if NodeID, err = GetNodeID(nodename); err != nil {
klog.Fatalf("GetNodeID failed for node=%s key=%s, err: %s", nodename, ZFSAffinityKey, err.Error())
}
} else {
// if key is not provided use the Driver's topology key and value
ZFSAffinityKey = ZFSTopologyKey
NodeID = nodename
if NodeID, err = GetNodeID(nodename); err != nil {
klog.Fatalf("GetNodeID failed for node=%s err: %s", nodename, err.Error())
}
klog.Infof("zfs: node(%s) affinity key=%s nodeid=%s", nodename, ZFSAffinityKey, NodeID)
klog.Infof("zfs: node(%s) has node affinity %s=%s", nodename, ZFSTopologyKey, NodeID)
} else if os.Getenv("OPENEBS_CONTROLLER_DRIVER") != "" {
akhilerm marked this conversation as resolved.
Show resolved Hide resolved
if OpenEBSNamespace == "" {
klog.Fatalf("OPENEBS_NAMESPACE environment variable not set for controller")
}

if ZFSAffinityKey == "" {
ZFSAffinityKey = ZFSTopologyKey
}
klog.Infof("zfs: controller will use affinity key=%s", ZFSAffinityKey)
}

GoogleAnalyticsEnabled = os.Getenv(GoogleAnalyticsKey)
Expand All @@ -118,9 +102,10 @@ func GetNodeID(nodename string) (string, error) {
return "", fmt.Errorf("failed to get the node %s", nodename)
}

nodeid, ok := node.Labels[ZFSAffinityKey]
nodeid, ok := node.Labels[ZFSTopologyKey]
if !ok {
return "", fmt.Errorf("node %s is not labelled with the key %s", nodename, ZFSAffinityKey)
// node is not labelled, use node name as nodeid
return nodename, nil
}
return nodeid, nil
}
Expand Down