Spanish Translation

pull/14851/head
Enrique Medina Montenegro 2019-06-12 16:56:34 +02:00
parent 944ab0d67d
commit edad9d9e8d
6 changed files with 896 additions and 0 deletions

View File

@ -0,0 +1,457 @@
---
title: Jobs - Ejecución hasta el final
content_template: templates/concept
feature:
title: Ejecución en lotes
description: >
Además de los servicios, Kubernetes puede gestionar tus trabajos por lotes y CI, sustituyendo los contenedores que fallen, si así se desea.
weight: 70
---
{{% capture overview %}}
Un Job crea uno o más Pods y se asegura de que un número específico de ellos termina de forma satisfactoria.
Conforme los pods terminan satisfactoriamente, el Job realiza el seguimiento de las ejecuciones satisfactorias.
Cuando se alcanza un número específico de ejecuciones satisfactorias, la tarea (esto es, el Job) se completa.
Al eliminar un Job se eliminan los Pods que haya creado.
Un caso simple de uso es crear un objeto Job para que se ejecute un Pod de manera fiable hasta el final.
El objeto Job arrancará un nuevo Pod si el primer Pod falla o se elimina (por ejemplo
como consecuencia de un fallo de hardware o un reinicio en un nodo).
También se puede usar un Job para ejecutar múltiples Pods en paralelo.
{{% /capture %}}
{{% capture body %}}
## Ejecutar un Job de ejemplo
Aquí se muestra un ejemplo de configuración de Job. Este ejemplo calcula los primeros 2000 decimales de π y los imprime por pantalla.
Tarda unos 10s en completarse.
{{< codenew file="controllers/job.yaml" >}}
Puedes ejecutar el ejemplo con este comando:
```shell
kubectl apply -f https://k8s.io/examples/controllers/job.yaml
```
```
job "pi" created
```
Comprueba el estado del Job con `kubectl`:
```shell
kubectl describe jobs/pi
```
```
Name: pi
Namespace: default
Selector: controller-uid=b1db589a-2c8d-11e6-b324-0209dc45a495
Labels: controller-uid=b1db589a-2c8d-11e6-b324-0209dc45a495
job-name=pi
Annotations: <none>
Parallelism: 1
Completions: 1
Start Time: Tue, 07 Jun 2016 10:56:16 +0200
Pods Statuses: 0 Running / 1 Succeeded / 0 Failed
Pod Template:
Labels: controller-uid=b1db589a-2c8d-11e6-b324-0209dc45a495
job-name=pi
Containers:
pi:
Image: perl
Port:
Command:
perl
-Mbignum=bpi
-wle
print bpi(2000)
Environment: <none>
Mounts: <none>
Volumes: <none>
Events:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
1m 1m 1 {job-controller } Normal SuccessfulCreate Created pod: pi-dtn4q
```
Para ver los Pods de un Job que se han completado, usa `kubectl get pods`.
Para listar todos los Pods que pertenecen a un Job de forma que sea legible, puedes usar un comando como:
```shell
pods=$(kubectl get pods --selector=job-name=pi --output=jsonpath='{.items[*].metadata.name}')
echo $pods
```
```
pi-aiw0a
```
En este caso, el selector es el mismo que el selector del Job. La opción `--output=jsonpath` indica un expresión
que simplemente obtiene el nombre de cada Pod en la lista devuelta.
Mira la salida estándar de uno de los Pods:
```shell
$ kubectl logs $pods
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632788659361533818279682303019520353018529689957736225994138912497217752834791315155748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035637076601047101819429555961989467678374494482553797747268471040475346462080466842590694912933136770289891521047521620569660240580381501935112533824300355876402474964732639141992726042699227967823547816360093417216412199245863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818347977535663698074265425278625518184175746728909777727938000816470600161452491921732172147723501414419735685481613611573525521334757418494684385233239073941433345477624168625189835694855620992192221842725502542568876717904946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886269456042419652850222106611863067442786220391949450471237137869609563643719172874677646575739624138908658326459958133904780275901
```
## Escribir una especificación de Job
Como con el resto de configuraciones de Kubernetes, un Job necesita los campos `apiVersion`, `kind`, y `metadata`.
Un Job también necesita la [sección `.spec`](https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status).
### Plantilla Pod
El campo `.spec.template` es el único campo obligatorio de `.spec`.
El campo `.spec.template` es una [plantilla Pod](/docs/concepts/workloads/pods/pod-overview/#pod-templates). Tiene exactamente el mismo esquema que un [pod](/docs/user-guide/pods),
excepto por el hecho de que está anidado y no tiene el campo `apiVersion` o `kind`.
Además de los campos olbigatorios de un Pod, una plantilla Pod de un Job debe indicar las etiquetas apropiadas
(ver [selector de pod](#pod-selector)) y una regla de reinicio apropiada.
Sólo se permite los valores `Never` o `OnFailure` para [`RestartPolicy`](/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy).
### Selector de Pod
El campo `.spec.selector` es opcional. En la práctica mayoría de los casos no deberías configurarlo.
Mira la sección sobre [configurar tu propio selector de pod](#specifying-your-own-pod-selector).
### Jobs en paralelo
Hay tres tipos principales de tarea aptos para ejecutarse como un Job:
1. Jobs no paralelos
- normalmente, sólo se arranca un Pod, a menos que el Pod falle.
- el Job se completa tan pronto como su Pod termine de forma satisfactoria.
1. Jobs en paralelo con un *cupo fijo de terminación*:
- se configura un valor positivo distinto de cero para el campo `.spec.completions`.
- el Job representa la tarea en general, y se completa cuando hay una ejecución satisfactoria de un Pod por cada valor dentro del rango de 1 a `.spec.completions`.
- **no implementado todavía:** A cada Pod se le pasa un índice diferenente dentro del rango de 1 a `.spec.completions`.
1. Jobs en paralelo con una *cola de trabajo*:
- no se especifica el campo `.spec.completions`, por defecto `.spec.parallelism`.
- los Pods deben coordinarse entre ellos mismos o a través de un servicio externo que determine quién debe trabajar en qué.
Por ejemplo, un Pod podría ir a buscar un lote de hasta N ítems de una cola de trabajo.
- cada Pod es capaz de forma independiente de determinar si sus compañeros han terminado o no, y como consecuencia el Job entero ha terminado.
- cuando _cualquier_ Pod del Job termina con éxito, no se crean nuevos Pods.
- una vez que al menos uno de los Pods ha terminado con éxito y todos los Pods han terminado, entonces el Job termina con éxito.
- una vez que cualquier Pod ha terminado con éxito, ningún otro Pod debería continuar trabajando en la misma tarea o escribiendo ningún resultado. Todos ellos deberían estar en proceso de terminarse.
En un Job _no paralelo_, no debes indicar el valor de `.spec.completions` ni `.spec.parallelism`. Cuando ambos se dejan
sin valor, ambos se predeterminan a 1.
En un Job con _cupo fijo de terminación_, deberías poner el valor de `.spec.completions` al número de terminaciones que se necesiten.
Puedes dar un valor a `.spec.parallelism`, o dejarlo sin valor, en cuyo caso se predetermina a 1.
En un Job con _cola de trabajo_, no debes indicar el valor de `.spec.completions`, y poner el valor de `.spec.parallelism` a
un entero no negativo.
Para más información acerca de cómo usar los distintos tipos de Job, ver la sección de [patrones de job](#job-patterns).
#### Controlar el paralelismo
El paralelismo solicitado (`.spec.parallelism`) puede usar cualquier valor no negativo.
Si no se indica, se predeterminad a 1.
Si se indica como 0, entonces el Job se pausa de forma efectiva hasta que se incremente.
El paralelismo actual (número de pods ejecutándose en cada momento) puede que sea mayor o menor que el solicitado,
por los siguientes motivos:
- Para los Jobs con _cupo fijo de terminaciones_, el número actual de pods ejecutándose en paralelo no excede el número de terminaciones pendientes.
Los valores superiores de `.spec.parallelism` se ignoran.
- Para los Jobs con _cola de trabajo_, no se arranca nuevos Pods después de que cualquier Pod se haya completado -- sin embargo, se permite que se completen los Pods pendientes.
- Cuando el controlador no ha tenido tiempo para reaccionar.
- Cuando el controlador no pudo crear los Pods por el motivo que fuera (falta de `ResourceQuota`, falta de permisos, etc.),
entonces puede que haya menos pods que los solicitados.
- El controlador puede que regule la creación de nuevos Pods debido al excesivo número de fallos anteriores en el mismo Job.
- Cuando un Pod se para de forma controlada, lleva tiempo pararlo.
## Gestionar Fallos de Pod y Contenedor
Un contenedor de un Pod puede fallar por cualquier motivo, como porque el proceso que se estaba ejecutando termina con un código de salida distinto de cero,
o porque se mató el contenedor por exceder un límite de memoria, etc. Si esto ocurre, y se tiene
`.spec.template.spec.restartPolicy = "OnFailure"`, entonces el Pod permance en el nodo,
pero el contenedor se vuelve a ejecutar. Por lo tanto, tu aplicación debe poder gestionar el caso en que se reinicia de forma local,
o bien especificar `.spec.template.spec.restartPolicy = "Never"`.
Ver el [ciclo de vida de un pod](/docs/concepts/workloads/pods/pod-lifecycle/#example-states) para más información sobre `restartPolicy`.
Un Pod entero puede también fallar por cualquier motivo, como cuando se expulsa al Pod del nodo
(porque el nodo se actualiza, reinicia, elimina, etc.), o si un contenedor del Pod falla
cuando `.spec.template.spec.restartPolicy = "Never"`. Cuando un Pod falla, entonces el controlador del Job
arranca un nuevo Pod. Esto quiere decir que tu aplicación debe ser capaz de gestionar el caso en que se reinicia en un nuevo pod.
En particular, debe ser capaz de gestionar los ficheros temporales, los bloqueos, los resultados incompletos, y cualquier otra dependencia
de ejecuciones previas.
Nótese que incluso si se configura `.spec.parallelism = 1` y `.spec.completions = 1` y
`.spec.template.spec.restartPolicy = "Never"`, el mismo programa puede arrancarse dos veces.
Si se especifica `.spec.parallelism` y `.spec.completions` con valores mayores que 1,
entonces puede que haya múltiples pods ejecutándose a la vez. Por ello, tus pods deben tolerar la concurrencia.
### Regla de retroceso de Pod por fallo
Hay situaciones en que quieres que el Job falle después de intentar ejecutarlo unas cuantas veces debido
a un error lógico en la configuración, etc.
Para hacerlo, pon el valor de `.spec.backoffLimit` al número de reintentos que quieres
antes de considerar el Job como fallido. El límite de retroceso se predetermina a 6.
Los Pods fallidos asociados al Job son recreados por el controlador del Job con un
retroceso exponencial (10s, 20s, 40s ...) limitado a seis minutos. El contador
de retroceso se resetea si no aparecen Pods fallidos antes del siguiente chequeo de estado del Job.
{{< note >}}
El problema [#54870](https://github.com/kubernetes/kubernetes/issues/54870) todavía existe en las versiones de Kubernetes anteriores a la versión 1.12
{{< /note >}}
## Terminación y Limpieza de un Job
Cuando un Job se completa, ya no se crea ningún Pod, pero tampoco se elimina los Pods. Guardarlos permite
ver todavía los logs de los pods acabados para comprobar errores, avisos, o cualquier otro resultado de diagnóstico.
El objeto job también se conserva una vez que se ha completado para que se pueda ver su estado. Es decisión del usuario si elimina
los viejos jobs después de comprobar su estado. Eliminar el job con el comando `kubectl` (ej. `kubectl delete jobs/pi` o `kubectl delete -f ./job.yaml`).
Cuando eliminas un job usando el comando `kubectl`, todos los pods que creó se eliminan también.
Por defecto, un Job se ejecutará de forma ininterrumpida a menos que uno de los Pods falle, en cuyo caso el Job se fija en el valor de
`.spec.backoffLimit` descrito arriba. Otra forma de acabar un Job es poniéndole un vencimiento activo.
Haz esto poniendo el valor del campo `.spec.activeDeadlineSeconds` del Job a un número de segundos.
El campo `activeDeadlineSeconds` se aplica a la duración del job, independientemente de cuántos Pods se hayan creado.
Una vez que el Job alcanza `activeDeadlineSeconds`, se terminan todos sus Pods y el estado del Job se pone como `type: Failed` con `reason: DeadlineExceeded`.
Fíjate que el campo `.spec.activeDeadlineSeconds` de un Job tiene precedencia sobre el campo `.spec.backoffLimit`.
Por lo tanto, un Job que está reintentando uno o más Pods fallidos no desplegará nuevos Pods una vez que alcance el límite de tiempo especificado por `activeDeadlineSeconds`,
incluso si todavía no se ha alcanzado el `backoffLimit`.
Ejemplo:
```yaml
apiVersion: batch/v1
kind: Job
metadata:
name: pi-with-timeout
spec:
backoffLimit: 5
activeDeadlineSeconds: 100
template:
spec:
containers:
- name: pi
image: perl
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
restartPolicy: Never
```
Fíjate que tanto la especificación del Job como la [especificación de la plantilla Pod](/docs/concepts/workloads/pods/init-containers/#detailed-behavior)
dentro del Job tienen un campo `activeDeadlineSeconds`. Asegúrate que pones el valor de este campo de forma adecuada.
## Limpiar los Jobs terminados automáticamente
Normalmente, los Jobs que han terminado ya no se necesitan en el sistema. Conservarlos sólo añade
más presión al servidor API. Si dichos Jobs no se gestionan de forma directa por un controlador de más alto nivel,
como los [CronJobs](/docs/concepts/workloads/controllers/cron-jobs/), los Jobs pueden
limpiarse por medio de CronJobs en base a la regla de limpieza basada en capacidad que se haya especificado.
### Mecanismo TTL para Jobs terminados
{{< feature-state for_k8s_version="v1.12" state="alpha" >}}
Otra forma de limpiar los Jobs terminados (bien `Complete` o `Failed`)
de forma automática es usando un mecanismo TTL proporcionado por un
[controlador TTL](/docs/concepts/workloads/controllers/ttlafterfinished/) de recursos finalizados,
indicando el valor `.spec.ttlSecondsAfterFinished` del Job.
Cuando el controlador TTL limpia el Job, lo eliminará en cascada,
esto es, eliminará sus objetos subordinados, como Pods, junto con el Job. Nótese
que cuando se elimina el Job, sus garantías de ciclo de vida, como los finalizadores,
se tendrán en cuenta.
Por ejemplo:
```yaml
apiVersion: batch/v1
kind: Job
metadata:
name: pi-with-ttl
spec:
ttlSecondsAfterFinished: 100
template:
spec:
containers:
- name: pi
image: perl
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
restartPolicy: Never
```
Aquí el Job `pi-with-ttl` será candidato a ser automáticamente eliminado, `100`
segundos después de que termine.
Si el campo se pone a `0`, el Job será candidato a ser automáticamente eliminado
inmediatamente después de haber terminado. Si no se pone valor al campo, este Job no será eliminado
por el controlador TTL una vez concluya.
Nótese que este mecanismo TTL está todavía en alpha, a través de la característica denominada `TTLAfterFinished`.
Para más información, ver la documentación del [controlador TTL](/docs/concepts/workloads/controllers/ttlafterfinished/) para
recursos terminados.
## Patrones de Job
El objeto Job puede usarse para dar soporte a la ejecución fiable de Pods en paralelo. El objeto Job
no se diseñó para dar soporte a procesos paralelos estrechamente comunicados, como los que comúnmente
se encuentran en la computación científica. Eso sí, permite el proceso paralelo de un conjunto de *ítems de trabajo* independientes, pero relacionados entre sí.
Estos pueden ser correos a enviar, marcos a renderizar, archivos a codificar, rangos de claves en una base de datos NoSQL a escanear, y demás.
En un sistema complejo, puede haber múltiples diferentes conjuntos de ítems de trabajo. Aquí sólo se está
considerando un conjunto de ítems de trabajo que el usuario quiere gestionar de forma conjunta &mdash; un *proceso por lotes*.
Hay varios patrones diferentes para computación en paralelo, cada uno con sus fortalezas y sus debilidades.
Los sacrificios a tener en cuenta son:
- Un objeto Job para cada ítem de trabajo vs. un objeto Job simple para todos los ítems de trabajo. El último es mejor
para grandes números de ítems de trabajo. El primero añade sobrecarga para el usuario y para el sistema
al tener que gestionar grandes números de objetos Job.
- El número de pods creados es igual al número de ítems de trabajo vs. cada Pod puede procesar múltiplese ítems de trabajo.
El primero típicamente requiere menos modificaciones al código existente y a los contenedores.
El último es mejor cuanto mayor sea el número de ítems de trabajo, por las mismas razones que antes..
- Varios enfoques usan una cola de trabajo. Ello requiere ejecutar un servicio de colas,
y modificaciones a las aplicaciones o contenedores existentes para que hagan uso de la cola de trabajo.
Otras estrategias son más fáciles de adaptar a una aplicación ya usando contenedores.
Los sacrificios a tener en cuenta se indican a continuación, donde las columnas 2 a 4 representan los sacrificios de arriba.
Los nombres de los patrones son también enlaces a ejemplos e información más detallada.
| Patrón | Objeto Job simple | ¿Menos pods que ítems de trabajo? | ¿No modificar la aplicación? | ¿Funciona en Kube 1.1? |
| -------------------------------------------------------------------- |:-----------------:|:---------------------------:|:-------------------:|:-------------------:|
| [Extensión de la Plantilla Job](/docs/tasks/job/parallel-processing-expansion/) | | | ✓ | ✓ |
| [Cola con Pod por Ítem de Trabajo](/docs/tasks/job/coarse-parallel-processing-work-queue/) | ✓ | | a veces | ✓ |
| [Cola con Cuenta Variable de Pods](/docs/tasks/job/fine-parallel-processing-work-queue/) | ✓ | ✓ | | ✓ |
| Job simple con Asignación Estática de Trabajo | ✓ | | ✓ | |
Cuando se especifican terminaciones con `.spec.completions`, cada Pod creado por el controlado del Job
tiene un [`spec`](https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status)idéntico.
Esto significa que todos los pods de una tarea tendrán la misma línea de comandos y la
misma imagne, los mismo volúmenes, y (casi) las mismas variables de entorno.
Estos patrones otorgan diferentes formas de organizar los pods para que trabajen en cosas distintas.
Esta tabla muestra la configuración necesaria para `.spec.parallelism` y `.spec.completions` para cada uno de los patrones.
Aquí, `T` es el número de ítems de trabajo.
| Patrón | `.spec.completions` | `.spec.parallelism` |
| -------------------------------------------------------------------- |:-------------------:|:--------------------:|
| [Extensión de la Plantilla Job](/docs/tasks/job/parallel-processing-expansion/) | 1 | debería ser 1 |
| [Cola con Pod por Ítem de Trabajo](/docs/tasks/job/coarse-parallel-processing-work-queue/) | T | cualquiera |
| [Cola con Cuenta Variable de Pods](/docs/tasks/job/fine-parallel-processing-work-queue/) | 1 | cualquiera |
| Job simple con Asignación Estática de Trabajo | T | cualquiera |
## Uso Avanzado
### Especificar tu propio selector de pod
Normalmente, cuando creas un objeto Job, no especificas el campo `.spec.selector`.
La lógica por defecto del sistema añade este campo cuando se crea el Job.
Se elige un valor de selector que no se entremezcle con otras tareas.
Sin embargo, en algunos casos, puede que necesites sobreescribir este selector que se configura de forma automática.
Para ello, puedes indicar el valor de `.spec.selector` en el Job.
Pero ten mucho cuidado cuando lo hagas. Si configuras un selector de etiquta que no
es único para los pods de ese Job, y que selecciona Pods que no tienen que ver,
entonces estos últimos pueden ser eliminados, o este Job puede contar los otros
Pods para terminarse, o uno o ambos Jobs pueden negarse a crear Pods o ejecutarse hasta el final.
Si se elige un selector que no es único, entonces otros controladores (ej. ReplicationController)
y sus Pods puede comportarse de forma impredecibles también. Kubernetes no te impide cometer un error
especificando el `.spec.selector`.
Aquí se muestra un ejemplo de un caso en que puede que necesites usar esta característica.
Digamos que el Job `viejo` todavía está ejeuctándose. Quieres que los Pods existentes
sigan corriendo, pero quieres que el resto de los Pods que se creen
usen una plantilla pod diferente y que el Job tenga un nombre nuevo.
Como no puedes modificar el Job porque esos campos no son modificables, eliminas el Job `old`,
pero _dejas sus pods ejecutándose_ mediante el comando `kubectl delete jobs/old --cascade=false`.
Antes de eliminarlo, apúntate el selector actual que está usando:
```
kind: Job
metadata:
name: viejo
...
spec:
selector:
matchLabels:
job-uid: a8f3d00d-c6d2-11e5-9f87-42010af00002
...
```
Entonces, creas un nuevo Job con el nombre `nuevo` y le configuras explícitamente el mismo selector.
Puesto que los Pods existentes tienen la etiqueta `job-uid=a8f3d00d-c6d2-11e5-9f87-42010af00002`,
son controlados por el Job `nuevo` igualmente.
Necesitas configurar `manualSelector: true` en el nuevo Job, ya qye no estás usando
el selector que normalmente se genera de forma automática por el sistema.
```
kind: Job
metadata:
name: nuevo
...
spec:
manualSelector: true
selector:
matchLabels:
job-uid: a8f3d00d-c6d2-11e5-9f87-42010af00002
...
```
El mismo Job nuevo tendrá un uid distinto a `a8f3d00d-c6d2-11e5-9f87-42010af00002`.
Poniendo `manualSelector: true` le dice al sistema que sabes lo que estás haciendo
y que te permita hacer este desajuste.
## Alternativas
### Pods simples
Cuando el nodo donde un Pod simple se estaba ejecutando se reinicia o falla, dicho pod se termina
y no será reinicado. Sin embargo, un Job creará nuevos Pods para sustituir a los que se han terminando.
Por esta razón, se recomienda que se use un Job en vez de un Pod simple, incluso si tu aplicación
sólo necesita un único Pod.
### Replication Controller
Los Jobs son complementarios a los [Replication Controllers](/docs/user-guide/replication-controller).
Un Replication Controller gestiona aquellos Pods que se espera que no terminen (ej. servidores web), y un Job
gestiona aquellos Pods que se espera que terminen (ej. tareas por lotes).
Como se discutió en el [Ciclo de vida de un Pod](/docs/concepts/workloads/pods/pod-lifecycle/), un `Job` *sólo* es apropiado
para aquellos pods con `RestartPolicy` igual a `OnFailure` o `Never`.
(Nota: Si `RestartPolicy` no se pone, el valor predeterminado es `Always`.)
### Job simple arranca que arranca un controlador de Pod
Otro patrón es aquel donde un Job simple crea un Pod que, a su vez, crea otros Pods, actuando como una especie
de controlador personalizado para esos Pods. Esto da la máxima flexibilidad, pero puede que
cueste un poco más de entender y ofrece menos integración con Kubernetes.
Un ejemplo de este patrón sería un Job que arranca un Pod que ejecuta una secuencia de comandos que, a su vez,
arranca un controlador maestro de Spark (ver el [ejemplo de spark](https://github.com/kubernetes/examples/tree/{{< param "githubbranch" >}}/staging/spark/README.md)),
ejecuta un manejador de spark, y a continuación lo limpia todo.
Una ventaja de este enfoque es que el proceso general obtiene la garantía del objeto Job,
además del control completo de los Pods que se crean y cómo se les asigna trabajo.
## Cron Jobs {#cron-jobs}
Puedes utilizar un [`CronJob`](/docs/concepts/workloads/controllers/cron-jobs/) para crear un Job que se ejecute en una hora/fecha determinadas, de forma similar
a la herramienta `cron` de Unix.
{{% /capture %}}

View File

@ -0,0 +1,370 @@
---
title: ReplicaSet
content_template: templates/concept
weight: 10
---
{{% capture overview %}}
El objeto de un ReplicaSet es el de mantener un conjunto estable de réplicas de Pods ejecutándose
en todo momento. Así, se usa en numerosas ocasiones para garantizar la disponibilidad de un
número específico de Pods idénticos.
{{% /capture %}}
{{% capture body %}}
## Cómo funciona un ReplicaSet
Un ReplicaSet se define con campos, incluyendo un selector que indica cómo identificar a los Pods que puede adquirir,
un número de réplicas indicando cuántos Pods debería gestionar, y una plantilla pod especificando los datos de los nuevos Pods
que debería crear para conseguir el número de réplicas esperado. Un ReplicaSet alcanza entonces su propósito
mediante la creación y eliminación de los Pods que sea necesario para alcanzar el número esperado.
Cuando un ReplicaSet necesita crear nuevos Pods, utiliza su plantilla Pod.
El enlace que un ReplicaSet tiene hacia sus Pods es a través del campo del Pod denominado [metadata.ownerReferences](/docs/concepts/workloads/controllers/garbage-collection/#owners-and-dependents),
el cual indica qué recurso es el propietario del objeto actual. Todos los Pods adquiridos por un ReplicaSet tienen su propia
información de identificación del ReplicaSet en su campo ownerReferences. Y es a través de este enlace
cómo el ReplicaSet conoce el estado de los Pods que está gestionando y actúa en consecuencia.
Un ReplicaSet identifica los nuevos Pods a adquirir usando su selector. Si hay un Pod que no tiene OwnerReference
o donde OwnerReference no es un controlador, pero coincide con el selector del ReplicaSet,
este será inmediatamente adquirido por dicho ReplicaSet.
## Cuándo usar un ReplicaSet
Un ReplicaSet garantiza que un número específico de réplicas de un pod se está ejeuctando en todo momento.
Sin embargo, un Deployment es un concepto de más alto nivel que gestiona ReplicaSets y
proporciona actualizaciones de forma declarativa de los Pods junto con muchas otras características útiles.
Por lo tanto, se recomienda el uso de Deployments en vez del uso directo de ReplicaSets, a no ser
que se necesite una orquestración personalizada de actualización o no se necesite las actualizaciones en absoluto.
En realidad, esto quiere decir que puede que nunca necesites manipular los objetos ReplicaSet:
en vez de ello, usa un Deployment, y define tu aplicación en la sección spec.
## Ejemplo
{{< codenew file="controllers/frontend.yaml" >}}
Si guardas este manifiesto en un archivo llamado `frontend.yaml` y lo lanzas en un clúster de Kubernetes,
se creará el ReplicaSet definido y los Pods que maneja.
```shell
kubectl apply -f http://k8s.io/examples/controllers/frontend.yaml
```
Puedes ver los ReplicaSets actuales desplegados:
```shell
kubectl get rs
```
Y ver el frontend que has creado:
```shell
NAME DESIRED CURRENT READY AGE
frontend 3 3 3 6s
```
También puedes comprobar el estado del replicaset:
```shell
kubectl describe rs/frontend
```
Y verás una salida parecida a la siguiente:
```shell
Name: frontend
Namespace: default
Selector: tier=frontend,tier in (frontend)
Labels: app=guestbook
tier=frontend
Annotations: <none>
Replicas: 3 current / 3 desired
Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
Labels: app=guestbook
tier=frontend
Containers:
php-redis:
Image: gcr.io/google_samples/gb-frontend:v3
Port: 80/TCP
Requests:
cpu: 100m
memory: 100Mi
Environment:
GET_HOSTS_FROM: dns
Mounts: <none>
Volumes: <none>
Events:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
1m 1m 1 {replicaset-controller } Normal SuccessfulCreate Created pod: frontend-qhloh
1m 1m 1 {replicaset-controller } Normal SuccessfulCreate Created pod: frontend-dnjpy
1m 1m 1 {replicaset-controller } Normal SuccessfulCreate Created pod: frontend-9si5l
```
Y por último, puedes comprobar los Pods que ha arrancado:
```shell
kubectl get Pods
```
Deberías ver la información de cada Pod similar a:
```shell
NAME READY STATUS RESTARTS AGE
frontend-9si5l 1/1 Running 0 1m
frontend-dnjpy 1/1 Running 0 1m
frontend-qhloh 1/1 Running 0 1m
```
También puedes verificar que la referencia de propietario de dichos pods está puesta al ReplicaSet frontend.
Para ello, obtén el yaml de uno de los Pods ejecutándose:
```shell
kubectl get pods frontend-9si5l -o yaml
```
La salida será parecida a esta, donde la información sobre el ReplicaSet aparece en el campo ownerReferences de los metadatos:
```shell
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: 2019-01-31T17:20:41Z
generateName: frontend-
labels:
tier: frontend
name: frontend-9si5l
namespace: default
ownerReferences:
- apiVersion: extensions/v1beta1
blockOwnerDeletion: true
controller: true
kind: ReplicaSet
name: frontend
uid: 892a2330-257c-11e9-aecd-025000000001
...
```
## Adquisiciones de Pods fuera de la plantilla
Aunque puedes crear Pods simples sin problemas, se recomienda encarecidamente asegurarse de que dichos Pods no tienen
etiquetas que puedan coincidir con el selector de alguno de tus ReplicaSets.
La razón de esta recomendación es que un ReplicaSet no se limita a poseer los Pods
especificados en su plantilla -- sino que puede adquirir otros Pods como se explicó en secciones anteriores.
Toma el ejemplo anterior del ReplicaSet frontend, y los Pods especificados en el siguiente manifiesto:
{{< codenew file="pods/pod-rs.yaml" >}}
Como estos Pods no tienen un Controlador (o cualquier otro objeto) como referencia de propietario
y como además su selector coincide con el del ReplicaSet frontend, este último los terminará adquiriendo de forma inmediata.
Supón que creas los Pods después de que el ReplicaSet frontend haya desplegado los suyos
para satisfacer su requisito de cuenta de réplicas:
```shell
kubectl apply -f http://k8s.io/examples/pods/pod-rs.yaml
```
Los nuevos Pods serán adquiridos por el ReplicaSet, e inmediatamente terminados ya que
el ReplicaSet estaría por encima del número deseado.
Obtener los Pods:
```shell
kubectl get Pods
```
La salida muestra que los nuevos Pods se han terminado, o están en el proceso de terminarse:
```shell
NAME READY STATUS RESTARTS AGE
frontend-9si5l 1/1 Running 0 1m
frontend-dnjpy 1/1 Running 0 1m
frontend-qhloh 1/1 Running 0 1m
pod2 0/1 Terminating 0 4s
```
Si creas primero los Pods:
```shell
kubectl apply -f http://k8s.io/examples/pods/pod-rs.yaml
```
Y entonces creas el ReplicaSet:
```shell
kubectl apply -f http://k8s.io/examples/controllers/frontend.yaml
```
Verás que el ReplicaSet ha adquirido dichos Pods y simplemente ha creado tantos nuevos
como necesarios para cumplir con su especificación hasta que el número de
sus nuevos Pods y los originales coincidan con la cuenta deseado. Al obtener los Pods:
```shell
kubectl get Pods
```
Veremos su salida:
```shell
NAME READY STATUS RESTARTS AGE
frontend-pxj4r 1/1 Running 0 5s
pod1 1/1 Running 0 13s
pod2 1/1 Running 0 13s
```
De esta forma, un ReplicaSet puede poseer un conjunto no homogéneo de Pods
## Escribir un manifiesto de ReplicaSet
Al igual que con el esto de los objeto de la API de Kubernetes, un ReplicaSet necesita los campos
`apiVersion`, `kind`, y `metadata`. Para los ReplicaSets, el tipo es siempre ReplicaSet.
En la versión 1.9 de Kubernetes, la versión `apps/v1` de la API en un tipo ReplicaSet es la versión actual y está habilitada por defecto.
La versión `apps/v1beta2` de la API se ha desaprobado.
Consulta las primeras líneas del ejemplo `frontend.yaml` como guía.
Un ReplicaSet también necesita una [sección `.spec`](https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status).
### Plantilla Pod
El campo `.spec.template` es una [plantilla pod](/docs/concepts/workloads/Pods/pod-overview/#pod-templates) que es
también necesita obligatoriamente tener etiquetas definidas. En nuestro ejemplo `frontend.yaml` teníamos una etiqueta: `tier: frontend`.
Lleva cuidado de que no se entremezcle con los selectores de otros controladores, no sea que traten de adquirir este Pod.
Para el campo de [regla de reinicio](/docs/concepts/workloads/Pods/pod-lifecycle/#restart-policy) de la plantilla,
`.spec.template.spec.restartPolicy`, el único valor permitido es `Always`, que es el valor predeterminado.
### Selector de Pod
El campo `.spec.selector` es un [selector de etiqueta](/docs/concepts/overview/working-with-objects/labels/).
Como se explicó [anteriormente](#how-a-replicaset-works), estas son las etiquetas que se usan para
identificar los Pods potenciales a adquirir. En nuestro ejemplo `frontend.yaml`, el selector era:
```shell
matchLabels:
tier: frontend
```
El el ReplicaSet, `.spec.template.metadata.labels` debe coincidir con `spec.selector`, o será
rechazado por la API.
{{< note >}}
Cuando 2 ReplicaSets especifican el mismo campo `.spec.selector`, pero los campos
`.spec.template.metadata.labels` y `.spec.template.spec` diferentes, cada ReplicaSet
ignora los Pods creados por el otro ReplicaSet.
{{< /note >}}
### Réplicas
Puedes configurar cuántos Pods deberían ejecutarse de forma concurrente indicando el campo `.spec.replicas`.
El ReplicaSet creará/eliminará sus Pods para alcanzar este número.
Si no indicas el valor del campo `.spec.replicas`, entonces por defecto se inicializa a 1.
## Trabajar con ReplicaSets
### Eliminar un ReplicaSet y sus Pods
Para eliminar un ReplicaSet y todos sus Pods, utiliza el comando [`kubectl delete`](/docs/reference/generated/kubectl/kubectl-commands#delete).
El [Recolector de basura](/docs/concepts/workloads/controllers/garbage-collection/) eliminará automáticamente
todos los Pods subordinados por defecto.
Cuando se usa la API REST o la librería `client-go`, se debe poner el valor de `propagationPolicy` a `Background` o
`Foreground` en la opción -d.
Por ejemplo:
```shell
kubectl proxy --port=8080
curl -X DELETE 'localhost:8080/apis/extensions/v1beta1/namespaces/default/replicasets/frontend' \
> -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Foreground"}' \
> -H "Content-Type: application/json"
```
### Eliminar sólo un ReplicaSet
Se puede eliminar un ReplicaSet sin afectar a ninguno de sus Pods usando el comando [`kubectl delete`](/docs/reference/generated/kubectl/kubectl-commands#delete) con la opción `--cascade=false`.
Cuando se usa la API REST o la librería `client-go`, se debe poner `propagationPolicy` a `Orphan`.
Por ejemplo:
```shell
kubectl proxy --port=8080
curl -X DELETE 'localhost:8080/apis/extensions/v1beta1/namespaces/default/replicasets/frontend' \
> -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Orphan"}' \
> -H "Content-Type: application/json"
```
Una vez que se ha eliminado el original, se puede crear un nuevo ReplicaSet para sustituirlo.
Mientras el viejo y el nuevo `.spec.selector` sean el mismo, el nuevo adoptará a los viejos Pods.
Sin embargo, no se esforzará en conseguir que los Pods existentes coincidan con una plantilla pod nueva, diferente.
Para actualizar dichos Pods a la nueva especificación de forma controlada,
usa una [actualización en línea](#rolling-updates).
### Aislar Pods de un ReplicaSet
Es posible aislar Pods de un ReplicaSet cambiando sus etiquetas. Esta técnica puede usarse
para eliminar Pods de un servicio para poder depurar, recuperar datos, etc. Los Pods
que se eliminar de esta forma serán sustituidos de forma automática (siempre que el
número de réplicas no haya cambiado).
### Escalar un ReplicaSet
Se puede aumentar o reducir fácilmente un ReplicaSet simplemente actualizando el campo `.spec.replicas`.
El controlador del ReplicaSet se asegura de que el número deseado de Pods con un selector
de etiquetas coincidente está disponible y operacional.
### ReplicaSet como blanco de un Horizontal Pod Autoscaler
Un ReplicaSet puede también ser el blanco de un
[Horizontal Pod Autoscalers (HPA)](/docs/tasks/run-application/horizontal-pod-autoscale/). Esto es,
un ReplicaSet puede auto-escalarse mediante un HPA. Aquí se muestra un ejemplo de HPA dirigido
al ReplicaSet que creamos en el ejemplo anterior.
{{< codenew file="controllers/hpa-rs.yaml" >}}
Si guardas este manifiesto en un archivo `hpa-rs.yaml` y lo lanzas contra el clúster de Kubernetes,
debería crear el HPA definido que auto-escala el ReplicaSet destino dependiendo del uso
de CPU de los Pods replicados.
```shell
kubectl apply -f https://k8s.io/examples/controllers/hpa-rs.yaml
```
Alternativamente, puedes usar el comando `kubectl autoscale` para conseguir el mismo objetivo
(¡y mucho más fácil!)
```shell
kubectl autoscale rs frontend --max=10
```
## Alternativas al ReplicaSet
### Deployment (recomendado)
Un[`Deployment`](/docs/concepts/workloads/controllers/deployment/) es un objeto que puede poseer ReplicaSets
y actualizar a estos y a sus Pods mediante actualizaciones en línea declarativas en el servidor.
Aunque que los ReplicaSets puede usarse independientemente, hoy en día se usan principalmente a través de los Deployments
como el mecanismo para orquestrar la creación, eliminación y actualización de los Pods.
Cuando usas Deployments no tienes que preocuparte de gestionar los ReplicaSets que crean.
Los Deployments poseen y gestionan sus ReplicaSets.
Por tanto, se recomienda que se use Deployments cuando se quiera ReplicaSets.
### Pods simples
A diferencia del caso en que un usuario creaba Pods de forma directa, un ReplicaSet sustituye los Pods que se eliminan
o se terminan por la razón que sea, como en el caso de un fallo de un nodo o
una intervención disruptiva de mantenimiento, como una actualización de kernel.
Por esta razón, se recomienda que se use un ReplicaSet incluso cuando la aplicación
sólo necesita un único Pod. Entiéndelo de forma similar a un proceso supervisor,
donde se supervisa múltiples Pods entre múltiples nodos en vez de procesos individuales
en un único nodo. Un ReplicaSet delega los reinicios del contenedor local a algún agente
del nodo (por ejemplo, Kubelet o Docker).
### Job
Usa un [`Job`](/docs/concepts/jobs/run-to-completion-finite-workloads/) en vez de un ReplicaSet para
aquellos Pods que se esperan que terminen por ellos mismos (esto es, trabajos por lotes).
### DaemonSet
Usa un [`DaemonSet`](/docs/concepts/workloads/controllers/daemonset/) en vez de un ReplicaSet para aquellos
Pods que proporcionan funcionalidad a nivel de servidor, como monitorización de servidor o
logging de servidor. Estos Pods tienen un ciclo de vida asociado al del servidor mismo:
el Pod necesita ejecutarse en el servidor antes de que los otros Pods comiencen, y es seguro
que terminen cuando el servidor esté listo para ser reiniciado/apagado.
### ReplicationController
Los ReplicaSets son los sucesores de los [_ReplicationControllers_](/docs/concepts/workloads/controllers/replicationcontroller/).
Los dos sirven al mismo propósito, y se comportan de forma similar, excepto porque un ReplicationController
no soporta los requisitos del selector basado en conjunto, como se describe en la [guía de usuario de etiquetas](/docs/concepts/overview/working-with-objects/labels/#label-selectors).
Por ello, se prefiere los ReplicaSets a los ReplicationControllers.
{{% /capture %}}

View File

@ -0,0 +1,21 @@
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: frontend
labels:
app: guestbook
tier: frontend
spec:
# modifica las réplicas según tu caso de uso
replicas: 3
selector:
matchLabels:
tier: frontend
template:
metadata:
labels:
tier: frontend
spec:
containers:
- name: php-redis
image: gcr.io/google_samples/gb-frontend:v3

View File

@ -0,0 +1,11 @@
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: frontend-scaler
spec:
scaleTargetRef:
kind: ReplicaSet
name: frontend
minReplicas: 3
maxReplicas: 10
targetCPUUtilizationPercentage: 50

View File

@ -0,0 +1,14 @@
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
template:
spec:
containers:
- name: pi
image: perl
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
restartPolicy: Never
backoffLimit: 4

View File

@ -0,0 +1,23 @@
apiVersion: v1
kind: Pod
metadata:
name: pod1
labels:
tier: frontend
spec:
containers:
- name: hello1
image: gcr.io/google-samples/hello-app:2.0
---
apiVersion: v1
kind: Pod
metadata:
name: pod2
labels:
tier: frontend
spec:
containers:
- name: hello2
image: gcr.io/google-samples/hello-app:1.0