Syntax highlighting manual fixes up to mesos.md (next is scratch.md)
This commit is contained in:
@@ -127,11 +127,6 @@ Yes.
|
||||
|
||||
For Kubernetes 1.0, we strongly recommend running the following set of admission control plug-ins (order matters):
|
||||
|
||||
```
|
||||
|
||||
```shell
|
||||
--admission-control=NamespaceLifecycle,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -88,26 +88,19 @@ To permit an action Policy with an unset namespace applies regardless of namespa
|
||||
|
||||
A service account automatically generates a user. The user's name is generated according to the naming convention:
|
||||
|
||||
```
|
||||
|
||||
```shell
|
||||
system:serviceaccount:<namespace>:<serviceaccountname>
|
||||
|
||||
```
|
||||
|
||||
Creating a new namespace also causes a new service account to be created, of this form:*
|
||||
|
||||
```
|
||||
|
||||
```shell
|
||||
system:serviceaccount:<namespace>:default
|
||||
|
||||
```
|
||||
|
||||
For example, if you wanted to grant the default service account in the kube-system full privilege to the API, you would add this line to your policy file:
|
||||
|
||||
```json
|
||||
|
||||
{"user":"system:serviceaccount:kube-system:default"}
|
||||
|
||||
```
|
||||
|
||||
The apiserver will need to be restarted to pickup the new policy lines.
|
||||
@@ -118,11 +111,9 @@ Other implementations can be developed fairly easily.
|
||||
The APIserver calls the Authorizer interface:
|
||||
|
||||
```go
|
||||
|
||||
type Authorizer interface {
|
||||
Authorize(a Attributes) error
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
to determine whether or not to allow each API action.
|
||||
|
||||
@@ -40,7 +40,7 @@ To prevent memory leaks or other resource issues in [cluster addons](https://rel
|
||||
|
||||
For example:
|
||||
|
||||
```yaml
|
||||
```yaml
|
||||
containers:
|
||||
- image: gcr.io/google_containers/heapster:v0.15.0
|
||||
name: heapster
|
||||
@@ -48,8 +48,8 @@ containers:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 200Mi
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
These limits, however, are based on data collected from addons running on 4-node clusters (see [#10335](http://issue.k8s.io/10335#issuecomment-117861225)). The addons consume a lot more resources when running on large deployment clusters (see [#5880](http://issue.k8s.io/5880#issuecomment-113984085)). So, if a large cluster is deployed without adjusting these values, the addons may continuously get killed because they keep hitting the limits.
|
||||
|
||||
To avoid running into cluster addon resource issues, when creating a cluster with many nodes, consider the following:
|
||||
|
||||
@@ -40,24 +40,20 @@ The node upgrade process is user-initiated and is described in the [GKE document
|
||||
|
||||
### Upgrading open source Google Compute Engine clusters
|
||||
|
||||
Upgrades on open source Google Compute Engine (GCE) clusters are controlled by the ```cluster/gce/upgrade.sh``` script.
|
||||
Upgrades on open source Google Compute Engine (GCE) clusters are controlled by the `cluster/gce/upgrade.sh` script.
|
||||
|
||||
Get its usage by running `cluster/gce/upgrade.sh -h`.
|
||||
|
||||
For example, to upgrade just your master to a specific version (v1.0.2):
|
||||
|
||||
```shell
|
||||
|
||||
cluster/gce/upgrade.sh -M v1.0.2
|
||||
|
||||
```
|
||||
|
||||
Alternatively, to upgrade your entire cluster to the latest stable release:
|
||||
|
||||
```shell
|
||||
|
||||
cluster/gce/upgrade.sh release/stable
|
||||
|
||||
```
|
||||
|
||||
### Other platforms
|
||||
@@ -70,10 +66,8 @@ recommend testing the upgrade on an experimental cluster before performing the u
|
||||
If your cluster runs short on resources you can easily add more machines to it if your cluster is running in [Node self-registration mode](node.html#self-registration-of-nodes).
|
||||
If you're using GCE or GKE it's done by resizing Instance Group managing your Nodes. It can be accomplished by modifying number of instances on `Compute > Compute Engine > Instance groups > your group > Edit group` [Google Cloud Console page](https://console.developers.google.com) or using gcloud CLI:
|
||||
|
||||
```
|
||||
|
||||
```shell
|
||||
gcloud compute instance-groups managed --zone compute-zone resize my-cluster-minon-group --new-size 42
|
||||
|
||||
```
|
||||
|
||||
Instance Group will take care of putting appropriate image on new machines and start them, while Kubelet will register its Node with API server to make it available for scheduling. If you scale the instance group down, system will randomly choose Nodes to kill.
|
||||
@@ -84,31 +78,32 @@ In other environments you may need to configure the machine yourself and tell th
|
||||
### Horizontal auto-scaling of nodes (GCE)
|
||||
|
||||
If you are using GCE, you can configure your cluster so that the number of nodes will be automatically scaled based on their CPU and memory utilization.
|
||||
Before setting up the cluster by ```kube-up.sh```, you can set ```KUBE_ENABLE_NODE_AUTOSCALER``` environment variable to ```true``` and export it.
|
||||
Before setting up the cluster by `kube-up.sh`, you can set `KUBE_ENABLE_NODE_AUTOSCALE`
|
||||
environment variable to `true`
|
||||
and export it.
|
||||
The script will create an autoscaler for the instance group managing your nodes.
|
||||
|
||||
The autoscaler will try to maintain the average CPU and memory utilization of nodes within the cluster close to the target value.
|
||||
The target value can be configured by ```KUBE_TARGET_NODE_UTILIZATION``` environment variable (default: 0.7) for ``kube-up.sh`` when creating the cluster.
|
||||
The target value can be configured by `KUBE_TARGET_NODE_UTILIZATION`
|
||||
environment variable (default: 0.7) for `kube-up.sh` when creating the cluster.
|
||||
The node utilization is the total node's CPU/memory usage (OS + k8s + user load) divided by the node's capacity.
|
||||
If the desired numbers of nodes in the cluster resulting from CPU utilization and memory utilization are different,
|
||||
the autoscaler will choose the bigger number.
|
||||
The number of nodes in the cluster set by the autoscaler will be limited from ```KUBE_AUTOSCALER_MIN_NODES``` (default: 1)
|
||||
to ```KUBE_AUTOSCALER_MAX_NODES``` (default: the initial number of nodes in the cluster).
|
||||
The number of nodes in the cluster set by the autoscaler will be limited from `KUBE_AUTOSCALER_MIN_NODES`
|
||||
(default: 1)
|
||||
to `KUBE_AUTOSCALER_MAX_NODES`
|
||||
(default: the initial number of nodes in the cluster).
|
||||
|
||||
The autoscaler is implemented as a Compute Engine Autoscaler.
|
||||
The initial values of the autoscaler parameters set by ``kube-up.sh`` and some more advanced options can be tweaked on
|
||||
The initial values of the autoscaler parameters set by `kube-up.sh` and some more advanced options can be tweaked on
|
||||
`Compute > Compute Engine > Instance groups > your group > Edit group`[Google Cloud Console page](https://console.developers.google.com)
|
||||
or using gcloud CLI:
|
||||
|
||||
```
|
||||
|
||||
```shell
|
||||
gcloud preview autoscaler --zone compute-zone <command>
|
||||
|
||||
```
|
||||
|
||||
Note that autoscaling will work properly only if node metrics are accessible in Google Cloud Monitoring.
|
||||
To make the metrics accessible, you need to create your cluster with ```KUBE_ENABLE_CLUSTER_MONITORING```
|
||||
equal to ```google``` or ```googleinfluxdb``` (```googleinfluxdb``` is the default value).
|
||||
Note that autoscaling will work properly only if node metrics are accessible in Google Cloud Monitoring. To make the metrics accessible, you need to create your cluster with `KUBE_ENABLE_CLUSTER_MONITORING` equal to `google` or `googleinfluxdb` (`googleinfluxdb` is the default value).
|
||||
|
||||
## Maintenance on a Node
|
||||
|
||||
@@ -123,9 +118,7 @@ If you want more control over the upgrading process, you may use the following w
|
||||
Mark the node to be rebooted as unschedulable:
|
||||
|
||||
```shell
|
||||
|
||||
kubectl replace nodes $NODENAME --patch='{"apiVersion": "v1", "spec": {"unschedulable": true}}'
|
||||
|
||||
```
|
||||
|
||||
This keeps new pods from landing on the node while you are trying to get them off.
|
||||
@@ -135,9 +128,7 @@ Get the pods off the machine, via any of the following strategies:
|
||||
* Delete pods with:
|
||||
|
||||
```shell
|
||||
|
||||
kubectl delete pods $PODNAME
|
||||
|
||||
```
|
||||
|
||||
For pods with a replication controller, the pod will eventually be replaced by a new pod which will be scheduled to a new node. Additionally, if the pod is part of a service, then clients will automatically be redirected to the new pod.
|
||||
@@ -149,9 +140,7 @@ Perform maintenance work on the node.
|
||||
Make the node schedulable again:
|
||||
|
||||
```shell
|
||||
|
||||
kubectl replace nodes $NODENAME --patch='{"apiVersion": "v1", "spec": {"unschedulable": false}}'
|
||||
|
||||
```
|
||||
|
||||
If you deleted the node's VM instance and created a new one, then a new schedulable node resource will
|
||||
@@ -193,11 +182,6 @@ for changes to this variable to take effect.
|
||||
You can use the `kube-version-change` utility to convert config files between different API versions.
|
||||
|
||||
```shell
|
||||
|
||||
$ hack/build-go.sh cmd/kube-version-change
|
||||
$ _output/local/go/bin/kube-version-change -i myPod.v1beta3.yaml -o myPod.v1.yaml
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -13,9 +13,7 @@ The first thing to debug in your cluster is if your nodes are all registered cor
|
||||
Run
|
||||
|
||||
```shell
|
||||
|
||||
kubectl get nodes
|
||||
|
||||
```
|
||||
|
||||
And verify that all of the nodes you expect to see are present and that they are all in the `Ready` state.
|
||||
@@ -108,7 +106,4 @@ Mitigations:
|
||||
- Mitigates: Kubelet software fault
|
||||
|
||||
- Action: [Multiple independent clusters](multi-cluster) (and avoid making risky changes to all clusters at once)
|
||||
- Mitigates: Everything listed above.
|
||||
|
||||
|
||||
|
||||
- Mitigates: Everything listed above.
|
||||
@@ -42,10 +42,5 @@ test key. On your master VM (or somewhere with firewalls configured such that
|
||||
you can talk to your cluster's etcd), try:
|
||||
|
||||
```shell
|
||||
|
||||
curl -fs -X PUT "http://${host}:${port}/v2/keys/_test"
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -12,8 +12,6 @@ or try [Google Container Engine](https://cloud.google.com/container-engine/) for
|
||||
Also, at this time high availability support for Kubernetes is not continuously tested in our end-to-end (e2e) testing. We will
|
||||
be working to add this continuous testing, but for now the single-node master installations are more heavily tested.
|
||||
|
||||
|
||||
|
||||
{% include pagetoc.html %}
|
||||
|
||||
## Overview
|
||||
@@ -85,10 +83,10 @@ a simple cluster set up, using etcd's built in discovery to build our cluster.
|
||||
|
||||
First, hit the etcd discovery service to create a new token:
|
||||
|
||||
```shell
|
||||
|
||||
curl https://discovery.etcd.io/new?size=3
|
||||
|
||||
```shell
|
||||
curl https://discovery.etcd.io/new?size=3
|
||||
```
|
||||
|
||||
On each node, copy the [etcd.yaml](high-availability/etcd.yaml) file into `/etc/kubernetes/manifests/etcd.yaml`
|
||||
|
||||
The kubelet on each node actively monitors the contents of that directory, and it will create an instance of the `etcd`
|
||||
@@ -103,16 +101,16 @@ for `${NODE_IP}` on each machine.
|
||||
|
||||
Once you copy this into all three nodes, you should have a clustered etcd set up. You can validate with
|
||||
|
||||
Once you copy this into all three nodes, you should have a clustered etcd set up. You can validate with
|
||||
|
||||
```shell
|
||||
|
||||
```shell
|
||||
etcdctl member list
|
||||
```
|
||||
|
||||
and
|
||||
|
||||
```
|
||||
|
||||
and
|
||||
|
||||
```shell
|
||||
etcdctl cluster-health
|
||||
```
|
||||
|
||||
You can also validate that this is working with `etcdctl set foo bar` on one node, and `etcd get foo`
|
||||
on a different node.
|
||||
|
||||
@@ -141,10 +139,10 @@ Once you have replicated etcd set up correctly, we will also install the apiserv
|
||||
|
||||
First you need to create the initial log file, so that Docker mounts a file instead of a directory:
|
||||
|
||||
Once you have replicated etcd set up correctly, we will also install the apiserver using the kubelet.
|
||||
|
||||
### Installing configuration files
|
||||
|
||||
```shell
|
||||
touch /var/log/kube-apiserver.log
|
||||
```
|
||||
|
||||
Next, you need to create a `/srv/kubernetes/` directory on each node. This directory includes:
|
||||
* basic_auth.csv - basic auth user and password
|
||||
* ca.crt - Certificate Authority cert
|
||||
@@ -193,14 +191,13 @@ In the future, we expect to more tightly integrate this lease-locking into the s
|
||||
|
||||
First, create empty log files on each node, so that Docker will mount the files not make new directories:
|
||||
|
||||
loses the election, it ensures that any master components running on the node (e.g. the scheduler) are stopped.
|
||||
```shell
|
||||
touch /var/log/kube-scheduler.log
|
||||
In the future, we expect to more tightly integrate this lease-locking into the scheduler and controller-manager binaries directly, as described in the [high availability design proposal](../proposals/high-availability)
|
||||
|
||||
### Installing configuration files
|
||||
touch /var/log/kube-controller-manager.log
|
||||
```
|
||||
|
||||
Next, set up the descriptions of the scheduler and controller manager pods on each node.
|
||||
First, create empty log files on each node, so that Docker will mount the files not make new directories:
|
||||
|
||||
by copying [kube-scheduler.yaml](high-availability/kube-scheduler.yaml) and [kube-controller-manager.yaml](high-availability/kube-controller-manager.yaml) into the `/srv/kubernetes/` directory.
|
||||
|
||||
### Running the podmaster
|
||||
|
||||
|
||||
@@ -40,32 +40,27 @@ This example will work in a custom namespace to demonstrate the concepts involve
|
||||
|
||||
Let's create a new namespace called limit-example:
|
||||
|
||||
```shell
|
||||
|
||||
```shell
|
||||
$ kubectl create -f docs/admin/limitrange/namespace.yaml
|
||||
namespace "limit-example" created
|
||||
$ kubectl get namespaces
|
||||
NAME LABELS STATUS AGE
|
||||
default <none> Active 5m
|
||||
limit-example <none> Active 53s
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
## Step 2: Apply a limit to the namespace
|
||||
|
||||
Let's create a simple limit in our namespace.
|
||||
|
||||
```shell
|
||||
|
||||
```shell
|
||||
$ kubectl create -f docs/admin/limitrange/limits.yaml --namespace=limit-example
|
||||
limitrange "mylimits" created
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
Let's describe the limits that we have imposed in our namespace.
|
||||
|
||||
```shell
|
||||
|
||||
```shell
|
||||
$ kubectl describe limits mylimits --namespace=limit-example
|
||||
Name: mylimits
|
||||
Namespace: limit-example
|
||||
@@ -75,9 +70,8 @@ Pod cpu 200m 2 - - -
|
||||
Pod memory 6Mi 1Gi - - -
|
||||
Container cpu 100m 2 200m 300m -
|
||||
Container memory 3Mi 1Gi 100Mi 200Mi -
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
In this scenario, we have said the following:
|
||||
|
||||
1. If a max constraint is specified for a resource (2 CPU and 1Gi memory in this case), then a limit
|
||||
@@ -104,20 +98,17 @@ of creation explaining why.
|
||||
Let's first spin up a replication controller that creates a single container pod to demonstrate
|
||||
how default values are applied to each pod.
|
||||
|
||||
```shell
|
||||
|
||||
```shell
|
||||
$ kubectl run nginx --image=nginx --replicas=1 --namespace=limit-example
|
||||
replicationcontroller "nginx" created
|
||||
$ kubectl get pods --namespace=limit-example
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
nginx-aq0mf 1/1 Running 0 35s
|
||||
$ kubectl get pods nginx-aq0mf --namespace=limit-example -o yaml | grep resources -C 8
|
||||
|
||||
```
|
||||
|
||||
```yaml
|
||||
|
||||
resourceVersion: "127"
|
||||
```
|
||||
|
||||
```yaml
|
||||
resourceVersion: "127"
|
||||
selfLink: /api/v1/namespaces/limit-example/pods/nginx-aq0mf
|
||||
uid: 51be42a7-7156-11e5-9921-286ed488f785
|
||||
spec:
|
||||
@@ -134,33 +125,27 @@ spec:
|
||||
memory: 100Mi
|
||||
terminationMessagePath: /dev/termination-log
|
||||
volumeMounts:
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
Note that our nginx container has picked up the namespace default cpu and memory resource *limits* and *requests*.
|
||||
|
||||
Let's create a pod that exceeds our allowed limits by having it have a container that requests 3 cpu cores.
|
||||
|
||||
```shell
|
||||
|
||||
```shell
|
||||
$ kubectl create -f docs/admin/limitrange/invalid-pod.yaml --namespace=limit-example
|
||||
Error from server: error when creating "docs/admin/limitrange/invalid-pod.yaml": Pod "invalid-pod" is forbidden: [Maximum cpu usage per Pod is 2, but limit is 3., Maximum cpu usage per Container is 2, but limit is 3.]
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
Let's create a pod that falls within the allowed limit boundaries.
|
||||
|
||||
```shell
|
||||
|
||||
```shell
|
||||
$ kubectl create -f docs/admin/limitrange/valid-pod.yaml --namespace=limit-example
|
||||
pod "valid-pod" created
|
||||
$ kubectl get pods valid-pod --namespace=limit-example -o yaml | grep -C 6 resources
|
||||
|
||||
```
|
||||
|
||||
```yaml
|
||||
|
||||
uid: 162a12aa-7157-11e5-9921-286ed488f785
|
||||
```
|
||||
|
||||
```yaml
|
||||
uid: 162a12aa-7157-11e5-9921-286ed488f785
|
||||
spec:
|
||||
containers:
|
||||
- image: gcr.io/google_containers/serve_hostname
|
||||
@@ -173,47 +158,36 @@ spec:
|
||||
requests:
|
||||
cpu: "1"
|
||||
memory: 512Mi
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
Note that this pod specifies explicit resource *limits* and *requests* so it did not pick up the namespace
|
||||
default values.
|
||||
|
||||
Note: The *limits* for CPU resource are not enforced in the default Kubernetes setup on the physical node
|
||||
that runs the container unless the administrator deploys the kubelet with the folllowing flag:
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
$ kubelet --help
|
||||
Usage of kubelet
|
||||
....
|
||||
--cpu-cfs-quota[=false]: Enable CPU CFS quota enforcement for containers that specify CPU limits
|
||||
$ kubelet --cpu-cfs-quota=true ...
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
## Step 4: Cleanup
|
||||
|
||||
To remove the resources used by this example, you can just delete the limit-example namespace.
|
||||
|
||||
```shell
|
||||
|
||||
```shell
|
||||
$ kubectl delete namespace limit-example
|
||||
namespace "limit-example" deleted
|
||||
$ kubectl get namespaces
|
||||
NAME LABELS STATUS AGE
|
||||
default <none> Active 20m
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
Cluster operators that want to restrict the amount of resources a single container or pod may consume
|
||||
are able to define allowable ranges per Kubernetes namespace. In the absence of any explicit assignments,
|
||||
the Kubernetes system is able to apply default resource *limits* and *requests* if desired in order to
|
||||
constrain the amount of resource a pod consumes on a node.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
constrain the amount of resource a pod consumes on a node.
|
||||
@@ -40,32 +40,27 @@ This example will work in a custom namespace to demonstrate the concepts involve
|
||||
|
||||
Let's create a new namespace called limit-example:
|
||||
|
||||
```shell
|
||||
|
||||
```shell
|
||||
$ kubectl create -f docs/admin/limitrange/namespace.yaml
|
||||
namespace "limit-example" created
|
||||
$ kubectl get namespaces
|
||||
NAME LABELS STATUS AGE
|
||||
default <none> Active 5m
|
||||
limit-example <none> Active 53s
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
## Step 2: Apply a limit to the namespace
|
||||
|
||||
Let's create a simple limit in our namespace.
|
||||
|
||||
```shell
|
||||
|
||||
```shell
|
||||
$ kubectl create -f docs/admin/limitrange/limits.yaml --namespace=limit-example
|
||||
limitrange "mylimits" created
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
Let's describe the limits that we have imposed in our namespace.
|
||||
|
||||
```shell
|
||||
|
||||
```shell
|
||||
$ kubectl describe limits mylimits --namespace=limit-example
|
||||
Name: mylimits
|
||||
Namespace: limit-example
|
||||
@@ -75,9 +70,8 @@ Pod cpu 200m 2 - - -
|
||||
Pod memory 6Mi 1Gi - - -
|
||||
Container cpu 100m 2 200m 300m -
|
||||
Container memory 3Mi 1Gi 100Mi 200Mi -
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
In this scenario, we have said the following:
|
||||
|
||||
1. If a max constraint is specified for a resource (2 CPU and 1Gi memory in this case), then a limit
|
||||
@@ -104,20 +98,17 @@ of creation explaining why.
|
||||
Let's first spin up a replication controller that creates a single container pod to demonstrate
|
||||
how default values are applied to each pod.
|
||||
|
||||
```shell
|
||||
|
||||
```shell
|
||||
$ kubectl run nginx --image=nginx --replicas=1 --namespace=limit-example
|
||||
replicationcontroller "nginx" created
|
||||
$ kubectl get pods --namespace=limit-example
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
nginx-aq0mf 1/1 Running 0 35s
|
||||
$ kubectl get pods nginx-aq0mf --namespace=limit-example -o yaml | grep resources -C 8
|
||||
|
||||
```
|
||||
|
||||
```yaml
|
||||
|
||||
resourceVersion: "127"
|
||||
```
|
||||
|
||||
```yaml
|
||||
resourceVersion: "127"
|
||||
selfLink: /api/v1/namespaces/limit-example/pods/nginx-aq0mf
|
||||
uid: 51be42a7-7156-11e5-9921-286ed488f785
|
||||
spec:
|
||||
@@ -134,33 +125,27 @@ spec:
|
||||
memory: 100Mi
|
||||
terminationMessagePath: /dev/termination-log
|
||||
volumeMounts:
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
Note that our nginx container has picked up the namespace default cpu and memory resource *limits* and *requests*.
|
||||
|
||||
Let's create a pod that exceeds our allowed limits by having it have a container that requests 3 cpu cores.
|
||||
|
||||
```shell
|
||||
|
||||
```shell
|
||||
$ kubectl create -f docs/admin/limitrange/invalid-pod.yaml --namespace=limit-example
|
||||
Error from server: error when creating "docs/admin/limitrange/invalid-pod.yaml": Pod "invalid-pod" is forbidden: [Maximum cpu usage per Pod is 2, but limit is 3., Maximum cpu usage per Container is 2, but limit is 3.]
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
Let's create a pod that falls within the allowed limit boundaries.
|
||||
|
||||
```shell
|
||||
|
||||
```shell
|
||||
$ kubectl create -f docs/admin/limitrange/valid-pod.yaml --namespace=limit-example
|
||||
pod "valid-pod" created
|
||||
$ kubectl get pods valid-pod --namespace=limit-example -o yaml | grep -C 6 resources
|
||||
|
||||
```
|
||||
|
||||
```yaml
|
||||
|
||||
uid: 162a12aa-7157-11e5-9921-286ed488f785
|
||||
```
|
||||
|
||||
```yaml
|
||||
uid: 162a12aa-7157-11e5-9921-286ed488f785
|
||||
spec:
|
||||
containers:
|
||||
- image: gcr.io/google_containers/serve_hostname
|
||||
@@ -173,47 +158,37 @@ spec:
|
||||
requests:
|
||||
cpu: "1"
|
||||
memory: 512Mi
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
Note that this pod specifies explicit resource *limits* and *requests* so it did not pick up the namespace
|
||||
default values.
|
||||
|
||||
Note: The *limits* for CPU resource are not enforced in the default Kubernetes setup on the physical node
|
||||
that runs the container unless the administrator deploys the kubelet with the folllowing flag:
|
||||
|
||||
```
|
||||
|
||||
```shell
|
||||
$ kubelet --help
|
||||
Usage of kubelet
|
||||
....
|
||||
--cpu-cfs-quota[=false]: Enable CPU CFS quota enforcement for containers that specify CPU limits
|
||||
$ kubelet --cpu-cfs-quota=true ...
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
## Step 4: Cleanup
|
||||
|
||||
To remove the resources used by this example, you can just delete the limit-example namespace.
|
||||
|
||||
```shell
|
||||
|
||||
```shell
|
||||
$ kubectl delete namespace limit-example
|
||||
namespace "limit-example" deleted
|
||||
$ kubectl get namespaces
|
||||
NAME LABELS STATUS AGE
|
||||
default <none> Active 20m
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
Cluster operators that want to restrict the amount of resources a single container or pod may consume
|
||||
are able to define allowable ranges per Kubernetes namespace. In the absence of any explicit assignments,
|
||||
the Kubernetes system is able to apply default resource *limits* and *requests* if desired in order to
|
||||
constrain the amount of resource a pod consumes on a node.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
constrain the amount of resource a pod consumes on a node.
|
||||
@@ -46,12 +46,10 @@ Look [here](namespaces/) for an in depth example of 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:
|
||||
@@ -61,15 +59,12 @@ Kubernetes starts with two initial namespaces:
|
||||
You can also get the summary of a specific namespace using:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get namespaces <name>
|
||||
|
||||
```
|
||||
|
||||
Or you can get detailed information with:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl describe namespaces <name>
|
||||
Name: default
|
||||
Labels: <none>
|
||||
@@ -81,7 +76,6 @@ Resource Limits
|
||||
Type Resource Min Max Default
|
||||
---- -------- --- --- ---
|
||||
Container cpu - - 100m
|
||||
|
||||
```
|
||||
|
||||
Note that these details show both resource quota (if present) as well as resource limit ranges.
|
||||
@@ -105,12 +99,10 @@ See the [design doc](../design/namespaces.html#phases) for more details.
|
||||
To create a new namespace, first create a new YAML file called `my-namespace.yaml` with the contents:
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: <insert-namespace-name-here>
|
||||
|
||||
```
|
||||
|
||||
Note that the name of your namespace must be a DNS compatible label.
|
||||
@@ -120,9 +112,7 @@ More information on the `finalizers` field can be found in the namespace [design
|
||||
Then run:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f ./my-namespace.yaml
|
||||
|
||||
```
|
||||
|
||||
### Working in namespaces
|
||||
@@ -135,9 +125,7 @@ and [Setting the namespace preference](/{{page.version}}/docs/user-guide/namespa
|
||||
You can delete a namespace with
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl delete namespaces <insert-some-namespace-name>
|
||||
|
||||
```
|
||||
|
||||
**WARNING, this deletes _everything_ under the namespace!**
|
||||
@@ -156,7 +144,4 @@ across namespaces, you need to use the fully qualified domain name (FQDN).
|
||||
## Design
|
||||
|
||||
Details of the design of namespaces in Kubernetes, including a [detailed example](../design/namespaces.html#example-openshift-origin-managing-a-kubernetes-namespace)
|
||||
can be found in the [namespaces design doc](../design/namespaces)
|
||||
|
||||
|
||||
|
||||
can be found in the [namespaces design doc](../design/namespaces)
|
||||
@@ -27,12 +27,12 @@ services, and replication controllers used by the cluster.
|
||||
|
||||
Assuming you have a fresh cluster, you can introspect the available namespace's by doing the following:
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl get namespaces
|
||||
NAME LABELS
|
||||
NAME LABELS
|
||||
default <none>
|
||||
|
||||
default <none>
|
||||
```
|
||||
|
||||
### Step Two: Create new namespaces
|
||||
|
||||
For this exercise, we will create two additional Kubernetes namespaces to hold our content.
|
||||
@@ -54,7 +54,7 @@ Use the file [`namespace-dev.json`](namespace-dev.json) which describes a develo
|
||||
|
||||
<!-- BEGIN MUNGE: EXAMPLE namespace-dev.json -->
|
||||
|
||||
<!-- BEGIN MUNGE: EXAMPLE namespace-dev.json -->
|
||||
```json
|
||||
{
|
||||
"kind": "Namespace",
|
||||
"apiVersion": "v1",
|
||||
@@ -64,35 +64,34 @@ Use the file [`namespace-dev.json`](namespace-dev.json) which describes a develo
|
||||
"name": "development"
|
||||
}
|
||||
}
|
||||
"name": "development"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
[Download example](namespace-dev.json)
|
||||
<!-- END MUNGE: EXAMPLE namespace-dev.json -->
|
||||
|
||||
Create the development namespace using kubectl.
|
||||
|
||||
<!-- END MUNGE: EXAMPLE namespace-dev.json -->
|
||||
|
||||
Create the development namespace using kubectl.
|
||||
|
||||
```shell
|
||||
$ kubectl create -f docs/admin/namespaces/namespace-dev.json
|
||||
```
|
||||
|
||||
And then lets create the production namespace using kubectl.
|
||||
|
||||
$ kubectl create -f docs/admin/namespaces/namespace-dev.json
|
||||
|
||||
```
|
||||
|
||||
```shell
|
||||
$ kubectl create -f docs/admin/namespaces/namespace-prod.json
|
||||
```
|
||||
|
||||
To be sure things are right, let's list all of the namespaces in our cluster.
|
||||
|
||||
```shell
|
||||
```shell
|
||||
$ kubectl get namespaces
|
||||
NAME LABELS STATUS
|
||||
default <none> Active
|
||||
development name=development Active
|
||||
|
||||
To be sure things are right, let's list all of the namespaces in our cluster.
|
||||
|
||||
```shell
|
||||
production name=production Active
|
||||
```
|
||||
|
||||
### Step Three: Create pods in each namespace
|
||||
|
||||
A Kubernetes namespace provides the scope for pods, services, and replication controllers in the cluster.
|
||||
@@ -103,7 +102,7 @@ To demonstrate this, let's spin up a simple replication controller and pod in th
|
||||
|
||||
We first check what is the current context:
|
||||
|
||||
### Step Three: Create pods in each namespace
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
@@ -127,32 +126,32 @@ users:
|
||||
- name: lithe-cocoa-92103_kubernetes-basic-auth
|
||||
user:
|
||||
password: h5M0FtUUIflBSdI7
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
username: admin
|
||||
```
|
||||
|
||||
The next step is to define a context for the kubectl client to work in each namespace. The value of "cluster" and "user" fields are copied from the current context.
|
||||
|
||||
client-certificate-data: REDACTED
|
||||
```shell
|
||||
$ kubectl config set-context dev --namespace=development --cluster=lithe-cocoa-92103_kubernetes --user=lithe-cocoa-92103_kubernetes
|
||||
token: 65rZW78y8HbwXXtSXuUw9DbP4FLjHi4b
|
||||
- name: lithe-cocoa-92103_kubernetes-basic-auth
|
||||
user:
|
||||
$ kubectl config set-context prod --namespace=production --cluster=lithe-cocoa-92103_kubernetes --user=lithe-cocoa-92103_kubernetes
|
||||
```
|
||||
|
||||
The above commands provided two request contexts you can alternate against depending on what namespace you
|
||||
wish to work against.
|
||||
|
||||
Let's switch to operate in the development namespace.
|
||||
|
||||
The next step is to define a context for the kubectl client to work in each namespace. The value of "cluster" and "user" fields are copied from the current context.
|
||||
|
||||
```shell
|
||||
|
||||
```shell
|
||||
$ kubectl config use-context dev
|
||||
```
|
||||
|
||||
You can verify your current context by doing the following:
|
||||
|
||||
|
||||
```
|
||||
|
||||
The above commands provided two request contexts you can alternate against depending on what namespace you
|
||||
wish to work against.
|
||||
```shell
|
||||
$ kubectl config view
|
||||
```
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
@@ -186,20 +185,20 @@ users:
|
||||
- name: lithe-cocoa-92103_kubernetes-basic-auth
|
||||
user:
|
||||
password: h5M0FtUUIflBSdI7
|
||||
user: lithe-cocoa-92103_kubernetes
|
||||
name: lithe-cocoa-92103_kubernetes
|
||||
- context:
|
||||
username: admin
|
||||
```
|
||||
|
||||
At this point, all requests we make to the Kubernetes cluster from the command line are scoped to the development namespace.
|
||||
|
||||
Let's create some content.
|
||||
|
||||
current-context: dev
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
```shell
|
||||
$ kubectl run snowflake --image=kubernetes/serve_hostname --replicas=2
|
||||
```
|
||||
|
||||
We have just created a replication controller whose replica size is 2 that is running the pod called snowflake with a basic container that just serves the hostname.
|
||||
|
||||
client-certificate-data: REDACTED
|
||||
```shell
|
||||
$ kubectl get rc
|
||||
CONTROLLER CONTAINER(S) IMAGE(S) SELECTOR REPLICAS
|
||||
snowflake snowflake kubernetes/serve_hostname run=snowflake 2
|
||||
@@ -207,30 +206,30 @@ snowflake snowflake kubernetes/serve_hostname run=snowflake 2
|
||||
$ kubectl get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
snowflake-8w0qn 1/1 Running 0 22s
|
||||
```
|
||||
|
||||
At this point, all requests we make to the Kubernetes cluster from the command line are scoped to the development namespace.
|
||||
snowflake-jrpzb 1/1 Running 0 22s
|
||||
```
|
||||
|
||||
And this is great, developers are able to do what they want, and they do not have to worry about affecting content in the production namespace.
|
||||
|
||||
Let's switch to the production namespace and show how resources in one namespace are hidden from the other.
|
||||
|
||||
|
||||
$ kubectl run snowflake --image=kubernetes/serve_hostname --replicas=2
|
||||
|
||||
```
|
||||
```shell
|
||||
$ kubectl config use-context prod
|
||||
```
|
||||
|
||||
The production namespace should be empty.
|
||||
|
||||
|
||||
```shell
|
||||
$ kubectl get rc
|
||||
CONTROLLER CONTAINER(S) IMAGE(S) SELECTOR REPLICAS
|
||||
|
||||
$ kubectl get pods
|
||||
snowflake snowflake kubernetes/serve_hostname run=snowflake 2
|
||||
|
||||
$ kubectl get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
```
|
||||
|
||||
Production likes to run cattle, so let's create some cattle pods.
|
||||
|
||||
snowflake-jrpzb 1/1 Running 0 22s
|
||||
```shell
|
||||
$ kubectl run cattle --image=kubernetes/serve_hostname --replicas=5
|
||||
|
||||
$ kubectl get rc
|
||||
@@ -243,9 +242,9 @@ cattle-97rva 1/1 Running 0 12s
|
||||
cattle-i9ojn 1/1 Running 0 12s
|
||||
cattle-qj3yv 1/1 Running 0 12s
|
||||
cattle-yc7vn 1/1 Running 0 12s
|
||||
|
||||
The production namespace should be empty.
|
||||
|
||||
cattle-zz7ea 1/1 Running 0 12s
|
||||
```
|
||||
|
||||
At this point, it should be clear that the resources users create in one namespace are hidden from the other namespace.
|
||||
|
||||
As the policy support in Kubernetes evolves, we will extend this scenario to show how you can provide different
|
||||
|
||||
@@ -27,11 +27,9 @@ services, and replication controllers used by the cluster.
|
||||
Assuming you have a fresh cluster, you can introspect the available namespace's by doing the following:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get namespaces
|
||||
NAME LABELS
|
||||
default <none>
|
||||
|
||||
```
|
||||
|
||||
### Step Two: Create new namespaces
|
||||
@@ -56,7 +54,6 @@ Use the file [`namespace-dev.json`](namespace-dev.json) which describes a develo
|
||||
<!-- BEGIN MUNGE: EXAMPLE namespace-dev.json -->
|
||||
|
||||
```json
|
||||
|
||||
{
|
||||
"kind": "Namespace",
|
||||
"apiVersion": "v1",
|
||||
@@ -67,7 +64,6 @@ Use the file [`namespace-dev.json`](namespace-dev.json) which describes a develo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
[Download example](namespace-dev.json)
|
||||
@@ -76,32 +72,25 @@ Use the file [`namespace-dev.json`](namespace-dev.json) which describes a develo
|
||||
Create the development namespace using kubectl.
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f docs/admin/namespaces/namespace-dev.json
|
||||
|
||||
```
|
||||
|
||||
And then lets create the production namespace using kubectl.
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl create -f docs/admin/namespaces/namespace-prod.json
|
||||
|
||||
```
|
||||
|
||||
To be sure things are right, let's list all of the namespaces in our cluster.
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get namespaces
|
||||
NAME LABELS STATUS
|
||||
default <none> Active
|
||||
development name=development Active
|
||||
production name=production Active
|
||||
|
||||
```
|
||||
|
||||
|
||||
### Step Three: Create pods in each namespace
|
||||
|
||||
A Kubernetes namespace provides the scope for pods, services, and replication controllers in the cluster.
|
||||
@@ -113,7 +102,6 @@ To demonstrate this, let's spin up a simple replication controller and pod in th
|
||||
We first check what is the current context:
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
@@ -138,16 +126,13 @@ users:
|
||||
user:
|
||||
password: h5M0FtUUIflBSdI7
|
||||
username: admin
|
||||
|
||||
```
|
||||
|
||||
The next step is to define a context for the kubectl client to work in each namespace. The value of "cluster" and "user" fields are copied from the current context.
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl config set-context dev --namespace=development --cluster=lithe-cocoa-92103_kubernetes --user=lithe-cocoa-92103_kubernetes
|
||||
$ kubectl config set-context prod --namespace=production --cluster=lithe-cocoa-92103_kubernetes --user=lithe-cocoa-92103_kubernetes
|
||||
|
||||
```
|
||||
|
||||
The above commands provided two request contexts you can alternate against depending on what namespace you
|
||||
@@ -156,21 +141,16 @@ wish to work against.
|
||||
Let's switch to operate in the development namespace.
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl config use-context dev
|
||||
|
||||
```
|
||||
|
||||
You can verify your current context by doing the following:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl config view
|
||||
|
||||
```
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
@@ -205,7 +185,6 @@ users:
|
||||
user:
|
||||
password: h5M0FtUUIflBSdI7
|
||||
username: admin
|
||||
|
||||
```
|
||||
|
||||
At this point, all requests we make to the Kubernetes cluster from the command line are scoped to the development namespace.
|
||||
@@ -213,15 +192,12 @@ At this point, all requests we make to the Kubernetes cluster from the command l
|
||||
Let's create some content.
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl run snowflake --image=kubernetes/serve_hostname --replicas=2
|
||||
|
||||
```
|
||||
|
||||
We have just created a replication controller whose replica size is 2 that is running the pod called snowflake with a basic container that just serves the hostname.
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get rc
|
||||
CONTROLLER CONTAINER(S) IMAGE(S) SELECTOR REPLICAS
|
||||
snowflake snowflake kubernetes/serve_hostname run=snowflake 2
|
||||
@@ -230,7 +206,6 @@ $ kubectl get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
snowflake-8w0qn 1/1 Running 0 22s
|
||||
snowflake-jrpzb 1/1 Running 0 22s
|
||||
|
||||
```
|
||||
|
||||
And this is great, developers are able to do what they want, and they do not have to worry about affecting content in the production namespace.
|
||||
@@ -238,27 +213,22 @@ And this is great, developers are able to do what they want, and they do not hav
|
||||
Let's switch to the production namespace and show how resources in one namespace are hidden from the other.
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl config use-context prod
|
||||
|
||||
```
|
||||
|
||||
The production namespace should be empty.
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl get rc
|
||||
CONTROLLER CONTAINER(S) IMAGE(S) SELECTOR REPLICAS
|
||||
|
||||
$ kubectl get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
|
||||
```
|
||||
|
||||
Production likes to run cattle, so let's create some cattle pods.
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl run cattle --image=kubernetes/serve_hostname --replicas=5
|
||||
|
||||
$ kubectl get rc
|
||||
@@ -272,13 +242,9 @@ cattle-i9ojn 1/1 Running 0 12s
|
||||
cattle-qj3yv 1/1 Running 0 12s
|
||||
cattle-yc7vn 1/1 Running 0 12s
|
||||
cattle-zz7ea 1/1 Running 0 12s
|
||||
|
||||
```
|
||||
|
||||
At this point, it should be clear that the resources users create in one namespace are hidden from the other namespace.
|
||||
|
||||
As the policy support in Kubernetes evolves, we will extend this scenario to show how you can provide different
|
||||
authorization rules for each namespace.
|
||||
|
||||
|
||||
|
||||
authorization rules for each namespace.
|
||||
@@ -108,9 +108,7 @@ on that subnet, and is passed to docker's `--bridge` flag.
|
||||
We start Docker with:
|
||||
|
||||
```shell
|
||||
|
||||
DOCKER_OPTS="--bridge=cbr0 --iptables=false --ip-masq=false"
|
||||
|
||||
DOCKER_OPTS="--bridge=cbr0 --iptables=false --ip-masq=false"
|
||||
```
|
||||
|
||||
This bridge is created by Kubelet (controlled by the `--configure-cbr0=true`
|
||||
@@ -127,18 +125,14 @@ itself) traffic that is bound for IPs outside the GCE project network
|
||||
(10.0.0.0/8).
|
||||
|
||||
```shell
|
||||
|
||||
iptables -t nat -A POSTROUTING ! -d 10.0.0.0/8 -o eth0 -j MASQUERADE
|
||||
|
||||
```
|
||||
|
||||
Lastly we enable IP forwarding in the kernel (so the kernel will process
|
||||
packets for bridged containers):
|
||||
|
||||
```shell
|
||||
|
||||
sysctl net.ipv4.ip_forward=1
|
||||
|
||||
```
|
||||
|
||||
The result of all this is that all `Pods` can reach each other and can egress
|
||||
@@ -183,7 +177,4 @@ IPs.
|
||||
|
||||
The early design of the networking model and its rationale, and some future
|
||||
plans are described in more detail in the [networking design
|
||||
document](../design/networking).
|
||||
|
||||
|
||||
|
||||
document](../design/networking).
|
||||
@@ -57,14 +57,12 @@ Node condition is represented as a json object. For example,
|
||||
the following conditions mean the node is in sane state:
|
||||
|
||||
```json
|
||||
|
||||
"conditions": [
|
||||
{
|
||||
"kind": "Ready",
|
||||
"status": "True",
|
||||
},
|
||||
]
|
||||
|
||||
```
|
||||
|
||||
If the Status of the Ready condition
|
||||
@@ -91,7 +89,6 @@ After creation, Kubernetes will check whether the node is valid or not.
|
||||
For example, if you try to create a node from the following content:
|
||||
|
||||
```json
|
||||
|
||||
{
|
||||
"kind": "Node",
|
||||
"apiVersion": "v1",
|
||||
@@ -102,7 +99,6 @@ For example, if you try to create a node from the following content:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Kubernetes will create a Node object internally (the representation), and
|
||||
@@ -165,9 +161,7 @@ preparatory step before a node reboot, etc. For example, to mark a node
|
||||
unschedulable, run this command:
|
||||
|
||||
```shell
|
||||
|
||||
kubectl replace nodes 10.1.2.3 --patch='{"apiVersion": "v1", "unschedulable": true}'
|
||||
|
||||
```
|
||||
|
||||
Note that pods which are created by a daemonSet controller bypass the Kubernetes scheduler,
|
||||
@@ -190,7 +184,6 @@ If you want to explicitly reserve resources for non-Pod processes, you can creat
|
||||
pod. Use the following template:
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
@@ -203,7 +196,6 @@ spec:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 100Mi
|
||||
|
||||
```
|
||||
|
||||
Set the `cpu` and `memory` values to the amount of resources you want to reserve.
|
||||
@@ -216,6 +208,3 @@ on each kubelet where you want to reserve resources.
|
||||
Node is a top-level resource in the kubernetes REST API. More details about the
|
||||
API object can be found at: [Node API
|
||||
object](http://kubernetes.io/v1.1/docs/api-reference/v1/definitions.html#_v1_node).
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -87,7 +87,6 @@ supply of Pod IPs.
|
||||
Kubectl supports creating, updating, and viewing quotas:
|
||||
|
||||
```shell
|
||||
|
||||
$ kubectl namespace myspace
|
||||
$ cat <<EOF > quota.json
|
||||
{
|
||||
@@ -122,7 +121,6 @@ pods 5 10
|
||||
replicationcontrollers 5 20
|
||||
resourcequotas 1 1
|
||||
services 3 5
|
||||
|
||||
```
|
||||
|
||||
## Quota and Cluster Capacity
|
||||
@@ -146,11 +144,8 @@ restrictions around nodes: pods from several namespaces may run on the same node
|
||||
|
||||
## Example
|
||||
|
||||
See a [detailed example for how to use resource quota](resourcequota/)..
|
||||
See a [detailed example for how to use resource quota](resourcequota/).
|
||||
|
||||
## Read More
|
||||
|
||||
See [ResourceQuota design doc](../design/admission_control_resource_quota) for more information.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -13,17 +13,15 @@ This example will work in a custom namespace to demonstrate the concepts involve
|
||||
|
||||
Let's create a new namespace called quota-example:
|
||||
|
||||
```shell
|
||||
|
||||
```shell
|
||||
$ kubectl create -f docs/admin/resourcequota/namespace.yaml
|
||||
namespace "quota-example" created
|
||||
$ kubectl get namespaces
|
||||
NAME LABELS STATUS AGE
|
||||
default <none> Active 2m
|
||||
quota-example <none> Active 39s
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
## Step 2: Apply a quota to the namespace
|
||||
|
||||
By default, a pod will run with unbounded CPU and memory requests/limits. This means that any pod in the
|
||||
@@ -37,21 +35,18 @@ checks the total resource *requests*, not resource *limits* of all containers/po
|
||||
|
||||
Let's create a simple quota in our namespace:
|
||||
|
||||
```shell
|
||||
|
||||
```shell
|
||||
$ kubectl create -f docs/admin/resourcequota/quota.yaml --namespace=quota-example
|
||||
resourcequota "quota" created
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
Once your quota is applied to a namespace, the system will restrict any creation of content
|
||||
in the namespace until the quota usage has been calculated. This should happen quickly.
|
||||
|
||||
You can describe your current quota usage to see what resources are being consumed in your
|
||||
namespace.
|
||||
|
||||
```shell
|
||||
|
||||
```shell
|
||||
$ kubectl describe quota quota --namespace=quota-example
|
||||
Name: quota
|
||||
Namespace: quota-example
|
||||
@@ -65,9 +60,8 @@ replicationcontrollers 0 20
|
||||
resourcequotas 1 1
|
||||
secrets 1 10
|
||||
services 0 5
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
## Step 3: Applying default resource requests and limits
|
||||
|
||||
Pod authors rarely specify resource requests and limits for their pods.
|
||||
@@ -77,26 +71,21 @@ cpu and memory by creating an nginx container.
|
||||
|
||||
To demonstrate, lets create a replication controller that runs nginx:
|
||||
|
||||
```shell
|
||||
|
||||
```shell
|
||||
$ kubectl run nginx --image=nginx --replicas=1 --namespace=quota-example
|
||||
replicationcontroller "nginx" created
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
Now let's look at the pods that were created.
|
||||
|
||||
```shell
|
||||
|
||||
```shell
|
||||
$ kubectl get pods --namespace=quota-example
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
What happened? I have no pods! Let's describe the replication controller to get a view of what is happening.
|
||||
|
||||
```shell
|
||||
|
||||
```shell
|
||||
kubectl describe rc nginx --namespace=quota-example
|
||||
Name: nginx
|
||||
Namespace: quota-example
|
||||
@@ -109,16 +98,14 @@ No volumes.
|
||||
Events:
|
||||
FirstSeen LastSeen Count From SubobjectPath Reason Message
|
||||
42s 11s 3 {replication-controller } FailedCreate Error creating: Pod "nginx-" is forbidden: Must make a non-zero request for memory since it is tracked by quota.
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
The Kubernetes API server is rejecting the replication controllers requests to create a pod because our pods
|
||||
do not specify any memory usage *request*.
|
||||
|
||||
So let's set some default values for the amount of cpu and memory a pod can consume:
|
||||
|
||||
```shell
|
||||
|
||||
```shell
|
||||
$ kubectl create -f docs/admin/resourcequota/limits.yaml --namespace=quota-example
|
||||
limitrange "limits" created
|
||||
$ kubectl describe limits limits --namespace=quota-example
|
||||
@@ -128,27 +115,23 @@ Type Resource Min Max Request Limit Limit/Request
|
||||
---- -------- --- --- ------- ----- -------------
|
||||
Container memory - - 256Mi 512Mi -
|
||||
Container cpu - - 100m 200m -
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
Now any time a pod is created in this namespace, if it has not specified any resource request/limit, the default
|
||||
amount of cpu and memory per container will be applied, and the request will be used as part of admission control.
|
||||
|
||||
Now that we have applied default resource *request* for our namespace, our replication controller should be able to
|
||||
create its pods.
|
||||
|
||||
```shell
|
||||
|
||||
```shell
|
||||
$ kubectl get pods --namespace=quota-example
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
nginx-fca65 1/1 Running 0 1m
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
And if we print out our quota usage in the namespace:
|
||||
|
||||
```shell
|
||||
|
||||
```shell
|
||||
$ kubectl describe quota quota --namespace=quota-example
|
||||
Name: quota
|
||||
Namespace: quota-example
|
||||
@@ -162,9 +145,8 @@ replicationcontrollers 1 20
|
||||
resourcequotas 1 1
|
||||
secrets 1 10
|
||||
services 0 5
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
You can now see the pod that was created is consuming explicit amounts of resources (specified by resource *request*),
|
||||
and the usage is being tracked by the Kubernetes system properly.
|
||||
|
||||
@@ -173,8 +155,4 @@ and the usage is being tracked by the Kubernetes system properly.
|
||||
Actions that consume node resources for cpu and memory can be subject to hard quota limits defined
|
||||
by the namespace quota. The resource consumption is measured by resource *request* in pod specification.
|
||||
|
||||
Any action that consumes those resources can be tweaked, or can pick up namespace level defaults to
|
||||
meet your end goal.
|
||||
|
||||
|
||||
|
||||
Any action that consumes those resources can be tweaked, or can pick up namespace level defaults to meet your end goal.
|
||||
@@ -13,17 +13,15 @@ This example will work in a custom namespace to demonstrate the concepts involve
|
||||
|
||||
Let's create a new namespace called quota-example:
|
||||
|
||||
```shell
|
||||
|
||||
```shell
|
||||
$ kubectl create -f docs/admin/resourcequota/namespace.yaml
|
||||
namespace "quota-example" created
|
||||
$ kubectl get namespaces
|
||||
NAME LABELS STATUS AGE
|
||||
default <none> Active 2m
|
||||
quota-example <none> Active 39s
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
## Step 2: Apply a quota to the namespace
|
||||
|
||||
By default, a pod will run with unbounded CPU and memory requests/limits. This means that any pod in the
|
||||
@@ -37,21 +35,18 @@ checks the total resource *requests*, not resource *limits* of all containers/po
|
||||
|
||||
Let's create a simple quota in our namespace:
|
||||
|
||||
```shell
|
||||
|
||||
```shell
|
||||
$ kubectl create -f docs/admin/resourcequota/quota.yaml --namespace=quota-example
|
||||
resourcequota "quota" created
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
Once your quota is applied to a namespace, the system will restrict any creation of content
|
||||
in the namespace until the quota usage has been calculated. This should happen quickly.
|
||||
|
||||
You can describe your current quota usage to see what resources are being consumed in your
|
||||
namespace.
|
||||
|
||||
```shell
|
||||
|
||||
```shell
|
||||
$ kubectl describe quota quota --namespace=quota-example
|
||||
Name: quota
|
||||
Namespace: quota-example
|
||||
@@ -65,9 +60,8 @@ replicationcontrollers 0 20
|
||||
resourcequotas 1 1
|
||||
secrets 1 10
|
||||
services 0 5
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
## Step 3: Applying default resource requests and limits
|
||||
|
||||
Pod authors rarely specify resource requests and limits for their pods.
|
||||
@@ -77,26 +71,21 @@ cpu and memory by creating an nginx container.
|
||||
|
||||
To demonstrate, lets create a replication controller that runs nginx:
|
||||
|
||||
```shell
|
||||
|
||||
```shell
|
||||
$ kubectl run nginx --image=nginx --replicas=1 --namespace=quota-example
|
||||
replicationcontroller "nginx" created
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
Now let's look at the pods that were created.
|
||||
|
||||
```shell
|
||||
|
||||
```shell
|
||||
$ kubectl get pods --namespace=quota-example
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
What happened? I have no pods! Let's describe the replication controller to get a view of what is happening.
|
||||
|
||||
```shell
|
||||
|
||||
```shell
|
||||
kubectl describe rc nginx --namespace=quota-example
|
||||
Name: nginx
|
||||
Namespace: quota-example
|
||||
@@ -109,16 +98,14 @@ No volumes.
|
||||
Events:
|
||||
FirstSeen LastSeen Count From SubobjectPath Reason Message
|
||||
42s 11s 3 {replication-controller } FailedCreate Error creating: Pod "nginx-" is forbidden: Must make a non-zero request for memory since it is tracked by quota.
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
The Kubernetes API server is rejecting the replication controllers requests to create a pod because our pods
|
||||
do not specify any memory usage *request*.
|
||||
|
||||
So let's set some default values for the amount of cpu and memory a pod can consume:
|
||||
|
||||
```shell
|
||||
|
||||
```shell
|
||||
$ kubectl create -f docs/admin/resourcequota/limits.yaml --namespace=quota-example
|
||||
limitrange "limits" created
|
||||
$ kubectl describe limits limits --namespace=quota-example
|
||||
@@ -128,27 +115,23 @@ Type Resource Min Max Request Limit Limit/Request
|
||||
---- -------- --- --- ------- ----- -------------
|
||||
Container memory - - 256Mi 512Mi -
|
||||
Container cpu - - 100m 200m -
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
Now any time a pod is created in this namespace, if it has not specified any resource request/limit, the default
|
||||
amount of cpu and memory per container will be applied, and the request will be used as part of admission control.
|
||||
|
||||
Now that we have applied default resource *request* for our namespace, our replication controller should be able to
|
||||
create its pods.
|
||||
|
||||
```shell
|
||||
|
||||
```shell
|
||||
$ kubectl get pods --namespace=quota-example
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
nginx-fca65 1/1 Running 0 1m
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
And if we print out our quota usage in the namespace:
|
||||
|
||||
```shell
|
||||
|
||||
```shell
|
||||
$ kubectl describe quota quota --namespace=quota-example
|
||||
Name: quota
|
||||
Namespace: quota-example
|
||||
@@ -162,19 +145,12 @@ replicationcontrollers 1 20
|
||||
resourcequotas 1 1
|
||||
secrets 1 10
|
||||
services 0 5
|
||||
|
||||
```
|
||||
|
||||
You can now see the pod that was created is consuming explicit amounts of resources (specified by resource *request*),
|
||||
and the usage is being tracked by the Kubernetes system properly.
|
||||
```
|
||||
|
||||
You can now see the pod that was created is consuming explicit amounts of resources (specified by resource *request*), and the usage is being tracked by the Kubernetes system properly.
|
||||
|
||||
## Summary
|
||||
|
||||
Actions that consume node resources for cpu and memory can be subject to hard quota limits defined
|
||||
by the namespace quota. The resource consumption is measured by resource *request* in pod specification.
|
||||
|
||||
Any action that consumes those resources can be tweaked, or can pick up namespace level defaults to
|
||||
meet your end goal.
|
||||
|
||||
|
||||
Actions that consume node resources for cpu and memory can be subject to hard quota limits defined by the namespace quota. The resource consumption is measured by resource *request* in pod specification.
|
||||
|
||||
Any action that consumes those resources can be tweaked, or can pick up namespace level defaults to meet your end goal.
|
||||
|
||||
+11
-11
@@ -13,11 +13,11 @@ The **salt-minion** service runs on the kubernetes-master and each kubernetes-no
|
||||
|
||||
Each salt-minion service is configured to interact with the **salt-master** service hosted on the kubernetes-master via the **master.conf** file [(except on GCE)](#standalone-salt-configuration-on-gce).
|
||||
|
||||
```shell
|
||||
```shell
|
||||
[root@kubernetes-master] $ cat /etc/salt/minion.d/master.conf
|
||||
master: kubernetes-master
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
The salt-master is contacted by each salt-minion and depending upon the machine information presented, the salt-master will provision the machine as either a kubernetes-master or kubernetes-node with all the required capabilities needed to run Kubernetes.
|
||||
|
||||
If you are running the Vagrant based environment, the **salt-api** service is running on the kubernetes-master. It is configured to enable the vagrant user to introspect the salt cluster in order to find out about machines in the Vagrant environment via a REST API.
|
||||
@@ -34,27 +34,27 @@ All remaining sections that refer to master/minion setups should be ignored for
|
||||
|
||||
Security is not enabled on the salt-master, and the salt-master is configured to auto-accept incoming requests from minions. It is not recommended to use this security configuration in production environments without deeper study. (In some environments this isn't as bad as it might sound if the salt master port isn't externally accessible and you trust everyone on your network.)
|
||||
|
||||
```shell
|
||||
```shell
|
||||
[root@kubernetes-master] $ cat /etc/salt/master.d/auto-accept.conf
|
||||
open_mode: True
|
||||
auto_accept: True
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
## Salt minion configuration
|
||||
|
||||
Each minion in the salt cluster has an associated configuration that instructs the salt-master how to provision the required resources on the machine.
|
||||
|
||||
An example file is presented below using the Vagrant based environment.
|
||||
|
||||
```shell
|
||||
```shell
|
||||
[root@kubernetes-master] $ cat /etc/salt/minion.d/grains.conf
|
||||
grains:
|
||||
etcd_servers: $MASTER_IP
|
||||
cloud_provider: vagrant
|
||||
roles:
|
||||
- kubernetes-master
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
Each hosting environment has a slightly different grains.conf file that is used to build conditional logic where required in the Salt files.
|
||||
|
||||
The following enumerates the set of defined key/value pairs that are supported today. If you add new ones, please make sure to update this list.
|
||||
@@ -85,8 +85,8 @@ In addition, a cluster may be running a Debian based operating system or Red Hat
|
||||
// something specific to Debian environment (apt-get, initd)
|
||||
{% endif %}
|
||||
{% endraw %}
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. When configuring default arguments for processes, it's best to avoid the use of EnvironmentFiles (Systemd in Red Hat environments) or init.d files (Debian distributions) to hold default values that should be common across operating system environments. This helps keep our Salt template files easy to understand for editors who may not be familiar with the particulars of each distribution.
|
||||
|
||||
@@ -62,7 +62,6 @@ of type `ServiceAccountToken` with an annotation referencing the service
|
||||
account, and the controller will update it with a generated token:
|
||||
|
||||
```json
|
||||
|
||||
secret.json:
|
||||
{
|
||||
"kind": "Secret",
|
||||
@@ -75,28 +74,20 @@ secret.json:
|
||||
},
|
||||
"type": "kubernetes.io/service-account-token"
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
```shell
|
||||
|
||||
kubectl create -f ./secret.json
|
||||
kubectl describe secret mysecretname
|
||||
|
||||
```
|
||||
|
||||
#### To delete/invalidate a service account token
|
||||
|
||||
```shell
|
||||
|
||||
kubectl delete secret mysecretname
|
||||
|
||||
```
|
||||
|
||||
### Service Account Controller
|
||||
|
||||
Service Account Controller manages ServiceAccount inside namespaces, and ensures
|
||||
a ServiceAccount named "default" exists in every active namespace.
|
||||
|
||||
|
||||
|
||||
a ServiceAccount named "default" exists in every active namespace.
|
||||
@@ -20,14 +20,14 @@ For example, this is how to start a simple web server as a static pod:
|
||||
|
||||
1. Choose a node where we want to run the static pod. In this example, it's `my-minion1`.
|
||||
|
||||
```shell
|
||||
[joe@host ~] $ ssh my-minion1
|
||||
```
|
||||
|
||||
```shell
|
||||
[joe@host ~] $ ssh my-minion1
|
||||
```
|
||||
|
||||
2. Choose a directory, say `/etc/kubelet.d` and place a web server pod definition there, e.g. `/etc/kubernetes.d/static-web.yaml`:
|
||||
|
||||
```shell
|
||||
[root@my-minion1 ~] $ mkdir /etc/kubernetes.d/
|
||||
|
||||
```shell
|
||||
[root@my-minion1 ~] $ mkdir /etc/kubernetes.d/
|
||||
[root@my-minion1 ~] $ cat <<EOF >/etc/kubernetes.d/static-web.yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
@@ -43,23 +43,22 @@ For example, this is how to start a simple web server as a static pod:
|
||||
- name: web
|
||||
containerPort: 80
|
||||
protocol: tcp
|
||||
EOF
|
||||
```
|
||||
|
||||
EOF
|
||||
```
|
||||
|
||||
2. Configure your kubelet daemon on the node to use this directory by running it with `--config=/etc/kubelet.d/` argument. On Fedora Fedora 21 with Kubernetes 0.17 edit `/etc/kubernetes/kubelet` to include this line:
|
||||
|
||||
```
|
||||
KUBELET_ARGS="--cluster-dns=10.254.0.10 --cluster-domain=kube.local --config=/etc/kubelet.d/"
|
||||
```
|
||||
|
||||
Instructions for other distributions or Kubernetes installations may vary.
|
||||
```
|
||||
KUBELET_ARGS="--cluster-dns=10.254.0.10 --cluster-domain=kube.local --config=/etc/kubelet.d/"
|
||||
```
|
||||
Instructions for other distributions or Kubernetes installations may vary.
|
||||
|
||||
3. Restart kubelet. On Fedora 21, this is:
|
||||
|
||||
```shell
|
||||
[root@my-minion1 ~] $ systemctl restart kubelet
|
||||
```
|
||||
|
||||
```shell
|
||||
[root@my-minion1 ~] $ systemctl restart kubelet
|
||||
```
|
||||
|
||||
## Pods created via HTTP
|
||||
|
||||
Kubelet periodically downloads a file specified by `--manifest-url=<URL>` argument and interprets it as a json/yaml file with a pod definition. It works the same as `--config=<directory>`, i.e. it's reloaded every now and then and changes are applied to running static pods (see below).
|
||||
@@ -68,50 +67,50 @@ Kubelet periodically downloads a file specified by `--manifest-url=<URL>` argume
|
||||
|
||||
When kubelet starts, it automatically starts all pods defined in directory specified in `--config=` or `--manifest-url=` arguments, i.e. our static-web. (It may take some time to pull nginx image, be patient'|):
|
||||
|
||||
```shell
|
||||
```shell
|
||||
[joe@my-minion1 ~] $ docker ps
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS NAMES
|
||||
f6d05272b57e nginx:latest "nginx" 8 minutes ago Up 8 minutes k8s_web.6f802af4_static-web-fk-minion1_default_67e24ed9466ba55986d120c867395f3c_378e5f3c
|
||||
```
|
||||
|
||||
f6d05272b57e nginx:latest "nginx" 8 minutes ago Up 8 minutes k8s_web.6f802af4_static-web-fk-minion1_default_67e24ed9466ba55986d120c867395f3c_378e5f3c
|
||||
```
|
||||
|
||||
If we look at our Kubernetes API server (running on host `my-master`), we see that a new mirror-pod was created there too:
|
||||
|
||||
```shell
|
||||
```shell
|
||||
[joe@host ~] $ ssh my-master
|
||||
[joe@my-master ~] $ kubectl get pods
|
||||
POD IP CONTAINER(S) IMAGE(S) HOST LABELS STATUS CREATED MESSAGE
|
||||
static-web-my-minion1 172.17.0.3 my-minion1/192.168.100.71 role=myrole Running 11 minutes
|
||||
web nginx Running 11 minutes
|
||||
```
|
||||
|
||||
web nginx Running 11 minutes
|
||||
```
|
||||
|
||||
Labels from the static pod are propagated into the mirror-pod and can be used as usual for filtering.
|
||||
|
||||
Notice we cannot delete the pod with the API server (e.g. via [`kubectl`](../user-guide/kubectl/kubectl) command), kubelet simply won't remove it.
|
||||
|
||||
```shell
|
||||
```shell
|
||||
[joe@my-master ~] $ kubectl delete pod static-web-my-minion1
|
||||
pods/static-web-my-minion1
|
||||
[joe@my-master ~] $ kubectl get pods
|
||||
POD IP CONTAINER(S) IMAGE(S) HOST ...
|
||||
static-web-my-minion1 172.17.0.3 my-minion1/192.168.100.71 ...
|
||||
```
|
||||
|
||||
static-web-my-minion1 172.17.0.3 my-minion1/192.168.100.71 ...
|
||||
```
|
||||
|
||||
Back to our `my-minion1` host, we can try to stop the container manually and see, that kubelet automatically restarts it in a while:
|
||||
|
||||
```shell
|
||||
```shell
|
||||
[joe@host ~] $ ssh my-minion1
|
||||
[joe@my-minion1 ~] $ docker stop f6d05272b57e
|
||||
[joe@my-minion1 ~] $ sleep 20
|
||||
[joe@my-minion1 ~] $ docker ps
|
||||
CONTAINER ID IMAGE COMMAND CREATED ...
|
||||
5b920cbaf8b1 nginx:latest "nginx -g 'daemon of 2 seconds ago ...
|
||||
```
|
||||
|
||||
5b920cbaf8b1 nginx:latest "nginx -g 'daemon of 2 seconds ago ...
|
||||
```
|
||||
|
||||
## Dynamic addition and removal of static pods
|
||||
|
||||
Running kubelet periodically scans the configured directory (`/etc/kubelet.d` in our example) for changes and adds/removes pods as files appear/disappear in this directory.
|
||||
|
||||
```shell
|
||||
```shell
|
||||
[joe@my-minion1 ~] $ mv /etc/kubernetes.d/static-web.yaml /tmp
|
||||
[joe@my-minion1 ~] $ sleep 20
|
||||
[joe@my-minion1 ~] $ docker ps
|
||||
@@ -120,11 +119,5 @@ Running kubelet periodically scans the configured directory (`/etc/kubelet.d` in
|
||||
[joe@my-minion1 ~] $ sleep 20
|
||||
[joe@my-minion1 ~] $ docker ps
|
||||
CONTAINER ID IMAGE COMMAND CREATED ...
|
||||
e7a62e3427f1 nginx:latest "nginx -g 'daemon of 27 seconds ago
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
e7a62e3427f1 nginx:latest "nginx -g 'daemon of 27 seconds ago
|
||||
```
|
||||
Reference in New Issue
Block a user