Syntax highlighting manual fixes up to mesos.md (next is scratch.md)
This commit is contained in:
@@ -20,11 +20,10 @@ or someone else setup the cluster and provided you with credentials and a locati
|
||||
|
||||
Check the location and credentials that kubectl knows about with this command:
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl config view
|
||||
$ kubectl config view
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
Many of the [examples](https://github.com/kubernetes/kubernetes/tree/master/examples/) provide an introduction to using
|
||||
kubectl and complete documentation is found in the [kubectl manual](kubectl/kubectl).
|
||||
|
||||
@@ -49,29 +48,27 @@ The following command runs kubectl in a mode where it acts as a reverse proxy.
|
||||
The following command runs kubectl in a mode where it acts as a reverse proxy. It handles
|
||||
locating the apiserver and authenticating.
|
||||
Run it like this:
|
||||
Run it like this:
|
||||
|
||||
```shell
|
||||
```shell
|
||||
|
||||
$ kubectl proxy --port=8080 &
|
||||
|
||||
```
|
||||
See [kubectl proxy](kubectl/kubectl_proxy) for more details.
|
||||
|
||||
See [kubectl proxy](kubectl/kubectl_proxy) for more details.
|
||||
Then you can explore the API with curl, wget, or a browser, like so:
|
||||
|
||||
```shell
|
||||
$ curl http://localhost:8080/api/
|
||||
{
|
||||
"versions": [
|
||||
"v1"
|
||||
{
|
||||
"versions": [
|
||||
]
|
||||
}
|
||||
|
||||
```
|
||||
#### Without kubectl proxy
|
||||
|
||||
|
||||
It is also possible to avoid using kubectl proxy by passing an authentication token
|
||||
directly to the apiserver, like this:
|
||||
|
||||
```shell
|
||||
@@ -80,8 +77,7 @@ $ curl $APISERVER/api --header "Authorization: Bearer $TOKEN" --insecure
|
||||
$ curl $APISERVER/api --header "Authorization: Bearer $TOKEN" --insecure
|
||||
{
|
||||
"versions": [
|
||||
$ TOKEN=$(kubectl config view | grep token | cut -f 2 -d ":" | tr -d " ")
|
||||
$ curl $APISERVER/api --header "Authorization: Bearer $TOKEN" --insecure
|
||||
"v1"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -125,7 +121,7 @@ From within a pod the recommended ways to connect to API are:
|
||||
at `/var/run/secrets/kubernetes.io/serviceaccount/token`.
|
||||
|
||||
From within a pod the recommended ways to connect to API are:
|
||||
service account is placed into the filesystem tree of each container in that pod,
|
||||
- run a kubectl proxy as one of the containers in the pod, or as a background
|
||||
process within a container. This proxies the
|
||||
Kubernetes API to the localhost interface of the pod, so that other processes
|
||||
in any container of the pod can access it. See this [example of using kubectl proxy
|
||||
@@ -173,7 +169,7 @@ You have several options for connecting to nodes, pods and services from outside
|
||||
not others. Browsers and other tools may or may not be installed. Cluster DNS may not work.
|
||||
|
||||
### Discovering builtin services
|
||||
access cluster services. This is a non-standard method, and will work on some clusters but
|
||||
|
||||
Typically, there are several services which are started on a cluster by kube-system. Get a list of these
|
||||
with the `kubectl cluster-info` command:
|
||||
|
||||
@@ -182,8 +178,7 @@ $ kubectl cluster-info
|
||||
|
||||
Kubernetes master is running at https://104.197.5.247
|
||||
elasticsearch-logging is running at https://104.197.5.247/api/v1/proxy/namespaces/kube-system/services/elasticsearch-logging
|
||||
|
||||
$ kubectl cluster-info
|
||||
kibana-logging is running at https://104.197.5.247/api/v1/proxy/namespaces/kube-system/services/kibana-logging
|
||||
kube-dns is running at https://104.197.5.247/api/v1/proxy/namespaces/kube-system/services/kube-dns
|
||||
grafana is running at https://104.197.5.247/api/v1/proxy/namespaces/kube-system/services/monitoring-grafana
|
||||
heapster is running at https://104.197.5.247/api/v1/proxy/namespaces/kube-system/services/monitoring-heapster
|
||||
@@ -202,8 +197,8 @@ about namespaces? 'proxy' verb? -->
|
||||
<!--- TODO: update this part of doc because it doesn't seem to be valid. What
|
||||
about namespaces? 'proxy' verb? -->
|
||||
|
||||
As mentioned above, you use the `kubectl cluster-info` command to retrieve the service's proxy URL. To create proxy URLs that include service endpoints, suffixes, and parameters, you simply append to the service's proxy URL:
|
||||
`http://`*`kubernetes_master_address`*`/`*`service_path`*`/`*`service_name`*`/`*`service_endpoint-suffix-parameter`*
|
||||
##### Examples
|
||||
|
||||
* To access the Elasticsearch service endpoint `_search?q=user:kimchy`, you would use: `http://104.197.5.247/api/v1/proxy/namespaces/kube-system/services/elasticsearch-logging/_search?q=user:kimchy`
|
||||
* To access the Elasticsearch cluster health information `_cluster/health?pretty=true`, you would use: `https://104.197.5.247/api/v1/proxy/namespaces/kube-system/services/elasticsearch-logging/_cluster/health?pretty=true`
|
||||
|
||||
@@ -215,8 +210,7 @@ about namespaces? 'proxy' verb? -->
|
||||
"number_of_nodes" : 1,
|
||||
"number_of_data_nodes" : 1,
|
||||
"active_primary_shards" : 5,
|
||||
"cluster_name" : "kubernetes_logging",
|
||||
"status" : "yellow",
|
||||
"active_shards" : 5,
|
||||
"relocating_shards" : 0,
|
||||
"initializing_shards" : 0,
|
||||
"unassigned_shards" : 5
|
||||
|
||||
@@ -8,14 +8,12 @@ It is also useful to be able to attach arbitrary non-identifying metadata, for r
|
||||
Like labels, annotations are key-value maps.
|
||||
|
||||
```json
|
||||
|
||||
"annotations": {
|
||||
"key1" : "value1",
|
||||
"key2" : "value2"
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Possible information that could be recorded in annotations:
|
||||
|
||||
* fields managed by a declarative configuration layer, to distinguish them from client- and/or server-set default values and other auto-generated fields, fields set by auto-sizing/auto-scaling systems, etc., in order to facilitate merging
|
||||
|
||||
@@ -24,11 +24,9 @@ your Service?
|
||||
The first step in debugging a Pod is taking a look at it. Check the current state of the Pod and recent events with the following command:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl describe pods ${POD_NAME}
|
||||
|
||||
```
|
||||
|
||||
Look at the state of the containers in the pod. Are they all `Running`? Have there been recent restarts?
|
||||
|
||||
Continue debugging depending on the state of the pods.
|
||||
@@ -62,38 +60,29 @@ First, take a look at the logs of
|
||||
the current container:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl logs ${POD_NAME} ${CONTAINER_NAME}
|
||||
|
||||
```
|
||||
|
||||
If your container has previously crashed, you can access the previous container's crash log with:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl logs --previous ${POD_NAME} ${CONTAINER_NAME}
|
||||
|
||||
```
|
||||
|
||||
Alternately, you can run commands inside that container with `exec`:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl exec ${POD_NAME} -c ${CONTAINER_NAME} -- ${CMD} ${ARG1} ${ARG2} ... ${ARGN}
|
||||
|
||||
```
|
||||
|
||||
Note that `-c ${CONTAINER_NAME}` is optional and can be omitted for Pods that only contain a single container.
|
||||
|
||||
As an example, to look at the logs from a running Cassandra pod, you might run
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl exec cassandra -- cat /var/log/cassandra/system.log
|
||||
|
||||
```
|
||||
|
||||
|
||||
If none of these approaches work, you can find the host machine that the pod is running on and SSH into that host,
|
||||
but this should generally not be necessary given tools in the Kubernetes API. Therefore, if you find yourself needing to ssh into a machine, please file a
|
||||
feature request on GitHub describing your use case and why these tools are insufficient.
|
||||
@@ -112,13 +101,11 @@ For example, run `kubectl create --validate -f mypod.yaml`.
|
||||
If you misspelled `command` as `commnd` then will give an error like this:
|
||||
|
||||
```
|
||||
|
||||
I0805 10:43:25.129850 46757 schema.go:126] unknown field: commnd
|
||||
I0805 10:43:25.129973 46757 schema.go:129] this may be a false alarm, see https://github.com/kubernetes/kubernetes/issues/6842
|
||||
pods/mypod
|
||||
|
||||
```
|
||||
|
||||
<!-- TODO: Now that #11914 is merged, this advice may need to be updated -->
|
||||
|
||||
The next thing to check is whether the pod on the apiserver
|
||||
@@ -148,11 +135,9 @@ First, verify that there are endpoints for the service. For every Service object
|
||||
You can view this resource with:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get endpoints ${SERVICE_NAME}
|
||||
|
||||
```
|
||||
|
||||
Make sure that the endpoints match up with the number of containers that you expect to be a member of your service.
|
||||
For example, if your Service is for an nginx container with 3 replicas, you would expect to see three different
|
||||
IP addresses in the Service's endpoints.
|
||||
@@ -163,7 +148,6 @@ If you are missing endpoints, try listing pods using the labels that Service use
|
||||
a Service where the labels are:
|
||||
|
||||
```yaml
|
||||
|
||||
...
|
||||
spec:
|
||||
- selector:
|
||||
@@ -171,15 +155,12 @@ spec:
|
||||
type: frontend
|
||||
|
||||
```
|
||||
|
||||
You can use:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get pods --selector=name=nginx,type=frontend
|
||||
|
||||
```
|
||||
|
||||
to list pods that match this selector. Verify that the list matches the Pods that you expect to provide your Service.
|
||||
|
||||
If the list of pods matches expectations, but your endpoints are still empty, it's possible that you don't
|
||||
|
||||
@@ -42,7 +42,6 @@ be said to have a request of 0.5 core and 128 MiB of memory and a limit of 1 cor
|
||||
memory.
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
@@ -69,7 +68,6 @@ spec:
|
||||
cpu: "500m"
|
||||
|
||||
```
|
||||
|
||||
## How Pods with Resource Requests are Scheduled
|
||||
|
||||
When a pod is created, the Kubernetes scheduler selects a node for the pod to
|
||||
@@ -123,7 +121,6 @@ until a place can be found. An event will be produced each time the scheduler
|
||||
place for the pod, like this:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl describe pod frontend | grep -A 3 Events
|
||||
Events:
|
||||
FirstSeen LastSeen Count From Subobject PathReason Message
|
||||
@@ -131,7 +128,6 @@ Events:
|
||||
|
||||
|
||||
```
|
||||
|
||||
In the case shown above, the pod "frontend" fails to be scheduled due to insufficient
|
||||
CPU resource on the node. Similar error messages can also suggest failure due to insufficient
|
||||
memory (PodExceedsFreeMemory). In general, if a pod or pods are pending with this message and
|
||||
@@ -145,7 +141,6 @@ You can check node capacities and amounts allocated with the `kubectl describe n
|
||||
For example:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl describe nodes gke-cluster-4-386701dd-node-ww4p
|
||||
Name: gke-cluster-4-386701dd-node-ww4p
|
||||
[ ... lines removed for clarity ...]
|
||||
@@ -169,7 +164,6 @@ TotalResourceLimits:
|
||||
[ ... lines removed for clarity ...]
|
||||
|
||||
```
|
||||
|
||||
Here you can see from the `Allocated resources` section that that a pod which ask for more than
|
||||
90 millicpus or more than 1341MiB of memory will not be able to fit on this node.
|
||||
|
||||
@@ -185,7 +179,6 @@ Your container may be terminated because it's resource-starved. To check if a co
|
||||
on the pod you are interested in:
|
||||
|
||||
```shell
|
||||
|
||||
[12:54:41] $ ./cluster/kubectl.sh describe pod simmemleak-hra99
|
||||
Name: simmemleak-hra99
|
||||
Namespace: default
|
||||
@@ -223,19 +216,16 @@ Events:
|
||||
Tue, 07 Jul 2015 12:53:51 -0700 Tue, 07 Jul 2015 12:53:51 -0700 1 {kubelet kubernetes-minion-tf0f} spec.containers{simmemleak} created Created with docker id 87348f12526a
|
||||
|
||||
```
|
||||
|
||||
The `Restart Count: 5` indicates that the `simmemleak` container in this pod was terminated and restarted 5 times.
|
||||
|
||||
You can call `get pod` with the `-o go-template=...` option to fetch the status of previously terminated containers:
|
||||
|
||||
```shell
|
||||
|
||||
[13:59:01] $ ./cluster/kubectl.sh get pod -o go-template='{{range.status.containerStatuses}}{{"Container Name: "}}{{.name}}{{"\r\nLastState: "}}{{.lastState}}{{end}}' simmemleak-60xbc
|
||||
Container Name: simmemleak
|
||||
LastState: map[terminated:map[exitCode:137 reason:OOM Killed startedAt:2015-07-07T20:58:43Z finishedAt:2015-07-07T20:58:43Z containerID:docker://0e4095bba1feccdfe7ef9fb6ebffe972b4b14285d5acdec6f0d3ae8a22fad8b2]][13:59:03] clusterScaleDoc ~/go/src/github.com/kubernetes/kubernetes $
|
||||
|
||||
```
|
||||
|
||||
We can see that this container was terminated because `reason:OOM Killed`, where *OOM* stands for Out Of Memory.
|
||||
|
||||
## Planned Improvements
|
||||
|
||||
@@ -14,7 +14,6 @@ In the declarative style, all configuration is stored in YAML or JSON configurat
|
||||
Kubernetes executes containers in [*Pods*](pods). A pod containing a simple Hello World container can be specified in YAML as follows:
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
@@ -27,7 +26,6 @@ spec: # specification of the pod's contents
|
||||
command: ["/bin/echo","hello'?,'?world"]
|
||||
|
||||
```
|
||||
|
||||
The value of `metadata.name`, `hello-world`, will be the name of the pod resource created, and must be unique within the cluster, whereas `containers[0].name` is just a nickname for the container within that pod. `image` is the name of the Docker image, which Kubernetes expects to be able to pull from a registry, the [Docker Hub](https://registry.hub.docker.com/) by default.
|
||||
|
||||
`restartPolicy: Never` indicates that we just want to run the container once and then terminate the pod.
|
||||
@@ -35,21 +33,17 @@ The value of `metadata.name`, `hello-world`, will be the name of the pod resourc
|
||||
The [`command`](containers.html#containers-and-commands) overrides the Docker container's `Entrypoint`. Command arguments (corresponding to Docker's `Cmd`) may be specified using `args`, as follows:
|
||||
|
||||
```yaml
|
||||
|
||||
command: ["/bin/echo"]
|
||||
command: ["/bin/echo"]
|
||||
args: ["hello","world"]
|
||||
|
||||
```
|
||||
|
||||
This pod can be created using the `create` command:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f ./hello-world.yaml
|
||||
pods/hello-world
|
||||
|
||||
```
|
||||
|
||||
`kubectl` prints the resource type and name of the resource created when successful.
|
||||
|
||||
## Validating configuration
|
||||
@@ -57,21 +51,17 @@ pods/hello-world
|
||||
If you're not sure you specified the resource correctly, you can ask `kubectl` to validate it for you:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f ./hello-world.yaml --validate
|
||||
|
||||
```
|
||||
|
||||
Let's say you specified `entrypoint` instead of `command`. You'd see output as follows:
|
||||
|
||||
```shell
|
||||
|
||||
I0709 06:33:05.600829 14160 schema.go:126] unknown field: entrypoint
|
||||
I0709 06:33:05.600988 14160 schema.go:129] this may be a false alarm, see http://issue.k8s.io/6842
|
||||
pods/hello-world
|
||||
|
||||
```
|
||||
|
||||
`kubectl create --validate` currently warns about problems it detects, but creates the resource anyway, unless a required field is absent or a field value is invalid. Unknown API fields are ignored, so be careful. This pod was created, but with no `command`, which is an optional field, since the image may specify an `Entrypoint`.
|
||||
View the [Pod API
|
||||
object](http://kubernetes.io/v1.1/docs/api-reference/v1/definitions.html#_v1_pod)
|
||||
@@ -82,7 +72,6 @@ to see the list of valid fields.
|
||||
Kubernetes [does not automatically run commands in a shell](https://github.com/kubernetes/kubernetes/wiki/User-FAQ#use-of-environment-variables-on-the-command-line) (not all images contain shells). If you would like to run your command in a shell, such as to expand environment variables (specified using `env`), you could do the following:
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
@@ -99,16 +88,13 @@ spec: # specification of the pod's contents
|
||||
args: ["/bin/echo \"${MESSAGE}\""]
|
||||
|
||||
```
|
||||
|
||||
However, a shell isn't necessary just to expand environment variables. Kubernetes will do it for you if you use [`$(ENVVAR)` syntax](/{{page.version}}/docs/design/expansion):
|
||||
|
||||
```yaml
|
||||
|
||||
command: ["/bin/echo"]
|
||||
command: ["/bin/echo"]
|
||||
args: ["$(MESSAGE)"]
|
||||
|
||||
```
|
||||
|
||||
## Viewing pod status
|
||||
|
||||
You can see the pod you created (actually all of your cluster's pods) using the `get` command.
|
||||
@@ -116,70 +102,58 @@ You can see the pod you created (actually all of your cluster's pods) using the
|
||||
If you're quick, it will look as follows:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
hello-world 0/1 Pending 0 0s
|
||||
|
||||
```
|
||||
|
||||
Initially, a newly created pod is unscheduled -- no node has been selected to run it. Scheduling happens after creation, but is fast, so you normally shouldn't see pods in an unscheduled state unless there's a problem.
|
||||
|
||||
After the pod has been scheduled, the image may need to be pulled to the node on which it was scheduled, if it hadn't been pulled already. After a few seconds, you should see the container running:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
hello-world 1/1 Running 0 5s
|
||||
|
||||
```
|
||||
|
||||
The `READY` column shows how many containers in the pod are running.
|
||||
|
||||
Almost immediately after it starts running, this command will terminate. `kubectl` shows that the container is no longer running and displays the exit status:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
hello-world 0/1 ExitCode:0 0 15s
|
||||
|
||||
```
|
||||
|
||||
## Viewing pod output
|
||||
|
||||
You probably want to see the output of the command you ran. As with [`docker logs`](https://docs.docker.com/userguide/usingdocker/), `kubectl logs` will show you the output:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl logs hello-world
|
||||
hello world
|
||||
|
||||
```
|
||||
|
||||
## Deleting pods
|
||||
|
||||
When you're done looking at the output, you should delete the pod:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl delete pod hello-world
|
||||
pods/hello-world
|
||||
|
||||
```
|
||||
|
||||
As with `create`, `kubectl` prints the resource type and name of the resource deleted when successful.
|
||||
|
||||
You can also use the resource/name format to specify the pod:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl delete pods/hello-world
|
||||
pods/hello-world
|
||||
|
||||
```
|
||||
|
||||
Terminated pods aren't currently automatically deleted, so that you can observe their final status, so be sure to clean up your dead pods.
|
||||
|
||||
On the other hand, containers and their logs are eventually deleted automatically in order to free up disk space on the nodes.
|
||||
|
||||
@@ -18,7 +18,6 @@ This guide uses a simple nginx server to demonstrate proof of concept. The same
|
||||
We did this in a previous example, but lets do it once again and focus on the networking perspective. Create an nginx pod, and note that it has a container port specification:
|
||||
|
||||
```yaml
|
||||
|
||||
$ cat nginxrc.yaml
|
||||
apiVersion: v1
|
||||
kind: ReplicationController
|
||||
@@ -38,28 +37,23 @@ spec:
|
||||
- containerPort: 80
|
||||
|
||||
```
|
||||
|
||||
This makes it accessible from any node in your cluster. Check the nodes the pod is running on:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f ./nginxrc.yaml
|
||||
$ kubectl get pods -l app=nginx -o wide
|
||||
my-nginx-6isf4 1/1 Running 0 2h e2e-test-beeps-minion-93ly
|
||||
my-nginx-t26zt 1/1 Running 0 2h e2e-test-beeps-minion-93ly
|
||||
|
||||
```
|
||||
|
||||
Check your pods' IPs:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get pods -l app=nginx -o json | grep podIP
|
||||
"podIP": "10.245.0.15",
|
||||
"podIP": "10.245.0.14",
|
||||
|
||||
```
|
||||
|
||||
You should be able to ssh into any node in your cluster and curl both IPs. Note that the containers are *not* using port 80 on the node, nor are there any special NAT rules to route traffic to the pod. This means you can run multiple nginx pods on the same node all using the same containerPort and access them from any other pod or node in your cluster using IP. Like Docker, ports can still be published to the host node's interface(s), but the need for this is radically diminished because of the networking model.
|
||||
|
||||
You can read more about [how we achieve this](../admin/networking.html#how-to-achieve-this) if you're curious.
|
||||
@@ -73,7 +67,6 @@ A Kubernetes Service is an abstraction which defines a logical set of Pods runni
|
||||
You can create a Service for your 2 nginx replicas with the following yaml:
|
||||
|
||||
```yaml
|
||||
|
||||
$ cat nginxsvc.yaml
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
@@ -89,23 +82,19 @@ spec:
|
||||
app: nginx
|
||||
|
||||
```
|
||||
|
||||
This specification will create a Service which targets TCP port 80 on any Pod with the `app=nginx` label, and expose it on an abstracted Service port (`targetPort`: is the port the container accepts traffic on, `port`: is the abstracted Service port, which can be any port other pods use to access the Service). View [service API object](http://kubernetes.io/v1.1/docs/api-reference/v1/definitions.html#_v1_service) to see the list of supported fields in service definition.
|
||||
Check your Service:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get svc
|
||||
NAME CLUSTER_IP EXTERNAL_IP PORT(S) SELECTOR AGE
|
||||
kubernetes 10.179.240.1 <none> 443/TCP <none> 8d
|
||||
nginxsvc 10.179.252.126 122.222.183.144 80/TCP,81/TCP,82/TCP run=nginx2 11m
|
||||
|
||||
```
|
||||
|
||||
As mentioned previously, a Service is backed by a group of pods. These pods are exposed through `endpoints`. The Service's selector will be evaluated continuously and the results will be POSTed to an Endpoints object also named `nginxsvc`. When a pod dies, it is automatically removed from the endpoints, and new pods matching the Service's selector will automatically get added to the endpoints. Check the endpoints, and note that the IPs are the same as the pods created in the first step:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl describe svc nginxsvc
|
||||
Name: nginxsvc
|
||||
Namespace: default
|
||||
@@ -123,7 +112,6 @@ NAME ENDPOINTS
|
||||
nginxsvc 10.245.0.14:80,10.245.0.15:80
|
||||
|
||||
```
|
||||
|
||||
You should now be able to curl the nginx Service on `10.0.116.146:80` from any node in your cluster. Note that the Service IP is completely virtual, it never hits the wire, if you're curious about how this works you can read more about the [service proxy](services.html#virtual-ips-and-service-proxies).
|
||||
|
||||
## Accessing the Service
|
||||
@@ -135,17 +123,14 @@ Kubernetes supports 2 primary modes of finding a Service - environment variables
|
||||
When a Pod is run on a Node, the kubelet adds a set of environment variables for each active Service. This introduces an ordering problem. To see why, inspect the environment of your running nginx pods:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl exec my-nginx-6isf4 -- printenv | grep SERVICE
|
||||
KUBERNETES_SERVICE_HOST=10.0.0.1
|
||||
KUBERNETES_SERVICE_PORT=443
|
||||
|
||||
```
|
||||
|
||||
Note there's no mention of your Service. This is because you created the replicas before the Service. Another disadvantage of doing this is that the scheduler might put both pods on the same machine, which will take your entire Service down if it dies. We can do this the right way by killing the 2 pods and waiting for the replication controller to recreate them. This time around the Service exists *before* the replicas. This will given you scheduler level Service spreading of your pods (provided all your nodes have equal capacity), as well as the right environment variables:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl scale rc my-nginx --replicas=0; kubectl scale rc my-nginx --replicas=2;
|
||||
$ kubectl get pods -l app=nginx -o wide
|
||||
NAME READY STATUS RESTARTS AGE NODE
|
||||
@@ -159,23 +144,19 @@ KUBERNETES_SERVICE_HOST=10.0.0.1
|
||||
NGINXSVC_SERVICE_PORT=80
|
||||
|
||||
```
|
||||
|
||||
### DNS
|
||||
|
||||
Kubernetes offers a DNS cluster addon Service that uses skydns to automatically assign dns names to other Services. You can check if it's running on your cluster:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get services kube-dns --namespace=kube-system
|
||||
NAME CLUSTER_IP EXTERNAL_IP PORT(S) SELECTOR AGE
|
||||
kube-dns 10.179.240.10 <none> 53/UDP,53/TCP k8s-app=kube-dns 8d
|
||||
|
||||
```
|
||||
|
||||
If it isn't running, you can [enable it](http://releases.k8s.io/release-1.1/cluster/addons/dns/README.md#how-do-i-configure-it). The rest of this section will assume you have a Service with a long lived IP (nginxsvc), and a dns server that has assigned a name to that IP (the kube-dns cluster addon), so you can talk to the Service from any pod in your cluster using standard methods (e.g. gethostbyname). Let's create another pod to test this:
|
||||
|
||||
```yaml
|
||||
|
||||
$ cat curlpod.yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
@@ -192,11 +173,9 @@ spec:
|
||||
restartPolicy: Always
|
||||
|
||||
```
|
||||
|
||||
And perform a lookup of the nginx Service
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f ./curlpod.yaml
|
||||
default/curlpod
|
||||
$ kubectl get pods curlpod
|
||||
@@ -210,7 +189,6 @@ Name: nginxsvc
|
||||
Address 1: 10.0.116.146
|
||||
|
||||
```
|
||||
|
||||
## Securing the Service
|
||||
|
||||
Till now we have only accessed the nginx server from within the cluster. Before exposing the Service to the internet, you want to make sure the communication channel is secure. For this, you will need:
|
||||
@@ -218,10 +196,9 @@ Till now we have only accessed the nginx server from within the cluster. Before
|
||||
* An nginx server configured to use the certificates
|
||||
* A [secret](secrets) that makes the certificates accessible to pods
|
||||
|
||||
You can acquire all these from the [nginx https example](../../examples/https-nginx/README), in short:
|
||||
You can acquire all these from the [nginx https example](https://github.com/kubernetes/kubernetes/tree/master/examples/https-nginx/README), in short:
|
||||
|
||||
```shell
|
||||
|
||||
$ make keys secret KEY=/tmp/nginx.key CERT=/tmp/nginx.crt SECRET=/tmp/secret.json
|
||||
$ kubectl create -f /tmp/secret.json
|
||||
secrets/nginxsecret
|
||||
@@ -231,11 +208,9 @@ default-token-il9rc kubernetes.io/service-account-token 1
|
||||
nginxsecret Opaque 2
|
||||
|
||||
```
|
||||
|
||||
Now modify your nginx replicas to start a https server using the certificate in the secret, and the Service, to expose both ports (80 and 443):
|
||||
|
||||
```yaml
|
||||
|
||||
$ cat nginx-app.yaml
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
@@ -282,14 +257,12 @@ spec:
|
||||
name: secret-volume
|
||||
|
||||
```
|
||||
|
||||
Noteworthy points about the nginx-app manifest:
|
||||
- It contains both rc and service specification in the same file
|
||||
- The [nginx server](../../examples/https-nginx/default.conf) serves http traffic on port 80 and https traffic on 443, and nginx Service exposes both ports.
|
||||
- The [nginx server](https://github.com/kubernetes/kubernetes/tree/master/examples/https-nginx/default.conf) serves http traffic on port 80 and https traffic on 443, and nginx Service exposes both ports.
|
||||
- Each container has access to the keys through a volume mounted at /etc/nginx/ssl. This is setup *before* the nginx server is started.
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl delete rc,svc -l app=nginx; kubectl create -f ./nginx-app.yaml
|
||||
replicationcontrollers/my-nginx
|
||||
services/nginxsvc
|
||||
@@ -297,11 +270,9 @@ services/nginxsvc
|
||||
replicationcontrollers/my-nginx
|
||||
|
||||
```
|
||||
|
||||
At this point you can reach the nginx server from any node.
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get pods -o json | grep -i podip
|
||||
"podIP": "10.1.0.80",
|
||||
node $ curl -k https://10.1.0.80
|
||||
@@ -309,13 +280,11 @@ node $ curl -k https://10.1.0.80
|
||||
<h1>Welcome to nginx!</h1>
|
||||
|
||||
```
|
||||
|
||||
Note how we supplied the `-k` parameter to curl in the last step, this is because we don't know anything about the pods running nginx at certificate generation time,
|
||||
so we have to tell curl to ignore the CName mismatch. By creating a Service we linked the CName used in the certificate with the actual DNS name used by pods during Service lookup.
|
||||
Lets test this from a pod (the same secret is being reused for simplicity, the pod only needs nginx.crt to access the Service):
|
||||
|
||||
```shell
|
||||
|
||||
$ cat curlpod.yaml
|
||||
vapiVersion: v1
|
||||
kind: ReplicationController
|
||||
@@ -355,13 +324,11 @@ $ kubectl exec curlpod -- curl https://nginxsvc --cacert /etc/nginx/ssl/nginx.cr
|
||||
...
|
||||
|
||||
```
|
||||
|
||||
## Exposing the Service
|
||||
|
||||
For some parts of your applications you may want to expose a Service onto an external IP address. Kubernetes supports two ways of doing this: NodePorts and LoadBalancers. The Service created in the last section already used `NodePort`, so your nginx https replica is ready to serve traffic on the internet if your node has a public IP.
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get svc nginxsvc -o json | grep -i nodeport -C 5
|
||||
{
|
||||
"name": "http",
|
||||
@@ -394,11 +361,9 @@ $ curl https://104.197.63.17:30645 -k
|
||||
<h1>Welcome to nginx!</h1>
|
||||
|
||||
```
|
||||
|
||||
Lets now recreate the Service to use a cloud load balancer, just change the `Type` of Service in the nginx-app.yaml from `NodePort` to `LoadBalancer`:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl delete rc, svc -l app=nginx
|
||||
$ kubectl create -f ./nginx-app.yaml
|
||||
$ kubectl get svc nginxsvc
|
||||
@@ -410,7 +375,6 @@ $ curl https://162.22.184.144 -k
|
||||
<title>Welcome to nginx!</title>
|
||||
|
||||
```
|
||||
|
||||
The IP address in the `EXTERNAL_IP` column is the one that is available on the public internet. The `CLUSTER_IP` is only available inside your
|
||||
cluster/private cloud network.
|
||||
|
||||
|
||||
@@ -5,44 +5,37 @@ kubectl port-forward forwards connections to a local port to a port on a pod. It
|
||||
|
||||
## Creating a Redis master
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl create examples/redis/redis-master.yaml
|
||||
pods/redis-master
|
||||
pods/redis-master
|
||||
|
||||
|
||||
```
|
||||
wait until the Redis master pod is Running and Ready,
|
||||
wait until the Redis master pod is Running and Ready,
|
||||
|
||||
```shell
|
||||
$ kubectl get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
$ kubectl get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
redis-master 2/2 Running 0 41s
|
||||
redis-master 2/2 Running 0 41s
|
||||
|
||||
```
|
||||
## Connecting to the Redis master[a]
|
||||
|
||||
## Connecting to the Redis master[a]
|
||||
The Redis master is listening on port 6397, to verify this,
|
||||
|
||||
```shell
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get pods redis-master -t='{{(index (index .spec.containers 0).ports 0).containerPort}}{{"\n"}}'
|
||||
6379
|
||||
|
||||
|
||||
```
|
||||
then we forward the port 6379 on the local workstation to the port 6379 of pod redis-master,
|
||||
|
||||
```shell
|
||||
then we forward the port 6379 on the local workstation to the port 6379 of pod redis-master,
|
||||
|
||||
$ kubectl port-forward redis-master 6379:6379
|
||||
I0710 14:43:38.274550 3655 portforward.go:225] Forwarding from 127.0.0.1:6379 -> 6379
|
||||
I0710 14:43:38.274797 3655 portforward.go:225] Forwarding from [::1]:6379 -> 6379
|
||||
$ kubectl port-forward redis-master 6379:6379
|
||||
|
||||
```
|
||||
To verify the connection is successful, we run a redis-cli on the local workstation,
|
||||
|
||||
```
|
||||
|
||||
```shell
|
||||
$ redis-cli
|
||||
@@ -8,11 +8,10 @@ You have seen the [basics](accessing-the-cluster) about `kubectl proxy` and `api
|
||||
|
||||
kube-ui is deployed as a cluster add-on. To find its apiserver proxy URL,
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl cluster-info | grep "KubeUI"
|
||||
KubeUI is running at https://173.255.119.104/api/v1/proxy/namespaces/kube-system/services/kube-ui
|
||||
KubeUI is running at https://173.255.119.104/api/v1/proxy/namespaces/kube-system/services/kube-ui
|
||||
|
||||
|
||||
```
|
||||
if this command does not find the URL, try the steps [here](ui.html#accessing-the-ui).
|
||||
|
||||
@@ -20,9 +19,8 @@ if this command does not find the URL, try the steps [here](ui.html#accessing-th
|
||||
## Connecting to the kube-ui service from your local workstation
|
||||
|
||||
The above proxy URL is an access to the kube-ui service provided by the apiserver. To access it, you still need to authenticate to the apiserver. `kubectl proxy` can handle the authentication.
|
||||
The above proxy URL is an access to the kube-ui service provided by the apiserver. To access it, you still need to authenticate to the apiserver. `kubectl proxy` can handle the authentication.
|
||||
|
||||
```shell
|
||||
$ kubectl proxy --port=8001
|
||||
|
||||
$ kubectl proxy --port=8001
|
||||
Starting to serve on localhost:8001
|
||||
|
||||
@@ -34,12 +34,10 @@ Currently the list of all services that are running at the time when the contain
|
||||
For a service named **foo** that maps to a container port named **bar**, the following variables are defined:
|
||||
|
||||
```shell
|
||||
|
||||
FOO_SERVICE_HOST=<the host the service is running on>
|
||||
FOO_SERVICE_PORT=<the port the service is running on>
|
||||
|
||||
```
|
||||
|
||||
Services have dedicated IP address, and are also surfaced to the container via DNS (If [DNS addon](http://releases.k8s.io/release-1.1/cluster/addons/dns/) is enabled). Of course DNS is still not an enumerable protocol, so we will continue to provide environment variables so that containers can do discovery.
|
||||
|
||||
## Container Hooks
|
||||
|
||||
@@ -19,30 +19,24 @@ clear what is expected, this document will use the following conventions.
|
||||
If the command "COMMAND" is expected to run in a `Pod` and produce "OUTPUT":
|
||||
|
||||
```shell
|
||||
|
||||
u@pod$ COMMAND
|
||||
OUTPUT
|
||||
|
||||
```
|
||||
|
||||
If the command "COMMAND" is expected to run on a `Node` and produce "OUTPUT":
|
||||
|
||||
```shell
|
||||
|
||||
u@node$ COMMAND
|
||||
OUTPUT
|
||||
|
||||
```
|
||||
|
||||
If the command is "kubectl ARGS":
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl ARGS
|
||||
OUTPUT
|
||||
|
||||
```
|
||||
|
||||
## Running commands in a Pod
|
||||
|
||||
For many steps here you will want to see what a `Pod` running in the cluster
|
||||
@@ -50,7 +44,6 @@ sees. Kubernetes does not directly support interactive `Pod`s (yet), but you ca
|
||||
approximate it:
|
||||
|
||||
```shell
|
||||
|
||||
$ cat <<EOF | kubectl create -f -
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
@@ -67,25 +60,20 @@ EOF
|
||||
pods/busybox-sleep
|
||||
|
||||
```
|
||||
|
||||
Now, when you need to run a command (even an interactive shell) in a `Pod`-like
|
||||
context, use:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl exec busybox-sleep -- <COMMAND>
|
||||
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl exec -ti busybox-sleep sh
|
||||
/ #
|
||||
|
||||
```
|
||||
|
||||
## Setup
|
||||
|
||||
For the purposes of this walk-through, let's run some `Pod`s. Since you're
|
||||
@@ -93,7 +81,6 @@ probably debugging your own `Service` you can substitute your own details, or yo
|
||||
can follow along and get a second data point.
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl run hostnames --image=gcr.io/google_containers/serve_hostname \
|
||||
--labels=app=hostnames \
|
||||
--port=9376 \
|
||||
@@ -102,12 +89,10 @@ CONTROLLER CONTAINER(S) IMAGE(S) SELECTOR
|
||||
hostnames hostnames gcr.io/google_containers/serve_hostname app=hostnames 3
|
||||
|
||||
```
|
||||
|
||||
Note that this is the same as if you had started the `ReplicationController` with
|
||||
the following YAML:
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
kind: ReplicationController
|
||||
metadata:
|
||||
@@ -129,11 +114,9 @@ spec:
|
||||
protocol: TCP
|
||||
|
||||
```
|
||||
|
||||
Confirm your `Pod`s are running:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get pods -l app=hostnames
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
hostnames-0uton 1/1 Running 0 12s
|
||||
@@ -141,7 +124,6 @@ hostnames-bvc05 1/1 Running 0 12s
|
||||
hostnames-yp2kp 1/1 Running 0 12s
|
||||
|
||||
```
|
||||
|
||||
## Does the Service exist?
|
||||
|
||||
The astute reader will have noticed that we did not actually create a `Service`
|
||||
@@ -153,53 +135,42 @@ have another `Pod` that consumes this `Service` by name you would get something
|
||||
like:
|
||||
|
||||
```shell
|
||||
|
||||
u@pod$ wget -qO- hostnames
|
||||
wget: bad address 'hostname'
|
||||
|
||||
```
|
||||
|
||||
or:
|
||||
|
||||
```shell
|
||||
|
||||
u@pod$ echo $HOSTNAMES_SERVICE_HOST
|
||||
|
||||
```
|
||||
|
||||
So the first thing to check is whether that `Service` actually exists:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get svc hostnames
|
||||
Error from server: service "hostnames" not found
|
||||
|
||||
```
|
||||
|
||||
So we have a culprit, let's create the `Service`. As before, this is for the
|
||||
walk-through - you can use your own `Service`'s details here.
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl expose rc hostnames --port=80 --target-port=9376
|
||||
service "hostnames" exposed
|
||||
|
||||
```
|
||||
|
||||
And read it back, just to be sure:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get svc hostnames
|
||||
NAME CLUSTER_IP EXTERNAL_IP PORT(S) SELECTOR AGE
|
||||
hostnames 10.0.0.1 <none> 80/TCP run=hostnames 1h
|
||||
|
||||
```
|
||||
|
||||
As before, this is the same as if you had started the `Service` with YAML:
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
@@ -214,7 +185,6 @@ spec:
|
||||
targetPort: 9376
|
||||
|
||||
```
|
||||
|
||||
Now you can confirm that the `Service` exists.
|
||||
|
||||
## Does the Service work by DNS?
|
||||
@@ -222,7 +192,6 @@ Now you can confirm that the `Service` exists.
|
||||
From a `Pod` in the same `Namespace`:
|
||||
|
||||
```shell
|
||||
|
||||
u@pod$ nslookup hostnames
|
||||
Server: 10.0.0.10
|
||||
Address: 10.0.0.10#53
|
||||
@@ -231,12 +200,10 @@ Name: hostnames
|
||||
Address: 10.0.1.175
|
||||
|
||||
```
|
||||
|
||||
If this fails, perhaps your `Pod` and `Service` are in different
|
||||
`Namespace`s, try a namespace-qualified name:
|
||||
|
||||
```shell
|
||||
|
||||
u@pod$ nslookup hostnames.default
|
||||
Server: 10.0.0.10
|
||||
Address: 10.0.0.10#53
|
||||
@@ -245,12 +212,10 @@ Name: hostnames.default
|
||||
Address: 10.0.1.175
|
||||
|
||||
```
|
||||
|
||||
If this works, you'll need to ensure that `Pod`s and `Service`s run in the same
|
||||
`Namespace`. If this still fails, try a fully-qualified name:
|
||||
|
||||
```shell
|
||||
|
||||
u@pod$ nslookup hostnames.default.svc.cluster.local
|
||||
Server: 10.0.0.10
|
||||
Address: 10.0.0.10#53
|
||||
@@ -259,7 +224,6 @@ Name: hostnames.default.svc.cluster.local
|
||||
Address: 10.0.1.175
|
||||
|
||||
```
|
||||
|
||||
Note the suffix here: "default.svc.cluster.local". The "default" is the
|
||||
`Namespace` we're operating in. The "svc" denotes that this is a `Service`.
|
||||
The "cluster.local" is your cluster domain.
|
||||
@@ -268,7 +232,6 @@ You can also try this from a `Node` in the cluster (note: 10.0.0.10 is my DNS
|
||||
`Service`):
|
||||
|
||||
```shell
|
||||
|
||||
u@node$ nslookup hostnames.default.svc.cluster.local 10.0.0.10
|
||||
Server: 10.0.0.10
|
||||
Address: 10.0.0.10#53
|
||||
@@ -277,7 +240,6 @@ Name: hostnames.default.svc.cluster.local
|
||||
Address: 10.0.1.175
|
||||
|
||||
```
|
||||
|
||||
If you are able to do a fully-qualified name lookup but not a relative one, you
|
||||
need to check that your `kubelet` is running with the right flags.
|
||||
The `--cluster-dns` flag needs to point to your DNS `Service`'s IP and the
|
||||
@@ -292,7 +254,6 @@ can take a step back and see what else is not working. The Kubernetes master
|
||||
`Service` should always work:
|
||||
|
||||
```shell
|
||||
|
||||
u@pod$ nslookup kubernetes.default
|
||||
Server: 10.0.0.10
|
||||
Address 1: 10.0.0.10
|
||||
@@ -301,7 +262,6 @@ Name: kubernetes
|
||||
Address 1: 10.0.0.1
|
||||
|
||||
```
|
||||
|
||||
If this fails, you might need to go to the kube-proxy section of this doc, or
|
||||
even go back to the top of this document and start over, but instead of
|
||||
debugging your own `Service`, debug DNS.
|
||||
@@ -312,7 +272,6 @@ The next thing to test is whether your `Service` works at all. From a
|
||||
`Node` in your cluster, access the `Service`'s IP (from `kubectl get` above).
|
||||
|
||||
```shell
|
||||
|
||||
u@node$ curl 10.0.1.175:80
|
||||
hostnames-0uton
|
||||
|
||||
@@ -323,7 +282,6 @@ u@node$ curl 10.0.1.175:80
|
||||
hostnames-bvc05
|
||||
|
||||
```
|
||||
|
||||
If your `Service` is working, you should get correct responses. If not, there
|
||||
are a number of things that could be going wrong. Read on.
|
||||
|
||||
@@ -334,7 +292,6 @@ It might sound silly, but you should really double and triple check that your
|
||||
verify it:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get service hostnames -o json
|
||||
{
|
||||
"kind": "Service",
|
||||
@@ -373,7 +330,6 @@ $ kubectl get service hostnames -o json
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Is the port you are trying to access in `spec.ports[]`? Is the `targetPort`
|
||||
correct for your `Pod`s? If you meant it to be a numeric port, is it a number
|
||||
(9376) or a string "9376"? If you meant it to be a named port, do your `Pod`s
|
||||
@@ -389,7 +345,6 @@ actually being selected by the `Service`.
|
||||
Earlier we saw that the `Pod`s were running. We can re-check that:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get pods -l app=hostnames
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
hostnames-0uton 1/1 Running 0 1h
|
||||
@@ -397,7 +352,6 @@ hostnames-bvc05 1/1 Running 0 1h
|
||||
hostnames-yp2kp 1/1 Running 0 1h
|
||||
|
||||
```
|
||||
|
||||
The "AGE" column says that these `Pod`s are about an hour old, which implies that
|
||||
they are running fine and not crashing.
|
||||
|
||||
@@ -406,13 +360,11 @@ has. Inside the Kubernetes system is a control loop which evaluates the
|
||||
selector of every `Service` and save the results into an `Endpoints` object.
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get endpoints hostnames
|
||||
NAME ENDPOINTS
|
||||
hostnames 10.244.0.5:9376,10.244.0.6:9376,10.244.0.7:9376
|
||||
|
||||
```
|
||||
|
||||
This confirms that the control loop has found the correct `Pod`s for your
|
||||
`Service`. If the `hostnames` row is blank, you should check that the
|
||||
`spec.selector` field of your `Service` actually selects for `metadata.labels`
|
||||
@@ -425,7 +377,6 @@ Let's check that the `Pod`s are actually working - we can bypass the `Service`
|
||||
mechanism and go straight to the `Pod`s.
|
||||
|
||||
```shell
|
||||
|
||||
u@pod$ wget -qO- 10.244.0.5:9376
|
||||
hostnames-0uton
|
||||
|
||||
@@ -436,7 +387,6 @@ u@pod$ wget -qO- 10.244.0.7:9376
|
||||
hostnames-yp2kp
|
||||
|
||||
```
|
||||
|
||||
We expect each `Pod` in the `Endpoints` list to return its own hostname. If
|
||||
this is not what happens (or whatever the correct behavior is for your own
|
||||
`Pod`s), you should investigate what's happening there. You might find
|
||||
@@ -455,12 +405,10 @@ Confirm that `kube-proxy` is running on your `Node`s. You should get something
|
||||
like the below:
|
||||
|
||||
```shell
|
||||
|
||||
u@node$ ps auxw | grep kube-proxy
|
||||
root 4194 0.4 0.1 101864 17696 ? Sl Jul04 25:43 /usr/local/bin/kube-proxy --master=https://kubernetes-master --kubeconfig=/var/lib/kube-proxy/kubeconfig --v=2
|
||||
|
||||
```
|
||||
|
||||
Next, confirm that it is not failing something obvious, like contacting the
|
||||
master. To do this, you'll have to look at the logs. Accessing the logs
|
||||
depends on your `Node` OS. On some OSes it is a file, such as
|
||||
@@ -468,7 +416,6 @@ depends on your `Node` OS. On some OSes it is a file, such as
|
||||
should see something like:
|
||||
|
||||
```shell
|
||||
|
||||
I0707 17:34:53.945651 30031 server.go:88] Running in resource-only container "/kube-proxy"
|
||||
I0707 17:34:53.945921 30031 proxier.go:121] Setting proxy IP to 10.240.115.247 and initializing iptables
|
||||
I0707 17:34:54.053023 30031 roundrobin.go:262] LoadBalancerRR: Setting endpoints for default/kubernetes: to [10.240.169.188:443]
|
||||
@@ -489,7 +436,6 @@ I0707 17:35:46.015868 30031 proxysocket.go:246] New UDP connection from 10.244
|
||||
I0707 17:35:46.017061 30031 proxysocket.go:246] New UDP connection from 10.244.3.2:55471
|
||||
|
||||
```
|
||||
|
||||
If you see error messages about not being able to contact the master, you
|
||||
should double-check your `Node` configuration and installation steps.
|
||||
|
||||
@@ -500,13 +446,11 @@ rules which implement `Service`s. Let's check that those rules are getting
|
||||
written.
|
||||
|
||||
```shell
|
||||
|
||||
u@node$ iptables-save | grep hostnames
|
||||
-A KUBE-PORTALS-CONTAINER -d 10.0.1.175/32 -p tcp -m comment --comment "default/hostnames:default" -m tcp --dport 80 -j REDIRECT --to-ports 48577
|
||||
-A KUBE-PORTALS-HOST -d 10.0.1.175/32 -p tcp -m comment --comment "default/hostnames:default" -m tcp --dport 80 -j DNAT --to-destination 10.240.115.247:48577
|
||||
|
||||
```
|
||||
|
||||
There should be 2 rules for each port on your `Service` (just one in this
|
||||
example) - a "KUBE-PORTALS-CONTAINER" and a "KUBE-PORTALS-HOST". If you do
|
||||
not see these, try restarting `kube-proxy` with the `-V` flag set to 4, and
|
||||
@@ -517,32 +461,26 @@ then look at the logs again.
|
||||
Assuming you do see the above rules, try again to access your `Service` by IP:
|
||||
|
||||
```shell
|
||||
|
||||
u@node$ curl 10.0.1.175:80
|
||||
hostnames-0uton
|
||||
|
||||
```
|
||||
|
||||
If this fails, we can try accessing the proxy directly. Look back at the
|
||||
`iptables-save` output above, and extract the port number that `kube-proxy` is
|
||||
using for your `Service`. In the above examples it is "48577". Now connect to
|
||||
that:
|
||||
|
||||
```shell
|
||||
|
||||
u@node$ curl localhost:48577
|
||||
hostnames-yp2kp
|
||||
|
||||
```
|
||||
|
||||
If this still fails, look at the `kube-proxy` logs for specific lines like:
|
||||
|
||||
```shell
|
||||
|
||||
Setting endpoints for default/hostnames:default to [10.244.0.5:9376 10.244.0.6:9376 10.244.0.7:9376]
|
||||
|
||||
```
|
||||
|
||||
If you don't see those, try restarting `kube-proxy` with the `-V` flag set to 4, and
|
||||
then look at the logs again.
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ A replication controller simply ensures that a specified number of pod "replicas
|
||||
The replication controller created to run nginx by `kubectl run` in the [Quick start](quick-start) could be specified using YAML as follows:
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
kind: ReplicationController
|
||||
metadata:
|
||||
@@ -33,7 +32,6 @@ spec:
|
||||
- containerPort: 80
|
||||
|
||||
```
|
||||
|
||||
Some differences compared to specifying just a pod are that the `kind` is `ReplicationController`, the number of `replicas` desired is specified, and the pod specification is under the `template` field. The names of the pods don't need to be specified explicitly because they are generated from the name of the replication controller.
|
||||
View the [replication controller API
|
||||
object](http://kubernetes.io/v1.1/docs/api-reference/v1/definitions.html#_v1_replicationcontroller)
|
||||
@@ -42,12 +40,10 @@ to view the list of supported fields.
|
||||
This replication controller can be created using `create`, just as with pods:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f ./nginx-rc.yaml
|
||||
replicationcontrollers/my-nginx
|
||||
|
||||
```
|
||||
|
||||
Unlike in the case where you directly create pods, a replication controller replaces pods that are deleted or terminated for any reason, such as in the case of node failure. For this reason, we recommend that you use a replication controller for a continuously running application even if your application requires only a single pod, in which case you can omit `replicas` and it will default to a single replica.
|
||||
|
||||
## Viewing replication controller status
|
||||
@@ -55,37 +51,31 @@ Unlike in the case where you directly create pods, a replication controller repl
|
||||
You can view the replication controller you created using `get`:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get rc
|
||||
CONTROLLER CONTAINER(S) IMAGE(S) SELECTOR REPLICAS
|
||||
my-nginx nginx nginx app=nginx 2
|
||||
|
||||
```
|
||||
|
||||
This tells you that your controller will ensure that you have two nginx replicas.
|
||||
|
||||
You can see those replicas using `get`, just as with pods you created directly:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
my-nginx-065jq 1/1 Running 0 51s
|
||||
my-nginx-buaiq 1/1 Running 0 51s
|
||||
|
||||
```
|
||||
|
||||
## Deleting replication controllers
|
||||
|
||||
When you want to kill your application, delete your replication controller, as in the [Quick start](quick-start):
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl delete rc my-nginx
|
||||
replicationcontrollers/my-nginx
|
||||
|
||||
```
|
||||
|
||||
By default, this will also cause the pods managed by the replication controller to be deleted. If there were a large number of pods, this may take a while to complete. If you want to leave the pods running, specify `--cascade=false`.
|
||||
|
||||
If you try to delete the pods before deleting the replication controller, it will just replace them, as it is supposed to do.
|
||||
@@ -95,33 +85,27 @@ If you try to delete the pods before deleting the replication controller, it wil
|
||||
Kubernetes uses user-defined key-value attributes called [*labels*](labels) to categorize and identify sets of resources, such as pods and replication controllers. The example above specified a single label in the pod template, with key `app` and value `nginx`. All pods created carry that label, which can be viewed using `-L`:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get pods -L app
|
||||
NAME READY STATUS RESTARTS AGE APP
|
||||
my-nginx-afv12 0/1 Running 0 3s nginx
|
||||
my-nginx-lg99z 0/1 Running 0 3s nginx
|
||||
|
||||
```
|
||||
|
||||
The labels from the pod template are copied to the replication controller's labels by default, as well -- all resources in Kubernetes support labels:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get rc my-nginx -L app
|
||||
CONTROLLER CONTAINER(S) IMAGE(S) SELECTOR REPLICAS APP
|
||||
my-nginx nginx nginx app=nginx 2 nginx
|
||||
|
||||
```
|
||||
|
||||
More importantly, the pod template's labels are used to create a [`selector`](labels.html#label-selectors) that will match pods carrying those labels. You can see this field by requesting it using the [Go template output format of `kubectl get`](kubectl/kubectl_get):
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get rc my-nginx -o template --template="{{.spec.selector}}"
|
||||
map[app:nginx]
|
||||
|
||||
```
|
||||
|
||||
You could also specify the `selector` explicitly, such as if you wanted to specify labels in the pod template that you didn't want to select on, but you should ensure that the selector will match the labels of the pods created from the pod template, and that it won't match pods created by other replication controllers. The most straightforward way to ensure the latter is to create a unique label value for the replication controller, and to specify it in both the pod template's labels and in the selector.
|
||||
|
||||
## What's next?
|
||||
|
||||
@@ -37,7 +37,6 @@ bring up 3 nginx pods.
|
||||
<!-- BEGIN MUNGE: EXAMPLE nginx-deployment.yaml -->
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
@@ -56,56 +55,48 @@ spec:
|
||||
- containerPort: 80
|
||||
|
||||
```
|
||||
|
||||
[Download example](nginx-deployment.yaml)
|
||||
<!-- END MUNGE: EXAMPLE nginx-deployment.yaml -->
|
||||
|
||||
Run the example by downloading the example file and then running this command:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f docs/user-guide/nginx-deployment.yaml
|
||||
deployment "nginx-deployment" created
|
||||
|
||||
```
|
||||
|
||||
Running a get immediately will give:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get deployments
|
||||
NAME UPDATEDREPLICAS AGE
|
||||
nginx-deployment 0/3 8s
|
||||
|
||||
```
|
||||
|
||||
This indicates that deployment is trying to update 3 replicas. It has not
|
||||
updated any one of those yet.
|
||||
|
||||
Running a get again after a minute, will give:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get deployments
|
||||
NAME UPDATEDREPLICAS AGE
|
||||
nginx-deployment 3/3 1m
|
||||
|
||||
```
|
||||
|
||||
This indicates that deployent has created all the 3 replicas.
|
||||
Running ```kubectl get rc``` and ```kubectl get pods``` will show the replication controller (RC) and pods created.
|
||||
Running ```kubectl get rc```
|
||||
and ```kubectl get pods```
|
||||
will show the replication controller (RC) and pods created.
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get rc
|
||||
CONTROLLER CONTAINER(S) IMAGE(S) SELECTOR REPLICAS AGE
|
||||
REPLICAS AGE
|
||||
deploymentrc-1975012602 nginx nginx:1.7.9 deployment.kubernetes.io/podTemplateHash=1975012602,app=nginx 3 2m
|
||||
|
||||
```
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
deploymentrc-1975012602-4f2tb 1/1 Running 0 1m
|
||||
@@ -113,7 +104,6 @@ deploymentrc-1975012602-j975u 1/1 Running 0 1m
|
||||
deploymentrc-1975012602-uashb 1/1 Running 0 1m
|
||||
|
||||
```
|
||||
|
||||
The created RC will ensure that there are 3 nginx pods at all time.
|
||||
|
||||
## Updating a Deployment
|
||||
@@ -125,7 +115,6 @@ For this, we update our deployment to be as follows:
|
||||
<!-- BEGIN MUNGE: EXAMPLE new-nginx-deployment.yaml -->
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
@@ -144,68 +133,57 @@ spec:
|
||||
- containerPort: 80
|
||||
|
||||
```
|
||||
|
||||
[Download example](new-nginx-deployment.yaml)
|
||||
<!-- END MUNGE: EXAMPLE new-nginx-deployment.yaml -->
|
||||
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl apply -f docs/user-guide/new-nginx-deployment.yaml
|
||||
deployment "nginx-deployment" configured
|
||||
|
||||
```
|
||||
|
||||
Running a get immediately will still give:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get deployments
|
||||
NAME UPDATEDREPLICAS AGE
|
||||
nginx-deployment 3/3 8s
|
||||
|
||||
```
|
||||
|
||||
This indicates that deployment status has not been updated yet (it is still
|
||||
showing old status).
|
||||
Running a get again after a minute, will give:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get deployments
|
||||
NAME UPDATEDREPLICAS AGE
|
||||
nginx-deployment 1/3 1m
|
||||
|
||||
```
|
||||
|
||||
This indicates that deployment has updated one of the three pods that it needs
|
||||
to update.
|
||||
Eventually, it will get around to updating all the pods.
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get deployments
|
||||
NAME UPDATEDREPLICAS AGE
|
||||
nginx-deployment 3/3 3m
|
||||
|
||||
```
|
||||
|
||||
We can run ```kubectl get rc``` to see that deployment updated the pods by creating a new RC
|
||||
We can run ```kubectl get rc```
|
||||
to see that deployment updated the pods by creating a new RC
|
||||
which it scaled up to 3 and scaled down the old RC to 0.
|
||||
|
||||
```shell
|
||||
|
||||
kubectl get rc
|
||||
CONTROLLER CONTAINER(S) IMAGE(S) SELECTOR REPLICAS AGE
|
||||
deploymentrc-1562004724 nginx nginx:1.9.1 deployment.kubernetes.io/podTemplateHash=1562004724,app=nginx 3 5m
|
||||
deploymentrc-1975012602 nginx nginx:1.7.9 deployment.kubernetes.io/podTemplateHash=1975012602,app=nginx 0 7m
|
||||
|
||||
```
|
||||
|
||||
Running get pods, will only show the new pods.
|
||||
|
||||
```shell
|
||||
|
||||
kubectl get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
deploymentrc-1562004724-0tgk5 1/1 Running 0 9m
|
||||
@@ -213,7 +191,6 @@ deploymentrc-1562004724-1rkfl 1/1 Running 0 8m
|
||||
deploymentrc-1562004724-6v702 1/1 Running 0 8m
|
||||
|
||||
```
|
||||
|
||||
Next time we want to update pods, we can just update the deployment again.
|
||||
|
||||
Deployment ensures that not all pods are down while they are being updated. By
|
||||
@@ -223,7 +200,6 @@ it first created a new pod, then deleted some old pods and created new ones. It
|
||||
does not kill old pods until a sufficient number of new pods have come up.
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl describe deployments
|
||||
Name: nginx-deployment
|
||||
Namespace: default
|
||||
@@ -245,7 +221,6 @@ Events:
|
||||
1m 1m 1 {deployment-controller } ScalingRC Scaled down rc deploymentrc-1975012602 to 0
|
||||
|
||||
```
|
||||
|
||||
Here we see that when we first created the deployment, it created an RC and scaled it up to 3 replicas directly.
|
||||
When we updated the deployment, it created a new RC and scaled it up to 1 and then scaled down the old RC by 1, so that at least 2 pods were available at all times.
|
||||
It then scaled up the new RC to 3 and when those pods were ready, it scaled down the old RC to 0.
|
||||
|
||||
@@ -12,7 +12,6 @@ How do I run an nginx container and expose it to the world? Checkout [kubectl ru
|
||||
With docker:
|
||||
|
||||
```shell
|
||||
|
||||
$ docker run -d --restart=always -e DOMAIN=cluster --name nginx-app -p 80:80 nginx
|
||||
a9ec34d9878748d2f33dc20cb25c714ff21da8d40558b45bfaec9955859075d0
|
||||
$ docker ps
|
||||
@@ -20,11 +19,9 @@ CONTAINER ID IMAGE COMMAND CREATED
|
||||
a9ec34d98787 nginx "nginx -g 'daemon of 2 seconds ago Up 2 seconds 0.0.0.0:80->80/tcp, 443/tcp nginx-app
|
||||
|
||||
```
|
||||
|
||||
With kubectl:
|
||||
|
||||
```shell
|
||||
|
||||
# start the pod running nginx
|
||||
$ kubectl run --image=nginx nginx-app --port=80 --env="DOMAIN=cluster"
|
||||
replicationcontroller "nginx-app" created
|
||||
@@ -32,17 +29,14 @@ replicationcontroller "nginx-app" created
|
||||
$ kubectl expose rc nginx-app --port=80 --name=nginx-http
|
||||
|
||||
```
|
||||
|
||||
With kubectl, we create a [replication controller](replication-controller) which will make sure that N pods are running nginx (where N is the number of replicas stated in the spec, which defaults to 1). We also create a [service](services) with a selector that matches the replication controller's selector. See the [Quick start](quick-start) for more information.
|
||||
|
||||
By default images are run in the background, similar to `docker run -d ...`, if you want to run things in the foreground, use:
|
||||
|
||||
```shell
|
||||
|
||||
kubectl run [-i] [--tty] --attach <name> --image=<image>
|
||||
|
||||
```
|
||||
|
||||
Unlike `docker run ...`, if `--attach` is specified, we attach to `stdin`, `stdout` and `stderr`, there is no ability to control which streams are attached (`docker -a ...`).
|
||||
|
||||
Because we start a replication controller for your container, it will be restarted if you terminate the attached process (e.g. `ctrl-c`), this is different than `docker run -it`.
|
||||
@@ -55,23 +49,19 @@ How do I list what is currently running? Checkout [kubectl get](kubectl/kubectl_
|
||||
With docker:
|
||||
|
||||
```shell
|
||||
|
||||
$ docker ps
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
a9ec34d98787 nginx "nginx -g 'daemon of About an hour ago Up About an hour 0.0.0.0:80->80/tcp, 443/tcp nginx-app
|
||||
|
||||
```
|
||||
|
||||
With kubectl:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get po
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
nginx-app-5jyvm 1/1 Running 0 1h
|
||||
|
||||
```
|
||||
|
||||
#### docker attach
|
||||
|
||||
How do I attach to a process that is already running in a container? Checkout [kubectl attach](kubectl/kubectl_attach)
|
||||
@@ -79,7 +69,6 @@ How do I attach to a process that is already running in a container? Checkout [
|
||||
With docker:
|
||||
|
||||
```shell
|
||||
|
||||
$ docker ps
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
a9ec34d98787 nginx "nginx -g 'daemon of 8 minutes ago Up 8 minutes 0.0.0.0:80->80/tcp, 443/tcp nginx-app
|
||||
@@ -87,11 +76,9 @@ $ docker attach -it a9ec34d98787
|
||||
...
|
||||
|
||||
```
|
||||
|
||||
With kubectl:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
nginx-app-5jyvm 1/1 Running 0 10m
|
||||
@@ -100,7 +87,6 @@ $ kubectl attach -it nginx-app-5jyvm
|
||||
|
||||
|
||||
```
|
||||
|
||||
#### docker exec
|
||||
|
||||
How do I execute a command in a container? Checkout [kubectl exec](kubectl/kubectl_exec).
|
||||
@@ -108,8 +94,6 @@ How do I execute a command in a container? Checkout [kubectl exec](kubectl/kubec
|
||||
With docker:
|
||||
|
||||
```shell
|
||||
|
||||
|
||||
$ docker ps
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
a9ec34d98787 nginx "nginx -g 'daemon of 8 minutes ago Up 8 minutes 0.0.0.0:80->80/tcp, 443/tcp nginx-app
|
||||
@@ -118,12 +102,9 @@ a9ec34d98787
|
||||
|
||||
|
||||
```
|
||||
|
||||
With kubectl:
|
||||
|
||||
```shell
|
||||
|
||||
|
||||
$ kubectl get po
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
nginx-app-5jyvm 1/1 Running 0 10m
|
||||
@@ -132,34 +113,27 @@ nginx-app-5jyvm
|
||||
|
||||
|
||||
```
|
||||
|
||||
What about interactive commands?
|
||||
|
||||
|
||||
With docker:
|
||||
|
||||
```shell
|
||||
|
||||
|
||||
$ docker exec -ti a9ec34d98787 /bin/sh
|
||||
|
||||
# exit
|
||||
|
||||
|
||||
```
|
||||
|
||||
With kubectl:
|
||||
|
||||
```shell
|
||||
|
||||
|
||||
$ kubectl exec -ti nginx-app-5jyvm -- /bin/sh
|
||||
|
||||
# exit
|
||||
|
||||
|
||||
```
|
||||
|
||||
For more information see [Getting into containers](getting-into-containers).
|
||||
|
||||
#### docker logs
|
||||
@@ -170,39 +144,30 @@ How do I follow stdout/stderr of a running process? Checkout [kubectl logs](kube
|
||||
With docker:
|
||||
|
||||
```shell
|
||||
|
||||
|
||||
$ docker logs -f a9e
|
||||
192.168.9.1 - - [14/Jul/2015:01:04:02 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.35.0" "-"
|
||||
192.168.9.1 - - [14/Jul/2015:01:04:03 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.35.0" "-"
|
||||
|
||||
|
||||
```
|
||||
|
||||
With kubectl:
|
||||
|
||||
```shell
|
||||
|
||||
|
||||
$ kubectl logs -f nginx-app-zibvs
|
||||
10.240.63.110 - - [14/Jul/2015:01:09:01 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.26.0" "-"
|
||||
10.240.63.110 - - [14/Jul/2015:01:09:02 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.26.0" "-"
|
||||
|
||||
|
||||
```
|
||||
|
||||
Now's a good time to mention slight difference between pods and containers; by default pods will not terminate if their processes exit. Instead it will restart the process. This is similar to the docker run option `--restart=always` with one major difference. In docker, the output for each invocation of the process is concatenated but for Kubernetes, each invocation is separate. To see the output from a previous run in Kubernetes, do this:
|
||||
|
||||
```shell
|
||||
|
||||
|
||||
$ kubectl logs --previous nginx-app-zibvs
|
||||
10.240.63.110 - - [14/Jul/2015:01:09:01 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.26.0" "-"
|
||||
10.240.63.110 - - [14/Jul/2015:01:09:02 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.26.0" "-"
|
||||
|
||||
|
||||
```
|
||||
|
||||
See [Logging](logging) for more information.
|
||||
|
||||
#### docker stop and docker rm
|
||||
@@ -212,8 +177,6 @@ How do I stop and delete a running process? Checkout [kubectl delete](kubectl/ku
|
||||
With docker
|
||||
|
||||
```shell
|
||||
|
||||
|
||||
$ docker ps
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
a9ec34d98787 nginx "nginx -g 'daemon of 22 hours ago Up 22 hours 0.0.0.0:80->80/tcp, 443/tcp nginx-app
|
||||
@@ -224,12 +187,9 @@ a9ec34d98787
|
||||
|
||||
|
||||
```
|
||||
|
||||
With kubectl:
|
||||
|
||||
```shell
|
||||
|
||||
|
||||
$ kubectl get rc nginx-app
|
||||
CONTROLLER CONTAINER(S) IMAGE(S) SELECTOR REPLICAS
|
||||
nginx-app nginx-app nginx run=nginx-app 1
|
||||
@@ -244,7 +204,6 @@ NAME READY STATUS RESTARTS AGE
|
||||
|
||||
|
||||
```
|
||||
|
||||
Notice that we don't delete the pod directly. With kubectl we want to delete the replication controller that owns the pod. If we delete the pod directly, the replication controller will recreate the pod.
|
||||
|
||||
#### docker login
|
||||
@@ -258,8 +217,6 @@ How do I get the version of my client and server? Checkout [kubectl version](kub
|
||||
With docker:
|
||||
|
||||
```shell
|
||||
|
||||
|
||||
$ docker version
|
||||
Client version: 1.7.0
|
||||
Client API version: 1.19
|
||||
@@ -274,19 +231,15 @@ OS/Arch (server): linux/amd64
|
||||
|
||||
|
||||
```
|
||||
|
||||
With kubectl:
|
||||
|
||||
```shell
|
||||
|
||||
|
||||
$ kubectl version
|
||||
Client Version: version.Info{Major:"0", Minor:"20.1", GitVersion:"v0.20.1", GitCommit:"", GitTreeState:"not a git tree"}
|
||||
Server Version: version.Info{Major:"0", Minor:"21+", GitVersion:"v0.21.1-411-g32699e873ae1ca-dirty", GitCommit:"32699e873ae1caa01812e41de7eab28df4358ee4", GitTreeState:"dirty"}
|
||||
|
||||
|
||||
```
|
||||
|
||||
#### docker info
|
||||
|
||||
How do I get miscellaneous info about my environment and configuration? Checkout [kubectl cluster-info](kubectl/kubectl_cluster-info).
|
||||
@@ -294,8 +247,6 @@ How do I get miscellaneous info about my environment and configuration? Checkout
|
||||
With docker:
|
||||
|
||||
```shell
|
||||
|
||||
|
||||
$ docker info
|
||||
Containers: 40
|
||||
Images: 168
|
||||
@@ -316,12 +267,9 @@ WARNING: No swap limit support
|
||||
|
||||
|
||||
```
|
||||
|
||||
With kubectl:
|
||||
|
||||
```shell
|
||||
|
||||
|
||||
$ kubectl cluster-info
|
||||
Kubernetes master is running at https://108.59.85.141
|
||||
KubeDNS is running at https://108.59.85.141/api/v1/proxy/namespaces/kube-system/services/kube-dns
|
||||
@@ -332,6 +280,3 @@ InfluxDB is running at https://108.59.85.141/api/v1/proxy/namespaces/kube-system
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -51,7 +51,6 @@ downward API:
|
||||
<!-- BEGIN MUNGE: EXAMPLE downward-api/dapi-pod.yaml -->
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
@@ -77,7 +76,6 @@ spec:
|
||||
restartPolicy: Never
|
||||
|
||||
```
|
||||
|
||||
[Download example](downward-api/dapi-pod.yaml)
|
||||
<!-- END MUNGE: EXAMPLE downward-api/dapi-pod.yaml -->
|
||||
|
||||
@@ -92,12 +90,10 @@ volume type and the different items represent the files to be created. `fieldPat
|
||||
Downward API volume permits to store more complex data like [`metadata.labels`](labels) and [`metadata.annotations`](annotations). Currently key/value pair set fields are saved using `key="value"` format:
|
||||
|
||||
```
|
||||
|
||||
key1="value1"
|
||||
key2="value2"
|
||||
|
||||
```
|
||||
|
||||
In future, it will be possible to specify an output format option.
|
||||
|
||||
Downward API volumes can expose:
|
||||
@@ -118,7 +114,6 @@ This is an example of a pod that consumes its labels and annotations via the dow
|
||||
<!-- BEGIN MUNGE: EXAMPLE downward-api/volume/dapi-volume.yaml -->
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
@@ -151,7 +146,6 @@ spec:
|
||||
fieldPath: metadata.annotations
|
||||
|
||||
```
|
||||
|
||||
[Download example](downward-api/volume/dapi-volume.yaml)
|
||||
<!-- END MUNGE: EXAMPLE downward-api/volume/dapi-volume.yaml -->
|
||||
|
||||
|
||||
@@ -19,24 +19,18 @@ Use the [`examples/downward-api/dapi-pod.yaml`](dapi-pod.yaml) file to create a
|
||||
downward API.
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f docs/user-guide/downward-api/dapi-pod.yaml
|
||||
|
||||
```
|
||||
|
||||
### Examine the logs
|
||||
|
||||
This pod runs the `env` command in a container that consumes the downward API. You can grep
|
||||
through the pod logs to see that the pod was injected with the correct values:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl logs dapi-test-pod | grep POD_
|
||||
2015-04-30T20:22:18.568024817Z MY_POD_NAME=dapi-test-pod
|
||||
2015-04-30T20:22:18.568087688Z MY_POD_NAMESPACE=default
|
||||
2015-04-30T20:22:18.568092435Z MY_POD_IP=10.0.1.6
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -19,24 +19,18 @@ Use the [`examples/downward-api/dapi-pod.yaml`](dapi-pod.yaml) file to create a
|
||||
downward API.
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f docs/user-guide/downward-api/dapi-pod.yaml
|
||||
|
||||
```
|
||||
|
||||
### Examine the logs
|
||||
|
||||
This pod runs the `env` command in a container that consumes the downward API. You can grep
|
||||
through the pod logs to see that the pod was injected with the correct values:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl logs dapi-test-pod | grep POD_
|
||||
2015-04-30T20:22:18.568024817Z MY_POD_NAME=dapi-test-pod
|
||||
2015-04-30T20:22:18.568087688Z MY_POD_NAMESPACE=default
|
||||
2015-04-30T20:22:18.568092435Z MY_POD_IP=10.0.1.6
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -13,24 +13,22 @@ Supported metadata fields:
|
||||
|
||||
### Step Zero: Prerequisites
|
||||
|
||||
This example assumes you have a Kubernetes cluster installed and running, and the ```kubectl``` command line tool somewhere in your path. Please see the [gettingstarted](..//{{page.version}}/docs/getting-started-guides/) for installation instructions for your platform.
|
||||
This example assumes you have a Kubernetes cluster installed and running, and the ```kubectl```
|
||||
command line tool somewhere in your path. Please see the [gettingstarted](..//{{page.version}}/docs/getting-started-guides/) for installation instructions for your platform.
|
||||
|
||||
### Step One: Create the pod
|
||||
|
||||
Use the `docs/user-guide/downward-api/dapi-volume.yaml` file to create a Pod with a downward API volume which stores pod labels and pod annotations to `/etc/labels` and `/etc/annotations` respectively.
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f docs/user-guide/downward-api/volume/dapi-volume.yaml
|
||||
|
||||
```
|
||||
|
||||
### Step Two: Examine pod/container output
|
||||
|
||||
The pod displays (every 5 seconds) the content of the dump files which can be executed via the usual `kubectl log` command
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl logs kubernetes-downwardapi-volume-example
|
||||
cluster="test-cluster1"
|
||||
rack="rack-22"
|
||||
@@ -41,13 +39,11 @@ kubernetes.io/config.seen="2015-08-24T13:47:23.432459138Z"
|
||||
kubernetes.io/config.source="api"
|
||||
|
||||
```
|
||||
|
||||
### Internals
|
||||
|
||||
In pod's `/etc` directory one may find the file created by the plugin (system files elided):
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl exec kubernetes-downwardapi-volume-example -i -t -- sh
|
||||
/ # ls -laR /etc
|
||||
/etc:
|
||||
@@ -68,5 +64,4 @@ drwxrwxrwt 3 0 0 180 Aug 24 13:03 ..
|
||||
/ #
|
||||
|
||||
```
|
||||
|
||||
The file `labels` is stored in a temporary directory (`..2015_08_24_13_03_44259413923` in the example above) which is symlinked to by `..downwardapi`. Symlinks for annotations and labels in `/etc` point to files containing the actual metadata through the `..downwardapi` indirection. This structure allows for dynamic atomic refresh of the metadata: updates are written to a new temporary directory, and the `..downwardapi` symlink is updated atomically using `rename(2)`.
|
||||
@@ -13,24 +13,22 @@ Supported metadata fields:
|
||||
|
||||
### Step Zero: Prerequisites
|
||||
|
||||
This example assumes you have a Kubernetes cluster installed and running, and the ```kubectl``` command line tool somewhere in your path. Please see the [gettingstarted](..//{{page.version}}/docs/getting-started-guides/) for installation instructions for your platform.
|
||||
This example assumes you have a Kubernetes cluster installed and running, and the ```kubectl```
|
||||
command line tool somewhere in your path. Please see the [gettingstarted](..//{{page.version}}/docs/getting-started-guides/) for installation instructions for your platform.
|
||||
|
||||
### Step One: Create the pod
|
||||
|
||||
Use the `docs/user-guide/downward-api/dapi-volume.yaml` file to create a Pod with a downward API volume which stores pod labels and pod annotations to `/etc/labels` and `/etc/annotations` respectively.
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f docs/user-guide/downward-api/volume/dapi-volume.yaml
|
||||
|
||||
```
|
||||
|
||||
### Step Two: Examine pod/container output
|
||||
|
||||
The pod displays (every 5 seconds) the content of the dump files which can be executed via the usual `kubectl log` command
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl logs kubernetes-downwardapi-volume-example
|
||||
cluster="test-cluster1"
|
||||
rack="rack-22"
|
||||
@@ -41,13 +39,11 @@ kubernetes.io/config.seen="2015-08-24T13:47:23.432459138Z"
|
||||
kubernetes.io/config.source="api"
|
||||
|
||||
```
|
||||
|
||||
### Internals
|
||||
|
||||
In pod's `/etc` directory one may find the file created by the plugin (system files elided):
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl exec kubernetes-downwardapi-volume-example -i -t -- sh
|
||||
/ # ls -laR /etc
|
||||
/etc:
|
||||
@@ -68,5 +64,4 @@ drwxrwxrwt 3 0 0 180 Aug 24 13:03 ..
|
||||
/ #
|
||||
|
||||
```
|
||||
|
||||
The file `labels` is stored in a temporary directory (`..2015_08_24_13_03_44259413923` in the example above) which is symlinked to by `..downwardapi`. Symlinks for annotations and labels in `/etc` point to files containing the actual metadata through the `..downwardapi` indirection. This structure allows for dynamic atomic refresh of the metadata: updates are written to a new temporary directory, and the `..downwardapi` symlink is updated atomically using `rename(2)`.
|
||||
@@ -44,8 +44,7 @@ your service.
|
||||
Run `curl <public ip>:80` to query the service. You should get
|
||||
something like this back:
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
Pod Name: show-rc-xxu6i
|
||||
Pod Namespace: default
|
||||
USER_VAR: important information
|
||||
@@ -66,8 +65,7 @@ Backend Container
|
||||
Backend Pod Name: backend-rc-6qiya
|
||||
Backend Namespace: default
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
First the frontend pod's information is printed. The pod name and
|
||||
[namespace](/{{page.version}}/docs/design/namespaces) are retrieved from the
|
||||
[Downward API](/{{page.version}}/docs/user-guide/downward-api). Next, `USER_VAR` is the name of
|
||||
|
||||
@@ -44,8 +44,7 @@ your service.
|
||||
Run `curl <public ip>:80` to query the service. You should get
|
||||
something like this back:
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
Pod Name: show-rc-xxu6i
|
||||
Pod Namespace: default
|
||||
USER_VAR: important information
|
||||
@@ -66,8 +65,7 @@ Backend Container
|
||||
Backend Pod Name: backend-rc-6qiya
|
||||
Backend Namespace: default
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
First the frontend pod's information is printed. The pod name and
|
||||
[namespace](/{{page.version}}/docs/design/namespaces) are retrieved from the
|
||||
[Downward API](/{{page.version}}/docs/user-guide/downward-api). Next, `USER_VAR` is the name of
|
||||
|
||||
@@ -10,29 +10,26 @@ Kubernetes exposes [services](services.html#environment-variables) through envir
|
||||
|
||||
We first create a pod and a service,
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl create -f examples/guestbook/redis-master-controller.yaml
|
||||
$ kubectl create -f examples/guestbook/redis-master-service.yaml
|
||||
```
|
||||
|
||||
```
|
||||
wait until the pod is Running and Ready,
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl get pod
|
||||
NAME READY REASON RESTARTS AGE
|
||||
redis-master-ft9ex 1/1 Running 0 12s
|
||||
```
|
||||
|
||||
```
|
||||
then we can check the environment variables of the pod,
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl exec redis-master-ft9ex env
|
||||
...
|
||||
REDIS_MASTER_SERVICE_PORT=6379
|
||||
REDIS_MASTER_SERVICE_HOST=10.0.0.219
|
||||
...
|
||||
```
|
||||
|
||||
```
|
||||
We can use these environment variables in applications to find the service.
|
||||
|
||||
|
||||
@@ -41,32 +38,28 @@ We can use these environment variables in applications to find the service.
|
||||
It is convenient to use `kubectl exec` to check if the volumes are mounted as expected.
|
||||
We first create a Pod with a volume mounted at /data/redis,
|
||||
|
||||
```shell
|
||||
```shell
|
||||
kubectl create -f docs/user-guide/walkthrough/pod-redis.yaml
|
||||
```
|
||||
|
||||
```
|
||||
wait until the pod is Running and Ready,
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl get pods
|
||||
NAME READY REASON RESTARTS AGE
|
||||
storage 1/1 Running 0 1m
|
||||
```
|
||||
|
||||
```
|
||||
we then use `kubectl exec` to verify that the volume is mounted at /data/redis,
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl exec storage ls /data
|
||||
redis
|
||||
```
|
||||
|
||||
```
|
||||
## Using kubectl exec to open a bash terminal in a pod
|
||||
|
||||
After all, open a terminal in a pod is the most direct way to introspect the pod. Assuming the pod/storage is still running, run
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl exec -ti storage -- bash
|
||||
root@storage:/data#
|
||||
```
|
||||
|
||||
```
|
||||
This gets you a terminal.
|
||||
@@ -27,7 +27,6 @@ First, we will start a replication controller running the image and expose it as
|
||||
<a name="kubectl-run"></a>
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl run php-apache --image=gcr.io/google_containers/hpa-example --requests=cpu=200m
|
||||
replicationcontroller "php-apache" created
|
||||
|
||||
@@ -35,11 +34,9 @@ $ kubectl expose rc php-apache --port=80 --type=LoadBalancer
|
||||
service "php-apache" exposed
|
||||
|
||||
```
|
||||
|
||||
Now, we will wait some time and verify that both the replication controller and the service were correctly created and are running. We will also determine the IP address of the service:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
php-apache-wa3t1 1/1 Running 0 12m
|
||||
@@ -48,21 +45,17 @@ $ kubectl describe services php-apache | grep "LoadBalancer Ingress"
|
||||
LoadBalancer Ingress: 146.148.24.244
|
||||
|
||||
```
|
||||
|
||||
We may now check that php-apache server works correctly by calling ``curl`` with the service's IP:
|
||||
|
||||
```shell
|
||||
|
||||
$ curl http://146.148.24.244
|
||||
OK!
|
||||
|
||||
```
|
||||
|
||||
Please notice that when exposing the service we assumed that our cluster runs on a provider which supports load balancers (e.g.: on GCE).
|
||||
If load balancers are not supported (e.g.: on Vagrant), we can expose php-apache service as ``ClusterIP`` and connect to it using the proxy on the master:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl expose rc php-apache --port=80 --type=ClusterIP
|
||||
service "php-apache" exposed
|
||||
|
||||
@@ -73,15 +66,12 @@ $ curl -k -u <admin>:<password> https://146.148.6.215/api/v1/proxy/namespaces/de
|
||||
OK!
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Step Two: Create horizontal pod autoscaler
|
||||
|
||||
Now that the server is running, we will create a horizontal pod autoscaler for it.
|
||||
To create it, we will use the [hpa-php-apache.yaml](hpa-php-apache.yaml) file, which looks like this:
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
@@ -98,7 +88,6 @@ spec:
|
||||
targetPercentage: 50
|
||||
|
||||
```
|
||||
|
||||
This defines a horizontal pod autoscaler that maintains between 1 and 10 replicas of the Pods
|
||||
controlled by the php-apache replication controller we created in the first step of these instructions.
|
||||
Roughly speaking, the horizontal autoscaler will increase and decrease the number of replicas
|
||||
@@ -109,32 +98,26 @@ See [here](/{{page.version}}/docs/design/horizontal-pod-autoscaler.html#autoscal
|
||||
We will create the autoscaler by executing the following command:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f docs/user-guide/horizontal-pod-autoscaling/hpa-php-apache.yaml
|
||||
horizontalpodautoscaler "php-apache" created
|
||||
|
||||
```
|
||||
|
||||
Alternatively, we can create the autoscaler using [kubectl autoscale](../kubectl/kubectl_autoscale).
|
||||
The following command will create the equivalent autoscaler as defined in the [hpa-php-apache.yaml](hpa-php-apache.yaml) file:
|
||||
|
||||
```
|
||||
|
||||
$ kubectl autoscale rc php-apache --cpu-percent=50 --min=1 --max=10
|
||||
replicationcontroller "php-apache" autoscaled
|
||||
|
||||
```
|
||||
|
||||
We may check the current status of autoscaler by running:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get hpa
|
||||
NAME REFERENCE TARGET CURRENT MINPODS MAXPODS AGE
|
||||
php-apache ReplicationController/default/php-apache/ 50% 0% 1 10 27s
|
||||
|
||||
```
|
||||
|
||||
Please note that the current CPU consumption is 0% as we are not sending any requests to the server
|
||||
(the ``CURRENT`` column shows the average across all the pods controlled by the corresponding replication controller).
|
||||
|
||||
@@ -144,44 +127,35 @@ Now, we will see how the autoscaler reacts on the increased load of the server.
|
||||
We will start an infinite loop of queries to our server (please run it in a different terminal):
|
||||
|
||||
```shell
|
||||
|
||||
$ while true; do curl http://146.148.6.244; done
|
||||
|
||||
```
|
||||
|
||||
We may examine, how CPU load was increased (the results should be visible after about 3-4 minutes) by executing:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get hpa
|
||||
NAME REFERENCE TARGET CURRENT MINPODS MAXPODS AGE
|
||||
php-apache ReplicationController/default/php-apache/ 50% 305% 1 10 4m
|
||||
|
||||
```
|
||||
|
||||
In the case presented here, it bumped CPU consumption to 305% of the request.
|
||||
As a result, the replication controller was resized to 7 replicas:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get rc
|
||||
CONTROLLER CONTAINER(S) IMAGE(S) SELECTOR REPLICAS AGE
|
||||
php-apache php-apache gcr.io/google_containers/hpa-example run=php-apache 7 18m
|
||||
|
||||
```
|
||||
|
||||
Now, we may increase the load even more by running yet another infinite loop of queries (in yet another terminal):
|
||||
|
||||
```shell
|
||||
|
||||
$ while true; do curl http://146.148.6.244; done
|
||||
|
||||
```
|
||||
|
||||
In the case presented here, it increased the number of serving pods to 10:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get hpa
|
||||
NAME REFERENCE TARGET CURRENT MINPODS MAXPODS AGE
|
||||
php-apache ReplicationController/default/php-apache/ 50% 65% 1 10 14m
|
||||
@@ -191,14 +165,12 @@ CONTROLLER CONTAINER(S) IMAGE(S) SELECTOR
|
||||
php-apache php-apache gcr.io/google_containers/hpa-example run=php-apache 10 24m
|
||||
|
||||
```
|
||||
|
||||
## Step Four: Stop load
|
||||
|
||||
We will finish our example by stopping the user load.
|
||||
We will terminate both infinite ``while`` loops sending requests to the server and verify the result state:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get hpa
|
||||
NAME REFERENCE TARGET CURRENT MINPODS MAXPODS AGE
|
||||
php-apache ReplicationController/default/php-apache/ 50% 0% 1 10 21m
|
||||
@@ -208,7 +180,6 @@ CONTROLLER CONTAINER(S) IMAGE(S) SELECTOR
|
||||
php-apache php-apache gcr.io/google_containers/hpa-example run=php-apache 1 31m
|
||||
|
||||
```
|
||||
|
||||
As we see, in the presented case CPU utilization dropped to 0, and the number of replicas dropped to 1.
|
||||
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ First, we will start a replication controller running the image and expose it as
|
||||
<a name="kubectl-run"></a>
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl run php-apache --image=gcr.io/google_containers/hpa-example --requests=cpu=200m
|
||||
replicationcontroller "php-apache" created
|
||||
|
||||
@@ -35,11 +34,9 @@ $ kubectl expose rc php-apache --port=80 --type=LoadBalancer
|
||||
service "php-apache" exposed
|
||||
|
||||
```
|
||||
|
||||
Now, we will wait some time and verify that both the replication controller and the service were correctly created and are running. We will also determine the IP address of the service:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
php-apache-wa3t1 1/1 Running 0 12m
|
||||
@@ -48,21 +45,17 @@ $ kubectl describe services php-apache | grep "LoadBalancer Ingress"
|
||||
LoadBalancer Ingress: 146.148.24.244
|
||||
|
||||
```
|
||||
|
||||
We may now check that php-apache server works correctly by calling ``curl`` with the service's IP:
|
||||
|
||||
```shell
|
||||
|
||||
$ curl http://146.148.24.244
|
||||
OK!
|
||||
|
||||
```
|
||||
|
||||
Please notice that when exposing the service we assumed that our cluster runs on a provider which supports load balancers (e.g.: on GCE).
|
||||
If load balancers are not supported (e.g.: on Vagrant), we can expose php-apache service as ``ClusterIP`` and connect to it using the proxy on the master:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl expose rc php-apache --port=80 --type=ClusterIP
|
||||
service "php-apache" exposed
|
||||
|
||||
@@ -73,15 +66,12 @@ $ curl -k -u <admin>:<password> https://146.148.6.215/api/v1/proxy/namespaces/de
|
||||
OK!
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Step Two: Create horizontal pod autoscaler
|
||||
|
||||
Now that the server is running, we will create a horizontal pod autoscaler for it.
|
||||
To create it, we will use the [hpa-php-apache.yaml](hpa-php-apache.yaml) file, which looks like this:
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
@@ -98,7 +88,6 @@ spec:
|
||||
targetPercentage: 50
|
||||
|
||||
```
|
||||
|
||||
This defines a horizontal pod autoscaler that maintains between 1 and 10 replicas of the Pods
|
||||
controlled by the php-apache replication controller we created in the first step of these instructions.
|
||||
Roughly speaking, the horizontal autoscaler will increase and decrease the number of replicas
|
||||
@@ -109,32 +98,26 @@ See [here](/{{page.version}}/docs/design/horizontal-pod-autoscaler.html#autoscal
|
||||
We will create the autoscaler by executing the following command:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f docs/user-guide/horizontal-pod-autoscaling/hpa-php-apache.yaml
|
||||
horizontalpodautoscaler "php-apache" created
|
||||
|
||||
```
|
||||
|
||||
Alternatively, we can create the autoscaler using [kubectl autoscale](../kubectl/kubectl_autoscale).
|
||||
The following command will create the equivalent autoscaler as defined in the [hpa-php-apache.yaml](hpa-php-apache.yaml) file:
|
||||
|
||||
```
|
||||
|
||||
$ kubectl autoscale rc php-apache --cpu-percent=50 --min=1 --max=10
|
||||
replicationcontroller "php-apache" autoscaled
|
||||
|
||||
```
|
||||
|
||||
We may check the current status of autoscaler by running:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get hpa
|
||||
NAME REFERENCE TARGET CURRENT MINPODS MAXPODS AGE
|
||||
php-apache ReplicationController/default/php-apache/ 50% 0% 1 10 27s
|
||||
|
||||
```
|
||||
|
||||
Please note that the current CPU consumption is 0% as we are not sending any requests to the server
|
||||
(the ``CURRENT`` column shows the average across all the pods controlled by the corresponding replication controller).
|
||||
|
||||
@@ -144,44 +127,35 @@ Now, we will see how the autoscaler reacts on the increased load of the server.
|
||||
We will start an infinite loop of queries to our server (please run it in a different terminal):
|
||||
|
||||
```shell
|
||||
|
||||
$ while true; do curl http://146.148.6.244; done
|
||||
|
||||
```
|
||||
|
||||
We may examine, how CPU load was increased (the results should be visible after about 3-4 minutes) by executing:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get hpa
|
||||
NAME REFERENCE TARGET CURRENT MINPODS MAXPODS AGE
|
||||
php-apache ReplicationController/default/php-apache/ 50% 305% 1 10 4m
|
||||
|
||||
```
|
||||
|
||||
In the case presented here, it bumped CPU consumption to 305% of the request.
|
||||
As a result, the replication controller was resized to 7 replicas:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get rc
|
||||
CONTROLLER CONTAINER(S) IMAGE(S) SELECTOR REPLICAS AGE
|
||||
php-apache php-apache gcr.io/google_containers/hpa-example run=php-apache 7 18m
|
||||
|
||||
```
|
||||
|
||||
Now, we may increase the load even more by running yet another infinite loop of queries (in yet another terminal):
|
||||
|
||||
```shell
|
||||
|
||||
$ while true; do curl http://146.148.6.244; done
|
||||
|
||||
```
|
||||
|
||||
In the case presented here, it increased the number of serving pods to 10:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get hpa
|
||||
NAME REFERENCE TARGET CURRENT MINPODS MAXPODS AGE
|
||||
php-apache ReplicationController/default/php-apache/ 50% 65% 1 10 14m
|
||||
@@ -191,14 +165,12 @@ CONTROLLER CONTAINER(S) IMAGE(S) SELECTOR
|
||||
php-apache php-apache gcr.io/google_containers/hpa-example run=php-apache 10 24m
|
||||
|
||||
```
|
||||
|
||||
## Step Four: Stop load
|
||||
|
||||
We will finish our example by stopping the user load.
|
||||
We will terminate both infinite ``while`` loops sending requests to the server and verify the result state:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get hpa
|
||||
NAME REFERENCE TARGET CURRENT MINPODS MAXPODS AGE
|
||||
php-apache ReplicationController/default/php-apache/ 50% 0% 1 10 21m
|
||||
@@ -208,7 +180,6 @@ CONTROLLER CONTAINER(S) IMAGE(S) SELECTOR
|
||||
php-apache php-apache gcr.io/google_containers/hpa-example run=php-apache 1 31m
|
||||
|
||||
```
|
||||
|
||||
As we see, in the presented case CPU utilization dropped to 0, and the number of replicas dropped to 1.
|
||||
|
||||
|
||||
|
||||
@@ -74,7 +74,6 @@ example, run these on your desktop/laptop:
|
||||
Verify by creating a pod that uses a private image, e.g.:
|
||||
|
||||
```yaml
|
||||
|
||||
$ cat <<EOF > /tmp/private-image-test-1.yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
@@ -92,26 +91,20 @@ pods/private-image-test-1
|
||||
$
|
||||
|
||||
```
|
||||
|
||||
If everything is working, then, after a few moments, you should see:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl logs private-image-test-1
|
||||
SUCCESS
|
||||
|
||||
```
|
||||
|
||||
If it failed, then you will see:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl describe pods/private-image-test-1 | grep "Failed"
|
||||
Fri, 26 Jun 2015 15:36:13 -0700 Fri, 26 Jun 2015 15:39:13 -0700 19 {kubelet node-i2hq} spec.containers{uses-private-image} failed Failed to pull image "user/privaterepo:v1": Error: image user/privaterepo:v1 not found
|
||||
|
||||
```
|
||||
|
||||
|
||||
You must ensure all nodes in the cluster have the same `.dockercfg`. Otherwise, pods will run on
|
||||
some nodes and fail to run on others. For example, if you use node autoscaling, then each instance
|
||||
template needs to include the `.dockercfg` or mount a drive that contains it.
|
||||
@@ -153,7 +146,6 @@ First, create a `.dockercfg`, such as running `docker login <registry.domain>`.
|
||||
Then put the resulting `.dockercfg` file into a [secret resource](secrets). For example:
|
||||
|
||||
```shell
|
||||
|
||||
$ docker login
|
||||
Username: janedoe
|
||||
Password: '�?'�?'�?'�?'�?'�?'�?'�?'�?'�?'�?
|
||||
@@ -182,7 +174,6 @@ secrets/myregistrykey
|
||||
$
|
||||
|
||||
```
|
||||
|
||||
If you get the error message `error: no objects passed to create`, it may mean the base64 encoded string is invalid.
|
||||
If you get an error message like `Secret "myregistrykey" is invalid: data[.dockercfg]: invalid value ...` it means
|
||||
the data was successfully un-base64 encoded, but could not be parsed as a dockercfg file.
|
||||
@@ -193,7 +184,6 @@ Now, you can create pods which reference that secret by adding an `imagePullSecr
|
||||
section to a pod definition.
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
@@ -206,7 +196,6 @@ spec:
|
||||
- name: myregistrykey
|
||||
|
||||
```
|
||||
|
||||
This needs to be done for each pod that is using a private registry.
|
||||
However, setting of this field can be automated by setting the imagePullSecrets
|
||||
in a [serviceAccount](service-accounts) resource.
|
||||
|
||||
@@ -18,26 +18,22 @@ Throughout this doc you will see a few terms that are sometimes used interchanga
|
||||
Typically, services and pods have IPs only routable by the cluster network. All traffic that ends up at an edge router is either dropped or forwarded elsewhere. Conceptually, this might look like:
|
||||
|
||||
```
|
||||
|
||||
internet
|
||||
internet
|
||||
|
|
||||
------------
|
||||
[ Services ]
|
||||
|
||||
```
|
||||
|
||||
An Ingress is a collection of rules that allow inbound connections to reach the cluster services.
|
||||
|
||||
```
|
||||
|
||||
internet
|
||||
internet
|
||||
|
|
||||
[ Ingress ]
|
||||
--|-----|--
|
||||
[ Services ]
|
||||
|
||||
```
|
||||
|
||||
It can be configured to give services externally-reachable urls, load balance traffic, terminate SSL, offer name based virtual hosting etc. Users request ingress by POSTing the Ingress resource to the API server. An [Ingress controller](#ingress-controllers) is responsible for fulfilling the Ingress, usually with a loadbalancer, though it may also configure your edge router or additional frontends to help handle the traffic in an HA manner.
|
||||
|
||||
## Prerequisites
|
||||
@@ -53,7 +49,6 @@ Before you start using the Ingress resource, there are a few things you should u
|
||||
A minimal Ingress might look like:
|
||||
|
||||
```yaml
|
||||
|
||||
01. apiVersion: extensions/v1beta1
|
||||
02. kind: Ingress
|
||||
03. metadata:
|
||||
@@ -68,7 +63,6 @@ A minimal Ingress might look like:
|
||||
12. servicePort: 80
|
||||
|
||||
```
|
||||
|
||||
*POSTing this to the API server will have no effect if you have not configured an [Ingress controller](#ingress-controllers).*
|
||||
|
||||
__Lines 1-4__: As with all other Kubernetes config, an Ingress needs `apiVersion`, `kind`, and `metadata` fields. For general information about working with config files, see [here](simple-yaml), [here](configuring-containers), and [here](working-with-resources).
|
||||
@@ -94,7 +88,6 @@ There are existing Kubernetes concepts that allow you to expose a single service
|
||||
<!-- BEGIN MUNGE: EXAMPLE ingress.yaml -->
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
@@ -105,20 +98,17 @@ spec:
|
||||
servicePort: 80
|
||||
|
||||
```
|
||||
|
||||
[Download example](ingress.yaml)
|
||||
<!-- END MUNGE: EXAMPLE ingress.yaml -->
|
||||
|
||||
If you create it using `kubectl -f` you should see:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get ing
|
||||
NAME RULE BACKEND ADDRESS
|
||||
test-ingress - testsvc:80 107.178.254.228
|
||||
|
||||
```
|
||||
|
||||
Where `107.178.254.228` is the IP allocated by the Ingress controller to satisfy this Ingress. The `RULE` column shows that all traffic send to the IP is directed to the Kubernetes Service listed under `BACKEND`.
|
||||
|
||||
### Simple fanout
|
||||
@@ -126,16 +116,13 @@ Where `107.178.254.228` is the IP allocated by the Ingress controller to satisfy
|
||||
As described previously, pods within kubernetes have ips only visible on the cluster network, so we need something at the edge accepting ingress traffic and proxying it to the right endpoints. This component is usually a highly available loadbalancer/s. An Ingress allows you to keep the number of loadbalancers down to a minimum, for example, a setup like:
|
||||
|
||||
```
|
||||
|
||||
foo.bar.com -> 178.91.123.132 -> / foo s1:80
|
||||
/ bar s2:80
|
||||
|
||||
```
|
||||
|
||||
would require an Ingress such as:
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
@@ -155,11 +142,9 @@ spec:
|
||||
servicePort: 80
|
||||
|
||||
```
|
||||
|
||||
When you create the Ingress with `kubectl create -f`:
|
||||
|
||||
```
|
||||
|
||||
$ kubectl get ing
|
||||
NAME RULE BACKEND ADDRESS
|
||||
test -
|
||||
@@ -168,7 +153,6 @@ test -
|
||||
/bar s2:80
|
||||
|
||||
```
|
||||
|
||||
The Ingress controller will provision an implementation specific loadbalancer that satisfies the Ingress, as long as the services (s1, s2) exist. When it has done so, you will see the address of the loadbalancer under the last column of the Ingress.
|
||||
|
||||
### Name based virtual hosting
|
||||
@@ -176,18 +160,14 @@ The Ingress controller will provision an implementation specific loadbalancer th
|
||||
Name-based virtual hosts use multiple host names for the same IP address.
|
||||
|
||||
```
|
||||
|
||||
|
||||
foo.bar.com --| |-> foo.bar.com s1:80
|
||||
| 178.91.123.132 |
|
||||
bar.foo.com --| |-> bar.foo.com s2:80
|
||||
|
||||
```
|
||||
|
||||
The following Ingress tells the backing loadbalancer to route requests based on the [Host header](https://tools.ietf.org/html/rfc7230#section-5.4).
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
@@ -208,8 +188,6 @@ spec:
|
||||
servicePort: 80
|
||||
|
||||
```
|
||||
|
||||
|
||||
__Default Backends__: An Ingress with no rules, like the one shown in the previous section, sends all traffic to a single default backend. You can use the same technique to tell a loadbalancer where to find your website's 404 page, by specifying a set of rules *and* a default backend. Traffic is routed to your default backend if none of the Hosts in your Ingress match the Host in the request header, and/or none of the paths match the url of the request.
|
||||
|
||||
### Loadbalancing
|
||||
@@ -223,7 +201,6 @@ It's also worth noting that even though health checks are not exposed directly t
|
||||
Say you'd like to add a new Host to an existing Ingress, you can update it by editing the resource:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get ing
|
||||
NAME RULE BACKEND ADDRESS
|
||||
test - 178.91.123.132
|
||||
@@ -232,11 +209,9 @@ test - 178.91.123.132
|
||||
$ kubectl edit ing test
|
||||
|
||||
```
|
||||
|
||||
This should pop up an editor with the existing yaml, modify it to include the new Host.
|
||||
|
||||
```yaml
|
||||
|
||||
spec:
|
||||
rules:
|
||||
- host: foo.bar.com
|
||||
@@ -256,11 +231,9 @@ spec:
|
||||
..
|
||||
|
||||
```
|
||||
|
||||
saving it will update the resource in the API server, which should tell the Ingress controller to reconfigure the loadbalancer.
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get ing
|
||||
NAME RULE BACKEND ADDRESS
|
||||
test - 178.91.123.132
|
||||
@@ -270,7 +243,6 @@ test - 178.91.123.132
|
||||
/foo s2:80
|
||||
|
||||
```
|
||||
|
||||
You can achieve the same by invoking `kubectl replace -f` on a modified Ingress yaml file.
|
||||
|
||||
## Future Work
|
||||
|
||||
@@ -12,7 +12,6 @@ your pods. But there are a number of ways to get even more information about you
|
||||
For this example we'll use a ReplicationController to create two pods, similar to the earlier example.
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
kind: ReplicationController
|
||||
metadata:
|
||||
@@ -35,27 +34,21 @@ spec:
|
||||
- containerPort: 80
|
||||
|
||||
```
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f ./my-nginx-rc.yaml
|
||||
replicationcontrollers/my-nginx
|
||||
|
||||
```
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get pods
|
||||
NAME READY REASON RESTARTS AGE
|
||||
my-nginx-gy1ij 1/1 Running 0 1m
|
||||
my-nginx-yv5cn 1/1 Running 0 1m
|
||||
|
||||
```
|
||||
|
||||
We can retrieve a lot more information about each of these pods using `kubectl describe pod`. For example:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl describe pod my-nginx-gy1ij
|
||||
Name: my-nginx-gy1ij
|
||||
Image(s): nginx
|
||||
@@ -90,7 +83,6 @@ Events:
|
||||
Thu, 09 Jul 2015 15:33:07 -0700 Thu, 09 Jul 2015 15:33:07 -0700 1 {kubelet kubernetes-minion-y3vk} spec.containers{nginx} started Started with docker id 56d7a7b14dac
|
||||
|
||||
```
|
||||
|
||||
Here you can see configuration information about the container(s) and Pod (labels, resource requirements, etc.), as well as status information about the container(s) and Pod (state, readiness, restart count, events, etc.)
|
||||
|
||||
The container state is one of Waiting, Running, or Terminated. Depending on the state, additional information will be provided -- here you can see that for a container in Running state, the system tells you when the container started.
|
||||
@@ -108,7 +100,6 @@ Lastly, you see a log of recent events related to your Pod. The system compresse
|
||||
A common scenario that you can detect using events is when you've created a Pod that won't fit on any node. For example, the Pod might request more resources than are free on any node, or it might specify a label selector that doesn't match any nodes. Let's say we created the previous Replication Controller with 5 replicas (instead of 2) and requesting 600 millicores instead of 500, on a four-node cluster where each (virtual) machine has 1 CPU. In that case one of the Pods will not be able to schedule. (Note that because of the cluster addon pods such as fluentd, skydns, etc., that run on each node, if we requested 1000 millicores then none of the Pods would be able to schedule.)
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get pods
|
||||
NAME READY REASON RESTARTS AGE
|
||||
my-nginx-9unp9 0/1 Pending 0 8s
|
||||
@@ -118,11 +109,9 @@ my-nginx-iichp 0/1 Running 0 8s
|
||||
my-nginx-tc2j9 0/1 Running 0 8s
|
||||
|
||||
```
|
||||
|
||||
To find out why the my-nginx-9unp9 pod is not running, we can use `kubectl describe pod` on the pending Pod and look at its events:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl describe pod my-nginx-9unp9
|
||||
Name: my-nginx-9unp9
|
||||
Image(s): nginx
|
||||
@@ -147,7 +136,6 @@ Events:
|
||||
Thu, 09 Jul 2015 23:56:21 -0700 Fri, 10 Jul 2015 00:01:30 -0700 21 {scheduler } failedScheduling Failed for reason PodFitsResources and possibly others
|
||||
|
||||
```
|
||||
|
||||
Here you can see the event generated by the scheduler saying that the Pod failed to schedule for reason `PodFitsResources` (and possibly others). `PodFitsResources` means there were not enough resources for the Pod on any of the nodes. Due to the way the event is generated, there may be other reasons as well, hence "and possibly others."
|
||||
|
||||
To correct this situation, you can use `kubectl scale` to update your Replication Controller to specify four or fewer replicas. (Or you could just leave the one Pod pending, which is harmless.)
|
||||
@@ -155,25 +143,20 @@ To correct this situation, you can use `kubectl scale` to update your Replicatio
|
||||
Events such as the ones you saw at the end of `kubectl describe pod` are persisted in etcd and provide high-level information on what is happening in the cluster. To list all events you can use
|
||||
|
||||
```
|
||||
|
||||
kubectl get events
|
||||
|
||||
```
|
||||
|
||||
but you have to remember that events are namespaced. This means that if you're interested in events for some namespaced object (e.g. what happened with Pods in namespace `my-namespace`) you need to explicitly provide a namespace to the command:
|
||||
|
||||
```
|
||||
|
||||
kubectl get events --namespace=my-namespace
|
||||
|
||||
```
|
||||
|
||||
To see events from all namespaces, you can use the `--all-namespaces` argument.
|
||||
|
||||
In addition to `kubectl describe pod`, another way to get extra information about a pod (beyond what is provided by `kubectl get pod`) is to pass the `-o yaml` output format flag to `kubectl get pod`. This will give you, in YAML format, even more information than `kubectl describe pod`--essentially all of the information the system has about the Pod. Here you will see things like annotations (which are key-value metadata without the label restrictions, that is used internally by Kubernetes system components), restart policy, ports, and volumes.
|
||||
|
||||
```yaml
|
||||
|
||||
$ kubectl get pod my-nginx-i595c -o yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
@@ -235,13 +218,11 @@ status:
|
||||
startTime: 2015-07-10T06:56:21Z
|
||||
|
||||
```
|
||||
|
||||
## Example: debugging a down/unreachable node
|
||||
|
||||
Sometimes when debugging it can be useful to look at the status of a node -- for example, because you've noticed strange behavior of a Pod that's running on the node, or to find out why a Pod won't schedule onto the node. As with Pods, you can use `kubectl describe node` and `kubectl get node -o yaml` to retrieve detailed information about nodes. For example, here's what you'll see if a node is down (disconnected from the network, or kubelet dies and won't restart, etc.). Notice the events that show the node is NotReady, and also notice that the pods are no longer running (they are evicted after five minutes of NotReady status).
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get nodes
|
||||
NAME LABELS STATUS
|
||||
kubernetes-minion-861h kubernetes.io/hostname=kubernetes-minion-861h NotReady
|
||||
@@ -322,7 +303,6 @@ status:
|
||||
systemUUID: ABE5F6B4-D44B-108B-C46A-24CCE16C8B6E
|
||||
|
||||
```
|
||||
|
||||
## What's next?
|
||||
|
||||
Learn about additional debugging tools, including:
|
||||
|
||||
@@ -20,7 +20,6 @@ It takes around 10s to complete.
|
||||
<!-- BEGIN MUNGE: EXAMPLE job.yaml -->
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Job
|
||||
metadata:
|
||||
@@ -42,23 +41,19 @@ spec:
|
||||
restartPolicy: Never
|
||||
|
||||
```
|
||||
|
||||
[Download example](job.yaml)
|
||||
<!-- END MUNGE: EXAMPLE job.yaml -->
|
||||
|
||||
Run the example job by downloading the example file and then running this command:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f ./job.yaml
|
||||
jobs/pi
|
||||
|
||||
```
|
||||
|
||||
Check on the status of the job using this command:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl describe jobs/pi
|
||||
Name: pi
|
||||
Namespace: default
|
||||
@@ -75,31 +70,26 @@ Events:
|
||||
|
||||
|
||||
```
|
||||
|
||||
To view completed pods of a job, use `kubectl get pods --show-all`. The `--show-all` will show completed pods too.
|
||||
|
||||
To list all the pods that belong to job in a machine readable form, you can use a command like this:
|
||||
|
||||
```shell
|
||||
|
||||
$ pods=$(kubectl get pods --selector=app=pi --output=jsonpath={.items..metadata.name})
|
||||
echo $pods
|
||||
pi-aiw0a
|
||||
|
||||
```
|
||||
|
||||
Here, the selector is the same as the selector for the job. The `--output=jsonpath` option specifies an expression
|
||||
that just gets the name from each pod in the returned list.
|
||||
|
||||
View the standard output of one of the pods:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl logs pi-aiw0a
|
||||
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632788659361533818279682303019520353018529689957736225994138912497217752834791315155748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035637076601047101819429555961989467678374494482553797747268471040475346462080466842590694912933136770289891521047521620569660240580381501935112533824300355876402474964732639141992726042699227967823547816360093417216412199245863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818347977535663698074265425278625518184175746728909777727938000816470600161452491921732172147723501414419735685481613611573525521334757418494684385233239073941433345477624168625189835694855620992192221842725502542568876717904946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886269456042419652850222106611863067442786220391949450471237137869609563643719172874677646575739624138908658326459958133904780275901
|
||||
|
||||
```
|
||||
|
||||
## Writing a Job Spec
|
||||
|
||||
As with all other Kubernetes config, a Job needs `apiVersion`, `kind`, and `metadata` fields. For
|
||||
|
||||
@@ -14,7 +14,6 @@ The result object is printed as its String() function.
|
||||
Given the input:
|
||||
|
||||
```json
|
||||
|
||||
{
|
||||
"kind": "List",
|
||||
"items":[
|
||||
@@ -51,7 +50,6 @@ Given the input:
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Function | Description | Example | Result
|
||||
---------|--------------------|--------------------|------------------
|
||||
text | the plain text | kind is {.kind} | kind is List
|
||||
|
||||
@@ -22,7 +22,7 @@ http://issue.k8s.io/1755
|
||||
|
||||
The below file contains a `current-context` which will be used by default by clients which are using the file to connect to a cluster. Thus, this kubeconfig file has more information in it then we will necessarily have to use in a given session. You can see it defines many clusters, and users associated with those clusters. The context itself is associated with both a cluster AND a user.
|
||||
|
||||
```yaml
|
||||
```yaml
|
||||
current-context: federal-context
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
@@ -60,8 +60,7 @@ users:
|
||||
user:
|
||||
client-certificate: path/to/my/client/cert
|
||||
client-key: path/to/my/client/key
|
||||
```
|
||||
|
||||
```
|
||||
### Building your own kubeconfig file
|
||||
|
||||
NOTE, that if you are deploying k8s via kube-up.sh, you do not need to create your own kubeconfig files, the script will do it for you.
|
||||
@@ -72,11 +71,10 @@ So, lets do a quick walk through the basics of the above file so you can easily
|
||||
|
||||
The above file would likely correspond to an api-server which was launched using the `--token-auth-file=tokens.csv` option, where the tokens.csv file looked something like this:
|
||||
|
||||
```
|
||||
```
|
||||
blue-user,blue-user,1
|
||||
mister-red,mister-red,2
|
||||
```
|
||||
|
||||
```
|
||||
Also, since we have other users who validate using **other** mechanisms, the api-server would have probably been launched with other authentication options (there are many such options, make sure you understand which ones YOU care about before crafting a kubeconfig file, as nobody needs to implement all the different permutations of possible authentication schemes).
|
||||
|
||||
- Since the user for the current context is "green-user", any client of the api-server using this kubeconfig file would naturally be able to log in succesfully, because we are providigin the green-user's client credentials.
|
||||
@@ -126,18 +124,17 @@ See [kubectl/kubectl_config.md](kubectl/kubectl_config) for help.
|
||||
|
||||
### Example
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl config set-credentials myself --username=admin --password=secret
|
||||
$ kubectl config set-cluster local-server --server=http://localhost:8080
|
||||
$ kubectl config set-context default-context --cluster=local-server --user=myself
|
||||
$ kubectl config use-context default-context
|
||||
$ kubectl config set contexts.default-context.namespace the-right-prefix
|
||||
$ kubectl config view
|
||||
```
|
||||
|
||||
```
|
||||
produces this output
|
||||
|
||||
```yaml
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
@@ -157,11 +154,10 @@ users:
|
||||
user:
|
||||
password: secret
|
||||
username: admin
|
||||
```
|
||||
|
||||
```
|
||||
and a kubeconfig file that looks like this
|
||||
|
||||
```yaml
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
@@ -181,11 +177,10 @@ users:
|
||||
user:
|
||||
password: secret
|
||||
username: admin
|
||||
```
|
||||
|
||||
```
|
||||
#### Commands for the example file
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl config set preferences.colors true
|
||||
$ kubectl config set-cluster cow-cluster --server=http://cow.org:8080 --api-version=v1
|
||||
$ kubectl config set-cluster horse-cluster --server=https://horse.org:4443 --certificate-authority=path/to/my/cafile
|
||||
@@ -195,8 +190,7 @@ $ kubectl config set-credentials green-user --client-certificate=path/to/my/clie
|
||||
$ kubectl config set-context queen-anne-context --cluster=pig-cluster --user=black-user --namespace=saw-ns
|
||||
$ kubectl config set-context federal-context --cluster=horse-cluster --user=green-user --namespace=chisel-ns
|
||||
$ kubectl config use-context federal-context
|
||||
```
|
||||
|
||||
```
|
||||
### Final notes for tying it all together
|
||||
|
||||
So, tying this all together, a quick start to creating your own kubeconfig file:
|
||||
|
||||
@@ -10,24 +10,20 @@ TODO: Auto-generate this file to ensure it's always in sync with any `kubectl` c
|
||||
Use the following syntax to run `kubectl` commands from your terminal window:
|
||||
|
||||
```
|
||||
|
||||
kubectl [command] [TYPE] [NAME] [flags]
|
||||
|
||||
```
|
||||
|
||||
where `command`, `TYPE`, `NAME`, and `flags` are:
|
||||
|
||||
* `command`: Specifies the operation that you want to perform on one or more resources, for example `create`, `get`, `describe`, `delete`.
|
||||
* `TYPE`: Specifies the [resource type](#resource-types). Resource types are case-sensitive and you can specify the singular, plural, or abbreviated forms. For example, the following commands produce the same output:
|
||||
|
||||
```
|
||||
|
||||
$ kubectl get pod pod1
|
||||
$ kubectl get pod pod1
|
||||
$ kubectl get pods pod1
|
||||
$ kubectl get po pod1
|
||||
|
||||
```
|
||||
|
||||
* `NAME`: Specifies the name of the resource. Names are case-sensitive. If the name is omitted, details for all resources are displayed, for example `$ kubectl get pods`.
|
||||
|
||||
When performing an operation on multiple resources, you can specify each resource by type and name or specify one or more files:
|
||||
@@ -112,11 +108,9 @@ The default output format for all `kubectl` commands is the human readable plain
|
||||
#### Syntax
|
||||
|
||||
```
|
||||
|
||||
kubectl [command] [TYPE] [NAME] -o=<output_format>
|
||||
|
||||
```
|
||||
|
||||
Depending on the `kubectl` operation, the following output formats are supported:
|
||||
|
||||
Output format | Description
|
||||
@@ -147,37 +141,29 @@ To define custom columns and output only the details that you want into a table,
|
||||
* Inline:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get pods <pod-name> -o=custom-columns=NAME:.metadata.name,RSRC:.metadata.resourceVersion
|
||||
$ kubectl get pods <pod-name> -o=custom-columns=NAME:.metadata.name,RSRC:.metadata.resourceVersion
|
||||
|
||||
```
|
||||
|
||||
* Template file:
|
||||
* Template file:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get pods <pod-name> -o=custom-columns-file=template.txt
|
||||
$ kubectl get pods <pod-name> -o=custom-columns-file=template.txt
|
||||
|
||||
```
|
||||
|
||||
where the `template.txt` file contains:
|
||||
where the `template.txt` file contains:
|
||||
|
||||
```
|
||||
|
||||
NAME RSRC
|
||||
NAME RSRC
|
||||
metadata.name metadata.resourceVersion
|
||||
|
||||
```
|
||||
|
||||
The result of running either command is:
|
||||
|
||||
```shell
|
||||
|
||||
NAME RSRC
|
||||
submit-queue 610995
|
||||
|
||||
```
|
||||
|
||||
### Sorting list objects
|
||||
|
||||
To output objects to a sorted list in your terminal window, you can add the `--sort-by` flag to a supported `kubectl` command. Sort your objects by specifying any numeric or string field with the `--sort-by` flag. To specify a field, use a [jsonpath](jsonpath) expression.
|
||||
@@ -185,11 +171,9 @@ To output objects to a sorted list in your terminal window, you can add the `--s
|
||||
#### Syntax
|
||||
|
||||
```
|
||||
|
||||
kubectl [command] [TYPE] [NAME] --sort-by=<jsonpath_exp>
|
||||
|
||||
```
|
||||
|
||||
##### Example
|
||||
|
||||
To print a list of pods sorted by name, you run:
|
||||
|
||||
@@ -7,14 +7,12 @@ Labels can be used to organize and to select subsets of objects. Labels can be
|
||||
Each object can have a set of key/value labels defined. Each Key must be unique for a given object.
|
||||
|
||||
```json
|
||||
|
||||
"labels": {
|
||||
"key1" : "value1",
|
||||
"key2" : "value2"
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
We'll eventually index and reverse-index labels for efficient queries and watches, use them to sort and group in UIs and CLIs, etc. We don't want to pollute labels with non-identifying, especially large and/or structured, data. Non-identifying information should be recorded using [annotations](annotations).
|
||||
|
||||
{% include pagetoc.html %}
|
||||
@@ -61,12 +59,10 @@ _Equality-_ or _inequality-based_ requirements allow filtering by label keys and
|
||||
Three kinds of operators are admitted `=`,`==`,`!=`. The first two represent _equality_ (and are simply synonyms), while the latter represents _inequality_. For example:
|
||||
|
||||
```
|
||||
|
||||
environment = production
|
||||
tier != frontend
|
||||
|
||||
```
|
||||
|
||||
The former selects all resources with key equal to `environment` and value equal to `production`.
|
||||
The latter selects all resources with key equal to `tier` and value distinct from `frontend`, and all resources with no labels with the `tier` key.
|
||||
One could filter for resources in `production` excluding `frontend` using the comma operator: `environment=production,tier!=frontend`
|
||||
@@ -77,14 +73,12 @@ One could filter for resources in `production` excluding `frontend` using the co
|
||||
_Set-based_ label requirements allow filtering keys according to a set of values. Three kinds of operators are supported: `in`,`notin` and exists (only the key identifier). For example:
|
||||
|
||||
```
|
||||
|
||||
environment in (production, qa)
|
||||
tier notin (frontend, backend)
|
||||
partition
|
||||
!partition
|
||||
|
||||
```
|
||||
|
||||
The first example selects all resources with key equal to `environment` and value equal to `production` or `qa`.
|
||||
The second example selects all resources with key equal to `tier` and values other than `frontend` and `backend`, and all resources with no labels with the `tier` key.
|
||||
The third example selects all resources including a label with key `partition`; no values are checked.
|
||||
@@ -107,35 +101,27 @@ LIST and WATCH operations may specify label selectors to filter the sets of obje
|
||||
Both label selector styles can be used to list or watch resources via a REST client. For example targetting `apiserver` with `kubectl` and using _equality-based_ one may write:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get pods -l environment=production,tier=frontend
|
||||
|
||||
```
|
||||
|
||||
or using _set-based_ requirements:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get pods -l 'environment in (production),tier in (frontend)'
|
||||
|
||||
```
|
||||
|
||||
As already mentioned _set-based_ requirements are more expressive. For instance, they can implement the _OR_ operator on values:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get pods -l 'environment in (production, qa)'
|
||||
|
||||
```
|
||||
|
||||
or restricting negative matching via _exists_ operator:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get pods -l 'environment,environment notin (frontend)'
|
||||
|
||||
```
|
||||
|
||||
### Set references in API objects
|
||||
|
||||
Some Kubernetes objects, such as [`service`s](services) and [`replicationcontroller`s](replication-controller), also use label selectors to specify sets of other resources, such as [pods](pods).
|
||||
@@ -147,22 +133,18 @@ The set of pods that a `service` targets is defined with a label selector. Simil
|
||||
Labels selectors for both objects are defined in `json` or `yaml` files using maps, and only _equality-based_ requirement selectors are supported:
|
||||
|
||||
```json
|
||||
|
||||
"selector": {
|
||||
"component" : "redis",
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```yaml
|
||||
|
||||
selector:
|
||||
component: redis
|
||||
|
||||
```
|
||||
|
||||
this selector (respectively in `json` or `yaml` format) is equivalent to `component=redis` or `component in (redis)`.
|
||||
|
||||
#### Job and other new resources
|
||||
@@ -170,7 +152,6 @@ this selector (respectively in `json` or `yaml` format) is equivalent to `compon
|
||||
Newer resources, such as [job](jobs), support _set-based_ requirements as well.
|
||||
|
||||
```yaml
|
||||
|
||||
selector:
|
||||
matchLabels:
|
||||
component: redis
|
||||
@@ -179,7 +160,6 @@ selector:
|
||||
- {key: environment, operator: NotIn, values: [dev]}
|
||||
|
||||
```
|
||||
|
||||
`matchLabels` is a map of `{key,value}` pairs. A single `{key,value}` in the `matchLabels` map is equivalent to an element of `matchExpressions`, whose `key` field is "key", the `operator` is "In", and the `values` array contains only "value". `matchExpressions` is a list of pod selector requirements. Valid operators include In, NotIn, Exists, and DoesNotExist. The values set must be non-empty in the case of In and NotIn. All of the requirements, from both `matchLabels` and `matchExpressions` are ANDed together -- they must all be satisfied in order to match.
|
||||
|
||||
|
||||
|
||||
@@ -6,38 +6,35 @@ This example shows two types of pod [health checks](../production-pods.html#live
|
||||
|
||||
The [exec-liveness.yaml](exec-liveness.yaml) demonstrates the container execution check.
|
||||
|
||||
```yaml
|
||||
livenessProbe:
|
||||
```yaml
|
||||
livenessProbe:
|
||||
exec:
|
||||
command:
|
||||
- cat
|
||||
- /tmp/health
|
||||
initialDelaySeconds: 15
|
||||
timeoutSeconds: 1
|
||||
```
|
||||
|
||||
```
|
||||
Kubelet executes the command `cat /tmp/health` in the container and reports failure if the command returns a non-zero exit code.
|
||||
|
||||
Note that the container removes the `/tmp/health` file after 10 seconds,
|
||||
|
||||
```shell
|
||||
```shell
|
||||
echo ok > /tmp/health; sleep 10; rm -rf /tmp/health; sleep 600
|
||||
```
|
||||
|
||||
```
|
||||
so when Kubelet executes the health check 15 seconds (defined by initialDelaySeconds) after the container started, the check would fail.
|
||||
|
||||
|
||||
The [http-liveness.yaml](http-liveness.yaml) demonstrates the HTTP check.
|
||||
|
||||
```yaml
|
||||
livenessProbe:
|
||||
```yaml
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 8080
|
||||
initialDelaySeconds: 15
|
||||
timeoutSeconds: 1
|
||||
```
|
||||
|
||||
```
|
||||
The Kubelet sends an HTTP request to the specified path and port to perform the health check. If you take a look at image/server.go, you will see the server starts to respond with an error code 500 after 10 seconds, so the check fails. The Kubelet sends the probe to the container's ip address by default which could be specified with `host` as part of httpGet probe. If the container listens on `127.0.0.1`, `host` should be specified as `127.0.0.1`. In general, if the container listens on its ip address or on all interfaces (0.0.0.0), there is no need to specify the `host` as part of the httpGet probe.
|
||||
|
||||
This [guide](../walkthrough/k8s201.html#health-checking) has more information on health checks.
|
||||
@@ -46,34 +43,31 @@ This [guide](../walkthrough/k8s201.html#health-checking) has more information on
|
||||
|
||||
To show the health check is actually working, first create the pods:
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl create -f docs/user-guide/liveness/exec-liveness.yaml
|
||||
$ kubectl create -f docs/user-guide/liveness/http-liveness.yaml
|
||||
```
|
||||
|
||||
```
|
||||
Check the status of the pods once they are created:
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
[...]
|
||||
liveness-exec 1/1 Running 0 13s
|
||||
liveness-http 1/1 Running 0 13s
|
||||
```
|
||||
|
||||
```
|
||||
Check the status half a minute later, you will see the container restart count being incremented:
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
[...]
|
||||
liveness-exec 1/1 Running 1 36s
|
||||
liveness-http 1/1 Running 1 36s
|
||||
```
|
||||
|
||||
```
|
||||
At the bottom of the *kubectl describe* output there are messages indicating that the liveness probes have failed, and the containers have been killed and recreated.
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl describe pods liveness-exec
|
||||
[...]
|
||||
Sat, 27 Jun 2015 13:43:03 +0200 Sat, 27 Jun 2015 13:44:34 +0200 4 {kubelet kubernetes-minion-6fbi} spec.containers{liveness} unhealthy Liveness probe failed: cat: can't open '/tmp/health': No such file or directory
|
||||
|
||||
@@ -6,8 +6,7 @@ This example shows two types of pod [health checks](../production-pods.html#live
|
||||
The [exec-liveness.yaml](exec-liveness.yaml) demonstrates the container execution check.
|
||||
|
||||
```yaml
|
||||
|
||||
livenessProbe:
|
||||
livenessProbe:
|
||||
exec:
|
||||
command:
|
||||
- cat
|
||||
@@ -16,25 +15,21 @@ The [exec-liveness.yaml](exec-liveness.yaml) demonstrates the container executio
|
||||
timeoutSeconds: 1
|
||||
|
||||
```
|
||||
|
||||
Kubelet executes the command `cat /tmp/health` in the container and reports failure if the command returns a non-zero exit code.
|
||||
|
||||
Note that the container removes the `/tmp/health` file after 10 seconds,
|
||||
|
||||
```shell
|
||||
|
||||
echo ok > /tmp/health; sleep 10; rm -rf /tmp/health; sleep 600
|
||||
|
||||
```
|
||||
|
||||
so when Kubelet executes the health check 15 seconds (defined by initialDelaySeconds) after the container started, the check would fail.
|
||||
|
||||
|
||||
The [http-liveness.yaml](http-liveness.yaml) demonstrates the HTTP check.
|
||||
|
||||
```yaml
|
||||
|
||||
livenessProbe:
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 8080
|
||||
@@ -42,7 +37,6 @@ The [http-liveness.yaml](http-liveness.yaml) demonstrates the HTTP check.
|
||||
timeoutSeconds: 1
|
||||
|
||||
```
|
||||
|
||||
The Kubelet sends an HTTP request to the specified path and port to perform the health check. If you take a look at image/server.go, you will see the server starts to respond with an error code 500 after 10 seconds, so the check fails. The Kubelet sends the probe to the container's ip address by default which could be specified with `host` as part of httpGet probe. If the container listens on `127.0.0.1`, `host` should be specified as `127.0.0.1`. In general, if the container listens on its ip address or on all interfaces (0.0.0.0), there is no need to specify the `host` as part of the httpGet probe.
|
||||
|
||||
This [guide](../walkthrough/k8s201.html#health-checking) has more information on health checks.
|
||||
@@ -52,16 +46,13 @@ This [guide](../walkthrough/k8s201.html#health-checking) has more information on
|
||||
To show the health check is actually working, first create the pods:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f docs/user-guide/liveness/exec-liveness.yaml
|
||||
$ kubectl create -f docs/user-guide/liveness/http-liveness.yaml
|
||||
|
||||
```
|
||||
|
||||
Check the status of the pods once they are created:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
[...]
|
||||
@@ -69,11 +60,9 @@ liveness-exec 1/1 Running 0
|
||||
liveness-http 1/1 Running 0 13s
|
||||
|
||||
```
|
||||
|
||||
Check the status half a minute later, you will see the container restart count being incremented:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
[...]
|
||||
@@ -81,11 +70,9 @@ liveness-exec 1/1 Running 1
|
||||
liveness-http 1/1 Running 1 36s
|
||||
|
||||
```
|
||||
|
||||
At the bottom of the *kubectl describe* output there are messages indicating that the liveness probes have failed, and the containers have been killed and recreated.
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl describe pods liveness-exec
|
||||
[...]
|
||||
Sat, 27 Jun 2015 13:43:03 +0200 Sat, 27 Jun 2015 13:44:34 +0200 4 {kubelet kubernetes-minion-6fbi} spec.containers{liveness} unhealthy Liveness probe failed: cat: can't open '/tmp/health': No such file or directory
|
||||
@@ -94,6 +81,3 @@ Sat, 27 Jun 2015 13:44:44 +0200 Sat, 27 Jun 2015 13:44:44 +0200 1 {kube
|
||||
Sat, 27 Jun 2015 13:44:44 +0200 Sat, 27 Jun 2015 13:44:44 +0200 1 {kubelet kubernetes-minion-6fbi} spec.containers{liveness} started Started with docker id ed6bb004ee10
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -10,12 +10,12 @@ Kubernetes components, such as kubelet and apiserver, use the [glog](https://god
|
||||
## Examining the logs of running containers
|
||||
|
||||
The logs of a running container may be fetched using the command `kubectl logs`. For example, given
|
||||
this pod specification [counter-pod.yaml](../../examples/blog-logging/counter-pod.yaml), which has a container which writes out some text to standard
|
||||
this pod specification [counter-pod.yaml](https://github.com/kubernetes/kubernetes/tree/master/examples/blog-logging/counter-pod.yaml), which has a container which writes out some text to standard
|
||||
output every second. (You can find different pod specifications [here](logging-demo/).)
|
||||
|
||||
<!-- BEGIN MUNGE: EXAMPLE ../../examples/blog-logging/counter-pod.yaml -->
|
||||
|
||||
```yaml
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
@@ -26,21 +26,19 @@ spec:
|
||||
image: ubuntu:14.04
|
||||
args: [bash, -c,
|
||||
'for ((i = 0; ; i++)); do echo "$i: $(date)"; sleep 1; done']
|
||||
```
|
||||
|
||||
[Download example](../../examples/blog-logging/counter-pod.yaml)
|
||||
```
|
||||
[Download example](https://github.com/kubernetes/kubernetes/tree/master/examples/blog-logging/counter-pod.yaml)
|
||||
<!-- END MUNGE: EXAMPLE ../../examples/blog-logging/counter-pod.yaml -->
|
||||
|
||||
we can run the pod:
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl create -f ./counter-pod.yaml
|
||||
pods/counter
|
||||
```
|
||||
|
||||
```
|
||||
and then fetch the logs:
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl logs counter
|
||||
0: Tue Jun 2 21:37:31 UTC 2015
|
||||
1: Tue Jun 2 21:37:32 UTC 2015
|
||||
@@ -49,12 +47,11 @@ $ kubectl logs counter
|
||||
4: Tue Jun 2 21:37:35 UTC 2015
|
||||
5: Tue Jun 2 21:37:36 UTC 2015
|
||||
...
|
||||
```
|
||||
|
||||
```
|
||||
If a pod has more than one container then you need to specify which container's log files should
|
||||
be fetched e.g.
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl logs kube-dns-v3-7r1l9 etcd
|
||||
2015/06/23 00:43:10 etcdserver: start to snapshot (applied: 30003, lastsnap: 20002)
|
||||
2015/06/23 00:43:10 etcdserver: compacted log at index 30003
|
||||
@@ -70,8 +67,7 @@ $ kubectl logs kube-dns-v3-7r1l9 etcd
|
||||
2015/06/23 04:51:03 etcdserver: compacted log at index 60006
|
||||
2015/06/23 04:51:03 etcdserver: saved snapshot at index 60006
|
||||
...
|
||||
```
|
||||
|
||||
```
|
||||
## Cluster level logging to Google Cloud Logging
|
||||
|
||||
The getting started guide [Cluster Level Logging to Google Cloud Logging](../getting-started-guides/logging)
|
||||
|
||||
@@ -10,7 +10,6 @@ You've deployed your application and exposed it via a service. Now what? Kuberne
|
||||
Many applications require multiple resources to be created, such as a Replication Controller and a Service. Management of multiple resources can be simplified by grouping them together in the same file (separated by `---` in YAML). For example:
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
@@ -42,35 +41,28 @@ spec:
|
||||
- containerPort: 80
|
||||
|
||||
```
|
||||
|
||||
Multiple resources can be created the same way as a single resource:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f ./nginx-app.yaml
|
||||
services/my-nginx-svc
|
||||
replicationcontrollers/my-nginx
|
||||
|
||||
```
|
||||
|
||||
The resources will be created in the order they appear in the file. Therefore, it's best to specify the service first, since that will ensure the scheduler can spread the pods associated with the service as they are created by the replication controller(s).
|
||||
|
||||
`kubectl create` also accepts multiple `-f` arguments:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f ./nginx-svc.yaml -f ./nginx-rc.yaml
|
||||
|
||||
```
|
||||
|
||||
And a directory can be specified rather than or in addition to individual files:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f ./nginx/
|
||||
|
||||
```
|
||||
|
||||
`kubectl` will read any files with suffixes `.yaml`, `.yml`, or `.json`.
|
||||
|
||||
It is a recommended practice to put resources related to the same microservice or application tier into the same file, and to group all of the files associated with your application in the same directory. If the tiers of your application bind to each other using DNS, then you can then simply deploy all of the components of your stack en masse.
|
||||
@@ -78,46 +70,37 @@ It is a recommended practice to put resources related to the same microservice o
|
||||
A URL can also be specified as a configuration source, which is handy for deploying directly from configuration files checked into github:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f https://raw.githubusercontent.com/GoogleCloudPlatform/kubernetes/master/docs/user-guide/replication.yaml
|
||||
replicationcontrollers/nginx
|
||||
|
||||
```
|
||||
|
||||
## Bulk operations in kubectl
|
||||
|
||||
Resource creation isn't the only operation that `kubectl` can perform in bulk. It can also extract resource names from configuration files in order to perform other operations, in particular to delete the same resources you created:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl delete -f ./nginx/
|
||||
replicationcontrollers/my-nginx
|
||||
services/my-nginx-svc
|
||||
|
||||
```
|
||||
|
||||
In the case of just two resources, it's also easy to specify both on the command line using the resource/name syntax:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl delete replicationcontrollers/my-nginx services/my-nginx-svc
|
||||
|
||||
```
|
||||
|
||||
For larger numbers of resources, one can use labels to filter resources. The selector is specified using `-l`:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl delete all -lapp=nginx
|
||||
replicationcontrollers/my-nginx
|
||||
services/my-nginx-svc
|
||||
|
||||
```
|
||||
|
||||
Because `kubectl` outputs resource names in the same syntax it accepts, it's easy to chain operations using `$()` or `xargs`:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get $(kubectl create -f ./nginx/ | grep my-nginx)
|
||||
CONTROLLER CONTAINER(S) IMAGE(S) SELECTOR REPLICAS
|
||||
my-nginx nginx nginx app=nginx 2
|
||||
@@ -125,47 +108,39 @@ NAME LABELS SELECTOR IP(S) PORT(S)
|
||||
my-nginx-svc app=nginx app=nginx 10.0.152.174 80/TCP
|
||||
|
||||
```
|
||||
|
||||
## Using labels effectively
|
||||
|
||||
The examples we've used so far apply at most a single label to any resource. There are many scenarios where multiple labels should be used to distinguish sets from one another.
|
||||
|
||||
For instance, different applications would use different values for the `app` label, but a multi-tier application, such as the [guestbook example](../../examples/guestbook/), would additionally need to distinguish each tier. The frontend could carry the following labels:
|
||||
For instance, different applications would use different values for the `app` label, but a multi-tier application, such as the [guestbook example](https://github.com/kubernetes/kubernetes/tree/master/examples/guestbook/), would additionally need to distinguish each tier. The frontend could carry the following labels:
|
||||
|
||||
```yaml
|
||||
|
||||
labels:
|
||||
labels:
|
||||
app: guestbook
|
||||
tier: frontend
|
||||
|
||||
```
|
||||
|
||||
while the Redis master and slave would have different `tier` labels, and perhaps even an additional `role` label:
|
||||
|
||||
```yaml
|
||||
|
||||
labels:
|
||||
labels:
|
||||
app: guestbook
|
||||
tier: backend
|
||||
role: master
|
||||
|
||||
```
|
||||
|
||||
and
|
||||
|
||||
```yaml
|
||||
|
||||
labels:
|
||||
labels:
|
||||
app: guestbook
|
||||
tier: backend
|
||||
role: slave
|
||||
|
||||
```
|
||||
|
||||
The labels allow us to slice and dice our resources along any dimension specified by a label:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f ./guestbook-fe.yaml -f ./redis-master.yaml -f ./redis-slave.yaml
|
||||
replicationcontrollers/guestbook-fe
|
||||
replicationcontrollers/guestbook-redis-master
|
||||
@@ -186,47 +161,39 @@ guestbook-redis-slave-2q2yf 1/1 Running 0 3m
|
||||
guestbook-redis-slave-qgazl 1/1 Running 0 3m
|
||||
|
||||
```
|
||||
|
||||
## Canary deployments
|
||||
|
||||
Another scenario where multiple labels are needed is to distinguish deployments of different releases or configurations of the same component. For example, it is common practice to deploy a *canary* of a new application release (specified via image tag) side by side with the previous release so that the new release can receive live production traffic before fully rolling it out. For instance, a new release of the guestbook frontend might carry the following labels:
|
||||
|
||||
```yaml
|
||||
|
||||
labels:
|
||||
labels:
|
||||
app: guestbook
|
||||
tier: frontend
|
||||
track: canary
|
||||
|
||||
```
|
||||
|
||||
and the primary, stable release would have a different value of the `track` label, so that the sets of pods controlled by the two replication controllers would not overlap:
|
||||
|
||||
```yaml
|
||||
|
||||
labels:
|
||||
labels:
|
||||
app: guestbook
|
||||
tier: frontend
|
||||
track: stable
|
||||
|
||||
```
|
||||
|
||||
The frontend service would span both sets of replicas by selecting the common subset of their labels, omitting the `track` label:
|
||||
|
||||
```yaml
|
||||
|
||||
selector:
|
||||
selector:
|
||||
app: guestbook
|
||||
tier: frontend
|
||||
|
||||
```
|
||||
|
||||
## Updating labels
|
||||
|
||||
Sometimes existing pods and other resources need to be relabeled before creating new resources. This can be done with `kubectl label`. For example:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl label pods -lapp=nginx tier=fe
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
my-nginx-v4-9gw19 1/1 Running 0 14m
|
||||
@@ -247,13 +214,11 @@ my-nginx-v4-sh6m8 1/1 Running 0 19m fe
|
||||
my-nginx-v4-wfof4 1/1 Running 0 16m fe
|
||||
|
||||
```
|
||||
|
||||
## Scaling your application
|
||||
|
||||
When load on your application grows or shrinks, it's easy to scale with `kubectl`. For instance, to increase the number of nginx replicas from 2 to 3, do:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl scale rc my-nginx --replicas=3
|
||||
scaled
|
||||
$ kubectl get pods -lapp=nginx
|
||||
@@ -263,7 +228,6 @@ my-nginx-divi2 1/1 Running 0 1h
|
||||
my-nginx-o0ef1 1/1 Running 0 1h
|
||||
|
||||
```
|
||||
|
||||
## Updating your application without a service outage
|
||||
|
||||
At some point, you'll eventually need to update your deployed application, typically by specifying a new image or image tag, as in the canary deployment scenario above. `kubectl` supports several update operations, each of which is applicable to different scenarios.
|
||||
@@ -273,7 +237,6 @@ To update a service without an outage, `kubectl` supports what is called ['rolli
|
||||
Let's say you were running version 1.7.9 of nginx:
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
kind: ReplicationController
|
||||
metadata:
|
||||
@@ -292,20 +255,16 @@ spec:
|
||||
- containerPort: 80
|
||||
|
||||
```
|
||||
|
||||
To update to version 1.9.1, you can use [`kubectl rolling-update --image`](/{{page.version}}/docs/design/simple-rolling-update):
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl rolling-update my-nginx --image=nginx:1.9.1
|
||||
Creating my-nginx-ccba8fbd8cc8160970f63f9a2696fc46
|
||||
|
||||
```
|
||||
|
||||
In another window, you can see that `kubectl` added a `deployment` label to the pods, whose value is a hash of the configuration, to distinguish the new pods from the old:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get pods -lapp=nginx -Ldeployment
|
||||
NAME READY STATUS RESTARTS AGE DEPLOYMENT
|
||||
my-nginx-1jgkf 1/1 Running 0 1h 2d1d7a8f682934a254002b56404b813e
|
||||
@@ -316,11 +275,9 @@ my-nginx-o0ef1 1/1 Running 0
|
||||
my-nginx-q6all 1/1 Running 0 8m 2d1d7a8f682934a254002b56404b813e
|
||||
|
||||
```
|
||||
|
||||
`kubectl rolling-update` reports progress as it progresses:
|
||||
|
||||
```shell
|
||||
|
||||
Updating my-nginx replicas: 4, my-nginx-ccba8fbd8cc8160970f63f9a2696fc46 replicas: 1
|
||||
At end of loop: my-nginx replicas: 4, my-nginx-ccba8fbd8cc8160970f63f9a2696fc46 replicas: 1
|
||||
At beginning of loop: my-nginx replicas: 3, my-nginx-ccba8fbd8cc8160970f63f9a2696fc46 replicas: 2
|
||||
@@ -340,11 +297,9 @@ Renaming my-nginx-ccba8fbd8cc8160970f63f9a2696fc46 to my-nginx
|
||||
my-nginx
|
||||
|
||||
```
|
||||
|
||||
If you encounter a problem, you can stop the rolling update midway and revert to the previous version using `--rollback`:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl kubectl rolling-update my-nginx --image=nginx:1.9.1 --rollback
|
||||
Found existing update in progress (my-nginx-ccba8fbd8cc8160970f63f9a2696fc46), resuming.
|
||||
Found desired replicas.Continuing update with existing controller my-nginx.
|
||||
@@ -353,13 +308,11 @@ Update succeeded. Deleting my-nginx-ccba8fbd8cc8160970f63f9a2696fc46
|
||||
my-nginx
|
||||
|
||||
```
|
||||
|
||||
This is one example where the immutability of containers is a huge asset.
|
||||
|
||||
If you need to update more than just the image (e.g., command arguments, environment variables), you can create a new replication controller, with a new name and distinguishing label value, such as:
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
kind: ReplicationController
|
||||
metadata:
|
||||
@@ -383,11 +336,9 @@ spec:
|
||||
- containerPort: 80
|
||||
|
||||
```
|
||||
|
||||
and roll it out:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl rolling-update my-nginx -f ./nginx-rc.yaml
|
||||
Creating my-nginx-v4
|
||||
At beginning of loop: my-nginx replicas: 4, my-nginx-v4 replicas: 1
|
||||
@@ -409,7 +360,6 @@ Update succeeded. Deleting my-nginx
|
||||
my-nginx-v4
|
||||
|
||||
```
|
||||
|
||||
You can also run the [update demo](update-demo/) to see a visual representation of the rolling update process.
|
||||
|
||||
## In-place updates of resources
|
||||
@@ -417,7 +367,6 @@ You can also run the [update demo](update-demo/) to see a visual representation
|
||||
Sometimes it's necessary to make narrow, non-disruptive updates to resources you've created. For instance, you might want to add an [annotation](annotations) with a description of your object. That's easiest to do with `kubectl patch`:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl patch rc my-nginx-v4 -p '{"metadata": {"annotations": {"description": "my frontend running nginx"}}}'
|
||||
my-nginx-v4
|
||||
$ kubectl get rc my-nginx-v4 -o yaml
|
||||
@@ -429,13 +378,11 @@ metadata:
|
||||
...
|
||||
|
||||
```
|
||||
|
||||
The patch is specified using json.
|
||||
|
||||
For more significant changes, you can `get` the resource, edit it, and then `replace` the resource with the updated version:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get rc my-nginx-v4 -o yaml > /tmp/nginx.yaml
|
||||
$ vi /tmp/nginx.yaml
|
||||
$ kubectl replace -f /tmp/nginx.yaml
|
||||
@@ -443,7 +390,6 @@ replicationcontrollers/my-nginx-v4
|
||||
$ rm $TMP
|
||||
|
||||
```
|
||||
|
||||
The system ensures that you don't clobber changes made by other users or components by confirming that the `resourceVersion` doesn't differ from the version you edited. If you want to update regardless of other changes, remove the `resourceVersion` field when you edit the resource. However, if you do this, don't use your original configuration file as the source since additional fields most likely were set in the live state.
|
||||
|
||||
## Disruptive updates
|
||||
@@ -451,13 +397,11 @@ The system ensures that you don't clobber changes made by other users or compone
|
||||
In some cases, you may need to update resource fields that cannot be updated once initialized, or you may just want to make a recursive change immediately, such as to fix broken pods created by a replication controller. To change such fields, use `replace --force`, which deletes and re-creates the resource. In this case, you can simply modify your original configuration file:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl replace -f ./nginx-rc.yaml --force
|
||||
replicationcontrollers/my-nginx-v4
|
||||
replicationcontrollers/my-nginx-v4
|
||||
|
||||
```
|
||||
|
||||
## What's next?
|
||||
|
||||
- [Learn about how to use `kubectl` for application introspection and debugging.](introspection-and-debugging)
|
||||
|
||||
@@ -32,14 +32,12 @@ for namespaces](/{{page.version}}/docs/admin/namespaces)
|
||||
You can list the current namespaces in a cluster using:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get namespaces
|
||||
NAME LABELS STATUS
|
||||
default <none> Active
|
||||
kube-system <none> Active
|
||||
|
||||
```
|
||||
|
||||
Kubernetes starts with two initial namespaces:
|
||||
* `default` The default namespace for objects with no other namespace
|
||||
* `kube-system` The namespace for objects created by the Kubernetes system
|
||||
@@ -51,12 +49,10 @@ To temporarily set the namespace for a request, use the `--namespace` flag.
|
||||
For example:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl --namespace=<insert-namespace-name-here> run nginx --image=nginx
|
||||
$ kubectl --namespace=<insert-namespace-name-here> get pods
|
||||
|
||||
```
|
||||
|
||||
### Setting the namespace preference
|
||||
|
||||
You can permanently save the namespace for all subsequent kubectl commands in that
|
||||
@@ -65,19 +61,15 @@ context.
|
||||
First get your current context:
|
||||
|
||||
```shell
|
||||
|
||||
$ export CONTEXT=$(kubectl config view | grep current-context | awk '{print $2}')
|
||||
|
||||
```
|
||||
|
||||
Then update the default namespace:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl config set-context $(CONTEXT) --namespace=<insert-namespace-name-here>
|
||||
|
||||
```
|
||||
|
||||
## Namespaces and DNS
|
||||
|
||||
When you create a [Service](services), it creates a corresponding [DNS entry](../admin/dns).
|
||||
|
||||
@@ -63,8 +63,7 @@ Each PV contains a spec and status, which is the specification and status of the
|
||||
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: pv0003
|
||||
@@ -79,7 +78,6 @@ Each PV contains a spec and status, which is the specification and status of the
|
||||
server: 172.17.0.2
|
||||
|
||||
```
|
||||
|
||||
### Capacity
|
||||
|
||||
Generally, a PV will have a specific storage capacity. This is set using the PV's `capacity` attribute. See the Kubernetes [Resource Model](../design/resources) to understand the units expected by `capacity`.
|
||||
@@ -130,7 +128,6 @@ The CLI will show the name of the PVC bound to the PV.
|
||||
Each PVC contains a spec and status, which is the specification and status of the claim.
|
||||
|
||||
```yaml
|
||||
|
||||
kind: PersistentVolumeClaim
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
@@ -143,7 +140,6 @@ spec:
|
||||
storage: 8Gi
|
||||
|
||||
```
|
||||
|
||||
### Access Modes
|
||||
|
||||
Claims use the same conventions as volumes when requesting storage with specific access modes.
|
||||
@@ -157,7 +153,6 @@ Claims, like pods, can request specific quantities of a resource. In this case,
|
||||
Pods access storage by using the claim as a volume. Claims must exist in the same namespace as the pod using the claim. The cluster finds the claim in the pod's namespace and uses it to get the `PersistentVolume` backing the claim. The volume is then mounted to the host and into the pod.
|
||||
|
||||
```yaml
|
||||
|
||||
kind: Pod
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
@@ -175,6 +170,3 @@ spec:
|
||||
claimName: myclaim
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -22,23 +22,19 @@ support local storage on the host at this time. There is no guarantee your pod
|
||||
|
||||
|
||||
```shell
|
||||
|
||||
# This will be nginx's webroot
|
||||
$ mkdir /tmp/data01
|
||||
$ echo 'I love Kubernetes storage!' > /tmp/data01/index.html
|
||||
|
||||
```
|
||||
|
||||
PVs are created by posting them to the API server.
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f docs/user-guide/persistent-volumes/volumes/local-01.yaml
|
||||
NAME LABELS CAPACITY ACCESSMODES STATUS CLAIM REASON
|
||||
pv0001 type=local 10737418240 RWO Available
|
||||
|
||||
```
|
||||
|
||||
## Requesting storage
|
||||
|
||||
Users of Kubernetes request persistent storage for their pods. They don't know how the underlying cluster is provisioned.
|
||||
@@ -47,7 +43,6 @@ They just know they can rely on their claim to storage and can manage its lifecy
|
||||
Claims must be created in the same namespace as the pods that use them.
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f docs/user-guide/persistent-volumes/claims/claim-01.yaml
|
||||
|
||||
$ kubectl get pvc
|
||||
@@ -67,13 +62,11 @@ NAME LABELS CAPACITY ACCESSMODES STATUS CLAIM
|
||||
pv0001 type=local 10737418240 RWO Bound default/myclaim-1
|
||||
|
||||
```
|
||||
|
||||
## Using your claim as a volume
|
||||
|
||||
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.
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f docs/user-guide/persistent-volumes/simpletest/pod.yaml
|
||||
|
||||
$ kubectl get pods
|
||||
@@ -87,19 +80,16 @@ frontendservice 10.0.0.241 <none> 3000/TCP name=frontend
|
||||
kubernetes 10.0.0.2 <none> 443/TCP <none> 2d
|
||||
|
||||
```
|
||||
|
||||
## 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).
|
||||
|
||||
```shell
|
||||
|
||||
$ 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 the team on [Slack](../../troubleshooting.html#slack) and ask!
|
||||
|
||||
Enjoy!
|
||||
|
||||
@@ -22,23 +22,19 @@ support local storage on the host at this time. There is no guarantee your pod
|
||||
|
||||
|
||||
```shell
|
||||
|
||||
# This will be nginx's webroot
|
||||
$ mkdir /tmp/data01
|
||||
$ echo 'I love Kubernetes storage!' > /tmp/data01/index.html
|
||||
|
||||
```
|
||||
|
||||
PVs are created by posting them to the API server.
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f docs/user-guide/persistent-volumes/volumes/local-01.yaml
|
||||
NAME LABELS CAPACITY ACCESSMODES STATUS CLAIM REASON
|
||||
pv0001 type=local 10737418240 RWO Available
|
||||
|
||||
```
|
||||
|
||||
## Requesting storage
|
||||
|
||||
Users of Kubernetes request persistent storage for their pods. They don't know how the underlying cluster is provisioned.
|
||||
@@ -47,7 +43,6 @@ They just know they can rely on their claim to storage and can manage its lifecy
|
||||
Claims must be created in the same namespace as the pods that use them.
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f docs/user-guide/persistent-volumes/claims/claim-01.yaml
|
||||
|
||||
$ kubectl get pvc
|
||||
@@ -67,13 +62,11 @@ NAME LABELS CAPACITY ACCESSMODES STATUS CLAIM
|
||||
pv0001 type=local 10737418240 RWO Bound default/myclaim-1
|
||||
|
||||
```
|
||||
|
||||
## Using your claim as a volume
|
||||
|
||||
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.
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f docs/user-guide/persistent-volumes/simpletest/pod.yaml
|
||||
|
||||
$ kubectl get pods
|
||||
@@ -87,19 +80,16 @@ frontendservice 10.0.0.241 <none> 3000/TCP name=frontend
|
||||
kubernetes 10.0.0.2 <none> 443/TCP <none> 2d
|
||||
|
||||
```
|
||||
|
||||
## 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).
|
||||
|
||||
```shell
|
||||
|
||||
$ 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 the team on [Slack](../../troubleshooting.html#slack) and ask!
|
||||
|
||||
Enjoy!
|
||||
|
||||
@@ -14,26 +14,21 @@ The kubectl binary doesn't have to be installed to be executable, but the rest o
|
||||
The simplest way to install is to copy or move kubectl into a dir already in PATH (e.g. `/usr/local/bin`). For example:
|
||||
|
||||
```shell
|
||||
|
||||
# OS X
|
||||
$ sudo cp kubernetes/platforms/darwin/amd64/kubectl /usr/local/bin/kubectl
|
||||
# Linux
|
||||
$ sudo cp kubernetes/platforms/linux/amd64/kubectl /usr/local/bin/kubectl
|
||||
|
||||
```
|
||||
|
||||
You also need to ensure it's executable:
|
||||
|
||||
```shell
|
||||
|
||||
$ sudo chmod +x /usr/local/bin/kubectl
|
||||
|
||||
```
|
||||
|
||||
If you prefer not to copy kubectl, you need to ensure the tool is in your path:
|
||||
|
||||
```shell
|
||||
|
||||
# OS X
|
||||
export PATH=<path/to/kubernetes-directory>/platforms/darwin/amd64:$PATH
|
||||
|
||||
@@ -41,7 +36,6 @@ export PATH=<path/to/kubernetes-directory>/platforms/darwin/amd64:$PATH
|
||||
export PATH=<path/to/kubernetes-directory>/platforms/linux/amd64:$PATH
|
||||
|
||||
```
|
||||
|
||||
## Configuring kubectl
|
||||
|
||||
In order for kubectl to find and access the Kubernetes cluster, it needs a [kubeconfig file](kubeconfig-file), which is created automatically when creating a cluster using kube-up.sh (see the [getting started guides](/{{page.version}}/docs/getting-started-guides/) for more about creating clusters). If you need access to a cluster you didn't create, see the [Sharing Cluster Access document](sharing-clusters).
|
||||
@@ -52,11 +46,9 @@ By default, kubectl configuration lives at `~/.kube/config`.
|
||||
Check that kubectl is properly configured by getting the cluster state:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl cluster-info
|
||||
|
||||
```
|
||||
|
||||
If you see a url response, you are ready to go.
|
||||
|
||||
## What's next?
|
||||
|
||||
@@ -9,10 +9,9 @@ You've seen [how to configure and deploy pods and containers](configuring-contai
|
||||
|
||||
The container file system only lives as long as the container does, so when a container crashes and restarts, changes to the filesystem will be lost and the container will restart from a clean slate. To access more-persistent storage, outside the container file system, you need a [*volume*](volumes). This is especially important to stateful applications, such as key-value stores and databases.
|
||||
|
||||
For example, [Redis](http://redis.io/) is a key-value cache and store, which we use in the [guestbook](../../examples/guestbook/) and other examples. We can add a volume to it to store persistent data as follows:
|
||||
For example, [Redis](http://redis.io/) is a key-value cache and store, which we use in the [guestbook](https://github.com/kubernetes/kubernetes/tree/master/examples/guestbook/) and other examples. We can add a volume to it to store persistent data as follows:
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
kind: ReplicationController
|
||||
metadata:
|
||||
@@ -39,7 +38,6 @@ spec:
|
||||
name: data # must match the name of the volume, above
|
||||
|
||||
```
|
||||
|
||||
`emptyDir` volumes live for the lifespan of the [pod](pods), which is longer than the lifespan of any one container, so if the container fails and is restarted, our storage will live on.
|
||||
|
||||
In addition to the local disk storage provided by `emptyDir`, Kubernetes supports many different network-attached storage solutions, including PD on GCE and EBS on EC2, which are preferred for critical data, and will handle details such as mounting and unmounting the devices on the nodes. See [the volumes doc](volumes) for more details.
|
||||
@@ -51,7 +49,6 @@ Many applications need credentials, such as passwords, OAuth tokens, and TLS key
|
||||
Kubernetes provides a mechanism, called [*secrets*](secrets), that facilitates delivery of sensitive credentials to applications. A `Secret` is a simple resource containing a map of data. For instance, a simple secret with a username and password might look as follows:
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
@@ -62,11 +59,9 @@ data:
|
||||
username: dmFsdWUtMQ0K
|
||||
|
||||
```
|
||||
|
||||
As with other resources, this secret can be instantiated using `create` and can be viewed with `get`:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f ./secret.yaml
|
||||
secrets/mysecret
|
||||
$ kubectl get secrets
|
||||
@@ -75,11 +70,9 @@ default-token-v9pyz kubernetes.io/service-account-token 2
|
||||
mysecret Opaque 2
|
||||
|
||||
```
|
||||
|
||||
To use the secret, you need to reference it in a pod or pod template. The `secret` volume source enables you to mount it as an in-memory directory into your containers.
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
kind: ReplicationController
|
||||
metadata:
|
||||
@@ -110,7 +103,6 @@ spec:
|
||||
name: supersecret
|
||||
|
||||
```
|
||||
|
||||
For more details, see the [secrets document](secrets), [example](secrets/) and [design doc](/{{page.version}}/docs/design/secrets).
|
||||
|
||||
## Authenticating with a private image registry
|
||||
@@ -121,7 +113,6 @@ First, create a `.dockercfg` file, such as running `docker login <registry.domai
|
||||
Then put the resulting `.dockercfg` file into a [secret resource](secrets). For example:
|
||||
|
||||
```shell
|
||||
|
||||
$ docker login
|
||||
Username: janedoe
|
||||
Password: '�?'�?'�?'�?'�?'�?'�?'�?'�?'�?'�?
|
||||
@@ -149,12 +140,10 @@ $ kubectl create -f ./image-pull-secret.yaml
|
||||
secrets/myregistrykey
|
||||
|
||||
```
|
||||
|
||||
Now, you can create pods which reference that secret by adding an `imagePullSecrets`
|
||||
section to a pod definition.
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
@@ -167,7 +156,6 @@ spec:
|
||||
- name: myregistrykey
|
||||
|
||||
```
|
||||
|
||||
## Helper containers
|
||||
|
||||
[Pods](pods) support running multiple containers co-located together. They can be used to host vertically integrated application stacks, but their primary motivation is to support auxiliary helper programs that assist the primary application. Typical examples are data pullers, data pushers, and proxies.
|
||||
@@ -175,7 +163,6 @@ spec:
|
||||
Such containers typically need to communicate with one another, often through the file system. This can be achieved by mounting the same volume into both containers. An example of this pattern would be a web server with a [program that polls a git repository](http://releases.k8s.io/release-1.1/contrib/git-sync/) for new updates:
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
kind: ReplicationController
|
||||
metadata:
|
||||
@@ -208,7 +195,6 @@ spec:
|
||||
name: www-data
|
||||
|
||||
```
|
||||
|
||||
More examples can be found in our [blog article](http://blog.kubernetes.io/2015/06/the-distributed-system-toolkit-patterns) and [presentation slides](http://www.slideshare.net/Docker/slideshare-burns).
|
||||
|
||||
## Resource management
|
||||
@@ -218,7 +204,6 @@ Kubernetes's scheduler will place applications only where they have adequate CPU
|
||||
If no resource requirements are specified, a nominal amount of resources is assumed. (This default is applied via a [LimitRange](../admin/limitrange/) for the default [Namespace](namespaces). It can be viewed with `kubectl describe limitrange limits`.) You may explicitly specify the amount of resources required as follows:
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
kind: ReplicationController
|
||||
metadata:
|
||||
@@ -248,7 +233,6 @@ spec:
|
||||
memory: 64Mi
|
||||
|
||||
```
|
||||
|
||||
The container will die due to OOM (out of memory) if it exceeds its specified limit, so specifying a value a little higher than expected generally improves reliability. By specifying request, pod is guaranteed to be able to use that much of resource when needed. See [Resource QoS](../proposals/resource-qos) for the difference between resource limits and requests.
|
||||
|
||||
If you're not sure how much resources to request, you can first launch the application without specifying resources, and use [resource usage monitoring](monitoring) to determine appropriate values.
|
||||
@@ -260,7 +244,6 @@ Many applications running for long periods of time eventually transition to brok
|
||||
A common way to probe an application is using HTTP, which can be specified as follows:
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
kind: ReplicationController
|
||||
metadata:
|
||||
@@ -286,7 +269,6 @@ spec:
|
||||
timeoutSeconds: 1
|
||||
|
||||
```
|
||||
|
||||
Other times, applications are only temporarily unable to serve, and will recover on their own. Typically in such cases you'd prefer not to kill the application, but don't want to send it requests, either, since the application won't respond correctly or at all. A common such scenario is loading large data or configuration files during application startup. Kubernetes provides *readiness probes* to detect and mitigate such situations. Readiness probes are configured similarly to liveness probes, just using the `readinessProbe` field. A pod with containers reporting that they are not ready will not receive traffic through Kubernetes [services](connecting-applications).
|
||||
|
||||
For more details (e.g., how to specify command-based probes), see the [example in the walkthrough](walkthrough/k8s201.html#health-checking), the [standalone example](liveness/), and the [documentation](pod-states.html#container-probes).
|
||||
@@ -301,7 +283,6 @@ Of course, nodes and applications may fail at any time, but many applications be
|
||||
The specification of a pre-stop hook is similar to that of probes, but without the timing-related parameters. For example:
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
kind: ReplicationController
|
||||
metadata:
|
||||
@@ -325,7 +306,6 @@ spec:
|
||||
command: ["/usr/sbin/nginx","-s","quit"]
|
||||
|
||||
```
|
||||
|
||||
## Termination message
|
||||
|
||||
In order to achieve a reasonably high level of availability, especially for actively developed applications, it's important to debug failures quickly. Kubernetes can speed debugging by surfacing causes of fatal errors in a way that can be display using [`kubectl`](kubectl/kubectl) or the [UI](ui), in addition to general [log collection](logging). It is possible to specify a `terminationMessagePath` where a container will write its 'death rattle'?, such as assertion failure messages, stack traces, exceptions, and so on. The default path is `/dev/termination-log`.
|
||||
@@ -333,7 +313,6 @@ In order to achieve a reasonably high level of availability, especially for acti
|
||||
Here is a toy example:
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
@@ -346,11 +325,9 @@ spec:
|
||||
args: ["sleep 60 && /bin/echo Sleep expired > /dev/termination-log"]
|
||||
|
||||
```
|
||||
|
||||
The message is recorded along with the other state of the last (i.e., most recent) termination:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f ./pod.yaml
|
||||
pods/pod-w-message
|
||||
$ sleep 70
|
||||
@@ -360,7 +337,6 @@ $ kubectl get pods/pod-w-message -o go-template="{{range .status.containerStatus
|
||||
0
|
||||
|
||||
```
|
||||
|
||||
## What's next?
|
||||
|
||||
[Learn more about managing deployments.](managing-deployments)
|
||||
|
||||
@@ -12,24 +12,20 @@ Once your application is packaged into a container and pushed to an image regist
|
||||
For example, [nginx](http://wiki.nginx.org/Main) is a popular HTTP server, with a [pre-built container on Docker hub](https://registry.hub.docker.com/_/nginx/). The [`kubectl run`](kubectl/kubectl_run) command below will create two nginx replicas, listening on port 80.
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl run my-nginx --image=nginx --replicas=2 --port=80
|
||||
CONTROLLER CONTAINER(S) IMAGE(S) SELECTOR REPLICAS
|
||||
my-nginx my-nginx nginx run=my-nginx 2
|
||||
|
||||
```
|
||||
|
||||
You can see that they are running by:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get po
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
my-nginx-l8n3i 1/1 Running 0 29m
|
||||
my-nginx-q7jo3 1/1 Running 0 29m
|
||||
|
||||
```
|
||||
|
||||
Kubernetes will ensure that your application keeps running, by automatically restarting containers that fail, spreading containers across nodes, and recreating containers on new nodes when nodes fail.
|
||||
|
||||
## Exposing your application to the Internet
|
||||
@@ -37,22 +33,18 @@ Kubernetes will ensure that your application keeps running, by automatically res
|
||||
Through integration with some cloud providers (for example Google Compute Engine and AWS EC2), Kubernetes enables you to request that it provision a public IP address for your application. To do this run:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl expose rc my-nginx --port=80 --type=LoadBalancer
|
||||
service "my-nginx" exposed
|
||||
|
||||
```
|
||||
|
||||
To find the public IP address assigned to your application, execute:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get svc my-nginx
|
||||
NAME CLUSTER_IP EXTERNAL_IP PORT(S) SELECTOR AGE
|
||||
my-nginx 10.179.240.1 25.1.2.3 80/TCP run=nginx 8d
|
||||
|
||||
```
|
||||
|
||||
You may need to wait for a minute or two for the external ip address to be provisioned.
|
||||
|
||||
In order to access your nginx landing page, you also have to make sure that traffic from external IPs is allowed. Do this by opening a [firewall to allow traffic on port 80](services-firewalls).
|
||||
@@ -62,14 +54,12 @@ In order to access your nginx landing page, you also have to make sure that traf
|
||||
To kill the application and delete its containers and public IP address, do:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl delete rc my-nginx
|
||||
replicationcontrollers/my-nginx
|
||||
$ kubectl delete svc my-nginx
|
||||
services/my-nginx
|
||||
|
||||
```
|
||||
|
||||
## What's next?
|
||||
|
||||
[Learn about how to configure common container parameters, such as commands and environment variables.](configuring-containers)
|
||||
|
||||
@@ -39,7 +39,6 @@ information on how Service Accounts work.
|
||||
This is an example of a simple secret, in yaml format:
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
@@ -50,7 +49,6 @@ data:
|
||||
username: dmFsdWUtMQ0K
|
||||
|
||||
```
|
||||
|
||||
The data field is a map. Its keys must match
|
||||
[`DNS_SUBDOMAIN`](../design/identifiers), except that leading dots are also
|
||||
allowed. The values are arbitrary data, encoded using base64. The values of
|
||||
@@ -67,7 +65,6 @@ that it should use the secret.
|
||||
This is an example of a pod that mounts a secret in a volume:
|
||||
|
||||
```json
|
||||
|
||||
{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Pod",
|
||||
@@ -95,7 +92,6 @@ This is an example of a pod that mounts a secret in a volume:
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Each secret you want to use needs its own `spec.volumes`.
|
||||
|
||||
If there are multiple containers in the pod, then each container needs its
|
||||
@@ -157,7 +153,6 @@ This is the result of commands
|
||||
executed inside the container from the example above:
|
||||
|
||||
```shell
|
||||
|
||||
$ ls /etc/foo/
|
||||
username
|
||||
password
|
||||
@@ -167,7 +162,6 @@ $ cat /etc/foo/password
|
||||
value-2
|
||||
|
||||
```
|
||||
|
||||
The program in a container is responsible for reading the secret(s) from the
|
||||
files. Currently, if a program expects a secret to be stored in an environment
|
||||
variable, then the user needs to modify the image to populate the environment
|
||||
@@ -211,7 +205,6 @@ update the data of existing secrets, but to create new ones with distinct names.
|
||||
To create a pod that uses an ssh key stored as a secret, we first need to create a secret:
|
||||
|
||||
```json
|
||||
|
||||
{
|
||||
"kind": "Secret",
|
||||
"apiVersion": "v1",
|
||||
@@ -225,7 +218,6 @@ To create a pod that uses an ssh key stored as a secret, we first need to create
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
**Note:** The serialized JSON and YAML values of secret data are encoded as
|
||||
base64 strings. Newlines are not valid within these strings and must be
|
||||
omitted.
|
||||
@@ -234,7 +226,6 @@ Now we can create a pod which references the secret with the ssh key and
|
||||
consumes it in a volume:
|
||||
|
||||
```json
|
||||
|
||||
{
|
||||
"kind": "Pod",
|
||||
"apiVersion": "v1",
|
||||
@@ -270,7 +261,6 @@ consumes it in a volume:
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
When the container's command runs, the pieces of the key will be available in:
|
||||
|
||||
/etc/secret-volume/id-rsa.pub
|
||||
@@ -287,7 +277,6 @@ credentials.
|
||||
The secrets:
|
||||
|
||||
```json
|
||||
|
||||
{
|
||||
"apiVersion": "v1",
|
||||
"kind": "List",
|
||||
@@ -317,11 +306,9 @@ The secrets:
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
The pods:
|
||||
|
||||
```json
|
||||
|
||||
{
|
||||
"apiVersion": "v1",
|
||||
"kind": "List",
|
||||
@@ -395,16 +382,13 @@ The pods:
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Both containers will have the following files present on their filesystems:
|
||||
|
||||
```shell
|
||||
|
||||
/etc/secret-volume/username
|
||||
/etc/secret-volume/username
|
||||
/etc/secret-volume/password
|
||||
|
||||
```
|
||||
|
||||
Note how the specs for the two pods differ only in one field; this facilitates
|
||||
creating pods with different capabilities from a common pod config template.
|
||||
|
||||
@@ -413,7 +397,6 @@ one called, say, `prod-user` with the `prod-db-secret`, and one called, say,
|
||||
`test-user` with the `test-db-secret`. Then, the pod spec can be shortened to, for example:
|
||||
|
||||
```json
|
||||
|
||||
{
|
||||
"kind": "Pod",
|
||||
"apiVersion": "v1",
|
||||
@@ -434,7 +417,6 @@ one called, say, `prod-user` with the `prod-db-secret`, and one called, say,
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Use-case: Secret visible to one container in a pod
|
||||
|
||||
<a name="use-case-two-containers"></a>
|
||||
|
||||
@@ -16,15 +16,12 @@ A secret contains a set of named byte arrays.
|
||||
Use the [`examples/secrets/secret.yaml`](secret.yaml) file to create a secret:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f docs/user-guide/secrets/secret.yaml
|
||||
|
||||
```
|
||||
|
||||
You can use `kubectl` to see information about the secret:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get secrets
|
||||
NAME TYPE DATA
|
||||
test-secret Opaque 2
|
||||
@@ -42,7 +39,6 @@ data-1: 9 bytes
|
||||
data-2: 11 bytes
|
||||
|
||||
```
|
||||
|
||||
## Step Two: Create a pod that consumes a secret
|
||||
|
||||
Pods consume secrets in volumes. Now that you have created a secret, you can create a pod that
|
||||
@@ -51,20 +47,14 @@ consumes it.
|
||||
Use the [`examples/secrets/secret-pod.yaml`](secret-pod.yaml) file to create a Pod that consumes the secret.
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f docs/user-guide/secrets/secret-pod.yaml
|
||||
|
||||
```
|
||||
|
||||
This pod runs a binary that displays the content of one of the pieces of secret data in the secret
|
||||
volume:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl logs secret-test-pod
|
||||
2015-04-29T21:17:24.712206409Z content of file "/etc/secret-volume/data-1": value-1
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -16,15 +16,12 @@ A secret contains a set of named byte arrays.
|
||||
Use the [`examples/secrets/secret.yaml`](secret.yaml) file to create a secret:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f docs/user-guide/secrets/secret.yaml
|
||||
|
||||
```
|
||||
|
||||
You can use `kubectl` to see information about the secret:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get secrets
|
||||
NAME TYPE DATA
|
||||
test-secret Opaque 2
|
||||
@@ -42,7 +39,6 @@ data-1: 9 bytes
|
||||
data-2: 11 bytes
|
||||
|
||||
```
|
||||
|
||||
## Step Two: Create a pod that consumes a secret
|
||||
|
||||
Pods consume secrets in volumes. Now that you have created a secret, you can create a pod that
|
||||
@@ -51,20 +47,14 @@ consumes it.
|
||||
Use the [`examples/secrets/secret-pod.yaml`](secret-pod.yaml) file to create a Pod that consumes the secret.
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f docs/user-guide/secrets/secret-pod.yaml
|
||||
|
||||
```
|
||||
|
||||
This pod runs a binary that displays the content of one of the pieces of secret data in the secret
|
||||
volume:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl logs secret-test-pod
|
||||
2015-04-29T21:17:24.712206409Z content of file "/etc/secret-volume/data-1": value-1
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -35,17 +35,14 @@ Every namespace has a default service account resource called `default`.
|
||||
You can list this and any other serviceAccount resources in the namespace with this command:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get serviceAccounts
|
||||
NAME SECRETS
|
||||
default 1
|
||||
|
||||
```
|
||||
|
||||
You can create additional serviceAccounts like this:
|
||||
|
||||
```shell
|
||||
|
||||
$ cat > /tmp/serviceaccount.yaml <<EOF
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
@@ -56,11 +53,9 @@ $ kubectl create -f /tmp/serviceaccount.yaml
|
||||
serviceaccounts/build-robot
|
||||
|
||||
```
|
||||
|
||||
If you get a complete dump of the service account object, like this:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get serviceaccounts/build-robot -o yaml
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
@@ -75,7 +70,6 @@ secrets:
|
||||
- name: build-robot-token-bvbk5
|
||||
|
||||
```
|
||||
|
||||
then you will see that a token has automatically been created and is referenced by the service account.
|
||||
|
||||
In the future, you will be able to configure different access policies for each service account.
|
||||
@@ -90,11 +84,9 @@ You cannot update the service account of an already created pod.
|
||||
You can clean up the service account from this example like this:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl delete serviceaccount/build-robot
|
||||
|
||||
```
|
||||
|
||||
<!-- TODO: describe how to create a pod with no Service Account. -->
|
||||
Note that if a pod does not have a `ServiceAccount` set, the `ServiceAccount` will be set to `default`.
|
||||
|
||||
@@ -104,7 +96,6 @@ Suppose we have an existing service account named "build-robot" as mentioned abo
|
||||
a new secret manually.
|
||||
|
||||
```shell
|
||||
|
||||
$ cat > /tmp/build-robot-secret.yaml <<EOF
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
@@ -118,11 +109,9 @@ $ kubectl create -f /tmp/build-robot-secret.yaml
|
||||
secrets/build-robot-secret
|
||||
|
||||
```
|
||||
|
||||
Now you can confirm that the newly built secret is populated with an API token for the "build-robot" service account.
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl describe secrets/build-robot-secret
|
||||
Name: build-robot-secret
|
||||
Namespace: default
|
||||
@@ -137,7 +126,6 @@ ca.crt: 1220 bytes
|
||||
token:
|
||||
|
||||
```
|
||||
|
||||
> Note that the content of `token` is elided here.
|
||||
|
||||
## Adding ImagePullSecrets to a service account
|
||||
@@ -146,17 +134,14 @@ First, create an imagePullSecret, as described [here](images.html#specifying-ima
|
||||
Next, verify it has been created. For example:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get secrets myregistrykey
|
||||
NAME TYPE DATA
|
||||
myregistrykey kubernetes.io/dockercfg 1
|
||||
|
||||
```
|
||||
|
||||
Next, read/modify/write the service account for the namespace to use this secret as an imagePullSecret
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get serviceaccounts default -o yaml > ./sa.yaml
|
||||
$ cat sa.yaml
|
||||
apiVersion: v1
|
||||
@@ -191,17 +176,14 @@ $ kubectl replace serviceaccount default -f ./sa.yaml
|
||||
serviceaccounts/default
|
||||
|
||||
```
|
||||
|
||||
Now, any new pods created in the current namespace will have this added to their spec:
|
||||
|
||||
```yaml
|
||||
|
||||
spec:
|
||||
imagePullSecrets:
|
||||
- name: myregistrykey
|
||||
|
||||
```
|
||||
|
||||
## Adding Secrets to a service account.
|
||||
|
||||
TODO: Test and explain how to use additional non-K8s secrets with an existing service account.
|
||||
|
||||
@@ -17,11 +17,9 @@ Google Compute Engine firewalls are documented [elsewhere](https://cloud.google.
|
||||
You can add a firewall with the `gcloud` command line tool:
|
||||
|
||||
```shell
|
||||
|
||||
$ gcloud compute firewall-rules create my-rule --allow=tcp:<port>
|
||||
|
||||
```
|
||||
|
||||
**Note**
|
||||
There is one important security note when using firewalls on Google Compute Engine:
|
||||
|
||||
|
||||
@@ -42,7 +42,6 @@ new instance. For example, suppose you have a set of `Pods` that each expose
|
||||
port 9376 and carry a label `"app=MyApp"`.
|
||||
|
||||
```json
|
||||
|
||||
{
|
||||
"kind": "Service",
|
||||
"apiVersion": "v1",
|
||||
@@ -64,7 +63,6 @@ port 9376 and carry a label `"app=MyApp"`.
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
This specification will create a new `Service` object named "my-service" which
|
||||
targets TCP port 9376 on any `Pod` with the `"app=MyApp"` label. This `Service`
|
||||
will also be assigned an IP address (sometimes called the "cluster IP"), which
|
||||
@@ -99,7 +97,6 @@ abstract other kinds of backends. For example:
|
||||
In any of these scenarios you can define a service without a selector:
|
||||
|
||||
```json
|
||||
|
||||
{
|
||||
"kind": "Service",
|
||||
"apiVersion": "v1",
|
||||
@@ -118,12 +115,10 @@ In any of these scenarios you can define a service without a selector:
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Because this has no selector, the corresponding `Endpoints` object will not be
|
||||
created. You can manually map the service to your own specific endpoints:
|
||||
|
||||
```json
|
||||
|
||||
{
|
||||
"kind": "Endpoints",
|
||||
"apiVersion": "v1",
|
||||
@@ -143,7 +138,6 @@ created. You can manually map the service to your own specific endpoints:
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
NOTE: Endpoint IPs may not be loopback (127.0.0.0/8), link-local
|
||||
(169.254.0.0/16), or link-local multicast ((224.0.0.0/24).
|
||||
|
||||
@@ -183,7 +177,6 @@ ports you must give all of your ports names, so that endpoints can be
|
||||
disambiguated. For example:
|
||||
|
||||
```json
|
||||
|
||||
{
|
||||
"kind": "Service",
|
||||
"apiVersion": "v1",
|
||||
@@ -212,7 +205,6 @@ disambiguated. For example:
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Choosing your own IP address
|
||||
|
||||
You can specify your own cluster IP address as part of a `Service` creation
|
||||
@@ -258,7 +250,6 @@ allocated cluster IP address 10.0.0.11 produces the following environment
|
||||
variables:
|
||||
|
||||
```shell
|
||||
|
||||
REDIS_MASTER_SERVICE_HOST=10.0.0.11
|
||||
REDIS_MASTER_SERVICE_PORT=6379
|
||||
REDIS_MASTER_PORT=tcp://10.0.0.11:6379
|
||||
@@ -268,7 +259,6 @@ REDIS_MASTER_PORT_6379_TCP_PORT=6379
|
||||
REDIS_MASTER_PORT_6379_TCP_ADDR=10.0.0.11
|
||||
|
||||
```
|
||||
|
||||
*This does imply an ordering requirement* - any `Service` that a `Pod` wants to
|
||||
access must be created before the `Pod` itself, or else the environment
|
||||
variables will not be populated. DNS does not have this restriction.
|
||||
@@ -367,7 +357,6 @@ information about the provisioned balancer will be published in the `Service`'s
|
||||
`status.loadBalancer` field. For example:
|
||||
|
||||
```json
|
||||
|
||||
{
|
||||
"kind": "Service",
|
||||
"apiVersion": "v1",
|
||||
@@ -402,7 +391,6 @@ information about the provisioned balancer will be published in the `Service`'s
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Traffic from the external load balancer will be directed at the backend `Pods`,
|
||||
though exactly how that works depends on the cloud provider. Some cloud providers allow
|
||||
the `loadBalancerIP` to be specified. In those cases, the load-balancer will be created
|
||||
@@ -421,7 +409,6 @@ In the ServiceSpec, `externalIPs` can be specified along with any of the `Servic
|
||||
In the example below, my-service can be accessed by clients on 80.11.12.10:80 (externalIP:port)
|
||||
|
||||
```json
|
||||
|
||||
{
|
||||
"kind": "Service",
|
||||
"apiVersion": "v1",
|
||||
@@ -447,7 +434,6 @@ In the example below, my-service can be accessed by clients on 80.11.12.10:80 (e
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Shortcomings
|
||||
|
||||
We expect that using iptables and userspace proxies for VIPs will work at
|
||||
|
||||
@@ -9,41 +9,32 @@ by `cluster/kube-up.sh`. Sample steps for sharing `kubeconfig` below.
|
||||
**1. Create a cluster**
|
||||
|
||||
```shell
|
||||
|
||||
$ cluster/kube-up.sh
|
||||
|
||||
```
|
||||
|
||||
**2. Copy `kubeconfig` to new host**
|
||||
|
||||
```shell
|
||||
|
||||
$ scp $HOME/.kube/config user@remotehost:/path/to/.kube/config
|
||||
|
||||
```
|
||||
|
||||
**3. On new host, make copied `config` available to `kubectl`**
|
||||
|
||||
* Option A: copy to default location
|
||||
|
||||
```shell
|
||||
|
||||
$ mv /path/to/.kube/config $HOME/.kube/config
|
||||
|
||||
```
|
||||
|
||||
* Option B: copy to working directory (from which kubectl is run)
|
||||
|
||||
```shell
|
||||
|
||||
$ mv /path/to/.kube/config $PWD
|
||||
|
||||
```
|
||||
|
||||
* Option C: manually pass `kubeconfig` location to `kubectl`
|
||||
|
||||
```shell
|
||||
|
||||
# via environment variable
|
||||
$ export KUBECONFIG=/path/to/.kube/config
|
||||
|
||||
@@ -51,14 +42,12 @@ $ export KUBECONFIG=/path/to/.kube/config
|
||||
$ kubectl ... --kubeconfig=/path/to/.kube/config
|
||||
|
||||
```
|
||||
|
||||
## Manually Generating `kubeconfig`
|
||||
|
||||
`kubeconfig` is generated by `kube-up` but you can generate your own
|
||||
using (any desired subset of) the following commands.
|
||||
|
||||
```shell
|
||||
|
||||
# create kubeconfig entry
|
||||
$ kubectl config set-cluster $CLUSTER_NICK \
|
||||
--server=https://1.1.1.1 \
|
||||
@@ -84,7 +73,6 @@ $ kubectl config set-credentials $USER_NICK \
|
||||
$ kubectl config set-context $CONTEXT_NAME --cluster=$CLUSTER_NICKNAME --user=$USER_NICK
|
||||
|
||||
```
|
||||
|
||||
Notes:
|
||||
* The `--embed-certs` flag is needed to generate a standalone
|
||||
`kubeconfig`, that will work as-is on another host.
|
||||
@@ -93,11 +81,9 @@ save config too. In the above commands the `--kubeconfig` file could be
|
||||
omitted if you first run
|
||||
|
||||
```shell
|
||||
|
||||
$ export KUBECONFIG=/path/to/standalone/.kube/config
|
||||
|
||||
```
|
||||
|
||||
* The ca_file, key_file, and cert_file referenced above are generated on the
|
||||
kube master at cluster turnup. They can be found on the master under
|
||||
`/srv/kubernetes`. Bearer token/basic auth are also generated on the kube master.
|
||||
@@ -118,7 +104,6 @@ If you create clusters A, B on host1, and clusters C, D on host2, you can
|
||||
make all four clusters available on both hosts by running
|
||||
|
||||
```shell
|
||||
|
||||
# on host2, copy host1's default kubeconfig, and merge it from env
|
||||
$ scp host1:/path/to/home1/.kube/config /path/to/other/.kube/config
|
||||
|
||||
@@ -130,7 +115,6 @@ $ scp host2:/path/to/home2/.kube/config /path/to/other/.kube/config
|
||||
$ export $KUBECONFIG=/path/to/other/.kube/config
|
||||
|
||||
```
|
||||
|
||||
Detailed examples and explanation of `kubeconfig` loading/merging rules can be found in [kubeconfig-file.md](kubeconfig-file).
|
||||
|
||||
|
||||
|
||||
@@ -12,54 +12,42 @@ From this point onwards, it is assumed that `kubectl` is on your path from one o
|
||||
The [`kubectl run`](kubectl/kubectl_run) line below will create two [nginx](https://registry.hub.docker.com/_/nginx/) [pods](pods) listening on port 80. It will also create a [replication controller](replication-controller) named `my-nginx` to ensure that there are always two pods running.
|
||||
|
||||
```shell
|
||||
|
||||
kubectl run my-nginx --image=nginx --replicas=2 --port=80
|
||||
|
||||
```
|
||||
|
||||
Once the pods are created, you can list them to see what is up and running:
|
||||
|
||||
```shell
|
||||
|
||||
kubectl get pods
|
||||
|
||||
```
|
||||
|
||||
You can also see the replication controller that was created:
|
||||
|
||||
```shell
|
||||
|
||||
kubectl get rc
|
||||
|
||||
```
|
||||
|
||||
To stop the two replicated containers, stop the replication controller:
|
||||
|
||||
```shell
|
||||
|
||||
kubectl stop rc my-nginx
|
||||
|
||||
```
|
||||
|
||||
### Exposing your pods to the internet.
|
||||
|
||||
On some platforms (for example Google Compute Engine) the kubectl command can integrate with your cloud provider to add a [public IP address](services.html#external-services) for the pods,
|
||||
to do this run:
|
||||
|
||||
```shell
|
||||
|
||||
kubectl expose rc my-nginx --port=80 --type=LoadBalancer
|
||||
|
||||
```
|
||||
|
||||
This should print the service that has been created, and map an external IP address to the service. Where to find this external IP address will depend on the environment you run in. For instance, for Google Compute Engine the external IP address is listed as part of the newly created service and can be retrieved by running
|
||||
|
||||
```shell
|
||||
|
||||
kubectl get services
|
||||
|
||||
```
|
||||
|
||||
In order to access your nginx landing page, you also have to make sure that traffic from external IPs is allowed. Do this by opening a firewall to allow traffic on port 80.
|
||||
|
||||
### Next: Configuration files
|
||||
|
||||
@@ -9,18 +9,15 @@ can be code reviewed, producing a more robust, reliable and archival system.
|
||||
### Running a container from a pod configuration file
|
||||
|
||||
```shell
|
||||
|
||||
$ cd kubernetes
|
||||
$ kubectl create -f ./pod.yaml
|
||||
|
||||
```
|
||||
|
||||
Where pod.yaml contains something like:
|
||||
|
||||
<!-- BEGIN MUNGE: EXAMPLE pod.yaml -->
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
@@ -35,26 +32,21 @@ spec:
|
||||
- containerPort: 80
|
||||
|
||||
```
|
||||
|
||||
[Download example](pod.yaml)
|
||||
<!-- END MUNGE: EXAMPLE pod.yaml -->
|
||||
|
||||
You can see your cluster's pods:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get pods
|
||||
|
||||
```
|
||||
|
||||
and delete the pod you just created:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl delete pods nginx
|
||||
|
||||
```
|
||||
|
||||
### Running a replicated set of containers from a configuration file
|
||||
|
||||
To run replicated containers, you need a [Replication Controller](replication-controller).
|
||||
@@ -62,18 +54,15 @@ A replication controller is responsible for ensuring that a specific number of p
|
||||
cluster.
|
||||
|
||||
```shell
|
||||
|
||||
$ cd kubernetes
|
||||
$ kubectl create -f ./replication.yaml
|
||||
|
||||
```
|
||||
|
||||
Where `replication.yaml` contains:
|
||||
|
||||
<!-- BEGIN MUNGE: EXAMPLE replication.yaml -->
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
kind: ReplicationController
|
||||
metadata:
|
||||
@@ -95,17 +84,12 @@ spec:
|
||||
- containerPort: 80
|
||||
|
||||
```
|
||||
|
||||
[Download example](replication.yaml)
|
||||
<!-- END MUNGE: EXAMPLE replication.yaml -->
|
||||
|
||||
To delete the replication controller (and the pods it created):
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl delete rc nginx
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -9,11 +9,10 @@ By default, the Kubernetes UI is deployed as a cluster addon. To access it, visi
|
||||
|
||||
If you find that you're not able to access the UI, it may be because the kube-ui service has not been started on your cluster. In that case, you can start it manually with:
|
||||
|
||||
```shell
|
||||
```shell
|
||||
kubectl create -f cluster/addons/kube-ui/kube-ui-rc.yaml --namespace=kube-system
|
||||
kubectl create -f cluster/addons/kube-ui/kube-ui-svc.yaml --namespace=kube-system
|
||||
```
|
||||
|
||||
```
|
||||
Normally, this should be taken care of automatically by the [`kube-addons.sh`](http://releases.k8s.io/release-1.1/cluster/saltbase/salt/kube-addons/kube-addons.sh) script that runs on the master.
|
||||
|
||||
## Using the UI
|
||||
|
||||
@@ -27,11 +27,10 @@ This example demonstrates the usage of Kubernetes to perform a [rolling update](
|
||||
|
||||
This example assumes that you have forked the repository and [turned up a Kubernetes cluster](/{{page.version}}/docs/getting-started-guides/):
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ cd kubernetes
|
||||
$ ./cluster/kube-up.sh
|
||||
```
|
||||
|
||||
```
|
||||
### Step One: Turn up the UX for the demo
|
||||
|
||||
You can use bash job control to run this in the background (note that you must use the default port -- 8001 -- for the following demonstration to work properly).
|
||||
@@ -39,41 +38,37 @@ This can sometimes spew to the output so you could also run it in a different te
|
||||
Kubernetes repository. Otherwise you will get "404 page not found" errors as the paths will not match. You can find more information about `kubectl proxy`
|
||||
[here](/{{page.version}}/docs/user-guide/kubectl/kubectl_proxy).
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl proxy --www=docs/user-guide/update-demo/local/ &
|
||||
I0218 15:18:31.623279 67480 proxy.go:36] Starting to serve on localhost:8001
|
||||
```
|
||||
|
||||
```
|
||||
Now visit the the [demo website](http://localhost:8001/static). You won't see anything much quite yet.
|
||||
|
||||
### Step Two: Run the replication controller
|
||||
|
||||
Now we will turn up two replicas of an [image](../images). They all serve on internal port 80.
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl create -f docs/user-guide/update-demo/nautilus-rc.yaml
|
||||
```
|
||||
|
||||
```
|
||||
After pulling the image from the Docker Hub to your worker nodes (which may take a minute or so) you'll see a couple of squares in the UI detailing the pods that are running along with the image that they are serving up. A cute little nautilus.
|
||||
|
||||
### Step Three: Try scaling the replication controller
|
||||
|
||||
Now we will increase the number of replicas from two to four:
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl scale rc update-demo-nautilus --replicas=4
|
||||
```
|
||||
|
||||
```
|
||||
If you go back to the [demo website](http://localhost:8001/static/index) you should eventually see four boxes, one for each pod.
|
||||
|
||||
### Step Four: Update the docker image
|
||||
|
||||
We will now update the docker image to serve a different image by doing a rolling update to a new Docker image.
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl rolling-update update-demo-nautilus --update-period=10s -f docs/user-guide/update-demo/kitten-rc.yaml
|
||||
```
|
||||
|
||||
```
|
||||
The rolling-update command in kubectl will do 2 things:
|
||||
|
||||
1. Create a new [replication controller](/{{page.version}}/docs/user-guide/replication-controller) with a pod template that uses the new image (`gcr.io/google_containers/update-demo:kitten`)
|
||||
@@ -85,39 +80,35 @@ But if the replica count had been specified, the final replica count of the new
|
||||
|
||||
### Step Five: Bring down the pods
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl delete rc update-demo-kitten
|
||||
```
|
||||
|
||||
```
|
||||
This first stops the replication controller by turning the target number of replicas to 0 and then deletes the controller.
|
||||
|
||||
### Step Six: Cleanup
|
||||
|
||||
To turn down a Kubernetes cluster:
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ ./cluster/kube-down.sh
|
||||
```
|
||||
|
||||
```
|
||||
Kill the proxy running in the background:
|
||||
After you are done running this demo make sure to kill it:
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ jobs
|
||||
[1]+ Running ./kubectl proxy --www=local/ &
|
||||
$ kill %1
|
||||
[1]+ Terminated: 15 ./kubectl proxy --www=local/
|
||||
```
|
||||
|
||||
```
|
||||
### Updating the Docker images
|
||||
|
||||
If you want to build your own docker images, you can set `$DOCKER_HUB_USER` to your Docker user id and run the included shell script. It can take a few minutes to download/upload stuff.
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ export DOCKER_HUB_USER=my-docker-id
|
||||
$ ./docs/user-guide/update-demo/build-images.sh
|
||||
```
|
||||
|
||||
```
|
||||
To use your custom docker image in the above examples, you will need to change the image name in `docs/user-guide/update-demo/nautilus-rc.yaml` and `docs/user-guide/update-demo/kitten-rc.yaml`.
|
||||
|
||||
### Image Copyright
|
||||
|
||||
@@ -27,11 +27,10 @@ This example demonstrates the usage of Kubernetes to perform a [rolling update](
|
||||
|
||||
This example assumes that you have forked the repository and [turned up a Kubernetes cluster](/{{page.version}}/docs/getting-started-guides/):
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ cd kubernetes
|
||||
$ ./cluster/kube-up.sh
|
||||
```
|
||||
|
||||
```
|
||||
### Step One: Turn up the UX for the demo
|
||||
|
||||
You can use bash job control to run this in the background (note that you must use the default port -- 8001 -- for the following demonstration to work properly).
|
||||
@@ -39,41 +38,37 @@ This can sometimes spew to the output so you could also run it in a different te
|
||||
Kubernetes repository. Otherwise you will get "404 page not found" errors as the paths will not match. You can find more information about `kubectl proxy`
|
||||
[here](/{{page.version}}/docs/user-guide/kubectl/kubectl_proxy).
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl proxy --www=docs/user-guide/update-demo/local/ &
|
||||
I0218 15:18:31.623279 67480 proxy.go:36] Starting to serve on localhost:8001
|
||||
```
|
||||
|
||||
```
|
||||
Now visit the the [demo website](http://localhost:8001/static). You won't see anything much quite yet.
|
||||
|
||||
### Step Two: Run the replication controller
|
||||
|
||||
Now we will turn up two replicas of an [image](../images). They all serve on internal port 80.
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl create -f docs/user-guide/update-demo/nautilus-rc.yaml
|
||||
```
|
||||
|
||||
```
|
||||
After pulling the image from the Docker Hub to your worker nodes (which may take a minute or so) you'll see a couple of squares in the UI detailing the pods that are running along with the image that they are serving up. A cute little nautilus.
|
||||
|
||||
### Step Three: Try scaling the replication controller
|
||||
|
||||
Now we will increase the number of replicas from two to four:
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl scale rc update-demo-nautilus --replicas=4
|
||||
```
|
||||
|
||||
```
|
||||
If you go back to the [demo website](http://localhost:8001/static/index) you should eventually see four boxes, one for each pod.
|
||||
|
||||
### Step Four: Update the docker image
|
||||
|
||||
We will now update the docker image to serve a different image by doing a rolling update to a new Docker image.
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl rolling-update update-demo-nautilus --update-period=10s -f docs/user-guide/update-demo/kitten-rc.yaml
|
||||
```
|
||||
|
||||
```
|
||||
The rolling-update command in kubectl will do 2 things:
|
||||
|
||||
1. Create a new [replication controller](/{{page.version}}/docs/user-guide/replication-controller) with a pod template that uses the new image (`gcr.io/google_containers/update-demo:kitten`)
|
||||
@@ -85,39 +80,35 @@ But if the replica count had been specified, the final replica count of the new
|
||||
|
||||
### Step Five: Bring down the pods
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl delete rc update-demo-kitten
|
||||
```
|
||||
|
||||
```
|
||||
This first stops the replication controller by turning the target number of replicas to 0 and then deletes the controller.
|
||||
|
||||
### Step Six: Cleanup
|
||||
|
||||
To turn down a Kubernetes cluster:
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ ./cluster/kube-down.sh
|
||||
```
|
||||
|
||||
```
|
||||
Kill the proxy running in the background:
|
||||
After you are done running this demo make sure to kill it:
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ jobs
|
||||
[1]+ Running ./kubectl proxy --www=local/ &
|
||||
$ kill %1
|
||||
[1]+ Terminated: 15 ./kubectl proxy --www=local/
|
||||
```
|
||||
|
||||
```
|
||||
### Updating the Docker images
|
||||
|
||||
If you want to build your own docker images, you can set `$DOCKER_HUB_USER` to your Docker user id and run the included shell script. It can take a few minutes to download/upload stuff.
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ export DOCKER_HUB_USER=my-docker-id
|
||||
$ ./docs/user-guide/update-demo/build-images.sh
|
||||
```
|
||||
|
||||
```
|
||||
To use your custom docker image in the above examples, you will need to change the image name in `docs/user-guide/update-demo/nautilus-rc.yaml` and `docs/user-guide/update-demo/kitten-rc.yaml`.
|
||||
|
||||
### Image Copyright
|
||||
|
||||
@@ -143,15 +143,12 @@ the PD is read-only or the replica count is 0 or 1.
|
||||
Before you can use a GCE PD with a pod, you need to create it.
|
||||
|
||||
```shell
|
||||
|
||||
gcloud compute disks create --size=500GB --zone=us-central1-a my-data-disk
|
||||
|
||||
```
|
||||
|
||||
#### Example pod
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
@@ -171,7 +168,6 @@ spec:
|
||||
fsType: ext4
|
||||
|
||||
```
|
||||
|
||||
### awsElasticBlockStore
|
||||
|
||||
An `awsElasticBlockStore` volume mounts an Amazon Web Services (AWS) [EBS
|
||||
@@ -195,18 +191,15 @@ There are some restrictions when using an awsElasticBlockStore volume:
|
||||
Before you can use a EBS volume with a pod, you need to create it.
|
||||
|
||||
```shell
|
||||
|
||||
aws ec2 create-volume --availability-zone eu-west-1a --size 10 --volume-type gp2
|
||||
|
||||
```
|
||||
|
||||
Make sure the zone matches the zone you brought up your cluster in. (And also check that the size and EBS volume
|
||||
type are suitable for your use!)
|
||||
|
||||
#### AWS EBS Example configuration
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
@@ -226,7 +219,6 @@ spec:
|
||||
fsType: ext4
|
||||
|
||||
```
|
||||
|
||||
(Note: the syntax of volumeID is currently awkward; #10181 fixes it)
|
||||
|
||||
### nfs
|
||||
@@ -241,7 +233,7 @@ writers simultaneously.
|
||||
__Important: You must have your own NFS server running with the share exported
|
||||
before you can use it__
|
||||
|
||||
See the [NFS example](../../examples/nfs/) for more details.
|
||||
See the [NFS example](https://github.com/kubernetes/kubernetes/tree/master/examples/nfs/) for more details.
|
||||
|
||||
### iscsi
|
||||
|
||||
@@ -260,7 +252,7 @@ and then serve it in parallel from as many pods as you need. Unfortunately,
|
||||
iSCSI volumes can only be mounted by a single consumer in read-write mode - no
|
||||
simultaneous readers allowed.
|
||||
|
||||
See the [iSCSI example](../../examples/iscsi/) for more details.
|
||||
See the [iSCSI example](https://github.com/kubernetes/kubernetes/tree/master/examples/iscsi/) for more details.
|
||||
|
||||
### flocker
|
||||
|
||||
@@ -275,7 +267,7 @@ can be "handed off" between pods as required.
|
||||
|
||||
__Important: You must have your own Flocker installation running before you can use it__
|
||||
|
||||
See the [Flocker example](../../examples/flocker/) for more details.
|
||||
See the [Flocker example](https://github.com/kubernetes/kubernetes/tree/master/examples/flocker/) for more details.
|
||||
|
||||
### glusterfs
|
||||
|
||||
@@ -290,7 +282,7 @@ simultaneously.
|
||||
__Important: You must have your own GlusterFS installation running before you
|
||||
can use it__
|
||||
|
||||
See the [GlusterFS example](../../examples/glusterfs/) for more details.
|
||||
See the [GlusterFS example](https://github.com/kubernetes/kubernetes/tree/master/examples/glusterfs/) for more details.
|
||||
|
||||
### rbd
|
||||
|
||||
@@ -310,7 +302,7 @@ and then serve it in parallel from as many pods as you need. Unfortunately,
|
||||
RBD volumes can only be mounted by a single consumer in read-write mode - no
|
||||
simultaneous writers allowed.
|
||||
|
||||
See the [RBD example](../../examples/rbd/) for more details.
|
||||
See the [RBD example](https://github.com/kubernetes/kubernetes/tree/master/examples/rbd/) for more details.
|
||||
|
||||
### gitRepo
|
||||
|
||||
@@ -322,7 +314,6 @@ rather than extending the Kubernetes API for every such use case.
|
||||
Here is a example for gitRepo volume:
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
@@ -341,7 +332,6 @@ spec:
|
||||
revision: "22f1d8406d464b0c0874075539c1f2e96c253775"
|
||||
|
||||
```
|
||||
|
||||
### secret
|
||||
|
||||
A `secret` volume is used to pass sensitive information, such as passwords, to
|
||||
|
||||
@@ -29,7 +29,7 @@ See [pods](/{{page.version}}/docs/user-guide/pods) for more details.
|
||||
|
||||
The simplest pod definition describes the deployment of a single container. For example, an nginx web server pod might be defined as such:
|
||||
|
||||
```yaml
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
@@ -40,8 +40,7 @@ spec:
|
||||
image: nginx
|
||||
ports:
|
||||
- containerPort: 80
|
||||
```
|
||||
|
||||
```
|
||||
A pod definition is a declaration of a _desired state_. Desired state is a very important concept in the Kubernetes model. Many things present a desired state to the system, and it is Kubernetes' responsibility to make sure that the current state matches the desired state. For example, when you create a Pod, you declare that you want the containers in it to be running. If the containers happen to not be running (e.g. program failure, ...), Kubernetes will continue to (re-)create them for you in order to drive them to the desired state. This process continues until the Pod is deleted.
|
||||
|
||||
See the [design document](../../design/README) for more details.
|
||||
@@ -51,31 +50,26 @@ See the [design document](../../design/README) for more details.
|
||||
|
||||
Create a pod containing an nginx server ([pod-nginx.yaml](pod-nginx.yaml)):
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl create -f docs/user-guide/walkthrough/pod-nginx.yaml
|
||||
```
|
||||
|
||||
```
|
||||
List all pods:
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl get pods
|
||||
```
|
||||
|
||||
```
|
||||
On most providers, the pod IPs are not externally accessible. The easiest way to test that the pod is working is to create a busybox pod and exec commands on it remotely. See the [command execution documentation](../kubectl/kubectl_exec) for details.
|
||||
|
||||
Provided the pod IP is accessible, you should be able to access its http endpoint with curl on port 80:
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ curl http://$(kubectl get pod nginx -o go-template={{.status.podIP}})
|
||||
```
|
||||
|
||||
```
|
||||
Delete the pod by name:
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl delete pod nginx
|
||||
```
|
||||
|
||||
|
||||
```
|
||||
#### Volumes
|
||||
|
||||
That's great for a simple static web server, but what about persistent storage?
|
||||
@@ -86,27 +80,25 @@ For this example we'll be creating a Redis pod with a named volume and volume mo
|
||||
|
||||
1. Define a volume:
|
||||
|
||||
```yaml
|
||||
volumes:
|
||||
```yaml
|
||||
volumes:
|
||||
- name: redis-persistent-storage
|
||||
emptyDir: {}
|
||||
```
|
||||
|
||||
```
|
||||
2. Define a volume mount within a container definition:
|
||||
|
||||
```yaml
|
||||
volumeMounts:
|
||||
```yaml
|
||||
volumeMounts:
|
||||
# name must match the volume name below
|
||||
- name: redis-persistent-storage
|
||||
# mount path within the container
|
||||
mountPath: /data/redis
|
||||
```
|
||||
|
||||
```
|
||||
Example Redis pod definition with a persistent storage volume ([pod-redis.yaml](pod-redis.yaml)):
|
||||
|
||||
<!-- BEGIN MUNGE: EXAMPLE pod-redis.yaml -->
|
||||
|
||||
```yaml
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
@@ -121,8 +113,7 @@ spec:
|
||||
volumes:
|
||||
- name: redis-persistent-storage
|
||||
emptyDir: {}
|
||||
```
|
||||
|
||||
```
|
||||
[Download example](pod-redis.yaml)
|
||||
<!-- END MUNGE: EXAMPLE pod-redis.yaml -->
|
||||
|
||||
@@ -146,7 +137,7 @@ The examples below are syntactically correct, but some of the images (e.g. kuber
|
||||
|
||||
However, often you want to have two different containers that work together. An example of this would be a web server, and a helper job that polls a git repository for new updates:
|
||||
|
||||
```yaml
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
@@ -170,8 +161,7 @@ spec:
|
||||
volumes:
|
||||
- name: www-data
|
||||
emptyDir: {}
|
||||
```
|
||||
|
||||
```
|
||||
Note that we have also added a volume here. In this case, the volume is mounted into both containers. It is marked `readOnly` in the web server's case, since it doesn't need to write to the directory.
|
||||
|
||||
Finally, we have also introduced an environment variable to the `git-monitor` container, which allows us to parameterize that container with the particular git repository that we want to track.
|
||||
@@ -180,4 +170,4 @@ Finally, we have also introduced an environment variable to the `git-monitor` co
|
||||
## What's Next?
|
||||
|
||||
Continue on to [Kubernetes 201](k8s201) or
|
||||
for a complete application see the [guestbook example](../../../examples/guestbook/README)
|
||||
for a complete application see the [guestbook example](https://github.com/kubernetes/kubernetes/tree/master/examples/guestbook/README)
|
||||
@@ -28,7 +28,6 @@ See [pods](/{{page.version}}/docs/user-guide/pods) for more details.
|
||||
The simplest pod definition describes the deployment of a single container. For example, an nginx web server pod might be defined as such:
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
@@ -41,7 +40,6 @@ spec:
|
||||
- containerPort: 80
|
||||
|
||||
```
|
||||
|
||||
A pod definition is a declaration of a _desired state_. Desired state is a very important concept in the Kubernetes model. Many things present a desired state to the system, and it is Kubernetes' responsibility to make sure that the current state matches the desired state. For example, when you create a Pod, you declare that you want the containers in it to be running. If the containers happen to not be running (e.g. program failure, ...), Kubernetes will continue to (re-)create them for you in order to drive them to the desired state. This process continues until the Pod is deleted.
|
||||
|
||||
See the [design document](../../design/README) for more details.
|
||||
@@ -52,38 +50,29 @@ See the [design document](../../design/README) for more details.
|
||||
Create a pod containing an nginx server ([pod-nginx.yaml](pod-nginx.yaml)):
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f docs/user-guide/walkthrough/pod-nginx.yaml
|
||||
|
||||
```
|
||||
|
||||
List all pods:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get pods
|
||||
|
||||
```
|
||||
|
||||
On most providers, the pod IPs are not externally accessible. The easiest way to test that the pod is working is to create a busybox pod and exec commands on it remotely. See the [command execution documentation](../kubectl/kubectl_exec) for details.
|
||||
|
||||
Provided the pod IP is accessible, you should be able to access its http endpoint with curl on port 80:
|
||||
|
||||
```shell
|
||||
|
||||
$ curl http://$(kubectl get pod nginx -o go-template={{.status.podIP}})
|
||||
|
||||
```
|
||||
|
||||
Delete the pod by name:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl delete pod nginx
|
||||
|
||||
```
|
||||
|
||||
|
||||
#### Volumes
|
||||
|
||||
That's great for a simple static web server, but what about persistent storage?
|
||||
@@ -95,31 +84,26 @@ For this example we'll be creating a Redis pod with a named volume and volume mo
|
||||
1. Define a volume:
|
||||
|
||||
```yaml
|
||||
|
||||
volumes:
|
||||
volumes:
|
||||
- name: redis-persistent-storage
|
||||
emptyDir: {}
|
||||
|
||||
```
|
||||
|
||||
2. Define a volume mount within a container definition:
|
||||
|
||||
```yaml
|
||||
|
||||
volumeMounts:
|
||||
volumeMounts:
|
||||
# name must match the volume name below
|
||||
- name: redis-persistent-storage
|
||||
# mount path within the container
|
||||
mountPath: /data/redis
|
||||
|
||||
```
|
||||
|
||||
Example Redis pod definition with a persistent storage volume ([pod-redis.yaml](pod-redis.yaml)):
|
||||
|
||||
<!-- BEGIN MUNGE: EXAMPLE pod-redis.yaml -->
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
@@ -136,7 +120,6 @@ spec:
|
||||
emptyDir: {}
|
||||
|
||||
```
|
||||
|
||||
[Download example](pod-redis.yaml)
|
||||
<!-- END MUNGE: EXAMPLE pod-redis.yaml -->
|
||||
|
||||
@@ -161,7 +144,6 @@ The examples below are syntactically correct, but some of the images (e.g. kuber
|
||||
However, often you want to have two different containers that work together. An example of this would be a web server, and a helper job that polls a git repository for new updates:
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
@@ -187,7 +169,6 @@ spec:
|
||||
emptyDir: {}
|
||||
|
||||
```
|
||||
|
||||
Note that we have also added a volume here. In this case, the volume is mounted into both containers. It is marked `readOnly` in the web server's case, since it doesn't need to write to the directory.
|
||||
|
||||
Finally, we have also introduced an environment variable to the `git-monitor` container, which allows us to parameterize that container with the particular git repository that we want to track.
|
||||
@@ -196,7 +177,7 @@ Finally, we have also introduced an environment variable to the `git-monitor` co
|
||||
## What's Next?
|
||||
|
||||
Continue on to [Kubernetes 201](k8s201) or
|
||||
for a complete application see the [guestbook example](../../../examples/guestbook/README)
|
||||
for a complete application see the [guestbook example](https://github.com/kubernetes/kubernetes/tree/master/examples/guestbook/README)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -18,16 +18,15 @@ Having already learned about Pods and how to create them, you may be struck by a
|
||||
|
||||
To add a label, add a labels section under metadata in the pod definition:
|
||||
|
||||
```yaml
|
||||
labels:
|
||||
```yaml
|
||||
labels:
|
||||
app: nginx
|
||||
```
|
||||
|
||||
```
|
||||
For example, here is the nginx pod definition with labels ([pod-nginx-with-label.yaml](pod-nginx-with-label.yaml)):
|
||||
|
||||
<!-- BEGIN MUNGE: EXAMPLE pod-nginx-with-label.yaml -->
|
||||
|
||||
```yaml
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
@@ -40,23 +39,20 @@ spec:
|
||||
image: nginx
|
||||
ports:
|
||||
- containerPort: 80
|
||||
```
|
||||
|
||||
```
|
||||
[Download example](pod-nginx-with-label.yaml)
|
||||
<!-- END MUNGE: EXAMPLE pod-nginx-with-label.yaml -->
|
||||
|
||||
Create the labeled pod ([pod-nginx-with-label.yaml](pod-nginx-with-label.yaml)):
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl create -f docs/user-guide/walkthrough/pod-nginx-with-label.yaml
|
||||
```
|
||||
|
||||
```
|
||||
List all pods with the label `app=nginx`:
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl get pods -l app=nginx
|
||||
```
|
||||
|
||||
```
|
||||
For more information, see [Labels](../labels).
|
||||
They are a core concept used by two additional Kubernetes building blocks: Replication Controllers and Services.
|
||||
|
||||
@@ -71,7 +67,7 @@ For example, here is a replication controller that instantiates two nginx pods (
|
||||
|
||||
<!-- BEGIN MUNGE: EXAMPLE replication-controller.yaml -->
|
||||
|
||||
```yaml
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ReplicationController
|
||||
metadata:
|
||||
@@ -96,8 +92,7 @@ spec:
|
||||
image: nginx
|
||||
ports:
|
||||
- containerPort: 80
|
||||
```
|
||||
|
||||
```
|
||||
[Download example](replication-controller.yaml)
|
||||
<!-- END MUNGE: EXAMPLE replication-controller.yaml -->
|
||||
|
||||
@@ -105,22 +100,19 @@ spec:
|
||||
|
||||
Create an nginx replication controller ([replication-controller.yaml](replication-controller.yaml)):
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl create -f docs/user-guide/walkthrough/replication-controller.yaml
|
||||
```
|
||||
|
||||
```
|
||||
List all replication controllers:
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl get rc
|
||||
```
|
||||
|
||||
```
|
||||
Delete the replication controller by name:
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl delete rc nginx-controller
|
||||
```
|
||||
|
||||
```
|
||||
For more information, see [Replication Controllers](../replication-controller).
|
||||
|
||||
|
||||
@@ -132,7 +124,7 @@ For example, here is a service that balances across the pods created in the prev
|
||||
|
||||
<!-- BEGIN MUNGE: EXAMPLE service.yaml -->
|
||||
|
||||
```yaml
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
@@ -149,8 +141,7 @@ spec:
|
||||
# traffic to.
|
||||
selector:
|
||||
app: nginx
|
||||
```
|
||||
|
||||
```
|
||||
[Download example](service.yaml)
|
||||
<!-- END MUNGE: EXAMPLE service.yaml -->
|
||||
|
||||
@@ -158,32 +149,28 @@ spec:
|
||||
|
||||
Create an nginx service ([service.yaml](service.yaml)):
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl create -f docs/user-guide/walkthrough/service.yaml
|
||||
```
|
||||
|
||||
```
|
||||
List all services:
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl get services
|
||||
```
|
||||
|
||||
```
|
||||
On most providers, the service IPs are not externally accessible. The easiest way to test that the service is working is to create a busybox pod and exec commands on it remotely. See the [command execution documentation](../kubectl/kubectl_exec) for details.
|
||||
|
||||
Provided the service IP is accessible, you should be able to access its http endpoint with curl on port 80:
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ export SERVICE_IP=$(kubectl get service nginx-service -o go-template={{.spec.clusterIP}})
|
||||
$ export SERVICE_PORT=$(kubectl get service nginx-service -o go-template'={{(index .spec.ports 0).port}}')
|
||||
$ curl http://${SERVICE_IP}:${SERVICE_PORT}
|
||||
```
|
||||
|
||||
```
|
||||
To delete the service by name:
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl delete service nginx-service
|
||||
```
|
||||
|
||||
```
|
||||
When created, each service is assigned a unique IP address. This address is tied to the lifespan of the Service, and will not change while the Service is alive. Pods can be configured to talk to the service, and know that communication to the service will be automatically load-balanced out to some pod that is a member of the set identified by the label selector in the Service.
|
||||
|
||||
For more information, see [Services](../services).
|
||||
@@ -210,7 +197,7 @@ Kubernetes.
|
||||
|
||||
However, in many cases this low-level health checking is insufficient. Consider, for example, the following code:
|
||||
|
||||
```go
|
||||
```go
|
||||
lockOne := sync.Mutex{}
|
||||
lockTwo := sync.Mutex{}
|
||||
|
||||
@@ -222,8 +209,7 @@ go func() {
|
||||
|
||||
lockTwo.Lock();
|
||||
lockOne.Lock();
|
||||
```
|
||||
|
||||
```
|
||||
This is a classic example of a problem in computer science known as ["Deadlock"](https://en.wikipedia.org/wiki/Deadlock). From Docker's perspective your application is
|
||||
still operating and the process is still running, but from your application's perspective your code is locked up and will never respond correctly.
|
||||
|
||||
@@ -244,7 +230,7 @@ Here is an example config for a pod with an HTTP health check ([pod-with-http-he
|
||||
|
||||
<!-- BEGIN MUNGE: EXAMPLE pod-with-http-healthcheck.yaml -->
|
||||
|
||||
```yaml
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
@@ -265,8 +251,7 @@ spec:
|
||||
timeoutSeconds: 1
|
||||
ports:
|
||||
- containerPort: 80
|
||||
```
|
||||
|
||||
```
|
||||
[Download example](pod-with-http-healthcheck.yaml)
|
||||
<!-- END MUNGE: EXAMPLE pod-with-http-healthcheck.yaml -->
|
||||
|
||||
@@ -275,4 +260,4 @@ For more information about health checking, see [Container Probes](../pod-states
|
||||
|
||||
## What's Next?
|
||||
|
||||
For a complete application see the [guestbook example](../../../examples/guestbook/).
|
||||
For a complete application see the [guestbook example](https://github.com/kubernetes/kubernetes/tree/master/examples/guestbook/).
|
||||
@@ -15,7 +15,6 @@ resource, a number of the fields of the resource are added.
|
||||
You can see this at work in the following example:
|
||||
|
||||
```shell
|
||||
|
||||
$ cat > /tmp/original.yaml <<EOF
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
@@ -37,7 +36,6 @@ $ wc -l /tmp/original.yaml /tmp/current.yaml
|
||||
60 total
|
||||
|
||||
```
|
||||
|
||||
The resource we posted had only 9 lines, but the one we got back had 51 lines.
|
||||
If you `diff -u /tmp/original.yaml /tmp/current.yaml`, you can see the fields added to the pod.
|
||||
The system adds fields in several ways:
|
||||
|
||||
Reference in New Issue
Block a user