Kubernetes: Meilleure prise en charge des conteneurs side-car dans les tâches par lots

Créé le 19 mai 2016  ·  116Commentaires  ·  Source: kubernetes/kubernetes

Considérez un Job avec deux conteneurs - un qui fait le travail puis se termine, et un autre qui n'est pas conçu pour jamais sortir explicitement mais fournit une sorte de fonctionnalité de support comme la collecte de journaux ou de métriques.

Quelles options existent pour faire quelque chose comme ça? Quelles options devraient exister?

Actuellement, le Job continuera à s'exécuter tant que le deuxième conteneur continuera à fonctionner, ce qui signifie que l'utilisateur doit modifier le deuxième conteneur d'une manière ou d'une autre pour détecter quand le premier est terminé afin qu'il puisse également se terminer proprement.

Cette question a été posée sur Stack Overflow il y a quelque temps sans meilleure réponse que de modifier le deuxième conteneur pour qu'il soit plus compatible avec Kubernetes, ce qui n'est pas idéal. Un autre client m'a récemment signalé cela comme un problème pour lui.

@kubernetes/goog-control-plane @erictune

arebatch areworkload-apjob kinfeature lifecyclfrozen prioritimportant-longterm siapps sinode

Commentaire le plus utile

Pour référence, voici la folie bash que j'utilise pour simuler le comportement de side-car souhaité :

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: {}

Tous les 116 commentaires

/sous

L'utilisation également d'un problème de vivacité comme suggéré ici http://stackoverflow.com/questions/36208211/sidecar-containers-in-kubernetes-jobs ne fonctionne pas car le pod sera considéré comme un échec et le travail global ne sera pas considéré comme réussi.

Que diriez-vous de déclarer une sonde de réussite de tâche afin que la tâche puisse la tester pour détecter la réussite au lieu d'attendre que le pod renvoie 0.
Une fois que la sonde a réussi, le pod peut être terminé.

La sonde peut-elle s'exécuter sur un conteneur qui est déjà sorti, ou y aurait-il
être une course où il est démoli?

Une autre option consiste à désigner certains codes de sortie comme ayant une signification particulière.

« Succès pour l'ensemble du pod » ou « échec pour l'ensemble du pod » sont tous deux
utile.

Cela devrait être sur l'objet Pod, c'est donc un gros changement d'API.

Le jeu. 22 septembre 2016 à 13:41, Ming Fang [email protected] a écrit :

Que diriez-vous de déclarer une sonde de réussite de tâche afin que la tâche puisse la tester pour
détecter le succès au lieu d'attendre que le pod renvoie 0.

Une fois que la sonde a réussi, le pod peut être terminé.

-
Vous recevez ceci parce que vous avez été mentionné.
Répondez directement à cet e-mail, consultez-le sur GitHub
https://github.com/kubernetes/kubernetes/issues/25908#issuecomment-249021627 ,
ou couper le fil
https://github.com/notifications/unsubscribe-auth/AHuudjrpVtef6U35RWRlZr3mDKcCRo7oks5qsugRgaJpZM4IiqQH
.

@erictune Bon point ; nous ne pouvons pas sonder un conteneur sorti.

Pouvons-nous désigner un conteneur particulier dans le pod comme conteneur « d'achèvement » afin que, lorsque ce conteneur se termine, nous puissions dire que le travail est terminé ?

Les conteneurs side-car ont tendance à avoir une longue durée de vie pour des choses comme l'expédition et la surveillance des grumes.
Nous pouvons les forcer à les terminer une fois le travail terminé.

Pouvons-nous désigner un conteneur particulier dans le pod comme conteneur « d'achèvement » afin que, lorsque ce conteneur se termine, nous puissions dire que le travail est terminé ?

Avez-vous examiné ce point de ici où vous ne définissez fondamentalement pas .spec.completions et dès que le premier conteneur se termine avec 0 code de sortie, les travaux sont terminés.

Les conteneurs side-car ont tendance à avoir une longue durée de vie pour des choses comme l'expédition et la surveillance des grumes.
Nous pouvons les forcer à les terminer une fois le travail terminé.

Personnellement, cela me ressemble plus à RS qu'à un travail, mais c'est mon opinion personnelle et surtout je ne connais pas tous les détails de votre configuration.

En règle générale, les discussions suivantes https://github.com/kubernetes/kubernetes/issues/17244 et https://github.com/kubernetes/kubernetes/issues/30243 abordent également ce sujet.

@soltysh le lien que vous avez envoyé ci-dessus, le point 3 fait référence à l'achèvement du pod et non à l'achèvement du conteneur.

Les deux conteneurs peuvent partager un emptyDir, et le premier conteneur et écrire un message "Je quitte maintenant" dans un fichier et l'autre peut quitter lorsqu'il voit ce message.

@erictune J'ai un cas d'utilisation qui, je pense, tombe dans ce seau et j'espère que vous pourrez me guider dans la bonne direction car il ne semble pas y avoir de moyen officiel recommandé de résoudre ce problème.

J'utilise la bibliothèque client-go pour tout coder ci-dessous :

J'ai donc un travail qui exécute essentiellement un outil dans un seul conteneur. Dès que l'outil a fini de s'exécuter, il est censé produire un fichier de résultats. Je n'arrive pas à capturer ce fichier de résultats car dès que l'outil a fini de s'exécuter, le pod est supprimé et je perds le fichier de résultats.

J'ai pu capturer ce fichier de résultats si j'utilisais HostPath comme VolumeSource et puisque j'exécute minikube localement, le fichier de résultats est enregistré sur mon poste de travail.

Mais je comprends que ce n'est pas recommandé et idéal pour les conteneurs de production. J'ai donc utilisé EmptyDir comme suggéré ci-dessus. Mais, encore une fois, si je fais cela, je ne peux pas vraiment le capturer car il est supprimé avec le pod lui-même.

Alors, devrais-je également résoudre mon problème en utilisant le modèle de conteneur side-car ?

En gros, faites ce que vous avez suggéré ci-dessus. Démarrez 2 conteneurs dans le pod chaque fois que la tâche démarre. 1 conteneur exécute le travail et dès que le travail est terminé, dépose un message qui est récupéré par l'autre conteneur qui récupère ensuite le fichier de résultat et le stocke quelque part ?

