Kubernetes: Mejor soporte para contenedores sidecar en trabajos por lotes

Creado en 19 may. 2016  ·  116Comentarios  ·  Fuente: kubernetes/kubernetes

Considere un trabajo con dos contenedores: uno que hace el trabajo y luego termina, y otro que no está diseñado para salir nunca explícitamente, pero proporciona algún tipo de funcionalidad de apoyo como registro o recopilación de métricas.

¿Qué opciones existen para hacer algo como esto? ¿Qué opciones deberían existir?

Actualmente, el trabajo seguirá ejecutándose mientras el segundo contenedor siga ejecutándose, lo que significa que el usuario tiene que modificar el segundo contenedor de alguna manera para detectar cuándo se realiza el primero para que también pueda salir limpiamente.

Esta pregunta se hizo en Stack Overflow hace un tiempo sin mejor respuesta que modificar el segundo contenedor para que sea más compatible con Kubernetes, lo cual no es ideal. Otro cliente me ha mencionado recientemente esto como un punto de dolor para ellos.

@ kubernetes / goog-control-plane @erictune

arebatch areworkload-apjob kinfeature lifecyclfrozen prioritimportant-longterm siapps sinode

Comentario más útil

Como referencia, aquí está la locura de bash que estoy usando para simular el comportamiento de sidecar deseado:

containers:
  - name: main
    image: gcr.io/some/image:latest
    command: ["/bin/bash", "-c"]
    args:
      - |
        trap "touch /tmp/pod/main-terminated" EXIT
        /my-batch-job/bin/main --config=/config/my-job-config.yaml
    volumeMounts:
      - mountPath: /tmp/pod
        name: tmp-pod
  - name: envoy
    image: gcr.io/our-envoy-plus-bash-image:latest
    command: ["/bin/bash", "-c"]
    args:
      - |
        /usr/local/bin/envoy --config-path=/my-batch-job/etc/envoy.json &
        CHILD_PID=$!
        (while true; do if [[ -f "/tmp/pod/main-terminated" ]]; then kill $CHILD_PID; fi; sleep 1; done) &
        wait $CHILD_PID
        if [[ -f "/tmp/pod/main-terminated" ]]; then exit 0; fi
    volumeMounts:
      - mountPath: /tmp/pod
        name: tmp-pod
        readOnly: true
volumes:
  - name: tmp-pod
    emptyDir: {}

Todos 116 comentarios

/sub

Además, el uso de un problema de vida como se sugiere aquí http://stackoverflow.com/questions/36208211/sidecar-containers-in-kubernetes-jobs no funciona ya que el pod se considerará fallado y el trabajo general no se considerará exitoso.

¿Qué tal si declaramos un sondeo de éxito del trabajo para que el trabajo pueda probarlo para detectar el éxito en lugar de esperar a que el pod devuelva 0?
Una vez que la sonda arroja resultados satisfactorios, se puede finalizar el pod.

¿Puede la sonda ejecutarse contra un contenedor que ya ha salido o
¿Será una carrera donde se está derribando?

Otra opción es designar ciertos códigos de salida con un significado especial.

Tanto el "éxito de todo el grupo de anuncios" como el "error de todo el grupo de anuncios" son
útil.

Esto debería estar en el objeto Pod, por lo que es un gran cambio de API.

El jueves 22 de septiembre de 2016 a la 1:41 p.m., Ming Fang [email protected] escribió:

¿Qué tal si declaramos una prueba de éxito del trabajo para que el trabajo pueda probarla?
detecta el éxito en lugar de esperar a que el pod devuelva 0.

Una vez que la sonda arroja resultados satisfactorios, se puede finalizar el pod.

-
Recibes esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/kubernetes/kubernetes/issues/25908#issuecomment -249021627,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/AHuudjrpVtef6U35RWRlZr3mDKcCRo7oks5qsugRgaJpZM4IiqQH
.

@erictune Buen punto; no podemos sondear un contenedor salido.

¿Podemos designar un contenedor en particular en la vaina como el contenedor de "finalización" para que cuando ese contenedor salga podamos decir que el trabajo se completó?

Los contenedores sidecar tienden a durar mucho tiempo para cosas como el envío y el seguimiento de troncos.
Podemos forzar su rescisión una vez que se complete el trabajo.

¿Podemos designar un contenedor en particular en la vaina como el contenedor de "finalización" para que cuando ese contenedor salga podamos decir que el trabajo se completó?

¿Ha mirado este punto de aquí donde básicamente no establece .spec.completions y tan pronto como el primer contenedor termina con el código de salida 0, el trabajo está terminado?

Los contenedores sidecar tienden a durar mucho tiempo para cosas como el envío y el seguimiento de troncos.
Podemos forzar su rescisión una vez que se complete el trabajo.

Personalmente, estos me parecen más a RS que a un trabajo, pero esa es mi opinión personal y, lo más importante, no conozco todos los detalles de su configuración.

En general, existen las siguientes discusiones https://github.com/kubernetes/kubernetes/issues/17244 y https://github.com/kubernetes/kubernetes/issues/30243 que también tocan este tema.

@soltysh el enlace que envió anteriormente, el punto 3 hace referencia a la finalización del pod y no a la finalización del contenedor.

Los dos contenedores pueden compartir un EmptyDir y el primer contenedor y escribir un mensaje "Estoy saliendo ahora" en un archivo y el otro puede salir cuando ve ese mensaje.

@erictune Tengo un caso de uso que creo que cae en este cubo y espero que pueda guiarme en la dirección correcta, ya que no parece haber ninguna forma oficial recomendada para resolver este problema.

Estoy usando la biblioteca client-go para codificar todo lo siguiente:

Entonces, tengo un trabajo que básicamente ejecuta una herramienta en un contenedor de un solo contenedor. Tan pronto como la herramienta termine de ejecutarse, se supone que generará un archivo de resultados. Parece que no puedo capturar este archivo de resultados porque tan pronto como la herramienta termina de ejecutarse, el pod se elimina y pierdo el archivo de resultados.

Pude capturar este archivo de resultados si usé HostPath como VolumeSource y como estoy ejecutando minikube localmente, el archivo de resultados se guarda en mi estación de trabajo.

Pero entiendo que eso no es recomendable y es ideal para contenedores de producción. Entonces, usé EmptyDir como se sugirió anteriormente. Pero, de nuevo, si hago eso, realmente no puedo capturarlo porque se elimina con el pod.

Entonces, ¿debería resolver mi problema usando también el patrón de contenedor sidecar?

Básicamente, haga lo que sugirió anteriormente. Inicie 2 contenedores en la cápsula cada vez que comience el trabajo. 1 contenedor ejecuta el trabajo y, tan pronto como se realiza el trabajo, arroja un mensaje que es recogido por el otro contenedor, que luego toma el archivo de resultados y lo almacena en algún lugar.

