Regional PD documentation; edited validation for Volumes page (#8714)
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
+30
-22
@@ -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)^```(?:(?P<type>yaml)\\w*\\n(?P<content>.+?)|\\w*\\n(?P<content>\\{.+?\\}))\\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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user