Je ne comprends pas pourquoi nous aurions besoin de 2 conteneurs en premier lieu. Pourquoi le conteneur de jobs ne peut-il pas faire tout cela tout seul ? C'est-à-dire, terminez le travail, enregistrez le fichier de résultats quelque part, accédez-y/lisez-le et stockez-le quelque part.

@anshumanbh je vous suggère :

  1. utilisez un stockage persistant, vous enregistrez le fichier résultat
  2. utilisez hostPath mount, qui est presque le même que 1, et vous l'avez déjà essayé
  3. téléchargez le fichier de résultat vers un emplacement distant connu (s3, google drive, dropbox), généralement tout type de lecteur partagé

@soltysh Je ne veux pas que le fichier soit stocké de manière permanente. À chaque course, je veux juste comparer ce résultat avec le dernier résultat. Donc, la façon dont je pensais le faire était de m'engager dans un référentiel github à chaque exécution, puis de faire un diff pour voir ce qui avait changé. Donc, pour ce faire, j'ai juste besoin de stocker le résultat temporairement quelque part afin que je puisse y accéder pour l'envoyer à Github. Avoir du sens ?

@anshumanbh parfaitement clair, et cela ne rentre toujours pas dans la catégorie des conteneurs side-car. Tout ce que vous voulez réaliser est actuellement réalisable avec ce que les emplois offrent.

@soltysh donc étant donné que je veux opter pour l'option 3 de la liste que vous avez suggérée ci-dessus, comment pourrais-je procéder pour la mettre en œuvre ?

Le problème auquel je suis confronté est que dès que le travail est terminé, le conteneur se ferme et je perds le fichier. Si je n'ai pas le fichier, comment le télécharger sur un lecteur partagé comme S3/Google Drive/Dropbox ? Je ne peux pas modifier le code du travail pour le télécharger automatiquement quelque part avant qu'il ne s'arrête, donc malheureusement, je devrais d'abord exécuter le travail, puis enregistrer le fichier quelque part.

Si vous ne pouvez pas modifier le code du travail, vous devez l'encapsuler de manière à pouvoir télécharger le fichier. Si vous travaillez avec une image déjà, étendez-la simplement avec le code de copie.

@soltysh oui, cela a du sens. Je pourrais faire ça. Cependant, la question suivante que j'ai est - supposons que je doive exécuter plusieurs tâches (pensez-y comme exécuter différents outils) et qu'aucun de ces outils n'a la partie de téléchargement intégrée. Donc, maintenant, je devrais construire ce wrapper et étendre chacun de ces outils avec la partie de téléchargement. Existe-t-il un moyen d'écrire le wrapper/l'extension une seule fois et de l'utiliser pour tous les outils ?

Le modèle de side-car ne conviendrait-il pas dans ce cas ?

Ouais, ça pourrait. Bien que j'essaie avec plusieurs conteneurs dans le même pod, pattern. Iow. votre pod exécute le conteneur de jobs et un conteneur supplémentaire attend la sortie et la télécharge. Je ne sais pas si c'est faisable, mais vous pouvez déjà l'essayer.

Ping doux - la prise en compte du side-car rendrait la gestion des proxys de microservices tels qu'Envoy beaucoup plus agréable. Y a-t-il des progrès à partager ?

L'état actuel des choses est que chaque conteneur a besoin d'outils groupés pour coordonner les durées de vie, ce qui signifie que nous ne pouvons pas utiliser directement les images de conteneur en amont. Cela complique également considérablement les modèles, car nous devons injecter des points de montage et argv supplémentaires.

Une suggestion précédente consistait à désigner certains conteneurs comme conteneurs « d'achèvement ». J'aimerais proposer le contraire - la possibilité de désigner certains conteneurs comme "side-cars". Lorsque le dernier conteneur non-side-car dans un pod se termine, le pod doit envoyer TERM aux side-cars. Ce serait analogue au concept de « thread d'arrière-plan » que l'on trouve dans de nombreuses bibliothèques de threads, par exemple Thread.daemon Python.

Exemple de configuration, lorsque le conteneur main se termine, le kubelet tuerait 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"]

Pour référence, voici la folie bash que j'utilise pour simuler le comportement de side-car souhaité :

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: {}

J'aimerais proposer le contraire - la possibilité de désigner certains conteneurs comme "side-cars". Lorsque le dernier conteneur non-side-car dans un pod se termine, le pod doit envoyer TERM aux side-cars.

@jmillikin-stripe J'aime cette idée, bien que je ne sois pas sûr que cela suive le principe consistant à traiter certains conteneurs différemment dans un Pod ou à introduire des dépendances entre eux. Je m'en remets à @erictune pour le dernier appel.

Bien que, avez-vous vérifié #17244, ce type de solution conviendrait-il à votre cas d'utilisation ? C'est ce que @erictune a mentionné quelques commentaires auparavant :

Une autre option consiste à désigner certains codes de sortie comme ayant une signification particulière.

@jmillikin-stripe J'aime cette idée, bien que je ne sois pas sûr que cela suive le principe consistant à traiter certains conteneurs différemment dans un Pod ou à introduire des dépendances entre eux. Je m'en remets à @erictune pour le dernier appel.

Je pense que Kubernetes devra peut-être être flexible sur le principe de ne pas traiter les conteneurs différemment. Nous (Stripe) ne voulons pas moderniser le code tiers tel qu'Envoy pour avoir des crochets de cycle de vie de style Lamprey, et essayer d'adopter une inversion exécutable de style Enveloppe serait beaucoup plus complexe que de laisser Kubelet mettre fin à des side-cars spécifiques.

Bien que, avez-vous vérifié #17244, ce type de solution conviendrait-il à votre cas d'utilisation ? C'est ce que @erictune a mentionné quelques commentaires auparavant :

Une autre option consiste à désigner certains codes de sortie comme ayant une signification particulière.