No entiendo por qué necesitaríamos 2 contenedores en primer lugar. ¿Por qué el contenedor de trabajos no puede hacer todo esto por sí solo? Es decir, termine el trabajo, guarde el archivo de resultados en algún lugar, acceda a él / léalo y guárdelo en algún lugar.

@anshumanbh Te sugiero:

  1. usa un almacenamiento persistente, guarda el archivo de resultados
  2. usa hostPath mount, que es casi lo mismo que 1, y ya lo has probado
  3. cargue el archivo de resultados en una ubicación remota conocida (s3, google drive, dropbox), generalmente cualquier tipo de unidad compartida

@soltysh No quiero que el archivo se almacene de forma permanente. En cada ejecución, solo quiero comparar ese resultado con el último resultado. Entonces, la forma en que estaba pensando en hacer esto era comprometerme con un repositorio de github en cada ejecución y luego hacer una diferencia para ver qué cambió. Entonces, para hacer eso, solo necesito almacenar el resultado temporalmente en algún lugar para poder acceder a él y enviarlo a Github. ¿Tener sentido?

@anshumanbh perfectamente claro, y aún así, eso no entra en la categoría de contenedor de

@soltysh, así que considerando que quiero

El problema al que me enfrento es que tan pronto como termina el trabajo, el contenedor sale y pierdo el archivo. Si no tengo el archivo, ¿cómo lo cargo en una unidad compartida como S3 / Google Drive / Dropbox? No puedo modificar el código del trabajo para cargarlo automáticamente en algún lugar antes de que se cierre, por lo que, desafortunadamente, primero tendría que ejecutar el trabajo y luego guardar el archivo en algún lugar ...

Si no puede modificar el código del trabajo, debe ajustarlo de tal manera que pueda cargar el archivo. Si con lo que está trabajando es una imagen, simplemente extiéndala con el código de copia.

@soltysh sí, eso tiene sentido. Yo podría hacer eso. Sin embargo, la siguiente pregunta que tengo es: suponga que necesito ejecutar varios trabajos (piense en ello como ejecutar diferentes herramientas) y ninguna de estas herramientas tiene la parte de carga incorporada. Entonces, ahora, tendría que construir ese contenedor y extender cada una de esas herramientas con la parte de carga. ¿Hay alguna forma de que pueda escribir el contenedor / extensión una vez y usarlo para todas las herramientas?

¿No encajaría el patrón del sidecar en ese caso?

Sí, podría. Aunque probaría con varios contenedores dentro del mismo pod, pattern. Iow. su pod está ejecutando el contenedor de trabajos y, junto con uno adicional, está esperando la salida y cargándola. No estoy seguro de cuán factible es esto, pero ya puede intentarlo.

El conocimiento suave de ping-sidecar haría que la administración de proxies de microservicio como Envoy sea mucho más agradable. ¿Hay algún progreso que compartir?

El estado actual de las cosas es que cada contenedor necesita herramientas agrupadas para coordinar la vida útil, lo que significa que no podemos usar directamente imágenes de contenedores ascendentes. También complica significativamente las plantillas, ya que tenemos que inyectar argv y puntos de montaje adicionales.

Una sugerencia anterior fue designar algunos contenedores como contenedores de "terminación". Me gustaría proponer lo contrario: la capacidad de designar algunos contenedores como "sidecars". Cuando finaliza el último contenedor que no es sidecar en un Pod, el Pod debe enviar TERM a los sidecars. Esto sería análogo al concepto de "subproceso en segundo plano" que se encuentra en muchas bibliotecas de subprocesos, por ejemplo, Thread.daemon Python.

Ejemplo de configuración, cuando el contenedor main termina, el kubelet mataría envoy :

containers:
  - name: main
    image: gcr.io/some/image:latest
    command: ["/my-batch-job/bin/main", "--config=/config/my-job-config.yaml"]
  - name: envoy
    image: lyft/envoy:latest
    sidecar: true
    command: ["/usr/local/bin/envoy", "--config-path=/my-batch-job/etc/envoy.json"]

Como referencia, aquí está la locura de bash que estoy usando para simular el comportamiento de sidecar deseado:

containers:
  - name: main
    image: gcr.io/some/image:latest
    command: ["/bin/bash", "-c"]
    args:
      - |
        trap "touch /tmp/pod/main-terminated" EXIT
        /my-batch-job/bin/main --config=/config/my-job-config.yaml
    volumeMounts:
      - mountPath: /tmp/pod
        name: tmp-pod
  - name: envoy
    image: gcr.io/our-envoy-plus-bash-image:latest
    command: ["/bin/bash", "-c"]
    args:
      - |
        /usr/local/bin/envoy --config-path=/my-batch-job/etc/envoy.json &
        CHILD_PID=$!
        (while true; do if [[ -f "/tmp/pod/main-terminated" ]]; then kill $CHILD_PID; fi; sleep 1; done) &
        wait $CHILD_PID
        if [[ -f "/tmp/pod/main-terminated" ]]; then exit 0; fi
    volumeMounts:
      - mountPath: /tmp/pod
        name: tmp-pod
        readOnly: true
volumes:
  - name: tmp-pod
    emptyDir: {}

Me gustaría proponer lo contrario: la capacidad de designar algunos contenedores como "sidecars". Cuando finaliza el último contenedor que no es sidecar en un Pod, el Pod debe enviar TERM a los sidecar.

@ jmillikin-stripe Me gusta esta idea, aunque no estoy seguro de si sigue el principio de tratar algunos contenedores de manera diferente en un Pod o introducir dependencias entre ellos. Aferraré a

Aunque, ¿ha marcado # 17244, este tipo de solución se ajusta a su caso de uso? Esto es lo que @erictune mencionó algunos comentarios antes:

Otra opción es designar ciertos códigos de salida con un significado especial.

@ jmillikin-stripe Me gusta esta idea, aunque no estoy seguro de si sigue el principio de tratar algunos contenedores de manera diferente en un Pod o introducir dependencias entre ellos. Aferraré a

Creo que Kubernetes puede necesitar ser flexible sobre el principio de no tratar los contenedores de manera diferente. Nosotros (Stripe) no queremos actualizar el código de terceros como Envoy para tener ganchos de ciclo de vida al estilo de Lamprey, y tratar de adoptar una inversión ejecutiva de estilo Envelope sería mucho más complejo que dejar que Kubelet termine sidecars específicos.

Aunque, ¿ha marcado # 17244, este tipo de solución se ajusta a su caso de uso? Esto es lo que @erictune mencionó algunos comentarios antes:

Otra opción es designar ciertos códigos de salida con un significado especial.

Me opongo firmemente a que Kubernetes o Kubelet interpreten los códigos de error con una granularidad más fina que "cero o distinto de cero". El uso de Borglet de los números mágicos del código de salida fue un error desagradable, y sería mucho peor en Kubernetes, donde una imagen de contenedor en particular podría ser un "principal" o un "sidecar" en diferentes Pods.

¿Quizás los ganchos adicionales del ciclo de vida serían suficientes para resolver esto?

