Tabla de contenido
1. Limitaciones de recursos
Al definir un Pod, opcionalmente puede establecer la cantidad de recursos necesarios para cada contenedor. Los recursos configurables más comunes son la CPU y el tamaño de la memoria, entre otros tipos de recursos.
Cuando se especifica un recurso de solicitud para un contenedor en un Pod, representa la cantidad mínima de recursos necesarios para que se ejecute el contenedor, y el programador usa esta información para decidir en qué nodo programar el Pod. Cuando también se especifican recursos límite para el contenedor, kubelet se asegurará de que el contenedor en ejecución no utilice más de los recursos límite establecidos. Kubelet también reservará la cantidad de recursos de solicitud establecida para el contenedor para que la utilice el contenedor.
Si el nodo donde se ejecuta el Pod tiene suficientes recursos disponibles, el contenedor puede usar más recursos que la solicitud establecida. Sin embargo, el contenedor no puede utilizar más recursos que el límite establecido.
Si se establece el valor del límite de memoria para el contenedor, pero no se establece el valor de solicitud de memoria, Kubernetes establecerá automáticamente un valor de solicitud que coincida con el límite de memoria. De manera similar, si el valor límite de CPU se establece para un contenedor pero el valor de solicitud de CPU no se establece, Kubernetes establece automáticamente el valor de solicitud de CPU y lo compara con el valor límite de CPU.
Ejemplo de sitio web oficial
https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/
Solicitudes de recursos y límites para Pods y contenedores:
spec.containers[].resources.requests.cpu //定义创建容器时预分配的CPU资源
spec.containers[].resources.requests.memory //定义创建容器时预分配的内存资源
spec.containers[].resources.limits.cpu //定义 cpu 的资源上限
spec.containers[].resources.limits.memory //定义内存的资源上限
unidad de recursos de CPU
- La solicitud y el límite de recursos de la CPU están en la CPU. Una CPU en Kubernetes equivale a 1 vCPU (1 hiperproceso).
- Kubernetes también admite solicitudes con CPU fraccionarias. Un contenedor cuyo spec.containers[].resources.requests.cpu es 0.5 puede obtener la mitad de los recursos de CPU de una CPU (similar a la división de tiempo de los recursos de CPU de Cgroup). La expresión 0.1 es equivalente a la expresión 100m (milicore), lo que significa que la cantidad total de tiempo de CPU que el contenedor puede usar cada 1000 milisegundos es 0.1*1000 milisegundos.
- Kubernetes no permite configurar recursos de CPU con una precisión inferior a 1 m.
unidad de recursos de memoria
La solicitud de memoria y el límite están en bytes. Se puede expresar como un número entero, o en unidades de exponente de base 10 (E, P, T, G, M, K), o en unidades de exponente de base 2 (Ei, Pi, Ti, Gi, Mi, Ki) para representar.
Por ejemplo: 1KB=10 3=1000, 1MB=10 6=1000000=1000KB, 1GB=10^9=1000000000=1000MB 1KiB
=2 10=1024, 1MiB=2 20=1048576=1024KiB
Ejemplo 1:
apiVersion: v1
kind: Pod
metadata:
name: frontend
spec:
containers:
- name: app
image: images.my-company.example/app:v4
env:
- name: MYSQL_ROOT_PASSWORD
value: "password"
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
- name: log-aggregator
image: images.my-company.example/log-aggregator:v6
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
El Pod en este ejemplo tiene dos contenedores. El valor de solicitud de cada contenedor es 0,25 CPU y 64 MiB de memoria, y el valor límite de cada contenedor es 0,5 CPU y 128 MiB de memoria. Entonces se puede considerar que la solicitud total de recursos del Pod es 0,5 CPU y 128 MiB de memoria, y el límite total de recursos es 1 CPU y 256 MiB de memoria.
Ejemplo 2:
vim pod2.yaml
apiVersion: v1
kind: Pod
metadata:
name: frontend
spec:
containers:
- name: web
image: nginx
env:
- name: WEB_ROOT_PASSWORD
value: "password"
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
- name: db
image: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: "abc123"
resources:
requests:
memory: "512Mi"
cpu: "0.5"
limits:
memory: "1Gi"
cpu: "1"
kubectl apply -f pod2.yaml
kubectl describe pod frontend
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
frontend 2/2 Running 5 15m 10.244.2.4 node02 <none> <none>
kubectl describe nodes node02 #由于当前虚拟机有2个CPU,所以Pod的CPU Limits一共占用了50%
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits AGE
--------- ---- ------------ ---------- --------------- ------------- ---
default frontend 500m (25%) 1 (50%) 128Mi (3%) 256Mi (6%) 16m
kube-system kube-flannel-ds-amd64-f4pbp 100m (5%) 100m (5%) 50Mi (1%) 50Mi (1%) 19h
kube-system kube-proxy-pj4wp 0 (0%) 0 (0%) 0 (0%) 0 (0%) 19h
Allocated resources:
(Total limits may be over 100 percent, i.e., overcommitted.)
Resource Requests Limits
-------- -------- ------
cpu 600m (30%) 1100m (55%)
memory 178Mi (4%) 306Mi (7%)
ephemeral-storage 0 (0%) 0 (0%)
2. Reiniciar la estrategia
- Cuando el contenedor en el Pod salga, reinicie el contenedor a través del kubelet en el nodo. Se aplica a todos los contenedores del Pod.
1. Siempre: Cuando el contenedor termina y sale, el contenedor siempre se reinicia. Política predeterminada
2. OnFailure: Cuando el contenedor sale de manera anormal (el código de estado de salida no es 0), el contenedor se reinicia; si el contenedor sale normalmente, el contenedor siempre se reinicia. el contenedor no se reinicia
3. Nunca: cuando el contenedor finaliza Salga y nunca reinicie el contenedor.
#Nota: K8S no admite el reinicio de los recursos del Pod, solo la eliminación y reconstrucción.
Cuando se usa yaml para crear tipos Deployment y StatefulSet, restartPolicy solo puede ser Siempre. Cuando kubectl run crea un Pod, puede elegir tres estrategias: Siempre, OnFailure y Nunca.
kubectl edit deployment nginx-deployment
......
restartPolicy: Always
//示例
vim pod3.yaml
apiVersion: v1
kind: Pod
metadata:
name: foo
spec:
containers:
- name: busybox
image: busybox
args:
- /bin/sh
- -c
- sleep 30; exit 3
kubectl apply -f pod3.yaml
//查看Pod状态,等容器启动后30秒后执行exit退出进程进入error状态,就会重启次数加1
kubectl get pods
NAME READY STATUS RESTARTS AGE
foo 1/1 Running 1 50s
kubectl delete -f pod3.yaml
vim pod3.yaml
apiVersion: v1
kind: Pod
metadata:
name: foo
spec:
containers:
- name: busybox
image: busybox
args:
- /bin/sh
- -c
- sleep 30; exit 3
restartPolicy: Never
#注意:跟container同一个级别
kubectl apply -f pod3.yaml
//容器进入error状态不会进行重启
kubectl get pods -w
3. Chequeo de salud, también llamado Sonda
- Las sondas son diagnósticos periódicos que realiza el kubelet en el contenedor.
Tres reglas para las sondas:
●livenessProbe: determina si el contenedor se está ejecutando. Si la sonda falla, kubelet mata el contenedor y el contenedor establece el estado del Pod de acuerdo con la política de reinicio. Si el contenedor no proporciona una prueba de actividad, el estado predeterminado es Correcto.
●readinessProbe: determina si el contenedor está listo para aceptar solicitudes. Si la detección falla, el controlador de punto final eliminará la dirección IP del Pod de todos los puntos finales de servicio que coincidan con el Pod. El estado listo antes del retraso inicial tiene como valor predeterminado Fallo. Si el contenedor no proporciona una prueba de preparación, el estado predeterminado es Correcto.
●startupProbe (agregado en la versión 1.17): determina si la aplicación en el contenedor se ha iniciado, principalmente para aplicaciones que no pueden determinar el tiempo de inicio específico. Si la sonda startupProbe está configurada, todas las demás sondas estarán inactivas hasta que el estado de startupProbe sea Correcto y ninguna otra sonda tendrá efecto hasta que sea exitosa. Si startupProbe falla, kubelet cerrará el contenedor y el contenedor se reiniciará de acuerdo con la política de reinicio. Si el contenedor no está configurado con startupProbe, el estado predeterminado es Éxito.
- Nota: Las reglas anteriores se pueden definir al mismo tiempo. Antes de que la prueba readinessProbe sea exitosa, el estado de ejecución del Pod no cambiará al estado listo.
La sonda admite tres métodos de inspección:
●exec: ejecuta el comando especificado dentro del contenedor. Si el código de retorno es 0 cuando sale el comando, el diagnóstico se considera exitoso.
●tcpSocket: realiza una inspección TCP (apretón de manos de tres vías) en la dirección IP del contenedor en el puerto especificado. Si el puerto está abierto, el diagnóstico se considera exitoso.
●httpGet: realiza una solicitud HTTPGet a la dirección IP del contenedor en el puerto y la ruta uri especificados. Si el código de estado de la respuesta es mayor o igual a 200 y menor a 400, el diagnóstico se considera exitoso.
Cada sonda tendrá uno de tres resultados:
●Éxito: Indica que el contenedor pasó la prueba.
●Fallo: Indica que el contenedor no pasó la prueba.
●Desconocido: Indica que la detección no se realiza normalmente.
Ejemplo de sitio web oficial:
https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
3.1 Ejemplo 1: modo ejecutivo
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-exec
spec:
containers:
- name: liveness
image: k8s.gcr.io/busybox
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 60
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
failureThreshold: 1
initialDelaySeconds: 5
periodSeconds: 5
#initialDelaySeconds: especifica que kubelet debe esperar 5 segundos antes de ejecutar la primera detección, es decir, la primera detección no comenzará hasta 6 segundos después de que se inicie el contenedor. El valor predeterminado es 0 segundos, el valor mínimo es 0.
#periodSeconds: especifica que kubelet debe realizar una prueba de supervivencia cada 5 segundos. El valor predeterminado es 10 segundos. El valor mínimo es 1.
#failureThreshold: cuando falla una sonda, la cantidad de veces que Kubernetes lo reintentará antes de darse por vencido. Abortar en el caso de detección de actividad significa reiniciar el contenedor. Los pods que se abandonen durante la detección de preparación se etiquetarán como no listos. El valor predeterminado es 3. El valor mínimo es 1.
#timeoutSeconds: cuántos segundos se deben esperar después de que se agote el tiempo de espera de la sonda. El valor predeterminado es 1 segundo. El valor mínimo es 1. (Antes de Kubernetes 1.20, la sonda ejecutiva ignoraba los timeoutSeconds y continuaba ejecutándose indefinidamente, posiblemente incluso más allá de la fecha límite configurada, hasta que se devolvían los resultados).
Puedes ver que solo hay un contenedor en el Pod. El kubelet debe esperar 5 segundos antes de realizar la primera sonda y realizará una sonda de supervivencia cada 5 segundos. kubelet ejecuta el comando cat /tmp/healthy en el contenedor para detectar. Si el comando se ejecuta correctamente y el valor de retorno es 0, kubelet considerará que el contenedor está sano y vivo. Cuando se alcanza el segundo 31, este comando devuelve un valor distinto de cero y el kubelet cerrará el contenedor y lo reiniciará.
vim exec.yaml
apiVersion: v1
kind: Pod
metadata:
name: liveness-exec
namespace: default
spec:
containers:
- name: liveness-exec-container
image: busybox
imagePullPolicy: IfNotPresent
command: ["/bin/sh","-c","touch /tmp/live ; sleep 30; rm -rf /tmp/live; sleep 3600"]
livenessProbe:
exec:
command: ["test","-e","/tmp/live"]
initialDelaySeconds: 1
periodSeconds: 3
kubectl create -f exec.yaml
kubectl describe pods liveness-exec
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 51s default-scheduler Successfully assigned default/liveness-exec-pod to node02
Normal Pulled 46s kubelet, node02 Container image "busybox" already present on machine
Normal Created 46s kubelet, node02 Created container liveness-exec-container
Normal Started 45s kubelet, node02 Started container liveness-exec-container
Warning Unhealthy 8s (x3 over 14s) kubelet, node02 Liveness probe failed:
Normal Killing 8s kubelet, node02 Container liveness-exec-container failed liveness probe,will be restarted
kubectl get pods -w
NAME READY STATUS RESTARTS AGE
liveness-exec 1/1 Running 1 85s
3.2 Ejemplo 2: método httpGet
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-http
spec:
containers:
- name: liveness
image: k8s.gcr.io/liveness
args:
- /server
livenessProbe:
httpGet:
path: /healthz
port: 8080
httpHeaders:
- name: Custom-Header
value: Awesome
initialDelaySeconds: 3
periodSeconds: 3
En este archivo de configuración, puede ver que Pod tiene un solo contenedor. El campo inicialDelaySeconds le dice a kubelet que debe esperar 3 segundos antes de realizar la primera sonda. El campo periodSeconds especifica que kubelet ejecuta una sonda de supervivencia cada 3 segundos. El kubelet enviará una solicitud HTTP GET al servicio que se ejecuta en el contenedor (el servicio escuchará en el puerto 8080) para realizar la detección. Si el controlador en la ruta /healthz en el servidor devuelve un código de éxito, kubelet considera que el contenedor está en buen estado. Si el controlador devuelve un código de error, kubelet cierra el contenedor y lo reinicia.
Cualquier código de retorno mayor o igual a 200 y menor que 400 indica éxito, otros códigos de retorno indican error.
vim httpget.yaml
apiVersion: v1
kind: Pod
metadata:
name: liveness-httpget
namespace: default
spec:
containers:
- name: liveness-httpget-container
image: soscscs/myapp:v1
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
livenessProbe:
httpGet:
port: http
path: /index.html
initialDelaySeconds: 1
periodSeconds: 3
timeoutSeconds: 10
kubectl create -f httpget.yaml
kubectl exec -it liveness-httpget -- rm -rf /usr/share/nginx/html/index.html
kubectl get pods
NAME READY STATUS RESTARTS AGE
liveness-httpget 1/1 Running 1 2m44s
3.3 Ejemplo 3: método tcpSocket
apiVersion: v1
kind: Pod
metadata:
name: goproxy
labels:
app: goproxy
spec:
containers:
- name: goproxy
image: k8s.gcr.io/goproxy:0.1
ports:
- containerPort: 8080
readinessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
Este ejemplo utiliza las sondas readinessProbe y livenessProbe. El kubelet enviará la primera sonda readinessProbe 5 segundos después de que se inicie el contenedor. Esto intentará conectarse al puerto 8080 del contenedor goproxy. Si la detección es exitosa, kubelet continuará ejecutando detecciones cada 10 segundos. Además de la sonda readinessProbe, esta configuración incluye una sonda livenessProbe. El kubelet realizará la primera detección de livenessProbe 15 segundos después de que se inicie el contenedor. Al igual que la sonda readinessProbe, intentará conectarse al puerto 8080 del contenedor goproxy. Si la sonda livenessProbe falla, el contenedor se reiniciará.
vim tcpsocket.yaml
apiVersion: v1
kind: Pod
metadata:
name: probe-tcp
spec:
containers:
- name: nginx
image: soscscs/myapp:v1
livenessProbe:
initialDelaySeconds: 5
timeoutSeconds: 1
tcpSocket:
port: 8080
periodSeconds: 10
failureThreshold: 2
kubectl create -f tcpsocket.yaml
kubectl exec -it probe-tcp -- netstat -natp
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 1/nginx: master pro
kubectl get pods -w
NAME READY STATUS RESTARTS AGE
probe-tcp 1/1 Running 0 1s
probe-tcp 1/1 Running 1 25s #第一次是 init(5秒) + period(10秒) * 2
probe-tcp 1/1 Running 2 45s #第二次是 period(10秒) + period(10秒) 重试了两次
probe-tcp 1/1 Running 3 65s
3.4 Ejemplo 4: Detección de preparación
vim readiness-httpget.yaml
apiVersion: v1
kind: Pod
metadata:
name: readiness-httpget
namespace: default
spec:
containers:
- name: readiness-httpget-container
image: soscscs/myapp:v1
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
readinessProbe:
httpGet:
port: 80
path: /index1.html
initialDelaySeconds: 1
periodSeconds: 3
livenessProbe:
httpGet:
port: http
path: /index.html
initialDelaySeconds: 1
periodSeconds: 3
timeoutSeconds: 10
kubectl create -f readiness-httpget.yaml
La detección de preparación falló y no se pudo ingresar al estado LISTO
kubectl get pods
NAME READY STATUS RESTARTS AGE
readiness-httpget 0/1 Running 0 18s
kubectl exec -it readiness-httpget sh
# cd /usr/share/nginx/html/
# ls
50x.html index.html
# echo 123 > index1.html
# exit
kubectl get pods
NAME READY STATUS RESTARTS AGE
readiness-httpget 1/1 Running 0 2m31s
kubectl exec -it readiness-httpget -- rm -rf /usr/share/nginx/html/index.html
kubectl get pods -w
NAME READY STATUS RESTARTS AGE
readiness-httpget 1/1 Running 0 4m10s
readiness-httpget 0/1 Running 1 4m15s
3.5 Ejemplo 5: Detección de preparación 2
vim readiness-myapp.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp1
labels:
app: myapp
spec:
containers:
- name: myapp
image: soscscs/myapp:v1
ports:
- name: http
containerPort: 80
readinessProbe:
httpGet:
port: 80
path: /index.html
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 10
---
apiVersion: v1
kind: Pod
metadata:
name: myapp2
labels:
app: myapp
spec:
containers:
- name: myapp
image: soscscs/myapp:v1
ports:
- name: http
containerPort: 80
readinessProbe:
httpGet:
port: 80
path: /index.html
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 10
---
apiVersion: v1
kind: Pod
metadata:
name: myapp3
labels:
app: myapp
spec:
containers:
- name: myapp
image: soscscs/myapp:v1
ports:
- name: http
containerPort: 80
readinessProbe:
httpGet:
port: 80
path: /index.html
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
name: myapp
spec:
selector:
app: myapp
type: ClusterIP
ports:
- name: http
port: 80
targetPort: 80
kubectl create -f readiness-myapp.yaml
kubectl get pods,svc,endpoints -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/myapp1 1/1 Running 0 3m42s 10.244.2.13 node02 <none> <none>
pod/myapp2 1/1 Running 0 3m42s 10.244.1.15 node01 <none> <none>
pod/myapp3 1/1 Running 0 3m42s 10.244.2.14 node02 <none> <none>
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
......
service/myapp ClusterIP 10.96.138.13 <none> 80/TCP 3m42s app=myapp
NAME ENDPOINTS AGE
......
endpoints/myapp 10.244.1.15:80,10.244.2.13:80,10.244.2.14:80 3m42s
kubectl exec -it pod/myapp1 -- rm -rf /usr/share/nginx/html/index.html
- La detección de preparación falla, el Pod no puede ingresar al estado LISTO y el controlador del punto final eliminará la dirección IP del Pod de los puntos finales.
kubectl get pods,svc,endpoints -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/myapp1 0/1 Running 0 5m17s 10.244.2.13 node02 <none> <none>
pod/myapp2 1/1 Running 0 5m17s 10.244.1.15 node01 <none> <none>
pod/myapp3 1/1 Running 0 5m17s 10.244.2.14 node02 <none> <none>
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
......
service/myapp ClusterIP 10.96.138.13 <none> 80/TCP 5m17s app=myapp
NAME ENDPOINTS AGE
......
endpoints/myapp 10.244.1.15:80,10.244.2.14:80 5m17s
4. Acciones de inicio y salida
im post.yaml
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-demo
spec:
containers:
- name: lifecycle-demo-container
image: soscscs/myapp:v1
lifecycle: #此为关键字段
postStart:
exec:
command: ["/bin/sh", "-c", "echo Hello from the postStart handler >> /var/log/nginx/message"]
preStop:
exec:
command: ["/bin/sh", "-c", "echo Hello from the poststop handler >> /var/log/nginx/message"]
volumeMounts:
- name: message-log
mountPath: /var/log/nginx/
readOnly: false
initContainers:
- name: init-myservice
image: soscscs/myapp:v1
command: ["/bin/sh", "-c", "echo 'Hello initContainers' >> /var/log/nginx/message"]
volumeMounts:
- name: message-log
mountPath: /var/log/nginx/
readOnly: false
volumes:
- name: message-log
hostPath:
path: /data/volumes/nginx/log/
type: DirectoryOrCreate
kubectl create -f post.yaml
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
lifecycle-demo 1/1 Running 0 2m8s 10.244.2.28 node02 <none> <none>
kubectl exec -it lifecycle-demo -- cat /var/log/nginx/message
Hello initContainers
Hello from the postStart handler
Ver en el nodo nodo02
[root@node02 ~]# cd /data/volumes/nginx/log/
[root@node02 log]# ls
access.log error.log message
[root@node02 log]# cat message
Hello initContainers
Hello from the postStart handler
#由上可知,init Container先执行,然后当一个主容器启动后,Kubernetes 将立即发送 postStart 事件。
//删除 pod 后,再在 node02 节点上查看
kubectl delete pod lifecycle-demo
[root@node02 log]# cat message
Hello initContainers
Hello from the postStart handler
Hello from the poststop handler
#由上可知,当在容器被终结之前, Kubernetes 将发送一个 preStop 事件。