Je suis très fortement opposé à ce que Kubernetes ou Kubelet interprètent les codes d'erreur avec une granularité plus fine que "zéro ou non". L'utilisation par Borglet de nombres magiques de code de sortie était un défaut désagréable, et ce serait bien pire dans Kubernetes où une image de conteneur particulière pourrait être soit un "principal" soit un "side-car" dans différents pods.

Peut-être que des hooks de cycle de vie supplémentaires seraient suffisants pour résoudre ce problème ?

Pourrait être:

  • PostStop : avec un moyen de déclencher des événements de cycle de vie sur d'autres conteneurs du pod (c'est-à-dire déclencher l'arrêt)
  • PeerStopped : signale qu'un conteneur "pair" dans le pod est mort - éventuellement avec le code de sortie comme argument

Cela pourrait également définir un moyen de définir des politiques personnalisées pour redémarrer un conteneur - ou même démarrer des conteneurs qui ne sont pas démarrés par défaut pour permettre un chaînage en guirlande de conteneurs (lorsque le conteneur a se termine, démarrez le conteneur b)

Manque aussi ça. Nous exécutons une tâche toutes les 30 minutes qui nécessite un client VPN pour la connectivité, mais il semble y avoir de nombreux cas d'utilisation où cela pourrait être très utile (par exemple, des éléments nécessitant un proxy kubectl). Actuellement, j'utilise jobSpec.concurrencyPolicy: Replace comme solution de contournement, mais bien sûr, cela ne fonctionne que si a.) vous pouvez vivre sans exécution de tâches parallèles et b.) Le temps d'exécution des tâches est plus court que l'intervalle de planification.

EDIT : dans mon cas d'utilisation, il serait tout à fait suffisant d'avoir une propriété dans la spécification du travail pour marquer un conteneur comme étant celui qui se termine et que le travail surveille celui-ci pour l'état de sortie et tue les autres.

Moi aussi, j'en ai besoin. Dans notre cas, il s'agit d'un travail qui utilise le conteneur cloudsql-proxy en tant que service annexe.

Et si vous ajoutiez éventuellement une annotation qui correspond au nom du conteneur « principal » dans le pod ? De cette façon, la spécification du pod n'a pas besoin d'être modifiée de quelque façon que ce soit.

De par la nature de la conception des Pods, cela semble être un cas d'utilisation très courant. @soltysh @erictune avez- vous l'intention de travailler dessus bientôt ? Heureux d'aider si possible :)

Besoin également de cette fonctionnalité. Pour notre cas d'utilisation :
le pod A doit contenir des conteneurs

  • conteneur A1 : un
  • conteneur A2 : conteneur side-car, qui ne fait que suivre les journaux du fichier vers la sortie standard

Ce que je veux : quand le conteneur A1 se termine avec succès, le pod A se termine avec succès. Pouvons-nous simplement étiqueter le conteneur A1 comme conteneur principal , lorsque le conteneur principal sort, le pod sort ? @erictune ( Cette idée est également décrite par @mingfang )

Salut les gars, je vois que ce problème est ouvert depuis un mois. Quelle est la dernière à ce sujet ? Nous avons un cas d'utilisation, où nous voulons exécuter un travail. Le travail exécute un conteneur main avec quelques side-car containers . Nous voulons que le travail se termine lorsque le conteneur main termine. L'état de l'art est-il de partager un file pour envoyer un signal entre les conteneurs ?

Cela ne me dérangerait pas de commencer à travailler là-dessus, j'aimerais savoir si quelqu'un pourrait revoir les PR à venir si je le fais (peut-être après kubecon).

cc @erictune @a-robinson @soltysh

@andrewsykim quelle approche main ne devrait pas démarrer tant que les side-cars n'ont pas été initialisés

Comme le conteneur principal ne devrait pas démarrer tant que les side-cars n'ont pas été initialisés

Je pense que ce cas n'est pas un problème puisque main devrait pouvoir vérifier quand le side-car est initialisé (ou utiliser une sonde de disponibilité). Ce n'est pas le cas pour ce problème car main aurait quitté :)

J'ai fini par écrire un script simple qui surveille l'API kubernetes et termine les travaux avec une annotation correspondante et dont le conteneur principal est sorti. Ce n'est pas parfait, mais cela répond à un besoin essentiel. Je peux le partager si les gens sont intéressés.

@ajbouh J'apprécierais personnellement si vous résumé . J'étais sur le point d'écrire quelque chose de similaire

J'ai le même cas d'utilisation de proxy Cloud SQL que @mrbobbytables. Afin de se connecter en toute sécurité au cloud SQL, il est recommandé d'utiliser le proxy, mais ce proxy ne se termine pas lorsque le travail est terminé, ce qui entraîne des hacks fous ou une surveillance qui ressemble à ce qui suit. Y a-t-il une voie à suivre à ce sujet ?

image

@amaxwell01 En https://issuetracker.google.com/issues/70746902 (edit : et je regrette certaines formulations que j'ai utilisées là dans le feu de l'action ; malheureusement, je ne peux pas l'éditer)

Merci @abevoelker, je suis votre message là-bas. En plus vos commentaires m'ont fait rire

Nous sommes également impactés par ce problème.
Nous avons plusieurs commandes de gestion django sur nos micro-services qui peuvent s'exécuter sur les tâches cron k8s mais échouent à cause du side-car cloudsqlproxy qui ne s'arrête pas à la fin du travail.
Une mise à jour sur quand nous pourrions avoir une solution ?
Le modèle de conteneur side-car est de plus en plus utilisé et beaucoup d'entre nous ne pourront pas utiliser les tâches cron et les tâches k8s jusqu'à ce que cela soit résolu.

Je voulais juste ajouter mon +1 pour cela. J'ai le même problème de proxy GCE Cloud SQL que tout le monde. Ça me tue... le déploiement de la barre échoue, ce qui à son tour échoue à l'application de ma terraforme.

J'aimerais vraiment voir une sorte de résolution à ce sujet... j'ai l' impression que ça pourrait marcher de @ajbouh... mais bon sang, c'est bidon.

