diff --git a/examples/persistent-volumes/simpletest/README.md b/examples/persistent-volumes/simpletest/README.md index 1911c6e4fea..93489a40e04 100644 --- a/examples/persistent-volumes/simpletest/README.md +++ b/examples/persistent-volumes/simpletest/README.md @@ -3,15 +3,19 @@ The purpose of this guide is to help you become familiar with Kubernetes Persistent Volumes. By the end of the guide, we'll have nginx serving content from your persistent volume. -This guide assumes knowledge of Kubernetes fundamentals and that a user has a cluster up and running. +This guide assumes knowledge of Kubernetes fundamentals and that you have a cluster up and running. ## Provisioning A PersistentVolume in Kubernetes represents a real piece of underlying storage capacity in the infrastructure. Cluster administrators must first create storage (create their GCE disks, export their NFS shares, etc.) in order for Kubernetes to mount it. -PVs are intended for "network volumes" like GCE Persistent Disks, NFS shares, and AWS ElasticBlockStore volumes. `HostPath` was included -for ease of development and testing. You'll create a local `HostPath` for this example. +PVs are intended for "network volumes" like GCE Persistent Disks, NFS shares, and AWS ElasticBlockStore volumes. ```HostPath``` was included +for ease of development and testing. You'll create a local ```HostPath``` for this example. + +> IMPORTANT! For ```HostPath``` to work, you will need to run a single node cluster. Kubernetes does not +support local storage on the host at this time. There is no guarantee your pod ends up on the correct node where the ```HostPath``` resides. + ``` @@ -28,17 +32,17 @@ PVs are created by posting them to the API server. cluster/kubectl.sh create -f examples/persistent-volumes/volumes/local-01.yaml cluster/kubectl.sh get pv -NAME LABELS CAPACITY ACCESSMODES STATUS CLAIM -pv0001 map[] 10737418240 RWO Available +NAME LABELS CAPACITY ACCESSMODES STATUS CLAIM +pv0001 map[] 10737418240 RWO Available ``` ## Requesting storage Users of Kubernetes request persistent storage for their pods. They don't know how the underlying cluster is provisioned. -They just know they can rely on their claim to storage and they can manage its lifecycle independently from the many pods that may use it. +They just know they can rely on their claim to storage and can manage its lifecycle independently from the many pods that may use it. -You must be in a namespace to create claims. +Claims must be created in the same namespace as the pods that use them. ``` @@ -60,7 +64,7 @@ myclaim-1 map[] Bound f5c3a89a-e50a-11e4-972f-80e6500a981e cluster/kubectl.sh get pv -NAME LABELS CAPACITY ACCESSMODES STATUS CLAIM +NAME LABELS CAPACITY ACCESSMODES STATUS CLAIM pv0001 map[] 10737418240 RWO Bound myclaim-1 / 6bef4c40-e50b-11e4-972f-80e6500a981e ``` @@ -70,7 +74,8 @@ pv0001 map[] 10737418240 RWO Claims are used as volumes in pods. Kubernetes uses the claim to look up its bound PV. The PV is then exposed to the pod. ``` -k create -f examples/persistent-volumes/simpletest/pod.yaml + +cluster/kubectl.sh create -f examples/persistent-volumes/simpletest/pod.yaml cluster/kubectl.sh get pods @@ -78,14 +83,30 @@ POD IP CONTAINER(S) IMAGE(S) HOST LABELS mypod 172.17.0.2 myfrontend nginx 127.0.0.1/127.0.0.1 Running 12 minutes -k create -f examples/persistent-volumes/simpletest/service.json +cluster/kubectl.sh create -f examples/persistent-volumes/simpletest/service.json cluster/kubectl.sh get services -Running: cluster/../cluster/gce/../../cluster/../_output/local/bin/darwin/amd64/kubectl --v=5 get services -NAME LABELS SELECTOR IP PORT(S) -kubernetes component=apiserver,provider=kubernetes 10.0.0.2 443/TCP -kubernetes-ro component=apiserver,provider=kubernetes 10.0.0.1 80/TCP + +NAME LABELS SELECTOR IP PORT(S) +frontendservice name=frontendhttp 10.0.0.241 3000/TCP +kubernetes component=apiserver,provider=kubernetes 10.0.0.2 443/TCP +kubernetes-ro component=apiserver,provider=kubernetes 10.0.0.1 80/TCP -curl 10.0.0.168:3000 -I love Kubernetes storage! ``` + +## Next steps + +You should be able to query your service endpoint and see what content nginx is serving. A "forbidden" error might mean you +need to disable SELinux (setenforce 0). + +``` + +curl 10.0.0.241:3000 +I love Kubernetes storage! + +``` + +Hopefully this simple guide is enough to get you started with PersistentVolumes. If you have any questions, join +```#google-containers``` on IRC and ask! + +Enjoy! diff --git a/examples/persistent-volumes/simpletest/pod.yaml b/examples/persistent-volumes/simpletest/pod.yaml index aea1502242b..f9bab5316ab 100644 --- a/examples/persistent-volumes/simpletest/pod.yaml +++ b/examples/persistent-volumes/simpletest/pod.yaml @@ -2,17 +2,19 @@ kind: Pod apiVersion: v1beta3 metadata: name: mypod + labels: + name: frontendhttp spec: containers: - - image: nginx - name: myfrontend + - name: myfrontend + image: dockerfile/nginx + ports: + - containerPort: 80 + name: "http-server" volumeMounts: - mountPath: "/var/www/html" name: mypd volumes: - name: mypd - source: - persistentVolumeClaim: - accessMode: ReadWriteOnce - claimRef: - name: myclaim-1 + persistentVolumeClaim: + claimName: myclaim-1 \ No newline at end of file diff --git a/examples/persistent-volumes/simpletest/service.json b/examples/persistent-volumes/simpletest/service.json new file mode 100644 index 00000000000..3fbbe5de485 --- /dev/null +++ b/examples/persistent-volumes/simpletest/service.json @@ -0,0 +1,9 @@ +{ + "apiVersion": "v1beta1", + "kind": "Service", + "id": "frontendservice", + "port": 3000, + "containerPort": "http-server", + "selector": { "name": "frontendhttp" }, + "createExternalLoadBalancer": false +} diff --git a/pkg/api/validation/validation.go b/pkg/api/validation/validation.go index d047164588c..dfe8d6c4b6e 100644 --- a/pkg/api/validation/validation.go +++ b/pkg/api/validation/validation.go @@ -319,6 +319,11 @@ func validateSource(source *api.VolumeSource) errs.ValidationErrorList { numVolumes++ allErrs = append(allErrs, validateGlusterfs(source.Glusterfs).Prefix("glusterfs")...) } + if source.PersistentVolumeClaimVolumeSource != nil { + numVolumes++ + allErrs = append(allErrs, validatePersistentClaimVolumeSource(source.PersistentVolumeClaimVolumeSource).Prefix("glusterfs")...) + } + if numVolumes != 1 { allErrs = append(allErrs, errs.NewFieldInvalid("", source, "exactly 1 volume type is required")) } @@ -394,6 +399,14 @@ func validateSecretVolumeSource(secretSource *api.SecretVolumeSource) errs.Valid return allErrs } +func validatePersistentClaimVolumeSource(claim *api.PersistentVolumeClaimVolumeSource) errs.ValidationErrorList { + allErrs := errs.ValidationErrorList{} + if claim.ClaimName == "" { + allErrs = append(allErrs, errs.NewFieldRequired("claimName")) + } + return allErrs +} + func validateNFS(nfs *api.NFSVolumeSource) errs.ValidationErrorList { allErrs := errs.ValidationErrorList{} if nfs.Server == "" { diff --git a/pkg/volumeclaimbinder/persistent_volume_claim_binder.go b/pkg/volumeclaimbinder/persistent_volume_claim_binder.go index b655fe6a3a0..da62b57cda8 100644 --- a/pkg/volumeclaimbinder/persistent_volume_claim_binder.go +++ b/pkg/volumeclaimbinder/persistent_volume_claim_binder.go @@ -18,6 +18,7 @@ package volumeclaimbinder import ( "fmt" + "reflect" "time" "github.com/GoogleCloudPlatform/kubernetes/pkg/api" @@ -30,7 +31,6 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/watch" "github.com/golang/glog" - "reflect" ) // PersistentVolumeClaimBinder is a controller that synchronizes PersistentVolumeClaims. @@ -94,7 +94,6 @@ func NewPersistentVolumeClaimBinder(kubeClient client.Interface, syncPeriod time syncClaim(volumeIndex, binderClient, claim) }, UpdateFunc: func(oldObj, newObj interface{}) { - // oldClaim := newObj.(*api.PersistentVolumeClaim) newClaim := newObj.(*api.PersistentVolumeClaim) if newClaim.Status.VolumeRef == nil { syncClaim(volumeIndex, binderClient, newClaim) diff --git a/pkg/volumeclaimbinder/persistent_volume_claim_binder_test.go b/pkg/volumeclaimbinder/persistent_volume_claim_binder_test.go index 4b6eab019e8..c6bc047afaa 100644 --- a/pkg/volumeclaimbinder/persistent_volume_claim_binder_test.go +++ b/pkg/volumeclaimbinder/persistent_volume_claim_binder_test.go @@ -17,10 +17,10 @@ limitations under the License. package volumeclaimbinder import ( + "fmt" "reflect" "testing" - "fmt" "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource" diff --git a/pkg/volumeclaimbinder/persistent_volume_index_test.go b/pkg/volumeclaimbinder/persistent_volume_index_test.go index 4ee00d6d1f1..4d6dccf7e3c 100644 --- a/pkg/volumeclaimbinder/persistent_volume_index_test.go +++ b/pkg/volumeclaimbinder/persistent_volume_index_test.go @@ -17,9 +17,10 @@ limitations under the License. package volumeclaimbinder import ( + "testing" + "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource" - "testing" ) func TestMatchVolume(t *testing.T) {