Podría ser:

  • PostStop: con un medio para desencadenar eventos del ciclo de vida en otros contenedores en el pod (es decir, desencadenar parada)
  • PeerStopped: señal de que un contenedor "peer" en el pod ha muerto, posiblemente con el código de salida como argumento

Esto también podría definir un medio para definir políticas personalizadas para reiniciar un contenedor, o incluso iniciar contenedores que no se inician de forma predeterminada para permitir la conexión en cadena de contenedores (cuando el contenedor a finaliza, inicie el contenedor b)

También falta esto. Ejecutamos un trabajo cada 30 minutos que necesita un cliente VPN para la conectividad, pero parece haber muchos casos de uso en los que esto podría ser muy útil (por ejemplo, cosas que necesitan un proxy kubectl). Actualmente, estoy usando jobSpec.concurrencyPolicy: Replace como solución pero, por supuesto, esto solo funciona si a.) Puede vivir sin ejecuciones de trabajos en paralelo y b.) El tiempo de ejecución del trabajo es más corto que el intervalo de programación.

EDITAR: en mi caso de uso, sería completamente suficiente tener alguna propiedad en la especificación del trabajo para marcar un contenedor como el que termina y hacer que el trabajo controle el estado de salida y elimine los restantes.

Yo también necesito esto. En nuestro caso, es un trabajo que utiliza el contenedor de proxy cloudsql como un servicio adicional.

¿Qué hay de la posibilidad de agregar una anotación que se asigne al nombre del contenedor "principal" en el pod? De esa manera, la especificación de la cápsula no necesita modificarse de ninguna manera.

Por la naturaleza de cómo están diseñados los Pods, esto parece un caso de uso muy común. @soltysh @erictune ¿ algún plan para trabajar en esto pronto? Me alegro de ayudar donde sea posible :)

También necesita esta característica. Para nuestro caso de uso :
la vaina A tiene contenedores

  • contenedor A1 : un
  • contenedor A2 : contenedor de sidecar, que solo registra los registros del archivo a la salida estándar

Lo que quiero : cuando el contenedor A1 se complete con éxito, la vaina A se complete con éxito. ¿Podemos simplemente etiquetar el contenedor A1 como contenedor principal , cuando el contenedor principal sale, cuando sale la cápsula? @erictune (Esta idea también es descrita por @mingfang )

Hola chicos, veo que este problema ha estado abierto durante un mes. ¿Qué es lo último en esto? Tenemos un caso de uso, donde queremos ejecutar un trabajo. El trabajo ejecuta un contenedor main con algunos sidecar containers . Queremos que el trabajo salga cuando salga el contenedor main . ¿Es el estado del arte compartir un file para enviar un signal entre los contenedores?

No me importaría comenzar a trabajar en esto, me gustaría saber si alguien podría revisar los próximos RP si lo hago (tal vez después de kubecon).

cc @erictune @ a-robinson @soltysh

@andrewsykim, ¿qué enfoque tomaría? Además, sé que lo estoy agregando aquí, ¿qué se necesitaría para agregar soporte para dependencias? Como el contenedor main no debería comenzar hasta que los sidecars se hayan inicializado

Como el contenedor principal no debería comenzar hasta que los sidecars se hayan inicializado

Creo que este caso no es un problema ya que main debería poder verificar cuándo se inicializa el sidecar (o usar una sonda de preparación). Este no es el caso de este problema porque main habría salido :)

Terminé escribiendo un script simple que observa la API de kubernetes y termina los trabajos con una anotación coincidente y cuyo contenedor principal ha salido. No es perfecto, pero responde a una necesidad fundamental. Puedo compartirlo si la gente está interesada.

@ajbouh Personalmente agradecería que compartieras eso como una esencia. Estaba a punto de escribir algo similar

@nrmitchi Aquí está la esencia del yaml que escribí. Es muy scripty, pero quizás sea un buen punto de partida para usted, en términos de qué API usar y cómo obtener algo que funcione. Puedo responder preguntas sobre lo que está haciendo si tiene alguna pregunta.

https://gist.github.com/ajbouh/79b3eb4833aa7b068de640c19060d126

Tengo el mismo caso de uso de proxy de Cloud SQL que @mrbobbytables. Para conectarse de forma segura a la nube SQL, se recomienda usar el proxy, pero ese proxy no termina cuando se realiza el trabajo, lo que da como resultado hacks locos o monitoreo que se parece a lo siguiente. ¿Hay algún camino a seguir en esto?

image

@ amaxwell01 Con respecto a la participación de Cloud SQL Proxy en esto, había abierto un problema con Google que podría destacar o ver actualizaciones: https://issuetracker.google.com/issues/70746902 (editar: y lamento algunas frases que usé allí en el calor del momento; lamentablemente no puedo editarlo)

Gracias @abevoelker . Estoy siguiendo tu publicación allí. Además tus comentarios me hicieron reír 👍

También nos afecta este problema.
Tenemos varios comandos de administración de django en nuestros microservicios que pueden ejecutarse en cronjobs k8s pero no tienen éxito debido al sidecar cloudsqlproxy que no se detiene al completar el trabajo.
¿Alguna actualización sobre cuándo podríamos tener una solución?
El patrón de contenedor sidecar se usa cada vez más y muchos de nosotros no podremos usar trabajos y cronjobs de k8s hasta que esto se resuelva.

Solo quería agregar mi +1 para esto. Tengo el mismo problema de GCE Cloud SQL Proxy que todos los demás. Me está matando ... el despliegue del timón falla, lo que a su vez falla en la aplicación de terraform.

Realmente me gustaría ver algún tipo de resolución sobre esto ... solo de @ajbouh parece que podría funcionar ... pero cielos, eso es hacky.

Para cualquier otra persona que requiera cloudsql-proxy , ¿encajaría en su caso de uso ejecutar cloudsql-proxy como un DaemonSet? En mi caso, tenía una implementación persistente y un CronJob que requería el proxy, por lo que tenía sentido separarlo de los pods individuales y, en su lugar, adjuntar una instancia por nodo.

Sí,

Hemos decidido eliminar los sidecars proxy de cloudsql y hemos creado un grupo de
proxies de cloudsql en su espacio de nombres central, funciona perfectamente y permite
mover la escalabilidad y simplificar las implementaciones.
Ahora podemos ejecutar trabajos y cronjobs sin ningún problema.

El miércoles 7 de febrero de 2018 a las 9:37 a.m., Rob Jackson [email protected]
escribió:

Para cualquier otra persona que requiera el proxy cloudsql, ¿se ajustaría a su caso de uso para
ejecutar el proxy de cloudsql como un DaemonSet? En mi caso tuve un persistente
Implementación y un CronJob que requiere el proxy, por lo que tenía sentido desconectar
de pods individuales y, en su lugar, adjunte una instancia por nodo.

-
Estás recibiendo esto porque comentaste.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/kubernetes/kubernetes/issues/25908#issuecomment-363710890 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/ACAWMwetx6gA_SrHL_RRbTMJVOhW1FKLks5tSW7JgaJpZM4IiqQH
.