Pour toute autre personne nécessitant cloudsql-proxy , cela conviendrait-il à votre cas d'utilisation d'exécuter le cloudsql-proxy tant que DaemonSet ? Dans mon cas, j'avais à la fois un déploiement persistant et un CronJob nécessitant le proxy, il était donc logique de le détacher des pods individuels et d'attacher à la place une instance par nœud.

Oui,

Nous avons décidé de supprimer les side-cars proxy cloudsql et de créer un pool de
proxys cloudsql dans leur espace de noms central, cela fonctionne parfaitement et permet
déplacer l'évolutivité et des déploiements plus faciles.
Maintenant, nous pouvons exécuter des tâches et des tâches cron sans aucun problème.

Le mercredi 7 février 2018 à 9h37, Rob Jackson [email protected]
a écrit:

Pour toute autre personne ayant besoin de cloudsql-proxy, cela correspondrait-il à votre cas d'utilisation pour
exécuter le cloudsql-proxy en tant que DaemonSet ? Dans mon cas, j'ai eu à la fois une persistance
Déploiement et un CronJob nécessitant le proxy, il était donc logique de se détacher
à partir de pods individuels et attachez à la place une instance par nœud.

-
Vous recevez ceci parce que vous avez commenté.
Répondez directement à cet e-mail, consultez-le sur GitHub
https://github.com/kubernetes/kubernetes/issues/25908#issuecomment-363710890 ,
ou couper le fil
https://github.com/notifications/unsubscribe-auth/ACAWMwetx6gA_SrHL_RRbTMJVOhW1FKLks5tSW7JgaJpZM4IiqQH
.

Intéressant, l'utilisation d'un deamonset semble être une bonne option. @RJacksonm1 & @devlounge - comment fonctionne la découverte du proxy cloud sql lors de l'utilisation de daemonsets ?

J'ai trouvé ça qui a l'air de faire l'affaire...
https://buoyant.io/2016/10/14/a-service-mesh-for-kubernetes-part-ii-pods-are-great-until-theyre-not/

Cela implique essentiellement d'utiliser quelque chose comme ceci pour obtenir l'adresse IP de l'hôte :

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

@RJacksonm1 - Avez-vous fait quelque chose de spécial pour que hostPort fonctionne ? Je reçois constamment connection refused lorsque je l'utilise en conjonction avec l'approche fieldPath: spec.nodeName 🤔

Edit : je me suis assuré que spec.nodeName passe correctement et je suis sur GKE v1.9.2-gke.1

@cvallance J'ai cloudsql-proxy s'exécutant sur le même hôte qu'elle-même, mais cela garantit que le cloudsql-proxy évoluera avec le cluster dans son ensemble (à l'origine, j'avais le proxy en tant que déploiement et HorizontalPodAutoscaler, mais l'a trouvé trop élevé/réduit, provoquant des erreurs MySQL has gone away dans l'application). Je suppose que ce n'est pas dans le véritable esprit d'un DaemonSet... 🤔

@RJacksonm1 - il fonctionne avec hostPort et spec.nodeName ... maintenant ils se connecteront directement au DaemonSet sur leur nœud 😄

La commande du proxy CloudSql ne fonctionne pas :
-instances={{ .Values.sqlConnectionName }}=tcp:{{ .Values.internalPort }}
Travail:
-instances={{ .Values.sqlConnectionName }}=tcp:0.0.0.0:{{ .Values.internalPort }}

Y a-t-il quelque chose que nous puissions faire pour obtenir une certaine traction sur cette question?
Il est ouvert depuis près de 2 ans et nous n'avons toujours que des solutions de contournement

Je soupçonne que même si je me porte volontaire pour mettre en œuvre cela, je ne pourrai pas le faire car cela nécessite l'approbation des gars internes concernant la solution à mettre en œuvre, les modifications de l'API, etc.

Qu'est-ce que je peux faire pour aider à faire cela?

Pour référence, j'ai créé une version side-car cloud-sql-proxy de la solution de contournement de @jmillikin-stripe où un fichier dans un volume partagé communique l'état au side-car.

Cela fonctionne bien, mais c'est de loin le hack le plus méchant dans ma configuration 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

Quelqu'un à l'interne du projet peut-il commenter l'avancement de ce problème ?

Même problème ici

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

