Regional PD documentation; edited validation for Volumes page (#8714)

This commit is contained in:
Cheng Xing
2018-06-01 07:52:56 -07:00
committed by k8s-ci-robot
parent e49f288730
commit 3e1465461f
3 changed files with 76 additions and 23 deletions
@@ -167,6 +167,7 @@ provisioner: kubernetes.io/gce-pd
parameters: parameters:
type: pd-standard type: pd-standard
zones: us-central1-a, us-central1-b zones: us-central1-a, us-central1-b
replication-type: none
``` ```
* `type`: `pd-standard` or `pd-ssd`. Default: `pd-standard` * `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 is specified, volumes are generally round-robin-ed across all active zones
where Kubernetes cluster has a node. `zone` and `zones` parameters must not where Kubernetes cluster has a node. `zone` and `zones` parameters must not
be used at the same time. 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 ### Glusterfs
+33 -1
View File
@@ -368,6 +368,38 @@ spec:
fsType: ext4 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 ### gitRepo
A `gitRepo` volume is an example of what can be done as a volume plugin. It 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 The following is an example PersistentVolume spec using a `local` volume and
`nodeAffinity`: `nodeAffinity`:
``` yaml ```yaml
apiVersion: v1 apiVersion: v1
kind: PersistentVolume kind: PersistentVolume
metadata: metadata:
+30 -22
View File
@@ -421,15 +421,15 @@ func TestExampleObjectSchemas(t *testing.T) {
"tcp-liveness-readiness": {&api.Pod{}}, "tcp-liveness-readiness": {&api.Pod{}},
}, },
"docs/tasks/debug-application-cluster": { "docs/tasks/debug-application-cluster": {
"counter-pod": {&api.Pod{}}, "counter-pod": {&api.Pod{}},
"event-exporter-deploy": {&api.ServiceAccount{}, &rbac.ClusterRoleBinding{}, &extensions.Deployment{}}, "event-exporter-deploy": {&api.ServiceAccount{}, &rbac.ClusterRoleBinding{}, &extensions.Deployment{}},
"fluentd-gcp-configmap": {&api.ConfigMap{}}, "fluentd-gcp-configmap": {&api.ConfigMap{}},
"fluentd-gcp-ds": {&extensions.DaemonSet{}}, "fluentd-gcp-ds": {&extensions.DaemonSet{}},
"nginx-dep": {&extensions.Deployment{}}, "nginx-dep": {&extensions.Deployment{}},
"node-problem-detector": {&extensions.DaemonSet{}}, "node-problem-detector": {&extensions.DaemonSet{}},
"node-problem-detector-configmap": {&extensions.DaemonSet{}}, "node-problem-detector-configmap": {&extensions.DaemonSet{}},
"shell-demo": {&api.Pod{}}, "shell-demo": {&api.Pod{}},
"termination": {&api.Pod{}}, "termination": {&api.Pod{}},
}, },
// TODO: decide whether federation examples should be added // TODO: decide whether federation examples should be added
"docs/tasks/inject-data-application": { "docs/tasks/inject-data-application": {
@@ -456,8 +456,8 @@ func TestExampleObjectSchemas(t *testing.T) {
"secret-pod": {&api.Pod{}}, "secret-pod": {&api.Pod{}},
}, },
"docs/tasks/job": { "docs/tasks/job": {
"cronjob": {&batch.CronJob{}}, "cronjob": {&batch.CronJob{}},
"job": {&batch.Job{}}, "job": {&batch.Job{}},
}, },
"docs/tasks/job/coarse-parallel-processing-work-queue": { "docs/tasks/job/coarse-parallel-processing-work-queue": {
"job": {&batch.Job{}}, "job": {&batch.Job{}},
@@ -620,12 +620,19 @@ func TestExampleObjectSchemas(t *testing.T) {
var sampleRegexp = regexp.MustCompile("(?ms)^```(?:(?P<type>yaml)\\w*\\n(?P<content>.+?)|\\w*\\n(?P<content>\\{.+?\\}))\\n^```") var sampleRegexp = regexp.MustCompile("(?ms)^```(?:(?P<type>yaml)\\w*\\n(?P<content>.+?)|\\w*\\n(?P<content>\\{.+?\\}))\\n^```")
var subsetRegexp = regexp.MustCompile("(?ms)\\.{3}") var subsetRegexp = regexp.MustCompile("(?ms)\\.{3}")
// Validates examples embedded in Markdown files.
func TestReadme(t *testing.T) { func TestReadme(t *testing.T) {
// BlockVolume required for local volume example
utilfeature.DefaultFeatureGate.Set("BlockVolume=true")
paths := []struct { paths := []struct {
file string 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 { for _, path := range paths {
@@ -639,7 +646,6 @@ func TestReadme(t *testing.T) {
if matches == nil { if matches == nil {
continue continue
} }
ix := 0
for _, match := range matches { for _, match := range matches {
var content, subtype string var content, subtype string
for i, name := range sampleRegexp.SubexpNames() { for i, name := range sampleRegexp.SubexpNames() {
@@ -655,21 +661,23 @@ func TestReadme(t *testing.T) {
continue 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)) json, err := yaml.ToJSON([]byte(content))
if err != nil { if err != nil {
t.Errorf("%s could not be converted to JSON: %v\n%s", path, err, string(content)) 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)) t.Errorf("%s did not decode correctly: %v\n%s", path, err, string(content))
continue continue
} }
if errors := validateObject(expectedType); len(errors) > 0 { if errors := validateObject(expectedType); len(errors) > 0 {
t.Errorf("%s did not validate correctly: %v", path, errors) t.Errorf("%s did not validate correctly: %v", path, errors)
} }