Interesante, usar un deamonset parece una buena opción. @ RJacksonm1 & @devlounge : ¿cómo funciona el descubrimiento del proxy SQL en la nube cuando se utilizan conjuntos de demonios?

Encontré esto que parece que funcionará ...
https://buoyant.io/2016/10/14/a-service-mesh-for-kubernetes-part-ii-pods-are-great-until-theyre-not/

Básicamente implica usar algo como esto para obtener la IP del host:

env:
- name: NODE_NAME
  valueFrom:
    fieldRef:
      fieldPath: spec.nodeName

@ RJacksonm1 - ¿ hostPort funcionara? Constantemente obtengo connection refused cuando lo uso junto con el enfoque fieldPath: spec.nodeName 🤔

Editar: Me he asegurado de que spec.nodeName esté comunicando correctamente y estoy en GKE v1.9.2-gke.1

@cvallance Tengo un servicio configurado para exponer el DaemonSet, al que mi aplicación puede acceder a través de DNS. Esto no garantiza que la aplicación se comunicará con la instancia cloudsql-proxy ejecuta en el mismo host que él mismo, pero sí garantiza que cloudsql-proxy escalará con el clúster como un todo (originalmente tenía el proxy como Implementación y HorizontalPodAutoscaler, pero encontró que aumentaba / reducía demasiado, lo que causaba errores MySQL has gone away en la aplicación). Supongo que esto no está en el verdadero espíritu de un DaemonSet ... 🤔

@ RJacksonm1 : lo hizo funcionar con hostPort y spec.nodeName ... ahora se conectarán directamente al DaemonSet en su nodo 😄

El comando de proxy de CloudSql no funciona:
-instances={{ .Values.sqlConnectionName }}=tcp:{{ .Values.internalPort }}
Laboral:
-instances={{ .Values.sqlConnectionName }}=tcp:0.0.0.0:{{ .Values.internalPort }}

🤦‍♂️

¿Hay algo que podamos hacer para impulsar este tema?
Ha estado abierto durante casi 2 años y todavía solo tenemos soluciones

Sospecho que incluso si me ofrezco como voluntario para implementar esto, no podré hacerlo, ya que necesita la aprobación de los chicos internos con respecto a qué solución implementar, cambios de API, etc.

¿Hay algo que pueda hacer para ayudar a hacer esto?

Como referencia, hice una versión de sidecar en la nube-sql-proxy de la solución alternativa de @ jmillikin-stripe donde un archivo en un volumen compartido comunica el estado al sidecar.