Serait-il judicieux de permettre aux utilisateurs de spécifier (par leur nom) les conteneurs d'un Job qu'ils souhaitent voir se terminer avec succès afin de marquer le Job Pod comme terminé (avec d'autres conteneurs arrêtés), comme ceci :

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

C'est-à-dire que le pod s'exécuterait, attendez que my-container se termine avec succès, puis terminez simplement cloudsql-proxy .

EDIT: En faisant défiler ce fil, je vois maintenant que cela a été proposé précédemment. @erictune ou quelqu'un d'autre peut-il expliquer pourquoi cela ne fonctionnerait pas ?

oui je pense que ce serait parfait Juste quelque chose qui vous permet de surveiller l'état du travail et de continuer le pipeline une fois terminé

Ouais, ce serait parfait.

J'aime cette idée @jpalomaki

Une préoccupation que j'ai avec l'approche consistant à résoudre ce problème uniquement au sein du contrôleur de tâche est que le pod continuera à s'exécuter une fois la tâche terminée. Actuellement, le pod entre dans la phase Terminé et le nœud peut libérer ces ressources.

Vous pourriez demander au contrôleur de tâche de supprimer le pod lorsque le contrôleur décide que c'est fait, mais ce serait également différent du comportement actuel, où l'enregistrement du pod terminé reste dans le serveur d'API (sans utiliser les ressources du nœud).

Pour ces raisons, il me semble plus propre d'aborder cela au niveau de l'API Pod, voire pas du tout. Le nœud est la seule chose qui devrait atteindre et tuer des conteneurs individuels, car les conteneurs "d'achèvement" qui vous intéressent sont déjà terminés. Cela pourrait prendre la forme d'une API au niveau du pod qui vous permet de spécifier la notion des conteneurs qu'il doit attendre, ou d'une API au niveau du pod pour permettre à des agents externes (par exemple le contrôleur de tâche) de forcer le pod à se terminer sans réellement supprimer le Pod.

Je recherche également une solution pour télécharger des fichiers produits par un conteneur si le conteneur du processeur s'est terminé avec succès.

Je ne suis pas sûr de comprendre l'argument de @mingfang contre le fait que le conteneur side-car surveille l'état du conteneur via l'API k8s pour savoir si et quand commencer à télécharger ou à quitter. Lorsque le conteneur side-car quitte le pod et le travail doivent être terminés avec succès.

Une autre pensée, qui ressemble à un hack, mais j'aimerais savoir à quel point il serait mauvais de transformer le conteneur de production de données en un conteneur d'initialisation et d'avoir le conteneur de téléchargement de données (qui n'aurait plus besoin d'être un conteneur side-car ) n'a démarré automatiquement qu'une fois le conteneur du processeur terminé avec succès. Dans mon cas, j'aurais également besoin d'un conteneur de téléchargement de données comme premier conteneur d'initialisation, pour fournir des données au conteneur de traitement. Si c'est une mauvaise idée, j'aimerais savoir pourquoi.

La promotion du side-car en un concept k8 de première classe ne résoudrait-elle pas ce problème ? Kubelet pourra mettre fin au pod si tous les conteneurs en cours d'exécution qu'il contient sont marqués comme side-car.

FWIW, j'ai contourné cela en déployant simplement un proxy Cloud SQL en tant que déploiement régulier ( replicas: 1 ) et j'ai fait en sorte que mes Job et CronJob utilisent via un type: ClusterIP un service. Les travaux se terminent bien maintenant.

J'aimerais une position officielle à ce sujet.

Si nous n'avons pas de support de l'API, nous devrions au moins avoir les solutions alternatives officiellement documentées afin que les gens sachent quoi faire lorsqu'ils rencontrent ce problème.

Je ne sais pas à qui envoyer un ping ni comment attirer l'attention sur cela...

Ce serait vraiment sympa de régler ce problème. En plus de la tâche qui ne disparaît jamais, l'état général du pod est apparemment incorrect :

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 

Ce qui est intéressant, c'est de noter l'état et le prêt pour l'initContainer (terminé, terminé, prêt = vrai) et le conteneur d'application principal (terminé, terminé, prêt = faux). Cela semble conduire à l'état Over Pod Ready de False - à mon avis, de manière incorrecte. Cela fait que ce pod est signalé comme ayant un problème sur nos tableaux de bord.

J'ai un autre client qui rencontre ce problème avec le proxy Cloud SQL en particulier. Ils aimeraient ne pas avoir à l'exécuter en tant que service persistant pour permettre aux tâches cron d'accéder à Cloud SQL.

@yuriatgoogle La solution la plus https://github.com/kubernetes/kubernetes/issues/25908#issuecomment -365924958

C'est un hack, mais il faudra le faire. Aucune infraction destinée à @phidah.

Il semble que beaucoup de gens le souhaitent pour diverses raisons. Ce serait bien d'avoir un soutien officiel. J'ai eu le même problème avec notre propre side-car et nos propres travaux, j'ai donc demandé au side-car d'utiliser l'API kube pour surveiller l'état de l'autre conteneur dans le pod, s'il se terminait par un completed le side-car quitterait 0, si il s'est trompé que le side-car sortirait 1. Ce n'est peut-être pas la solution la plus élégante, mais cela a fait l'affaire sans que nos développeurs aient beaucoup changé. le code est ici si quelqu'un est intéressé : https://github.com/uswitch/vault-creds/blob/master/cmd/main.go#L132.

Cela me rappelle une chanson de Gorillaz M1 A1...

Bonjour? Hellooooooo? Est-ce que quelqu'un est là?

Oui, s'il vous plaît, obtenez un peu de traction +1

Ainsi les solutions proposées qui nécessitent une évolution en amont sont :

  1. sidecar: true par @jmillikin-stripe
  2. Crochets de cycle de vie supplémentaires par @msperl
  3. jobCompletedWith par @jpalomaki

Solution temporaire pour side-car, un hacky (mais fonctionne):

  1. Pour cloudsql-proxy side-car par @phidah

J'aimerais voir la réponse du mainteneur de Kubernetes concernant les solutions proposées et veuillez nous donner des recommandations sur la façon de résoudre ce cas d'utilisation en utilisant la version existante de kubernetes. Merci!

Je viens de découvrir ce fil après avoir passé une journée à essayer d'écrire un agent de journal qui téléchargerait le stdout / stderr de ma tâche de rendu dans une base de données, pour découvrir que la présence de l'agent dans le pod signifierait que le travail ne se terminerait jamais.

Parmi les suggestions données ci-dessus, j'aime le « side-car : vrai » le meilleur, car il est simple et précis - très compréhensible pour un développeur comme moi. J'appellerais probablement cela quelque chose de légèrement différent, car «side-car» est en réalité un modèle de conception de pod qui s'applique à plus que des travaux et implique d'autres choses que les exigences d'achèvement. Si vous vouliez excuser mon bikeshedding, je l'appellerais probablement quelque chose comme « ambient : vrai » pour indiquer que le travail peut être considéré comme terminé même si cette tâche est toujours en cours d'exécution. D'autres mots peuvent être « auxiliaire » ou « soutien ».

J'ai également rencontré ce problème, pour le même flux de travail que beaucoup d'autres ont décrit (un conteneur side-car utilisé pour les connexions proxy ou la collecte de métriques, et n'a aucune utilité après la sortie réussie de l'autre conteneur du pod).

Une suggestion précédente consistait à désigner certains conteneurs comme conteneurs « d'achèvement ». J'aimerais proposer le contraire - la possibilité de désigner certains conteneurs comme "side-cars". Lorsque le dernier conteneur non-side-car dans un pod se termine, le pod doit envoyer TERM aux side-cars.

C'est aussi ma solution idéale. Je pourrais suggérer SIGHUP au lieu de SIGTERM - cela semble être le cas d'utilisation exact pour lequel la sémantique de SIGHUP est pertinente ! - mais je serais heureux avec l'un ou l'autre.

Dans l'état actuel des choses, l'exécution de tâches sur Kubernetes nécessite soit de corriger manuellement les images de conteneur en amont pour gérer la communication inter-conteneur spécifique à Kubernetes lorsque le conteneur non-side-car se termine, soit d'intervenir manuellement pour terminer le side-car pour chaque tâche afin que le pod zombie ne le fasse pas. traîner. Ni l'un ni l'autre n'est particulièrement agréable.

Je serais prêt à créer un correctif pour cela, mais j'aimerais obtenir des conseils de @kubernetes/sig-apps-feature-requests avant de creuser dans n'importe quel code. Sommes-nous d'accord pour ajouter un champ sidecar à la spécification du pod pour que cela fonctionne ? J'hésite à apporter des modifications aux spécifications du pod sans être certain que nous le voulons. Peut-être utiliser des annotations pour le moment ?

@andrewsykim Je suis ce problème depuis un certain temps (je n'ai tout simplement pas essayé de le résoudre moi-même), mais je suggérerais simplement d'utiliser des annotations pour le moment.

Mon raisonnement est que :

  • Ce problème existe depuis près de 2 ans et n'a pas vraiment attiré l'attention du noyau kubernetes. Par conséquent, si nous attendons d'apporter des modifications aux spécifications du pod ou d'une entrée directe, nous attendrons probablement longtemps.
  • Il est beaucoup plus facile d'attirer l'attention sur un PR viable qu'un vieux problème.
  • Il devrait être agréable à chacun de changer d'approche d'annotation pour utiliser un attribut de pod à l'avenir

Les pensées?

Salut, j'ai parlé à certains des gars de sig-apps chez kubecon à propos de ce problème, fondamentalement ce n'est pas quelque chose qui est sur leur feuille de route immédiate mais c'est quelque chose qu'ils pensent être un cas d'utilisation valide. Ils sont très ouverts à quelqu'un de la communauté qui s'attaque à cela.

J'ai créé un PR pour une proposition d'amélioration afin de résoudre ce problème, j'espère donc que cela générera une discussion https://github.com/kubernetes/community/pull/2148.

Merci d'avoir préparé ça @Joseph-Irving ! On dirait qu'il y a plus de détails à régler pour cela, donc je vais m'abstenir de travailler jusque-là :)

problème persistant à long terme :(

cc @ kow3ns @janetkuo

Sans vouloir compliquer davantage les choses, il serait également utile de pouvoir exécuter un conteneur de style "side-car" à côté de initContainers .

Mon cas d'utilisation est similaire à celui des personnes ici, je dois exécuter un proxy cloud sql en même temps qu'un initContainer qui exécute les migrations de bases de données. Comme les initContainers sont exécutés un à la fois, je ne vois pas de moyen de le faire, sauf pour exécuter le proxy en tant que déploiement + service, mais je m'attends à ce qu'il existe d'autres cas d'utilisation (gestion des journaux, etc.) où ce ne serait pas un travail approprié environ.

@mcfedr Il existe une proposition d'amélioration raisonnablement active qui pourrait apprécier cette observation concernant le comportement du conteneur d'initialisation. Je ne sais pas si cela fait partie du champ d'application de cette proposition ou d'une amélioration connexe, mais je pense que c'est suffisamment lié pour qu'il soit logique de le soulever pour examen.

Nonobstant les problèmes potentiels de mise en œuvre/compatibilité, votre modèle idéal serait probablement que les conteneurs d'initialisation side-car s'exécutent simultanément avec des conteneurs init non side-car, qui continuent de s'exécuter de manière séquentielle comme maintenant, et que les side-cars se terminent avant le démarrage des conteneurs de séquence principale ?

pour ce que ça vaut, je voudrais également exprimer la nécessité d'ignorer les side-cars qui fonctionnent toujours comme CloudSQL Proxy et.al.

J'ai réussi à tuer le conteneur cloudsql après 30 secondes car je sais que mon script ne prendrait pas autant de temps. Voici ma démarche :

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

Et ça marche pour moi.
Voyez-vous les gars un inconvénient dans cette approche?

Comme je pense qu'ils sont liés et facilement adaptables à CronJobs également, voici ma solution : https://github.com/GoogleCloudPlatform/cloudsql-proxy/issues/128#issuecomment -413444029

Il est basé sur l'une des solutions de contournement publiées ici, mais utilise preStop car il est destiné aux déploiements. Le piégeage du side-car fonctionnerait à merveille.

Suite à ce problème. Utilisation également du conteneur cloud_sql_proxy comme side-car dans cronjob
J'ai utilisé l' implémentation du délai d'attente par @stiko

Le simple fait d'ajouter à la conversation la solution proposée par @ oxygen0211 sur l'utilisation de Replace est une solution de contournement décente pour le moment, assurez-vous de la vérifier si vous rencontrez ce problème comme je l'ai fait.

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

Nous avons ce KEP provisoirement approuvé https://github.com/kubernetes/community/pull/2148 , nous avons encore quelques points sur lesquels nous devons nous mettre d'accord mais j'espère qu'il arrivera à un endroit où le travail pourra commencer relativement bientôt . Remarque Les KEP seront déplacés vers https://github.com/kubernetes/enhancements le 30, donc si vous voulez suivre, ce sera là-bas.

Jusqu'à ce que le support side-car arrive, vous pouvez utiliser une solution de niveau docker qui peut être facilement supprimée ultérieurement : https://gist.github.com/janosroden/78725e3f846763aa3a660a6b2116c7da

Il utilise un conteneur privilégié avec un socket docker monté et des étiquettes kubernetes standard pour gérer les conteneurs dans le travail.

Nous avions le même problème avec Istio et son side car, et ce que nous avons décidé de faire est de supprimer le pod via curl + crochet preStop comme celui-ci

donnez à votre travail une règle RBAC minimale comme celle-ci

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

et POD_NAME et POD_NAMESPACE à votre ENV comme ça

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

et enfin, ajoutez un crochet preStop comme

 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 peu désordonné mais un peu plus sûr et moins compliqué que d'essayer de tuer le bon conteneur docker.

Je viens de lancer ceci ici, mais j'ai créé il y a quelque temps un contrôleur qui était destiné à surveiller les changements de pod en cours et à envoyer un SIGTERM aux conteneurs side-car de manière appropriée. Ce n'est certainement pas le plus robuste, et honnêtement, je ne l'ai pas utilisé depuis un moment, mais cela peut être utile.

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

Merci à @jpalomaki à https://github.com/kubernetes/kubernetes/issues/25908#issuecomment -371469801 pour la suggestion d'exécuter cloud_sql_proxy tant que déploiement avec le service ClusterIP , et à @ cvallance sur https://github.com/kubernetes/kubernetes/issues/25908#issuecomment -364255363 pour le conseil sur la définition de tcp:0.0.0.0 dans le paramètre cloud_sql_proxy instances pour autoriser non -les connexions locales au processus. Ensemble, ils ont permis de laisser les tâches cron utiliser le proxy sans difficulté.

problème à long terme (note à moi-même)

Même problème. Vous cherchez un moyen ou une documentation officielle sur la façon d'utiliser le travail GKE cron avec Cloud SQL

Note latérale :
Google a mis à jour sa documentation Cloud SQL -> Connexion à partir de Google Kubernetes Engine , maintenant en plus du Connecting using the Cloud SQL Proxy Docker image vous pouvez Connecting using a private IP address
Donc, si vous êtes ici pour la même raison que je suis ici (à cause du cloud_sql_proxy), vous pouvez maintenant utiliser la nouvelle fonctionnalité d'IP privée

Note latérale :
Google a mis à jour sa documentation Cloud SQL -> Connexion à partir de Google Kubernetes Engine , maintenant en plus du Connecting using the Cloud SQL Proxy Docker image vous pouvez Connecting using a private IP address
Donc, si vous êtes ici pour la même raison que je suis ici (à cause du cloud_sql_proxy), vous pouvez maintenant utiliser la nouvelle fonctionnalité d'IP privée

La fonction IP privée semble devoir supprimer tout le cluster et en recréer un ........ ?

@cropse Cela n'est nécessaire que si votre cluster n'est pas natif de VPC.

J'ai fait une solution de

Juste pour ajouter mes deux cents: les tests de barre échouent également si l'injection de side-car istio se produit car la nacelle ne se termine jamais.

@dansiviter vous pouvez vérifier ma solution de contournement, j'ai déjà testé dans mon projet avec helm.

hâte de voir cela mis en œuvre! :)

nous avons le même problème avec les tâches normales lorsqu'un proxy Istio y est injecté, au-dessus de cela, nous voulons également cela car nous voulons exécuter des tâches CI avec Prow.
par exemple, conteneur d'application Rails + conteneur de base de données side-car à des fins de test.

@cropse Merci. Je ne l'ai pas essayé car nous aurions besoin de le configurer pour tous les tests. Nous autorisons simplement le pod (les tests Helm n'autorisent malheureusement pas Job) à échouer et nous comptons sur l'inspection manuelle du journal jusqu'à ce que ce problème soit résolu à long terme. Cependant, cela devient également un problème pour d'autres emplois, nous devons donc peut-être reconsidérer cette position.

Pour info, le problème de suivi de cette fonctionnalité est ici https://github.com/kubernetes/enhancements/issues/753 si les gens veulent suivre, nous avons un KEP, fait du prototypage (il y a une branche/vidéo POC ), doivent encore régler certains des détails de mise en œuvre avant qu'il ne soit dans un état implémentable.

Note latérale :
Google a mis à jour sa documentation Cloud SQL -> Connexion à partir de Google Kubernetes Engine , maintenant en plus du Connecting using the Cloud SQL Proxy Docker image vous pouvez Connecting using a private IP address
Donc, si vous êtes ici pour la même raison que je suis ici (à cause du cloud_sql_proxy), vous pouvez maintenant utiliser la nouvelle fonctionnalité d'IP privée

J'étais ici pour la même raison, cependant, notre Cloud SQL a été provisionné avant que cette fonctionnalité ne soit prête. J'ai combiné les suggestions précédentes et je suis sorti ceci (probablement pas idéal, mais cela fonctionne) pour mon graphique de barre 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 "$@"

Serait-ce le bon moment pour une notion de conteneurs side-car dans Kubernetes et permettre le nettoyage des pods en fonction de la fin des conteneurs non-side-car ?

@Willux Je suis sur mon téléphone au

@krancour merci pour la mise à jour. J'ai dû manquer ce détail. Il n'y avait pas beaucoup d'activité ici ces derniers temps, alors je voulais juste m'assurer qu'il y avait quelque chose en cours :)

Pour référence, j'ai créé une version side-car cloud-sql-proxy de la solution de contournement de @jmillikin-stripe où un fichier dans un volume partagé communique l'état au side-car.

Cela fonctionne bien, mais c'est de loin le hack le plus méchant dans ma configuration 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

Quelqu'un à l'interne du projet peut-il commenter l'avancement de ce problème ?

Est-il juste de supposer que c'est la meilleure option pour ceux d'entre nous qui travaillent sur la version stable de GKE, qui ne rattrapera probablement pas Kubernetes 1.18 avant quelques mois au moins ?

@Datamance à ce stade, le KEP pour résoudre ce problème semble être en attente indéfiniment .

J'ai posté il y a quelque temps ce commentaire , qui était mon ancienne solution. Je n'essaie pas de pousser mes propres trucs ici, juste ce commentaire a été perdu dans les "100 commentaires de plus..." de github et j'ai pensé que le refaire surface pourrait être à nouveau utile.

@nrmitchi merci d'avoir republié ça. Je fais partie de ceux qui l'avaient négligé dans la mer de commentaires et cela ressemble à une solution fantastique à court terme.

Nous proposons une approche différente si vous ajoutez les éléments suivants à vos conteneurs Pod :

    securityContext:
            capabilities:
                   add:
                    - SYS_PTRACE

alors vous pourrez grep le Pid dans d'autres conteneurs, nous exécuterons ce qui suit à la fin de notre conteneur principal :
sql_proxy_pid=$(pgrep cloud_sql_proxy) && kill -INT $sql_proxy_pid

@krancour content que cela ait aidé. Si vous regardez le réseau dans ce référentiel, il y a quelques forks qui sont presque certainement dans un meilleur endroit que mon original, et qu'il serait peut-être préférable de construire/utiliser.

IIRC la fourchette de limonade-hq avait quelques ajouts utiles.

@nrmitchi , j'ai

Pouvez-vous brièvement commenter les conditions préalables éventuelles qui ne sont pas mentionnées dans le README ?

Par exemple, les images sur lesquelles sont basés vos side-cars nécessitent-elles une prise de conscience particulière de cette solution de contournement ? Par exemple, ont-ils besoin d'écouter sur un port spécifique un signal du contrôleur ? Ou peut-être doivent-ils inclure un certain shell (bash ?)

@krancour Je ferai

Il a été conçu à l'époque de telle sorte que les conteneurs en question n'avaient pas besoin de connaître la solution de contournement. Nous utilisions principalement des applications tierces dans le side-car (par exemple, je crois que stripe/veneur en faisait partie), et nous ne voulions pas bifurquer/modifier.

La seule exigence des side-cars est qu'ils écoutent correctement un signal SIGTERM, puis s'arrêtent. Je me souviens avoir eu quelques problèmes avec du code tiers exécuté dans des side-cars qui attendaient un signal différent et devaient être contournés, mais en réalité, le contrôleur aurait dû simplement autoriser la spécification du signal envoyé (c'est-à-dire SIGINT au lieu de SIGTERM).

Ils n'ont besoin d'écouter aucun port pour un signal, car le contrôleur utilise un exec pour signaler directement le processus principal du side-car. IIRC au moment où cette fonctionnalité a été copiée du code kubernetes car elle n'existait pas dans le client. Je crois que cela existe maintenant dans le client officiel et devrait probablement être mis à jour.

Nous proposons une approche différente si vous ajoutez les éléments suivants à vos conteneurs Pod :

    securityContext:
            capabilities:
                   add:
                    - SYS_PTRACE

alors vous pourrez grep le Pid dans d'autres conteneurs, nous exécuterons ce qui suit à la fin de notre conteneur principal :
sql_proxy_pid=$(pgrep cloud_sql_proxy) && kill -INT $sql_proxy_pid

@ruiyang2015 merci pour ce hack.
Si quelqu'un l'implémente, assurez-vous de comprendre les implications du partage d'un processus entre les conteneurs

@nrmitchi

utilise un exec pour signaler directement le processus principal du side-car

C'est en partie pourquoi j'ai demandé... Je suppose, en particulier, que je me demande si cela ne fonctionne pas pour les conteneurs basés sur des images qui sont construites FROM scratch .

@krancour Fair point, je ne suis jamais allé le tester avec des containers qui étaient hors de scratch . En regardant le code (ou ma version d'origine; cela aurait pu changer dans forked), il semble qu'il va dépendre de bash , mais devrait pouvoir être modifié.

ça va dépendre de bash, mais devrait pouvoir être modifié

Bien sûr, mais tant qu'il s'exécute, cela dépendra toujours d'un binaire présent dans le conteneur et pour un conteneur de travail, il n'y a rien là-bas, sauf ce que vous y mettez explicitement. ??

Compte tenu de cette limitation, je ne peux pas l'utiliser pour un cas d'utilisation où les conteneurs en cours d'exécution pourraient être totalement arbitraires et spécifiés par un tiers. Oh-- et j'ai aussi des conteneurs Windows en jeu.

Je vais mentionner ce que je vais régler à la place. C'est probablement trop lourd pour la plupart des cas d'utilisation, mais je le mentionne au cas où le cas d'utilisation de quelqu'un d'autre serait suffisamment similaire au mien pour s'en tirer...

Je peux me permettre le luxe de simplement _supprimer_ un pod dont le conteneur "principal" est sorti, tant que j'enregistre d'abord l'état de sortie. Je vais donc finir par écrire un contrôleur qui surveillera l'achèvement de certains conteneurs désignés (via une annotation), enregistrera son succès ou son échec dans une banque de données qui suit déjà l'état du "travail", puis supprimera entièrement le pod.

Pour faire bonne mesure, je mettrai probablement un peu de retard sur la suppression du pod pour maximiser les chances de mon agrégation de journaux central d'obtenir les dernières lignes de la sortie du conteneur principal avant qu'il ne soit torpillé.

Lourd, mais peut fonctionner pour certains.

@krancour Tout à fait vrai. Tel quel, le contrôleur ne fonctionnera pas pour des bases d'utilisation arbitraires. Honnêtement, je ne suis jamais revenu en arrière et j'ai essayé d'abstraire une partie de la mise en œuvre pour prendre en charge d'autres cas, car je pensais vraiment que le KEP mentionné précédemment aurait été fusionné et aurait rendu le besoin de cette fonctionnalité discutable.

Étant donné que ce problème date d'environ 4 ans, que le KEP n'est encore allé nulle part et que l'état de l'art est un script shell inline hacky remplaçant chaque point d'entrée, j'ai décidé de codifier le hack "standard" (pierres tombales dans un volume partagé ) dans un binaire Go qui peut être facilement intégré dans des images de conteneur à l'aide d'une construction en plusieurs étapes.

https://github.com/karlkfi/kubexit

Il y a plusieurs façons de l'utiliser :

  1. Intégrez-le à vos images
  2. Chargez-le latéralement à l'aide d'un conteneur d'initialisation et d'un volume éphémère.
  3. Provisionnez-le sur chaque nœud et chargez-le latéralement dans des conteneurs à l'aide d'un montage de liaison hôte

Edit : v0.2.0 prend désormais en charge les « dépendances de naissance » (démarrage différé) et les « dépendances de mort » (auto-terminaison).

Commentaire Drive-by : cela ressemble exactement à https://github.com/kubernetes/enhancements/issues/753

@vanzin comme cela a été noté précédemment , que KEP est en attente indéfinie.

Mon cas d'utilisation est que Vault fournit des informations d'identification pour qu'un CronJob s'exécute. Une fois la tâche terminée, le side-car Vault est toujours en cours d'exécution avec le travail en attente et cela déclenche le système de surveillance en pensant que quelque chose ne va pas. C'est dommage ce qui est arrivé au KEP.

Cette page vous a été utile?
0 / 5 - 0 notes