Primeros pasos con Kubernetes (VIII): Resource Limits
Anteriormente, hemos visto como una aplicación se puede autoescalar en base a consumos de recursos. Ahora procederemos a ver como podemos asignar un límite de recursos para una aplicación. Imaginemos que tenemos 10 aplicaciones a desplegar, algunas de ellas hacen mucho uso de memoria y poco uso de CPU, pero otras aplicaciones el caso contrario, poca memoria y un uso masivo de CPU. Para poder aprovechar mejor los recursos se puede configurar para cada aplicación el uso de cpu y memoria; de esta manera una aplicación que no use mucha CPU podemos restringir su uso y así permitir que otra aplicación que hace un uso masivo pueda disponer de más CPU en momentos de estres.
Con todo esto también se evita, que si hay un bug en una aplicación y este hace que los tiempos de CPU se disparen (por ejemplo un bucle infinito), la aplicación empiece a consumir el 100% de los recursos y deje al resto con menos CPU de la que necesitan para trabajar. El mismo caso se puede dar si hay un bug de memory leak, si la memoria se encuentra limitada, el bug de memory leak afectará hasta el límite máximo indicado pero no empezará a consumir más memoria que puede ser usada por otras aplicaciones.
Es una buena práctica definir dichos límites para limitar la afectación que pueda ocasionar una aplicación en el resto de aplicaciones que se encuentren en un nodo.
Para ello jugaremos con dos aplicaciones, una de ellas (memory) incrementa su uso de memoria continuamente y sin límite, la otra es el ya conocido Hello World que venimos viendo a lo largo del documento.
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: hello
spec:
replicas: 1
template:
metadata:
labels:
app: hello
spec:
containers:
- name: hello
image: gcr.io/k8slabs-142707/hello:v1
ports:
- containerPort: 8080
resources:
limits:
cpu: 10m
Podemos ver como hemos limitado el uso de CPU a 10m (el 1% de un core de CPU).
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: memory
spec:
replicas: 1
template:
metadata:
labels:
app: memory
spec:
containers:
- name: memory
image: gcr.io/k8slabs-142707/memory:v1
ports:
- containerPort: 8080
resources:
limits:
memory: 100Mi
var input = []; // initialise an empty array
do {
input.push("kkkkkkkkkkkkk"); // the array will dynamically grow
} while (1);
En la aplicación memory podemos ver el incremento de memoria mediante un bucle y la aplicación la hemos limitado a 100Mb de memoria.
A continuación lanzaremos las dos aplicaciones y realizaremos las siguientes validaciones.
- Observaremos como la aplicación memory se reinicia cada X tiempo, cuando cada Pod supera el límite de 100 Mb de uso. Con esto aseguramos que la aplicación no consuma todos los recursos de memoria de un nodo y afecte al resto de aplicaciones desplegadas en ese nodo.
- Lanzamos llamadas continuas contra la aplicación hello, con lo que haremos que el consumo de CPU se dispare (como ya hemos visto en ejemplos anteriores). Entonces monitorizaremos el consumo de CPU del nodo donde se encuentra desplegado y veremos que no se supera el 1% de consumo de CPU. De hecho veremos que los tiempos de respuesta de la aplicación son más lentos que en pruebas anteriores, dado que ahora el uso de CPU se encuentra restringido.
A continuación podemos ver los scripts que realizan estas pruebas y validaciones.
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
hello-2452618930-0h6dt 1/1 Running 0 45s
memory-4172153614-vw388 0/1 CrashLoopBackOff 2 46s
$ kubectl describe po memory-4172153614-vw388
Name: memory-4172153614-vw388
Namespace: default
Node: gke-bs-default-pool-28f5092a-y4wc/10.132.0.4
Start Time: Tue, 11 Oct 2016 09:51:31 +0000
Labels: app=memory
pod-template-hash=4172153614
Status: Running
IP: 10.64.1.8
Controllers: ReplicaSet/memory-4172153614
Containers:
memory:
Container ID: docker://d78d9a4cd714ae32084ec9eea2700e6e204d3af5a279f16018b0c4d76028312c
Image: gcr.io/k8slabs-142707/memory:v1
Image ID: docker://sha256:1728e937497c13d6372e6dad0f995ed8650cea20d08e47eebdd0230ea68baed5
Port: 8080/TCP
Limits:
memory: 100Mi
Requests:
cpu: 100m
memory: 100Mi
State: Terminated
Reason: OOMKilled
Exit Code: 137
Started: Tue, 11 Oct 2016 09:52:58 +0000
Finished: Tue, 11 Oct 2016 09:52:59 +0000
Last State: Terminated
Reason: OOMKilled
Exit Code: 137
Started: Tue, 11 Oct 2016 09:52:16 +0000
Finished: Tue, 11 Oct 2016 09:52:17 +0000
Ready: False
Restart Count: 4
Environment Variables:
Conditions:
Type Status
Initialized True
Ready False
PodScheduled True
Volumes:
default-token-yeeok:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-yeeok
QoS Tier: Burstable
Events:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
1m 1m 1 {default-scheduler } Normal Scheduled Successfully assigned memory-4172153614-vw388 to gke-bs-default-pool-28f5092a-y4wc
1m 1m 1 {kubelet gke-bs-default-pool-28f5092a-y4wc} spec.containers{memory} Normal Created Created container with docker id 1c2f549916bc; Security:[seccomp=unconfined]
1m 1m 1 {kubelet gke-bs-default-pool-28f5092a-y4wc} spec.containers{memory} Normal Started Started container with docker id 1c2f549916bc
1m 1m 1 {kubelet gke-bs-default-pool-28f5092a-y4wc} spec.containers{memory} Normal Created Created container with docker id 27c37af9dc35; Security:[seccomp=unconfined]
1m 1m 1 {kubelet gke-bs-default-pool-28f5092a-y4wc} spec.containers{memory} Normal Started Started container with docker id 27c37af9dc35
1m 1m 2 {kubelet gke-bs-default-pool-28f5092a-y4wc} Warning FailedSync Error syncing pod, skipping: failed to "StartContainer" for "memory" with CrashLoopBackOff: "Back-off 10s restarting failed container=memory pod=memory-4172153614-vw388_default(49e634c2-8f98-11e6-a4e8-42010a840fc6)"
1m 1m 1 {kubelet gke-bs-default-pool-28f5092a-y4wc} spec.containers{memory} Normal Started Started container with docker id cf017fe09a72
1m 1m 1 {kubelet gke-bs-default-pool-28f5092a-y4wc} spec.containers{memory} Normal Created Created container with docker id cf017fe09a72; Security:[seccomp=unconfined]
1m 1m 2 {kubelet gke-bs-default-pool-28f5092a-y4wc} Warning FailedSync Error syncing pod, skipping: failed to "StartContainer" for "memory" with CrashLoopBackOff: "Back-off 20s restarting failed container=memory pod=memory-4172153614-vw388_default(49e634c2-8f98-11e6-a4e8-42010a840fc6)"
54s 54s 1 {kubelet gke-bs-default-pool-28f5092a-y4wc} spec.containers{memory} Normal Created Created container with docker id f20653bddc5c; Security:[seccomp=unconfined]
54s 54s 1 {kubelet gke-bs-default-pool-28f5092a-y4wc} spec.containers{memory} Normal Started Started container with docker id f20653bddc5c
53s 26s 3 {kubelet gke-bs-default-pool-28f5092a-y4wc} Warning FailedSync Error syncing pod, skipping: failed to "StartContainer" for "memory" with CrashLoopBackOff: "Back-off 40s restarting failed container=memory pod=memory-4172153614-vw388_default(49e634c2-8f98-11e6-a4e8-42010a840fc6)"
12s 12s 1 {kubelet gke-bs-default-pool-28f5092a-y4wc} spec.containers{memory} Normal Created Created container with docker id d78d9a4cd714; Security:[seccomp=unconfined]
1m 12s 5 {kubelet gke-bs-default-pool-28f5092a-y4wc} spec.containers{memory} Normal Pulled Container image "gcr.io/k8slabs-142707/memory:v1" already present on machine
12s 12s 1 {kubelet gke-bs-default-pool-28f5092a-y4wc} spec.containers{memory} Normal Started Started container with docker id d78d9a4cd714
1m 11s 8 {kubelet gke-bs-default-pool-28f5092a-y4wc} spec.containers{memory} Warning BackOff Back-off restarting failed docker container
11s 11s 1 {kubelet gke-bs-default-pool-28f5092a-y4wc} Warning FailedSync Error syncing pod, skipping: failed to "StartContainer" for "memory" with CrashLoopBackOff: "Back-off 1m20s restarting failed container=memory pod=memory-4172153614-vw388_default(49e634c2-8f98-11e6-a4e8-42010a840fc6)"
$ kubectl get svc
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello 10.67.242.214 104.199.1.118 80/TCP 13m
kubernetes 10.67.240.1 443/TCP 1h
memory 10.67.242.56 130.211.91.75 80/TCP 13m
$ while true; do curl http://104.199.1.118;done
Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!
Mientras se lanzan las peticiones masivas, en otra consola ejecutamos lo siguiente
$ kubectl get no
NAME STATUS AGE
gke-bs-default-pool-28f5092a-chrz Ready 1h
gke-bs-default-pool-28f5092a-j9g5 Ready 1h
gke-bs-default-pool-28f5092a-y4wc Ready 1h
$ kubectl describe no gke-bs-default-pool-28f5092a-y4wc
Name: gke-bs-default-pool-28f5092a-y4wc
Labels: beta.kubernetes.io/arch=amd64
beta.kubernetes.io/instance-type=n1-standard-1
beta.kubernetes.io/os=linux
cloud.google.com/gke-nodepool=default-pool
failure-domain.beta.kubernetes.io/region=europe-west1
failure-domain.beta.kubernetes.io/zone=europe-west1-d
kubernetes.io/hostname=gke-bs-default-pool-28f5092a-y4wc
Taints:
CreationTimestamp: Tue, 11 Oct 2016 08:33:56 +0000
Phase:
Conditions:
Type Status LastHeartbeatTime LastTransitionTime Reason Message
---- ------ ----------------- ------------------ ------ -------
NetworkUnavailable False Tue, 11 Oct 2016 10:09:05 +0000 Tue, 11 Oct 2016 10:09:05 +0000 RouteCreated RouteController created a route
OutOfDisk False Tue, 11 Oct 2016 10:09:02 +0000 Tue, 11 Oct 2016 08:33:56 +0000 KubeletHasSufficientDisk kubelet has sufficient disk space available
MemoryPressure False Tue, 11 Oct 2016 10:09:02 +0000 Tue, 11 Oct 2016 08:33:56 +0000 KubeletHasSufficientMemory kubelet has sufficient memory available
DiskPressure False Tue, 11 Oct 2016 10:09:02 +0000 Tue, 11 Oct 2016 08:33:56 +0000 KubeletHasNoDiskPressure kubelet has no disk pressure
Ready True Tue, 11 Oct 2016 10:09:02 +0000 Tue, 11 Oct 2016 08:34:28 +0000 KubeletReady kubelet is posting ready status. AppArmor enabled
Addresses: 10.132.0.4,130.211.92.164
Capacity:
alpha.kubernetes.io/nvidia-gpu: 0
cpu: 1
memory: 3788388Ki
pods: 110
Allocatable:
alpha.kubernetes.io/nvidia-gpu: 0
cpu: 1
memory: 3788388Ki
pods: 110
System Info:
Machine ID: ca884066752b8a2220d10f9a57fca3ac
System UUID: 7823B355-2309-9DEF-EFBE-2BA9A2554F9C
Boot ID: f6419218-dc9e-4c24-bced-abf3165ddfb6
Kernel Version: 4.4.14+
OS Image: Google Container-VM Image
Operating System: linux
Architecture: amd64
Container Runtime Version: docker://1.11.2
Kubelet Version: v1.4.0
Kube-Proxy Version: v1.4.0
PodCIDR: 10.64.1.0/24
ExternalID: 3397695991050214778
Non-terminated Pods: (4 in total)
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits
--------- ---- ------------ ---------- --------------- -------------
default hello-2452618930-0h6dt 10m (1%) 10m (1%) 0 (0%) 0 (0%)
default memory-4172153614-vw388 100m (10%) 0 (0%) 100Mi (2%) 100Mi (2%)
kube-system fluentd-cloud-logging-gke-bs-default-pool-28f5092a-y4wc 80m (8%) 0 (0%) 200Mi (5%) 200Mi (5%)
kube-system kube-proxy-gke-bs-default-pool-28f5092a-y4wc 100m (10%) 0 (0%) 0 (0%) 0 (0%)
Allocated resources:
(Total limits may be over 100 percent, i.e., overcommitted. More info: http://releases.k8s.io/HEAD/docs/user-guide/compute-resources.md)
CPU Requests CPU Limits Memory Requests Memory Limits
------------ ---------- --------------- -------------
290m (28%) 10m (1%) 300Mi (8%) 300Mi (8%)
No events.
No hay comentarios
Publicar un comentario