Funciona bien, pero es, con mucho, el truco más desagradable en mi configuración de K8s :(

apiVersion: batch/v1
kind: Job
metadata:
  name: example-job
spec:
  template:
    spec:
      containers:
      - name: example-job
        image: eu.gcr.io/example/example-job:latest
        command: ["/bin/sh", "-c"]
        args:
          - |
            trap "touch /tmp/pod/main-terminated" EXIT
            run-job.sh
        volumeMounts:
          - mountPath: /tmp/pod
            name: tmp-pod
      - name: cloudsql-proxy
        image: gcr.io/cloudsql-docker/gce-proxy:1.11
        command: ["/bin/sh", "-c"]
        args:
          - |
            /cloud_sql_proxy --dir=/cloudsql -instances=example:europe-west3:example=tcp:3306 -credential_file=/secrets/cloudsql/credentials.json &
            CHILD_PID=$!
            (while true; do if [[ -f "/tmp/pod/main-terminated" ]]; then kill $CHILD_PID; echo "Killed $CHILD_PID as the main container terminated."; fi; sleep 1; done) &
            wait $CHILD_PID
            if [[ -f "/tmp/pod/main-terminated" ]]; then exit 0; echo "Job completed. Exiting..."; fi
        volumeMounts:
          - name: cloudsql-instance-credentials
            mountPath: /secrets/cloudsql
            readOnly: true
          - name: cloudsql
            mountPath: /cloudsql
          - mountPath: /tmp/pod
            name: tmp-pod
            readOnly: true
      restartPolicy: Never
      volumes:
        - name: cloudsql-instance-credentials
          secret:
            secretName: cloudsql-instance-credentials
        - name: cloudsql
          emptyDir:
        - name: tmp-pod
          emptyDir: {}
  backoffLimit: 1

¿Alguien interno del proyecto puede comentar sobre el progreso de este problema?

El mismo problema aquí

cc @ kubernetes / sig-apps-feature-orders @ kubernetes / sig-node-feature-orders

¿Tendría sentido permitir que los usuarios especifiquen (por nombre) los contenedores en un trabajo que desean ver completos con éxito para marcar el pod de trabajos como terminado (con otros contenedores detenidos), así:

apiVersion: batch/v2beta1
kind: Job
metadata:
  name: my-job
  namespace: app
spec:
  template:
    spec:
      containers:
        - name: my-container
          image: my-job-image
          ...
        - name: cloudsql-proxy
          image: gcr.io/cloudsql-docker/gce-proxy:1.11
          ...
  backoffLimit: 2
  jobCompletedWith:
    - my-container

Es decir, el pod se ejecutará, espere hasta que my-container salga correctamente y luego simplemente termine cloudsql-proxy .

EDITAR: Desplazándome hacia arriba en este hilo, ahora veo que esto se ha propuesto anteriormente. ¿Puede @erictune o alguien más volver a elaborar sobre por qué esto no funcionaría?

sí, creo que sería perfecto. Solo algo que le permite ver el estado del trabajo y continuar la canalización una vez que se haya completado

Sí, sería perfecto.

Me gusta esta idea @jpalomaki

Una preocupación que tengo con el enfoque de resolver esto puramente dentro del controlador de trabajo es que el Pod continuará ejecutándose después de que finalice el trabajo. Actualmente, el Pod entra en la fase Terminado y el Nodo puede liberar esos recursos.

Puede hacer que el controlador de trabajo elimine el Pod cuando el controlador decida que está hecho, pero eso también sería diferente del comportamiento actual, donde el registro del Pod terminado permanece en el servidor API (sin consumir recursos del nodo).

Por estas razones, me parece más limpio abordar esto en el nivel de la API de Pod, si es que lo hace. El nodo es lo único que debería estar metiendo la mano y matando contenedores individuales porque los contenedores de "finalización" que le interesan ya terminaron. Esto podría tomar la forma de una API de nivel de pod que le permite especificar la noción de qué contenedores debe esperar, o una API de nivel de pod para permitir que los agentes externos (p. Ej., El controlador de trabajos) obliguen al pod a finalizar sin eliminar realmente la vaina.

También estoy buscando una solución para cargar archivos producidos por un contenedor si el contenedor del procesador salió correctamente.

No estoy seguro de entender el argumento de @mingfang en contra de que el contenedor sidecar observe el estado del contenedor a través de la API k8s para saber si y cuándo comenzar a cargar o salir. Cuando el contenedor del sidecar sale de la vaina y el trabajo debe salir correctamente.

Otro pensamiento, que parece un truco, pero me gustaría saber qué tan malo sería convertir el contenedor de producción de datos en un contenedor de inicio, y tener el contenedor de carga de datos (que ya no necesitaría ser un contenedor de sidecar ) se inicia automáticamente solo después de que el contenedor del procesador se haya cerrado correctamente. En mi caso, también necesitaría un contenedor de descarga de datos como primer contenedor de inicio, para proporcionar datos al contenedor de procesamiento. Si esta es una idea particularmente mala, me encantaría saber por qué.

¿No resolvería este problema promocionar el sidecar a un concepto de k8 de primera clase? Kubelet podrá terminar el pod si todos los contenedores en ejecución están marcados como sidecar.

FWIW, solucioné esto simplemente implementando el proxy de Cloud SQL como una implementación regular ( replicas: 1 ) e hice que mi Job y CronJob usaran a través de un type: ClusterIP Servicio. Los trabajos se completan bien ahora.

Me encantaría tener un puesto oficial sobre esto.

Si no vamos a tener algún soporte de la API, al menos deberíamos tener las soluciones alternativas documentadas oficialmente para que la gente sepa qué hacer cuando se encuentre con este problema.

No estoy seguro de a quién hacer ping o cómo llamar la atención sobre esto ...

Sería muy bueno que se solucionara este problema. Además de que el trabajo nunca desaparece, el estado general del pod es aparentemente incorrecto:

Init Containers:
  initializer:
    State:          Terminated
      Reason:       Completed
      Exit Code:    0
      Started:      Wed, 21 Mar 2018 17:52:57 -0500
      Finished:     Wed, 21 Mar 2018 17:52:57 -0500
    Ready:          True
Containers:
  sideCar:
    State:          Running
      Started:      Wed, 21 Mar 2018 17:53:40 -0500
    Ready:          True
  mainContainer:
    State:          Terminated
      Reason:       Completed
      Exit Code:    0
      Started:      Wed, 21 Mar 2018 17:53:41 -0500
      Finished:     Wed, 21 Mar 2018 17:55:12 -0500
    Ready:          False
Conditions:
  Type           Status
  Initialized    True 
  Ready          False 
  PodScheduled   True 

Lo que es interesante es tener en cuenta el Estado y Listo para initContainer (Terminado, Completado, Listo = Verdadero) y el contenedor de la aplicación principal (Terminado, Completado, Listo = Falso). Eso parece estar impulsando el estado de Falso sobre Pod Ready, en mi opinión, incorrectamente. Esto está provocando que este Pod se marque como un problema en nuestros paneles.

Tengo otro cliente que se encuentra con este problema específicamente con el proxy de Cloud SQL. Les gustaría no tener que ejecutarlo como un servicio persistente para permitir que los trabajos cron accedan a Cloud SQL.

@yuriatgoogle La solución más fácil sigue siendo bash y emptyDir "magic" como: https://github.com/kubernetes/kubernetes/issues/25908#issuecomment -365924958

Es un truco, pero tendrá que funcionar. Sin ofender a @phidah.

Definitivamente parece que mucha gente quiere esto por una variedad de razones. Sería bueno contar con algún apoyo oficial. Tuve el mismo problema con nuestro propio sidecar y trabajos, así que hice que el sidecar usara la api de kube para ver el estado del otro contenedor en el pod, si terminaba con un completed el sidecar saldría 0, si cometió un error, el sidecar saldría 1. Quizás no sea la solución más elegante, pero funcionó sin necesidad de que nuestros desarrolladores cambiaran mucho. el código está aquí si alguien está interesado: https://github.com/uswitch/vault-creds/blob/master/cmd/main.go#L132.

Esto me recuerda a una canción de Gorillaz M1 A1 ...

¿Hola? Hellooooooo? ¿Hay alguien ahí?

Sí, consigamos algo de tracción +1

Entonces, las soluciones propuestas que requieren cambios ascendentes son:

  1. sidecar: true por @ jmillikin-stripe
  2. Ganchos de ciclo de vida adicionales de @msperl
  3. jobCompletedWith por @jpalomaki

Solución temporal para sidecar, una hacky (pero funciona):

  1. Por cloudsql-proxy sidecar de @phidah

Me encantaría ver la respuesta del mantenedor de Kubernetes con respecto a las soluciones propuestas y, por favor, dénos recomendaciones sobre cómo resolver este caso de uso utilizando la versión existente de Kubernetes. ¡Gracias!

Acabo de descubrir este hilo después de pasar un día tratando de escribir un agente de registro que cargaría el stdout / stderr de mi tarea de renderizado en una base de datos, solo para descubrir que la presencia del agente en el pod significaría que el trabajo nunca terminaría.

De las sugerencias dadas anteriormente, me gusta el 'sidecar: verdadero' el mejor, ya que es simple y al grano, muy comprensible para un desarrollador como yo. Probablemente lo llamaría algo ligeramente diferente, ya que 'sidecar' es realmente un patrón de diseño de pod que se aplica a más que solo trabajos e implica otras cosas además de los requisitos de finalización. Si me disculpa, probablemente lo llamaría algo como 'ambient: true' para indicar que el trabajo se puede considerar completado incluso si esta tarea todavía se está ejecutando. Otras palabras pueden ser "auxiliar" o "apoyo".

También me encontré con este problema, para el mismo flujo de trabajo que muchos otros han descrito (un contenedor de sidecar que se usa para hacer conexiones proxy o recopilar métricas, y no tiene ningún propósito después de que el otro contenedor en el pod sale con éxito).

Una sugerencia anterior fue designar algunos contenedores como contenedores de "terminación". Me gustaría proponer lo contrario: la capacidad de designar algunos contenedores como "sidecars". Cuando finaliza el último contenedor que no es sidecar en un Pod, el Pod debe enviar TERM a los sidecar.

Esta es también mi solución ideal. Podría sugerir SIGHUP en lugar de SIGTERM; ¡este parece ser el caso de uso exacto para el que la semántica de SIGHUP es relevante! - pero estaría feliz con cualquiera de los dos.

Tal como está, la ejecución de trabajos en Kubernetes requiere parchear manualmente las imágenes de contenedores ascendentes para manejar la comunicación entre contenedores específica de Kubernetes cuando finaliza el contenedor sin sidecar, o intervenir manualmente para terminar el sidecar de cada trabajo para que el pod zombie no lo haga. andar. Ninguno es particularmente agradable.

Estaría dispuesto a hacer un parche para esto, pero me gustaría recibir alguna orientación de @ kubernetes / sig-apps-feature-request antes de profundizar en cualquier código. ¿Estamos de acuerdo con agregar un campo sidecar a la especificación del pod para que esto funcione? Dudo en realizar cambios en las especificaciones de la cápsula sin estar seguro de que lo queremos. ¿Quizás usar anotaciones por ahora?

@andrewsykim He estado siguiendo este problema por un tiempo (simplemente no he intentado abordarlo yo mismo), pero sugeriría que solo use anotaciones por ahora.

Mi razonamiento es que:

  • Este problema ha existido durante casi 2 años y realmente no ha atraído mucha atención del núcleo de Kubernetes. Por lo tanto, si esperamos para realizar cambios en la especificación del pod, o esperamos una entrada directa, probablemente estaremos esperando mucho tiempo.
  • Es mucho más fácil llamar la atención sobre un PR viable que sobre un problema antiguo.
  • Debería ser bonito cambiar un enfoque de anotación para usar un atributo de pod en el futuro

¿Pensamientos?

Hola, hablé con algunos de los chicos de sig-apps en kubecon sobre este problema, básicamente no es algo que esté en su hoja de ruta inmediata, pero es algo que creen que es un caso de uso válido. Están muy abiertos a que alguien de la comunidad aborde esto.

Creé un PR para una propuesta de mejora para resolver esto, así que espero que esto genere alguna discusión https://github.com/kubernetes/community/pull/2148.

¡Gracias por armar eso @ Joseph-Irving! Parece que hay más detalles que deben abordarse para esto, así que me detendré en hacer cualquier trabajo hasta entonces :)

