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

Issue 63: Added support for ephemeral storage #215

Merged
merged 26 commits into from
Aug 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
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
33 changes: 33 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ The project is currently alpha. While no breaking API changes are currently plan
* [Usage](#usage)
* [Installation of the Operator](#install-the-operator)
* [Deploy a sample Zookeeper Cluster](#deploy-a-sample-zookeeper-cluster)
* [Deploy a sample ZooKeeper Cluster with Ephemeral Storage](#Deploy-a-sample-zookeeper-cluster-with-ephemeral-storage)
pbelgundi marked this conversation as resolved.
Show resolved Hide resolved
* [Deploy a sample Zookeeper Cluster to a cluster using Istio](#deploy-a-sample-zookeeper-cluster-with-istio)
* [Upgrade a Zookeeper Cluster](#upgrade-a-zookeeper-cluster)
* [Uninstall the Zookeeper Cluster](#uninstall-the-zookeeper-cluster)
Expand Down Expand Up @@ -155,6 +156,38 @@ svc/zookeeper-client ClusterIP 10.31.243.173 <none> 2181/TCP
svc/zookeeper-headless ClusterIP None <none> 2888/TCP,3888/TCP 2m
```

### Deploy a sample Zookeeper cluster with Ephemeral storage

Create a Yaml file called `zk.yaml` with the following content to install a 3-node Zookeeper cluster.

```yaml
apiVersion: "zookeeper.pravega.io/v1beta1"
kind: "ZookeeperCluster"
metadata:
name: "example"
spec:
replicas: 3
storageType: ephemeral
```
```
$ kubectl create -f zk.yaml
```

After a couple of minutes, all cluster members should become ready.

```
$ kubectl get zk
NAME REPLICAS READY REPLICAS VERSION DESIRED VERSION INTERNAL ENDPOINT EXTERNAL ENDPOINT AGE
example 3 3 0.2.7 0.2.7 10.100.200.18:2181 N/A 94s
```
>Note: User should only provide value for either the field persistence or ephemeral in the spec if none of the values is specified default is persistence
>Note: In case of ephemeral storage, the cluster may not be able to come back up if more than quorum number of nodes are restarted simultaneously.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please also mention data loss on node restart.

>Note: In case of ephemeral storage, there will be loss of data when the node gets restarted.
### Deploy a sample Zookeeper cluster with Istio
Create a Yaml file called `zk-with-istio.yaml` with the following content to install a 3-node Zookeeper cluster.

Expand Down
3 changes: 3 additions & 0 deletions charts/zookeeper/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ The following table lists the configurable parameters of the Zookeeper chart and
| `config.tickTime` | Length of a single tick which is the basic time unit used by Zookeeper (measured in milliseconds) | `2000` |
| `config.syncLimit` | Amount of time (in ticks) to allow followers to sync with Zookeeper | `2` |
| `config.quorumListenOnAllIPs` | Whether Zookeeper server will listen for connections from its peers on all available IP addresses | `false` |
| `storageType` | Type of storage that can be used it can take either ephemeral or persistence as value | `persistence` |
| `persistence.reclaimPolicy` | Reclaim policy for persistent volumes | `Delete` |
| `persistence.storageClassName` | Storage class for persistent volumes | `standard` |
| `persistence.volumeSize` | Size of the volume requested for persistent volumes | `20Gi` |
| `ephemeral.emptydirvolumesource.medium` | What type of storage medium should back the directory. | `""` |
| `ephemeral.emptydirvolumesource.sizeLimit` | Total amount of local storage required for the EmptyDir volume. | |
12 changes: 12 additions & 0 deletions charts/zookeeper/templates/zookeeper.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,22 @@ spec:
syncLimit: {{ .Values.config.syncLimit }}
quorumListenOnAllIPs: {{ .Values.config.quorumListenOnAllIPs }}
{{- end }}
storageType: {{ .Values.storageType }}
{{- if eq .Values.storageType "ephemeral" }}
ephemeral:
{{- if .Values.ephemeral.emptydirvolumesource }}
emptydirvolumesource:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add the check before this.
add the following if block before setting value for emptydirvolumesource

ephemeral:
   enabled: {{ .Values.ephemeral.enabled }}
   {{- if .Values.ephemeral.emptydirvolumesource }}
   emptydirvolumesource:
      medium: {{ .Values.ephemeral.emptydirvolumesource.medium }}
      sizeLimit: {{ .Values.ephemeral.emptydirvolumesource.sizeLimit }}
   {{- end }}

Also the check in front of persistence can be changed to be created only when ephemeral.enabled is set to false

medium: {{ .Values.ephemeral.emptydirvolumesource.medium }}
{{- if .Values.ephemeral.emptydirvolumesource.sizeLimit }}
sizeLimit: {{ .Values.ephemeral.emptydirvolumesource.sizeLimit }}
{{- end }}
{{- end }}
{{- else }}
persistence:
reclaimPolicy: {{ .Values.persistence.reclaimPolicy }}
spec:
storageClassName: {{ .Values.persistence.storageClassName }}
resources:
requests:
storage: {{ .Values.persistence.volumeSize }}
{{- end }}
12 changes: 12 additions & 0 deletions charts/zookeeper/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,25 @@ config: {}
# syncLimit: 2
# quorumListenOnAllIPs: false

## configure the storage type
## accepted values : persistence/ephemeral
## default option is persistence
storageType: persistence

persistence:
storageClassName: standard
## specifying reclaim policy for PersistentVolumes
## accepted values - Delete / Retain
reclaimPolicy: Delete
volumeSize: 20Gi

ephemeral:
emptydirvolumesource:
## specifying Medium for emptydirvolumesource
## accepted values - ""/Memory
#medium: ""
#sizeLimit: 20Gi

hooks:
image:
repository: lachlanevenson/k8s-kubectl
Expand Down
17 changes: 17 additions & 0 deletions deploy/cr/ECS/zookeeper_v1beta1_zookeepercluster_cr.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
apiVersion: zookeeper.pravega.io/v1beta1
kind: ZookeeperCluster
metadata:
name: zookeeper
spec:
replicas: 3
image:
repository: pravega/zookeeper
tag: 0.2.8
storageType: persistence
persistence:
reclaimPolicy: Retain
spec:
storageClassName: "standard"
resources:
requests:
storage: 20Gi
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ spec:
image:
repository: pravega/zookeeper
tag: 0.2.8
storageType: persistence
persistence:
reclaimPolicy: Delete
spec:
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ require (
github.com/operator-framework/operator-sdk v0.17.0
github.com/pkg/errors v0.9.1
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f // indirect
golang.org/x/tools v0.0.0-20200331202046-9d5940d49312 // indirect
k8s.io/api v0.17.5
k8s.io/apimachinery v0.17.5
k8s.io/client-go v12.0.0+incompatible
Expand Down
7 changes: 7 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,7 @@ github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0 h1:reN85Pxc5larApoH1keMBiu2GWtPqXQ1nc9gx+jOU+E=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
Expand Down Expand Up @@ -778,6 +779,7 @@ github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSf
github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
Expand Down Expand Up @@ -852,6 +854,8 @@ golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHl
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
Expand Down Expand Up @@ -1004,9 +1008,12 @@ golang.org/x/tools v0.0.0-20191111182352-50fa39b762bc/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200115044656-831fdb1e1868/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200327195553-82bb89366a1e h1:qCZ8SbsZMjT0OuDPCEBxgLZic4NMj8Gj4vNXiTVRAaA=
golang.org/x/tools v0.0.0-20200327195553-82bb89366a1e/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200331202046-9d5940d49312 h1:2PHG+Ia3gK1K2kjxZnSylizb//eyaMG8gDFbOG7wLV8=
golang.org/x/tools v0.0.0-20200331202046-9d5940d49312/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
Expand Down
45 changes: 34 additions & 11 deletions pkg/apis/zookeeper/v1beta1/zookeepercluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ package v1beta1

import (
"fmt"
"strings"

v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
Expand Down Expand Up @@ -59,13 +60,19 @@ type ZookeeperClusterSpec struct {
Ports []v1.ContainerPort `json:"ports,omitempty"`

// Pod defines the policy to create pod for the zookeeper cluster.
//
// Updating the Pod does not take effect on any existing pods.
Pod PodPolicy `json:"pod,omitempty"`

//StorageType is used to tell which type of storage we will be using
//It can take either Ephemeral or persistence
//Default StorageType is Persistence storage
StorageType string `json:"storageType,omitempty"`
// Persistence is the configuration for zookeeper persistent layer.
// PersistentVolumeClaimSpec and VolumeReclaimPolicy can be specified in here.
Persistence *Persistence `json:"persistence,omitempty"`
// Ephemeral is the configuration which helps create ephemeral storage
// At anypoint only one of Persistence or Ephemeral should be present in the manifest
Ephemeral *Ephemeral `json:"ephemeral,omitempty"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we move this under storage, we can provide multiple storage options under strorage like ephemeral and persistent storage

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have changed the structure and added storage struct and moved persistence and ephemeral in it


// Conf is the zookeeper configuration, which will be used to generate the
// static zookeeper configuration. If no configuration is provided required
Expand Down Expand Up @@ -160,18 +167,27 @@ func (s *ZookeeperClusterSpec) withDefaults(z *ZookeeperCluster) (changed bool)
if s.Pod.withDefaults(z) {
changed = true
}
if s.Persistence == nil {
s.Persistence = &Persistence{}
changed = true
}
if s.Persistence.withDefaults() {
changed = true
if strings.EqualFold(s.StorageType, "ephemeral") {
if s.Ephemeral == nil {
s.Ephemeral = &Ephemeral{}
s.Ephemeral.EmptyDirVolumeSource = v1.EmptyDirVolumeSource{}
changed = true
}
} else {
if s.Persistence == nil {
s.StorageType = "persistence"
s.Persistence = &Persistence{}
changed = true
}
if s.Persistence.withDefaults() {
s.StorageType = "persistence"
changed = true
}
}
return changed
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// ZookeeperCluster is the Schema for the zookeeperclusters API
// +k8s:openapi-gen=true
type ZookeeperCluster struct {
Expand Down Expand Up @@ -400,17 +416,24 @@ type Persistence struct {
// The default value is Retain.
VolumeReclaimPolicy VolumeReclaimPolicy `json:"reclaimPolicy,omitempty"`
// PersistentVolumeClaimSpec is the spec to describe PVC for the container
// This field is optional. If no PVC spec, stateful containers will use
// emptyDir as volume.
// This field is optional. If no PVC is specified default persistentvolume
// will get created.
PersistentVolumeClaimSpec v1.PersistentVolumeClaimSpec `json:"spec,omitempty"`
}

type Ephemeral struct {
//EmptyDirVolumeSource is optional and this will create the emptydir volume
//It has two parameters Medium and SizeLimit which are optional as well
//Medium specifies What type of storage medium should back this directory.
//SizeLimit specifies Total amount of local storage required for this EmptyDir volume.
EmptyDirVolumeSource v1.EmptyDirVolumeSource `json:"emptydirvolumesource,omitempty"`
}

func (p *Persistence) withDefaults() (changed bool) {
if !p.VolumeReclaimPolicy.isValid() {
changed = true
p.VolumeReclaimPolicy = VolumeReclaimPolicyRetain
}

p.PersistentVolumeClaimSpec.AccessModes = []v1.PersistentVolumeAccessMode{
v1.ReadWriteOnce,
}
Expand Down
13 changes: 13 additions & 0 deletions pkg/apis/zookeeper/v1beta1/zookeepercluster_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,19 @@ var _ = Describe("ZookeeperCluster Types", func() {
})
})

Context(" Ephemeral Storage", func() {
var z1 v1beta1.ZookeeperCluster
BeforeEach(func() {
z1 = *z.DeepCopy()
z1.Spec.StorageType = "ephemeral"
z1.WithDefaults()
})

It("should set the ephemeralstorage and value for EmptyDirVolumeSource.Medium to ''", func() {
Ω(fmt.Sprintf("%s", z1.Spec.Ephemeral.EmptyDirVolumeSource.Medium)).To(Equal(""))
})
})

Context("Conf", func() {
var c v1beta1.ZookeeperConfig

Expand Down
5 changes: 2 additions & 3 deletions pkg/apis/zookeeper/v1beta1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -610,7 +610,7 @@ func (r *ReconcileZookeeperCluster) yamlConfigMap(instance *zookeeperv1beta1.Zoo
}

func (r *ReconcileZookeeperCluster) reconcileFinalizers(instance *zookeeperv1beta1.ZookeeperCluster) (err error) {
if instance.Spec.Persistence.VolumeReclaimPolicy != zookeeperv1beta1.VolumeReclaimPolicyDelete {
if instance.Spec.Persistence != nil && instance.Spec.Persistence.VolumeReclaimPolicy != zookeeperv1beta1.VolumeReclaimPolicyDelete {
return nil
}
if instance.DeletionTimestamp.IsZero() {
Expand Down
8 changes: 8 additions & 0 deletions pkg/test/e2e/e2eutil/spec_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,11 @@ func NewClusterWithVersion(namespace, version string) *api.ZookeeperCluster {
}
return cluster
}

func NewClusterWithEmptyDir(namespace string) *api.ZookeeperCluster {
cluster := NewDefaultCluster(namespace)
cluster.Spec = api.ZookeeperClusterSpec{
StorageType: "ephemeral",
}
return cluster
}
Loading