From 3e1465461f010abde551322071ddca7300641941 Mon Sep 17 00:00:00 2001 From: Cheng Xing Date: Fri, 1 Jun 2018 07:52:56 -0700 Subject: [PATCH] Regional PD documentation; edited validation for Volumes page (#8714) --- .../docs/concepts/storage/storage-classes.md | 13 +++++ content/en/docs/concepts/storage/volumes.md | 34 +++++++++++- test/examples_test.go | 52 +++++++++++-------- 3 files changed, 76 insertions(+), 23 deletions(-) diff --git a/content/en/docs/concepts/storage/storage-classes.md b/content/en/docs/concepts/storage/storage-classes.md index 76bf11dc72..82bf103c8e 100644 --- a/content/en/docs/concepts/storage/storage-classes.md +++ b/content/en/docs/concepts/storage/storage-classes.md @@ -167,6 +167,7 @@ provisioner: kubernetes.io/gce-pd parameters: type: pd-standard zones: us-central1-a, us-central1-b + replication-type: none ``` * `type`: `pd-standard` or `pd-ssd`. Default: `pd-standard` @@ -177,6 +178,18 @@ parameters: is specified, volumes are generally round-robin-ed across all active zones where Kubernetes cluster has a node. `zone` and `zones` parameters must not be used at the same time. +* `replication-type`: `none` or `regional-pd`. Default: `none`. + +If `replication-type` is set to `none`, a regular (zonal) PD will be provisioned. + +If `replication-type` is set to `regional-pd`, a +[Regional Persistent Disk](https://cloud.google.com/compute/docs/disks/#repds) +will be provisioned. In this case, users must use `zones` instead of `zone` to +specify the desired replication zones. If exactly two zones are specified, the +Regional PD will be provisioned in those zones. If more than two zones are +specified, Kubernetes will arbitrarily choose among the specified zones. If the +`zones` parameter is omitted, Kubernetes will arbitrarily choose among zones +managed by the cluster. ### Glusterfs diff --git a/content/en/docs/concepts/storage/volumes.md b/content/en/docs/concepts/storage/volumes.md index ef48a0c421..b7d3d95854 100644 --- a/content/en/docs/concepts/storage/volumes.md +++ b/content/en/docs/concepts/storage/volumes.md @@ -368,6 +368,38 @@ spec: fsType: ext4 ``` +#### Regional Persistent Disks +{{< feature-state for_k8s_version="v1.10" state="beta" >}} + +The [Regional Persistent Disks](https://cloud.google.com/compute/docs/disks/#repds) feature allows the creation of Persistent Disks that are available in two zones within the same region. In order to use this feature, the volume must be provisioned as a PersistentVolume; referencing the volume directly from a pod is not supported. + +#### Manually provisioning a Regional PD PersistentVolume +Dynamic provisioning is possible using a [StorageClass for GCE PD](/docs/concepts/storage/storage-classes/#gce). +Before creating a PersistentVolume, you must create the PD: +```shell +gcloud beta compute disks create --size=500GB my-data-disk + --region us-central1 + --replica-zones us-central1-a,us-central1-b +``` +Example PersistentVolume spec: + +```yaml +apiVersion: v1 +kind: PersistentVolume +metadata: + name: test-volume + labels: + failure-domain.beta.kubernetes.io/zone: us-central1-a__us-central1-b +spec: + capacity: + storage: 400Gi + accessModes: + - ReadWriteOnce + gcePersistentDisk: + pdName: my-data-disk + fsType: ext4 +``` + ### gitRepo A `gitRepo` volume is an example of what can be done as a volume plugin. It @@ -527,7 +559,7 @@ durability characteristics of the underlying disk. The following is an example PersistentVolume spec using a `local` volume and `nodeAffinity`: -``` yaml +```yaml apiVersion: v1 kind: PersistentVolume metadata: diff --git a/test/examples_test.go b/test/examples_test.go index bc94dec7ec..48de1ea664 100644 --- a/test/examples_test.go +++ b/test/examples_test.go @@ -421,15 +421,15 @@ func TestExampleObjectSchemas(t *testing.T) { "tcp-liveness-readiness": {&api.Pod{}}, }, "docs/tasks/debug-application-cluster": { - "counter-pod": {&api.Pod{}}, - "event-exporter-deploy": {&api.ServiceAccount{}, &rbac.ClusterRoleBinding{}, &extensions.Deployment{}}, - "fluentd-gcp-configmap": {&api.ConfigMap{}}, - "fluentd-gcp-ds": {&extensions.DaemonSet{}}, - "nginx-dep": {&extensions.Deployment{}}, - "node-problem-detector": {&extensions.DaemonSet{}}, - "node-problem-detector-configmap": {&extensions.DaemonSet{}}, - "shell-demo": {&api.Pod{}}, - "termination": {&api.Pod{}}, + "counter-pod": {&api.Pod{}}, + "event-exporter-deploy": {&api.ServiceAccount{}, &rbac.ClusterRoleBinding{}, &extensions.Deployment{}}, + "fluentd-gcp-configmap": {&api.ConfigMap{}}, + "fluentd-gcp-ds": {&extensions.DaemonSet{}}, + "nginx-dep": {&extensions.Deployment{}}, + "node-problem-detector": {&extensions.DaemonSet{}}, + "node-problem-detector-configmap": {&extensions.DaemonSet{}}, + "shell-demo": {&api.Pod{}}, + "termination": {&api.Pod{}}, }, // TODO: decide whether federation examples should be added "docs/tasks/inject-data-application": { @@ -456,8 +456,8 @@ func TestExampleObjectSchemas(t *testing.T) { "secret-pod": {&api.Pod{}}, }, "docs/tasks/job": { - "cronjob": {&batch.CronJob{}}, - "job": {&batch.Job{}}, + "cronjob": {&batch.CronJob{}}, + "job": {&batch.Job{}}, }, "docs/tasks/job/coarse-parallel-processing-work-queue": { "job": {&batch.Job{}}, @@ -620,12 +620,19 @@ func TestExampleObjectSchemas(t *testing.T) { var sampleRegexp = regexp.MustCompile("(?ms)^```(?:(?Pyaml)\\w*\\n(?P.+?)|\\w*\\n(?P\\{.+?\\}))\\n^```") var subsetRegexp = regexp.MustCompile("(?ms)\\.{3}") +// Validates examples embedded in Markdown files. func TestReadme(t *testing.T) { + // BlockVolume required for local volume example + utilfeature.DefaultFeatureGate.Set("BlockVolume=true") + paths := []struct { file string - expectedType []runtime.Object + expectedType []runtime.Object // List of all valid types for the whole doc }{ - {"../content/en/docs/concepts/storage/volumes.md", []runtime.Object{&api.Pod{}}}, + {"../content/en/docs/concepts/storage/volumes.md", []runtime.Object{ + &api.Pod{}, + &api.PersistentVolume{}, + }}, } for _, path := range paths { @@ -639,7 +646,6 @@ func TestReadme(t *testing.T) { if matches == nil { continue } - ix := 0 for _, match := range matches { var content, subtype string for i, name := range sampleRegexp.SubexpNames() { @@ -655,21 +661,23 @@ func TestReadme(t *testing.T) { continue } - var expectedType runtime.Object - if len(path.expectedType) == 1 { - expectedType = path.expectedType[0] - } else { - expectedType = path.expectedType[ix] - ix++ - } json, err := yaml.ToJSON([]byte(content)) if err != nil { t.Errorf("%s could not be converted to JSON: %v\n%s", path, err, string(content)) } - if err := runtime.DecodeInto(testapi.Default.Codec(), json, expectedType); err != nil { + + var expectedType runtime.Object + for _, expectedType = range path.expectedType { + err = runtime.DecodeInto(testapi.Default.Codec(), json, expectedType) + if err == nil { + break + } + } + if err != nil { t.Errorf("%s did not decode correctly: %v\n%s", path, err, string(content)) continue } + if errors := validateObject(expectedType); len(errors) > 0 { t.Errorf("%s did not validate correctly: %v", path, errors) }