problema-persistente-a-largo-plazo :(

cc @ kow3ns @janetkuo

Sin querer complicar más el asunto, también sería útil poder ejecutar un contenedor de estilo "sidecar" junto con initContainers .

Mi caso de uso es similar al de las personas aquí, necesito ejecutar el proxy SQL en la nube al mismo tiempo que un initContainer que ejecuta migraciones de bases de datos. Como los initContainers se ejecutan uno a la vez, no veo una forma de hacerlo, excepto para ejecutar el proxy como un servicio de implementación +, pero espero que haya otros casos de uso (administración de registros, etc.) en los que eso no sería un trabajo adecuado alrededor.

@mcfedr Hay una propuesta de mejora razonablemente activa que podría apreciar esa observación con respecto al comportamiento del contenedor de inicio. No me queda claro si eso está dentro del alcance de esta propuesta o una mejora relacionada, pero creo que está lo suficientemente relacionado como para que tenga sentido plantearlo para su consideración.

A pesar de los posibles problemas de implementación / compatibilidad, su modelo ideal presumiblemente sería que los contenedores de inicio de sidecar se ejecutaran simultáneamente con contenedores de inicio de no sidecar, que continúan ejecutándose secuencialmente como ahora, y que los sidecars terminen antes de que se inicien los contenedores de secuencia principal.

por lo que vale, también me gustaría expresar la necesidad de ignorar los sidecars que aún se ejecutan como CloudSQL Proxy et.al.

Me las arreglé para matar el contenedor de cloudsql después de 30 segundos, ya que sé que mi script no tomaría tanto tiempo. Aquí está mi enfoque:

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: schedule
spec:
  concurrencyPolicy: Forbid
  schedule: "*/10 * * * *"
  startingDeadlineSeconds: 40
  jobTemplate:
    spec:
      completions: 1
      template:
        spec:
          containers:
          - image: someimage
            name: imagename
            args:
            - php
            - /var/www/html/artisan
            - schedule:run
          - command: ["sh", "-c"]
            args:
            - /cloud_sql_proxy -instances=cloudsql_instance=tcp:3306 -credential_file=some_secret_file.json & pid=$! && (sleep 30 && kill -9 $pid 2>/dev/null)
            image: gcr.io/cloudsql-docker/gce-proxy:1.11
            imagePullPolicy: IfNotPresent
            name: cloudsql
            resources: {}
            volumeMounts:
            - mountPath: /secrets/cloudsql
              name: secretname
              readOnly: true
          restartPolicy: OnFailure
          volumes:
          - name: secretname
            secret:
              defaultMode: 420
              secretName: secretname

Y me está funcionando.
¿Ven algún inconveniente en este enfoque?

Como creo que también están relacionados y son fácilmente adaptables para CronJobs, esta es mi solución: https://github.com/GoogleCloudPlatform/cloudsql-proxy/issues/128#issuecomment -413444029

Se basa en una de las soluciones alternativas publicadas aquí, pero usa preStop porque está destinado a implementaciones. Atrapar el sidecar funcionaría de maravilla.

Siguiendo este problema. También se usa el contenedor cloud_sql_proxy como sidecar en cronjob
Usé la implementación de tiempo de espera de @stiko

Simplemente agregar a la conversación la solución propuesta por @ oxygen0211 sobre el uso de Reemplazar es una solución decente por ahora, asegúrese de verificarlo si se encuentra con este problema como lo hice yo.

https://github.com/kubernetes/kubernetes/issues/25908#issuecomment -327396198

Tenemos este KEP aprobado provisionalmente https://github.com/kubernetes/community/pull/2148 , todavía tenemos algunas cosas en las que debemos estar de acuerdo, pero esperamos que llegue a un lugar donde el trabajo pueda comenzar relativamente pronto . Tenga en cuenta que los KEP se trasladarán a https://github.com/kubernetes/enhancements el día 30, por lo que si desea seguirlo, estará allí.

Hasta que llegue el soporte de sidecar, puede usar una solución de nivel de ventana acoplable que se puede eliminar fácilmente más adelante: https://gist.github.com/janosroden/78725e3f846763aa3a660a6b2116c7da

Utiliza un contenedor privilegiado con un conector acoplable montado y etiquetas de kubernetes estándar para administrar contenedores en el trabajo.

Estábamos teniendo el mismo problema con Istio y su sidecar, y lo que decidimos hacer es eliminar el pod a través de curl + preStop hook como este.

dale a tu trabajo una regla mínima de RBAC como esta

apiVersion: v1
kind: ServiceAccount
metadata:
  name: myservice-job
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: myservice-role
rules:
  - apiGroups: [""]
    resources: ["pods"]
    verbs: ["delete"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: myservice-job-rolebinding
subjects:
  - kind: ServiceAccount
    name: myservice-job
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: myservice-role

y POD_NAME y POD_NAMESPACE a su ENV así

   env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace

y finalmente, agregue un gancho preStop como

 lifecycle:
      preStop:
        exec:
          command: 
            - "/bin/bash" 
            - "-c"
            - "curl -X DELETE -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt https://$KUBERNETES_SERVICE_HOST/api/v1/namespaces/$POD_NAMESPACE/pods/$POD_NAME?gracePeriodSeconds=1"

Un poco desordenado pero un poco más seguro y menos delicado que intentar matar el contenedor de la ventana acoplable correcto.

Solo lancé esto aquí, pero preparé un controlador hace un tiempo que estaba destinado a monitorear los cambios de pod en ejecución y enviar un SIGTERM a los contenedores de sidecar de manera adecuada. Definitivamente no es el más robusto y, sinceramente, no lo he usado en un tiempo, pero puede ser de ayuda.

https://github.com/nrmitchi/k8s-controller-sidecars

Gracias a @jpalomaki en https://github.com/kubernetes/kubernetes/issues/25908#issuecomment -371469801 por la sugerencia de ejecutar cloud_sql_proxy como una implementación con ClusterIP servicio, y a @ cvallance en https://github.com/kubernetes/kubernetes/issues/25908#issuecomment -364255363 para el consejo sobre la configuración de tcp:0.0.0.0 en el parámetro cloud_sql_proxy instances para permitir que no -conexiones locales al proceso. Juntos, hicieron que sea sencillo permitir que los trabajos cron usen el proxy.

problema a largo plazo (nota para mí mismo)

Mismo problema. Buscando una forma o documentos oficiales sobre cómo usar GKE trabajo cron con Cloud SQL

Nota al margen:
Google actualizó su Cloud SQL -> Conectando desde la documentación Connecting using the Cloud SQL Proxy Docker image puedes Connecting using a private IP address
Entonces, si está aquí por la misma razón por la que yo estoy aquí (debido a cloud_sql_proxy), puede usar ahora la nueva función de IP privada

Nota al margen:
Google actualizó su Cloud SQL -> Conectando desde la documentación Connecting using the Cloud SQL Proxy Docker image puedes Connecting using a private IP address
Entonces, si está aquí por la misma razón por la que yo estoy aquí (debido a cloud_sql_proxy), puede usar ahora la nueva función de IP privada

¿La función de IP privada parece necesaria para eliminar todo el clúster y volver a crear uno ...?

@cropse Eso solo es necesario si su clúster no es nativo de VPC.

Hice una solución para este problema, no es la gran solución, pero funcionó, espero que esto ayude antes de que se agregue la función, y VPC es una forma de solucionarlo, pero eliminar todo el clúster sigue siendo doloroso.

Solo para agregar mis dos centavos: las pruebas de timón también se rompen si se produce la inyección de istio sidecar ya que la cápsula nunca se completa.

@dansiviter puede verificar mi solución alternativa, ya probé en mi proyecto con helm.

¡Espero ver esto implementado! :)

tenemos el mismo problema con los trabajos normales cuando se le inyecta un proxy de Istio, por encima de eso también queremos esto porque queremos ejecutar trabajos de CI con Prow.
por ejemplo, contenedor de la aplicación Rails + contenedor de la base de datos del sidecar para realizar pruebas.

@cropse Gracias. No lo he probado ya que tendríamos que configurarlo para todas las pruebas. Solo permitimos que el Pod (las pruebas de timón no permiten el trabajo, desafortunadamente) falle y confiamos en inspeccionar manualmente el registro hasta que este problema se solucione a largo plazo. Sin embargo, también se está convirtiendo en un problema para otros trabajos, por lo que es posible que tengamos que reconsiderar esa posición.

Para su información, el problema de seguimiento de esta función está aquí https://github.com/kubernetes/enhancements/issues/753 si la gente quiere seguir adelante, tenemos un KEP, hicimos algunos prototipos (hay una rama / video de POC ), todavía es necesario aclarar algunos de los detalles de implementación antes de que esté en un estado implementable.

Nota al margen:
Google actualizó su Cloud SQL -> Conectando desde la documentación Connecting using the Cloud SQL Proxy Docker image puedes Connecting using a private IP address
Entonces, si está aquí por la misma razón por la que yo estoy aquí (debido a cloud_sql_proxy), puede usar ahora la nueva función de IP privada

Estuve aquí por la misma razón, sin embargo, nuestro Cloud SQL se aprovisionó antes de que esta función estuviera lista. Combiné sugerencias anteriores y obtuve esto (probablemente no sea ideal, pero funciona) para mi gráfico de timón de dbmate migrator.

      containers:
      - name: migrator
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
        imagePullPolicy: {{ .Values.image.pullPolicy }}
        command: ["/bin/bash", "-c"]
        args:
          - |
            /cloud_sql_proxy -instances={{ .Values.gcp.project }}:{{ .Values.gcp.region }}:{{ .Values.gcp.cloudsql_database }}=tcp:5432 -credential_file=/secrets/cloudsql/credentials.json &
            ensure_proxy_is_up.sh dbmate up
        env:
        - name: DATABASE_URL
          valueFrom:
            secretKeyRef:
              name: mysecret
              key: DATABASE_URL
        volumeMounts:
          - name: cloudsql-instance-credentials
            mountPath: /secrets/cloudsql
            readOnly: true
      volumes:
        - name: cloudsql-instance-credentials
          secret:
            secretName: cloudsql-instance-credentials

ensure_proxy_is_up.sh

#!/bin/bash

until pg_isready -d $(echo $DATABASE_URL); do
    sleep 1
done

# run the command that was passed in
exec "$@"

¿Sería un buen momento para una noción de contenedores sidecar en Kubernetes y permitir la limpieza de vainas en función de si los contenedores que no son sidecar han terminado?

@Willux Estoy en el

@krancour gracias por la actualización. Debo haberme perdido ese detalle. No hubo mucha actividad aquí últimamente, así que solo quería asegurarme de que haya algo en curso :)

Como referencia, hice una versión de sidecar en la nube-sql-proxy de la solución alternativa de @ jmillikin-stripe donde un archivo en un volumen compartido comunica el estado al sidecar.

Funciona bien, pero es, con mucho, el truco más desagradable en mi configuración de K8s :(

apiVersion: batch/v1
kind: Job
metadata:
  name: example-job
spec:
  template:
    spec:
      containers:
      - name: example-job
        image: eu.gcr.io/example/example-job:latest
        command: ["/bin/sh", "-c"]
        args:
          - |
            trap "touch /tmp/pod/main-terminated" EXIT
            run-job.sh
        volumeMounts:
          - mountPath: /tmp/pod
            name: tmp-pod
      - name: cloudsql-proxy
        image: gcr.io/cloudsql-docker/gce-proxy:1.11
        command: ["/bin/sh", "-c"]
        args:
          - |
            /cloud_sql_proxy --dir=/cloudsql -instances=example:europe-west3:example=tcp:3306 -credential_file=/secrets/cloudsql/credentials.json &
            CHILD_PID=$!
            (while true; do if [[ -f "/tmp/pod/main-terminated" ]]; then kill $CHILD_PID; echo "Killed $CHILD_PID as the main container terminated."; fi; sleep 1; done) &
            wait $CHILD_PID
            if [[ -f "/tmp/pod/main-terminated" ]]; then exit 0; echo "Job completed. Exiting..."; fi
        volumeMounts:
          - name: cloudsql-instance-credentials
            mountPath: /secrets/cloudsql
            readOnly: true
          - name: cloudsql
            mountPath: /cloudsql
          - mountPath: /tmp/pod
            name: tmp-pod
            readOnly: true
      restartPolicy: Never
      volumes:
        - name: cloudsql-instance-credentials
          secret:
            secretName: cloudsql-instance-credentials
        - name: cloudsql
          emptyDir:
        - name: tmp-pod
          emptyDir: {}
  backoffLimit: 1

¿Alguien interno del proyecto puede comentar sobre el progreso de este problema?

¿Es justo suponer que esta es la mejor opción para aquellos de nosotros que trabajamos en el canal de versión estable de GKE, que probablemente no se pondrá al día con Kubernetes 1.18 durante unos meses como mínimo?

@Datamance en este punto, el KEP para abordar este problema parece que está indefinidamente en espera .

Publiqué hace un tiempo este comentario , que era mi antigua solución. No estoy tratando de presionar mis propias cosas aquí, solo ese comentario se ha perdido en los "100 comentarios más ..." de github y pensé que resurgirlo podría ser útil nuevamente.

@nrmitchi gracias por

Descubrimos un enfoque diferente, si agrega lo siguiente a sus contenedores de Pod:

    securityContext:
            capabilities:
                   add:
                    - SYS_PTRACE

luego podrá grep del Pid en otros contenedores, ejecutaremos lo siguiente al final de nuestro contenedor principal:
sql_proxy_pid=$(pgrep cloud_sql_proxy) && kill -INT $sql_proxy_pid

@krancour me alegro de haber ayudado. Si miras la red en ese repositorio, hay un par de bifurcaciones que están casi definitivamente en un lugar mejor que el original, y podría ser mejor construir a partir de / usar.

IIRC, el tenedor de limonada-hq tenía algunas adiciones útiles.

@nrmitchi , he estado mirando el código, pero puede ser más rápido preguntarte ...

¿Puede comentar brevemente sobre los requisitos previos que puedan existir que no se mencionan en el archivo README?

Por ejemplo, ¿las imágenes en las que se basan sus sidecares requieren algún conocimiento especial de esta solución? Por ejemplo, ¿necesitan escuchar en un puerto específico una señal del controlador? O tal vez deben incluir un cierto caparazón (¿bash?)

@krancour Comenzaré mi respuesta con una nota de que esta solución se escribió hace un par de años y mi memoria puede estar un poco oxidada.

Fue diseñado en ese momento de tal manera que los contenedores en cuestión no necesitaban ser conscientes de la solución alternativa. Usábamos principalmente aplicaciones de terceros en sidecar (por ejemplo, creo que stripe / veneur era una) y no queríamos bifurcar / modificar.

El único requisito de los sidecars es que escuchen correctamente una señal SIGTERM y luego se apaguen. Recuerdo haber tenido algunos problemas con el código de terceros que se ejecutaba en sidecars que esperaban una señal diferente y tenían que solucionarse, pero en realidad el controlador debería haber permitido que se especificara la señal enviada (es decir, SIGINT en lugar de SIGTERM).

No necesitan escuchar ningún puerto en busca de una señal, ya que el controlador usa un exec para señalar el proceso principal del sidecar directamente. IIRC en el momento en que esa funcionalidad se copió del código de Kubernetes porque no existía en el cliente. Creo que esto existe en el cliente oficial ahora y probablemente debería actualizarse.

Descubrimos un enfoque diferente, si agrega lo siguiente a sus contenedores de Pod:

    securityContext:
            capabilities:
                   add:
                    - SYS_PTRACE

luego podrá grep del Pid en otros contenedores, ejecutaremos lo siguiente al final de nuestro contenedor principal:
sql_proxy_pid=$(pgrep cloud_sql_proxy) && kill -INT $sql_proxy_pid

@ ruiyang2015 gracias por este truco.
Sin embargo, si alguien lo implementa, asegúrese de comprender las implicaciones de compartir un proceso ns entre los contenedores

@nrmitchi

utiliza un ejecutivo para señalar el proceso principal del sidecar directamente

Esa es parte de la razón por la que pregunté ... Supongo que, específicamente, me pregunto si esto no funciona para contenedores basados ​​en imágenes construidas FROM scratch .

@krancour Punto justo, nunca fui y lo probé con contenedores que estaban fuera de scratch . Mirando el código (o mi versión original; esto podría haber cambiado en bifurcado) parece que va a depender de bash , pero debería poder modificarse.

dependerá de bash, pero debería poder modificarse

Claro, pero mientras se esté ejecutando, siempre dependerá de algún binario que esté presente en el contenedor y, para un contenedor de scratch, no hay nada, excepto lo que ponga allí explícitamente. 🤷‍♂

Dada esa limitación, no puedo usar esto para un caso de uso donde los contenedores que se están ejecutando pueden ser totalmente arbitrarios y especificados por un tercero. Ah, y también tengo contenedores de Windows en juego.

En su lugar, mencionaré lo que voy a decidir. Probablemente sea demasiado torpe para la mayoría de los casos de uso, pero lo menciono en caso de que el caso de uso de otra persona sea lo suficientemente similar al mío como para salirse con la suya ...

Puedo permitirme el lujo de simplemente _eliminar_ una cápsula cuyo contenedor "principal" ha salido, siempre que registre primero el estado de salida. Así que terminaré escribiendo un controlador que monitoreará algún contenedor designado (a través de anotaciones) para su finalización, registrará su éxito o falla en un almacén de datos que ya rastrea el estado del "trabajo" y luego eliminará el pod por completo.

Por si acaso, probablemente pondré un poco de retraso en la eliminación de la vaina para maximizar las posibilidades de mi agregación de registro central de obtener las últimas líneas de la salida del contenedor principal antes de que sea torpedeado.

Torpe, pero puede funcionar para algunos.

@krancour Totalmente cierto. Tal como está, el controlador no funcionará para bases de uso arbitrarias. Honestamente, nunca volví e intenté abstraer parte de la implementación para respaldar otros casos porque realmente pensé que el KEP mencionado anteriormente se habría fusionado y habría hecho que la necesidad de esta funcionalidad fuera discutible.

Dado que este problema tiene como 4 años, el KEP no ha desaparecido todavía, y el estado del arte es un script de shell en línea pirateado que reemplaza cada punto de entrada, decidí codificar el truco "estándar" (lápidas en un volumen compartido ) en un binario Go que se puede convertir fácilmente en imágenes de contenedores mediante una compilación de varias etapas.

https://github.com/karlkfi/kubexit

Hay algunas formas de usarlo:

  1. Hornéalo en tus imágenes
  2. Cárguelo lateralmente usando un contenedor de inicio y un volumen efímero.
  3. Aprovisionarlo en cada nodo y cargarlo lateralmente en contenedores usando un montaje de enlace de host

Editar: v0.2.0 ahora admite "dependencias de nacimiento" (inicio diferido) y "dependencias de muerte" (terminación automática).

Comentario de drive-by: esto se ve exactamente como https://github.com/kubernetes/enhancements/issues/753

@vanzin, como se ha señalado antes , KEP está en espera indefinida.

Mi caso de uso para esto es que Vault proporciona credenciales para que se ejecute un CronJob. Una vez que se realiza la tarea, el sidecar de Vault todavía se está ejecutando con el trabajo en un estado pendiente y eso hace que el sistema de monitoreo piense que algo anda mal. Es una pena lo que pasó con el KEP.

¿Fue útil esta página
0 / 5 - 0 calificaciones