Kubernetes: Melhor suporte para contêineres secundários em trabalhos em lote

Criado em 19 mai. 2016  ·  116Comentários  ·  Fonte: kubernetes/kubernetes

Considere um trabalho com dois contêineres - um que faz o trabalho e depois termina, e outro que não foi projetado para sair explicitamente, mas fornece algum tipo de funcionalidade de suporte, como registro ou coleta de métricas.

Que opções existem para fazer algo assim? Quais opções devem existir?

Atualmente, o trabalho continuará em execução enquanto o segundo contêiner continuar em execução, o que significa que o usuário deve modificar o segundo contêiner de alguma forma para detectar quando o primeiro é concluído para que ele também possa sair sem problemas.

Esta pergunta foi feita no Stack Overflow há algum tempo sem uma resposta melhor do que modificar o segundo contêiner para ser mais ciente do Kubernetes, o que não é o ideal. Outro cliente recentemente mencionou isso para mim como um ponto problemático para eles.

@ kubernetes / goog-control-plane @erictune

arebatch areworkload-apjob kinfeature lifecyclfrozen prioritimportant-longterm siapps sinode

Comentários muito úteis

Para referência, aqui está a loucura do bash que estou usando para simular o comportamento desejado do sidecar:

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 comentários

/sub

Também usar um problema de vivacidade, conforme sugerido aqui, http://stackoverflow.com/questions/36208211/sidecar-containers-in-kubernetes-jobs não funciona, pois o pod será considerado com falha e o trabalho geral não será considerado bem-sucedido.

Que tal declararmos uma sondagem de sucesso do job para que o Job possa sondá-la para detectar o sucesso em vez de esperar que o pod retorne 0.
Assim que a análise retornar com sucesso, o pod pode ser encerrado.

Pode sondar executado em um contêiner que já saiu, ou haveria
ser uma corrida onde está sendo demolido?

Outra opção é designar certos códigos de saída como tendo um significado especial.

Tanto "sucesso para o pod inteiro" ou "falha para o pod inteiro" são ambos
útil.

Isso precisaria estar no objeto Pod, portanto, é uma grande mudança na API.

Na quinta-feira, 22 de setembro de 2016 às 13h41, Ming Fang [email protected] escreveu:

Que tal declararmos um teste de sucesso do trabalho para que o trabalho possa sondá-lo para
detectar o sucesso em vez de esperar que o pod retorne 0.

Assim que a análise retornar com sucesso, o pod pode ser encerrado.

-
Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/kubernetes/kubernetes/issues/25908#issuecomment -249021627,
ou silenciar o tópico
https://github.com/notifications/unsubscribe-auth/AHuudjrpVtef6U35RWRlZr3mDKcCRo7oks5qsugRgaJpZM4IiqQH
.

@erictune Bom argumento; não podemos sondar um contêiner encerrado.

Podemos designar um contêiner específico no pod como o contêiner de "conclusão" para que, quando esse contêiner sair, possamos dizer que o trabalho está concluído?

Os contêineres de sidecar tendem a ter vida longa para coisas como envio de toras e monitoramento.
Podemos forçar o encerramento deles assim que o trabalho for concluído.

Podemos designar um contêiner específico no pod como o contêiner de "conclusão" para que, quando esse contêiner sair, possamos dizer que o trabalho está concluído?

Você olhou para este ponto de aqui, onde você basicamente não define .spec.completions e assim que o primeiro contêiner terminar com o código de saída 0, o trabalho estará concluído.

Os contêineres de sidecar tendem a ter vida longa para coisas como envio de toras e monitoramento.
Podemos forçar o encerramento deles assim que o trabalho for concluído.

Pessoalmente, eles me parecem mais RS do que um trabalho, mas essa é minha opinião pessoal e, o mais importante, não sei todos os detalhes de sua configuração.

Geralmente, há as seguintes discussões https://github.com/kubernetes/kubernetes/issues/17244 e https://github.com/kubernetes/kubernetes/issues/30243 que também tocam neste tópico.

@soltysh o link que você enviou acima, o ponto 3 faz referência à conclusão de pod e não à conclusão de contêiner.

Os dois contêineres podem compartilhar um emptyDir, e o primeiro contêiner grava uma mensagem "Estou saindo agora" em um arquivo e o outro pode sair quando vir essa mensagem.

@erictune Eu tenho um caso de uso que acho que se encaixa neste balde e espero que você possa me guiar na direção certa, uma vez que não parece haver nenhuma maneira oficialmente recomendada para resolver esse problema.

Estou usando a biblioteca client-go para codificar tudo abaixo:

Então, eu tenho um trabalho que basicamente executa uma ferramenta em um pod de um contêiner. Assim que a execução da ferramenta termina, ela deve produzir um arquivo de resultados. Não consigo capturar este arquivo de resultados porque, assim que a ferramenta termina de funcionar, o pod exclui e eu perco o arquivo de resultados.

Consegui capturar este arquivo de resultados se usasse HostPath como VolumeSource e, como estou executando o minikube localmente, o arquivo de resultados é salvo em minha estação de trabalho.

Mas, eu entendo que não é recomendado e é ideal para contêineres de produção. Então, usei EmptyDir conforme sugerido acima. Mas, novamente, se eu fizer isso, não posso realmente capturá-lo porque ele é excluído com o próprio pod.

Portanto, devo resolver meu problema usando o padrão de contêiner de sidecar também?

Basicamente, faça o que você sugeriu acima. Inicie 2 contêineres no pod sempre que o trabalho for iniciado. 1 contêiner executa o trabalho e, assim que o trabalho é concluído, descarta uma mensagem que é captada pelo outro contêiner que, em seguida, pega o arquivo de resultado e o armazena em algum lugar?

Não consigo entender por que precisaríamos de 2 contêineres em primeiro lugar. Por que o contêiner de tarefas não pode fazer tudo isso sozinho? Ou seja, termine o trabalho, salve o arquivo de resultados em algum lugar, acesse / leia e armazene em algum lugar.

@anshumanbh, eu sugiro que você:

  1. usar um armazenamento persistente, você salva o arquivo de resultado
  2. use hostPath mount, que é quase o mesmo que 1, e você já experimentou
  3. faça upload do arquivo de resultado para um local remoto conhecido (s3, google drive, dropbox), geralmente qualquer tipo de drive compartilhado

@soltysh Não quero que o arquivo seja armazenado permanentemente. Em cada corrida, eu só quero comparar esse resultado com o último resultado. Então, a maneira como eu estava pensando em fazer isso era me comprometer com um repositório github a cada execução e, em seguida, fazer uma comparação para ver o que mudou. Então, para fazer isso, eu só preciso armazenar o resultado temporariamente em algum lugar para que eu possa acessá-lo e enviá-lo ao Github. Faz sentido?

@anshumanbh perfeitamente claro, e ainda assim não se enquadra na categoria de contêiner de carro lateral. Tudo o que você deseja realizar atualmente é possível com o que os empregos proporcionam.

@soltysh então considerando que quero ir para a opção 3 da lista que você sugeriu acima, como eu faria para implementá-la?

O problema que estou enfrentando é que, assim que o trabalho termina, o contêiner sai e eu perco o arquivo. Se eu não tiver o arquivo, como faço o upload para um drive compartilhado como S3 / Google Drive / Dropbox? Não posso modificar o código do trabalho para carregá-lo automaticamente em algum lugar antes de encerrar, então, infelizmente, eu teria que primeiro executar o trabalho e depois salvar o arquivo em algum lugar.

Se você não pode modificar o código do trabalho, você precisa envolvê-lo de forma a poder fazer o upload do arquivo. Se o que você está trabalhando é uma imagem, basta estendê-la com o código de cópia.

@soltysh sim, faz sentido. Eu poderia fazer isso. No entanto, a próxima pergunta que tenho é - suponha que eu precise executar vários trabalhos (pense nisso como executar ferramentas diferentes) e nenhuma dessas ferramentas possui a parte de upload incorporada. Então, agora, eu teria que construir esse wrapper e estender cada uma dessas ferramentas com a parte de upload. Existe uma maneira de escrever o invólucro / extensão uma vez e usá-lo para todas as ferramentas?

O padrão do carro lateral não caberia nesse caso?

Sim, poderia. Embora eu tente com vários recipientes dentro do mesmo pod, padrão. Uau. seu pod está executando o contêiner de trabalho e ao lado de outro adicional, aguardando a saída e fazendo o upload. Não tenho certeza de como isso é viável, mas você já pode tentar.

O reconhecimento suave do ping - sidecar tornaria o gerenciamento de proxies de microsserviço, como o Envoy, muito mais agradável. Existe algum progresso para compartilhar?

O estado atual das coisas é que cada contêiner precisa de ferramentas agrupadas para coordenar os tempos de vida, o que significa que não podemos usar imagens de contêiner de upstream diretamente. Isso também complica significativamente os modelos, pois temos que injetar argv e pontos de montagem extras.

Uma sugestão anterior era designar alguns contêineres como contêineres de "conclusão". Eu gostaria de propor o oposto - a capacidade de designar alguns contêineres como "side-cars". Quando o último contêiner não secundário em um pod termina, o pod deve enviar TERM para os carros secundários. Isso seria análogo ao conceito de "thread de segundo plano" encontrado em muitas bibliotecas de threading, por exemplo, Thread.daemon do Python.

Configuração de exemplo, quando o contêiner main termina, o kubelet mataria 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"]

Para referência, aqui está a loucura do bash que estou usando para simular o comportamento desejado do sidecar:

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

Eu gostaria de propor o oposto - a capacidade de designar alguns contêineres como "side-cars". Quando o último contêiner não secundário em um pod termina, o pod deve enviar TERM para os sidecars.

@ jmillikin-stripe Gosto dessa ideia, embora não tenha certeza se segue o princípio de tratar alguns contêineres de maneira diferente em um Pod ou introduzir dependências entre eles. Vou adiar para @erictune para a chamada final.

Embora você tenha verificado o número 17244, esse tipo de solução se ajusta ao seu caso de uso? Isso é o que @erictune mencionou alguns comentários antes:

Outra opção é designar certos códigos de saída como tendo um significado especial.

@ jmillikin-stripe Gosto dessa ideia, embora não tenha certeza se segue o princípio de tratar alguns contêineres de maneira diferente em um Pod ou introduzir dependências entre eles. Vou adiar para @erictune para a chamada final.

Acho que o Kubernetes pode precisar ser flexível quanto ao princípio de não tratar os contêineres de maneira diferente. Nós (Stripe) não queremos reformar código de terceiros, como o Envoy, para ter ganchos de ciclo de vida no estilo Lampreia, e tentar adotar uma inversão executiva no estilo Envelope seria muito mais complexo do que deixar Kubelet encerrar carros secundários específicos.

Embora você tenha verificado o número 17244, esse tipo de solução se ajusta ao seu caso de uso? Isso é o que @erictune mencionou alguns comentários antes:

Outra opção é designar certos códigos de saída como tendo um significado especial.

Eu me oponho fortemente a Kubernetes ou Kubelet interpretando códigos de erro em uma granularidade mais fina do que "zero ou diferente de zero". O uso de números mágicos de código de saída por Borglet era um recurso desagradável e seria muito pior no Kubernetes, onde uma imagem de contêiner específica poderia ser um "principal" ou "secundário" em pods diferentes.

Talvez ganchos de ciclo de vida adicionais fossem suficientes para resolver isso?

Poderia ser:

  • PostStop: com um meio de acionar eventos de ciclo de vida em outros contêineres no pod (ou seja, parada de gatilho)
  • PeerStopped: sinaliza que um contêiner "par" no pod morreu - possivelmente com o código de saída como argumento

Isso também pode definir um meio de definir políticas personalizadas para reiniciar um contêiner - ou mesmo iniciar contêineres que não são iniciados por padrão para permitir algum encadeamento de contêineres (quando o contêiner a termina, inicia o contêiner b)

Também faltando isso. Executamos um trabalho a cada 30 minutos que precisa de um cliente VPN para conectividade, mas parece haver muitos casos de uso em que isso pode ser muito útil (por exemplo, coisas que precisam do proxy kubectl). Atualmente, estou usando jobSpec.concurrencyPolicy: Replace como uma solução alternativa, mas é claro que isso só funciona se a.) Você pode viver sem execuções paralelas de trabalho e b.) O tempo de execução do trabalho é menor do que o intervalo de agendamento.

EDITAR: no meu caso de uso, seria completamente suficiente ter alguma propriedade na especificação do trabalho para marcar um contêiner como o de encerramento e fazer com que o trabalho monitore aquele para o status de saída e elimine os restantes.

Eu também preciso disso. Em nosso caso, é um trabalho que usa o contêiner cloudsql-proxy como um serviço secundário.

Que tal possivelmente adicionar uma anotação que mapeie para o nome do contêiner "principal" no pod? Dessa forma, a especificação do pod não precisa ser modificada de forma alguma.

Pela natureza de como os pods são projetados, este parece ser um caso de uso muito comum. @soltysh @erictune algum plano de trabalhar nisso em breve? Fico feliz em ajudar sempre que possível :)

Também precisa desse recurso. Para nosso caso de uso :
o pod A tem para os contêineres

  • container A1 : um
  • contêiner A2 : contêiner secundário, que apenas segue os registros do arquivo para o stdout

O que eu quero : quando o contêiner A1 for concluído com sucesso, o pod A será concluído com sucesso. Podemos apenas rotular o contêiner A1 como o contêiner principal , quando o contêiner principal sai, o pod sai? @erictune (Esta ideia também é descrita por @mingfang )

Olá pessoal, vejo que este problema está aberto há um mês. Quais são as novidades sobre isso? Temos um caso de uso em que queremos executar um trabalho. O trabalho executa um contêiner main com alguns side-car containers . Queremos que o trabalho saia quando o contêiner main sair. É o estado da arte compartilhar file para enviar signal entre os contêineres?

Eu não me importaria de começar algum trabalho nisso, gostaria de saber se alguém poderia revisar os próximos PRs se eu fizer isso (talvez depois do kubecon).

cc @erictune @ a-robinson @soltysh

@andrewsykim que abordagem você tomaria. Além disso, sei que estou adicionando aqui, o que seria necessário para adicionar suporte para dependências. Como o contêiner main , não deve iniciar até que os carros laterais sejam inicializados

Como o contêiner principal, não deve ser iniciado até que os sidecars tenham inicializado

Acho que este caso não é um problema, pois main deve ser capaz de verificar quando o sidecar é inicializado (ou usar um teste de prontidão). Este não é o caso para este problema porque main teria saído :)

Acabei escrevendo um script simples que observa a API do kubernetes e encerra trabalhos com uma anotação correspondente e cujo contêiner principal foi encerrado. Não é perfeito, mas atende às necessidades básicas. Posso compartilhar se as pessoas estiverem interessadas.

@ajbouh Eu pessoalmente agradeceria se você compartilhasse isso como um ponto principal. Eu estava prestes a escrever algo semelhante

@nrmitchi Aqui está um resumo do yaml que escrevi. É muito script de shell, mas talvez seja um bom ponto de partida para você, em termos de quais APIs usar e como obter algo que funcione. Posso responder a perguntas sobre o que está fazendo, se você tiver alguma dúvida.

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

Tenho o mesmo caso de uso de proxy do Cloud SQL que @mrbobbytables. Para se conectar com segurança ao Cloud SQL, é recomendado usar o proxy, mas esse proxy não é encerrado quando o trabalho é concluído, o que resulta em hacks malucos ou monitoramento parecido com o seguinte. Existe algum caminho a seguir nisso?

image

@ amaxwell01 Com relação ao envolvimento do Cloud SQL Proxy nisso, eu abri um problema com o Google que você poderia https://issuetracker.google.com/issues/70746902 (editar: e lamento algumas frases que usei lá no calor do momento; infelizmente não posso editá-lo)

Obrigado @abevoelker , estou acompanhando sua postagem aí. Além disso, seus comentários me fizeram rir 👍

Também somos impactados por este problema.
Temos vários comandos de gerenciamento django em nossos microsserviços que podem ser executados em cronjobs k8s, mas não têm sucesso por causa do arquivo secundário do cloudsqlproxy que não para na conclusão do trabalho.
Alguma atualização sobre quando poderíamos ter uma solução?
O padrão de contêiner secundário é usado cada vez mais e muitos de nós não serão capazes de usar cronjobs e jobs do k8s até que isso seja resolvido.

Só queria dar meu +1 por isso. Tenho o mesmo problema de GCE Cloud SQL Proxy que todos os outros. Isso está me matando ... a implantação do leme falha, o que por sua vez falha na aplicação do terreno.

Eu realmente gostaria de ver algum tipo de resolução sobre isso ... apenas de @ajbouh parece que poderia funcionar ... mas caramba, isso é hacky.

Para qualquer outra pessoa que requeira cloudsql-proxy , caberia em seu caso de uso executar cloudsql-proxy como um DaemonSet? No meu caso, eu tinha uma implantação persistente e um CronJob que exigia o proxy, então fazia sentido desanexá-lo de pods individuais e, em vez disso, anexar uma instância por nó.

Sim,

Decidimos remover os sidecars de proxy do cloudsql e construímos um pool de
proxies cloudsql em seu namespace central, funciona perfeitamente e permite
mova a escalabilidade e implementações mais fáceis.
Agora podemos executar jobs e cronjobs sem nenhum problema.

Na quarta-feira, 7 de fevereiro de 2018 às 9h37, Rob Jackson [email protected]
escreveu:

Para qualquer outra pessoa que necessite do cloudsql-proxy, seria adequado para o seu caso de uso
executar o cloudsql-proxy como um DaemonSet? No meu caso, tive um persistente
Implantação e um CronJob exigindo o proxy, então fazia sentido desanexar
a partir de pods individuais e, em vez disso, anexe uma instância por nó.

-
Você está recebendo isto porque comentou.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/kubernetes/kubernetes/issues/25908#issuecomment-363710890 ,
ou silenciar o tópico
https://github.com/notifications/unsubscribe-auth/ACAWMwetx6gA_SrHL_RRbTMJVOhW1FKLks5tSW7JgaJpZM4IiqQH
.

Interessante, usar um deamonset parece uma boa opção. @ RJacksonm1 & @devlounge - como a descoberta do proxy sql em nuvem funciona ao usar daemonsets?

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

Basicamente envolve o uso de algo assim para obter o ip do host:

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

@ RJacksonm1 - Você fez alguma coisa especial para que hostPort funcionasse? Estou constantemente recebendo connection refused ao usá-lo em conjunto com a abordagem fieldPath: spec.nodeName 🤔

Editar: verifiquei se spec.nodeName está passando corretamente e estou no GKE v1.9.2-gke.1

@cvallance Eu tenho um serviço configurado para expor o DaemonSet, que meu aplicativo pode acessar via DNS. Isso não garante que o aplicativo se comunique com a instância cloudsql-proxy em execução no mesmo host que ele, mas garante que cloudsql-proxy será escalado com o cluster como um todo (originalmente eu tinha o proxy como uma implantação e um HorizontalPodAutoscaler, mas descobri que ele aumentou / diminuiu muito, causando MySQL has gone away erros no aplicativo). Acho que isso não está no verdadeiro espírito de um DaemonSet ... 🤔

@ RJacksonm1 - funcionou com hostPort e spec.nodeName ... agora eles vão se conectar diretamente ao DaemonSet em seu nó 😄

O comando CloudSql Proxy não funciona:
-instances={{ .Values.sqlConnectionName }}=tcp:{{ .Values.internalPort }}
Trabalhando:
-instances={{ .Values.sqlConnectionName }}=tcp:0.0.0.0:{{ .Values.internalPort }}

🤦‍♂️

Há algo que possamos fazer para obter um pouco de tração sobre esse problema?
Está aberto há quase 2 anos e ainda só temos soluções alternativas

Eu suspeito que mesmo se eu me oferecer para implementar isso, eu não serei capaz, pois isso precisa de alguma aprovação do pessoal interno sobre qual solução implementar, mudanças de API, etc.

Posso fazer alguma coisa para ajudar a concluir isso?

Para referência, fiz uma versão do arquivo secundário cloud-sql-proxy da solução alternativa de @jmillikin-stripe, em que um arquivo em um volume compartilhado comunica o estado ao arquivo secundário.

Funciona bem, mas é de longe o hack mais desagradável em minha configuração 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

Alguém interno do projeto pode comentar sobre o andamento desse problema?

Mesmo problema aqui

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

Faria sentido permitir que os usuários especifiquem (por nome) os contêineres em um trabalho que desejam ver concluído com êxito, a fim de marcar o pod de trabalho como concluído (com outros contêineres parados), assim:

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

Ou seja, o pod seria executado, espere até que my-container saia com sucesso e, em seguida, apenas encerre cloudsql-proxy .

EDIT: Rolando para cima este tópico, agora vejo que isso foi proposto anteriormente. O @erictune ou outra pessoa pode reelaborar sobre por que isso não funcionaria?

sim, acho que seria perfeito. Apenas algo que permite que você observe o status do trabalho e continue o pipeline depois de concluído

Sim, isso seria perfeito.

Eu gosto dessa ideia @jpalomaki

Uma preocupação que tenho com a abordagem de resolver isso puramente dentro do controlador de trabalho é que o pod continuará a ser executado após a conclusão do trabalho. Atualmente, o Pod entra na fase Terminated e o Node pode liberar esses recursos.

Você poderia fazer com que o controlador de trabalho excluísse o pod quando o controlador decidir que está feito, mas isso também seria diferente do comportamento atual, em que o registro do pod encerrado permanece no servidor de API (sem ocupar recursos do nó).

Por essas razões, parece-me mais limpo abordar isso no nível da API do Pod, se é que o faz. O Nó é a única coisa que deve alcançar e eliminar os containers individuais porque os containers de "conclusão" com os quais você se preocupa já foram encerrados. Isso pode assumir a forma de uma API de nível de pod, que permite especificar a noção de quais contêineres devem ser aguardados, ou uma API de nível de pod para permitir que agentes externos (por exemplo, o controlador de job) force o encerramento do pod sem realmente excluí-lo o Pod.

Também estou procurando uma solução para fazer upload de arquivos produzidos por um contêiner se o contêiner do processador foi encerrado com êxito.

Não tenho certeza se entendi o argumento de @mingfang contra fazer o contêiner secundário observar o status do contêiner por meio da API k8s para saber se e quando começar a enviar ou sair. Quando o contêiner de arquivo secundário sai do pod e o job deve ser encerrado com sucesso.

Outro pensamento, que parece um hack, mas eu gostaria de saber o quão ruim seria transformar o contêiner de produção de dados em um contêiner init e ter o contêiner de upload de dados (que não precisaria mais ser um contêiner secundário ) iniciado automaticamente somente depois que o contêiner do processador foi encerrado com êxito. No meu caso, eu também precisaria de um contêiner de download de dados como o primeiro contêiner de inicialização, para fornecer dados ao contêiner de processamento. Se essa for uma ideia particularmente ruim, eu adoraria saber o porquê.

Promover o sidecar a um conceito k8s de primeira classe não resolveria esse problema? O Kubelet poderá encerrar o pod se todos os contêineres em execução nele estiverem marcados como arquivos secundários.

FWIW, eu contornei isso apenas implantando o proxy do Cloud SQL como uma implantação regular ( replicas: 1 ) e fiz meus Job e CronJob usá-lo por meio de um type: ClusterIP serviço. Os trabalhos terminam bem agora.

Eu adoraria uma posição oficial sobre isso.

Se não vamos ter algum suporte da API, devemos pelo menos ter as soluções alternativas oficialmente documentadas para que as pessoas saibam o que fazer quando encontrarem esse problema.

Não tenho certeza de quem enviar ping ou como chamar a atenção para isso ...

Seria muito bom que isso fosse resolvido. Além de o trabalho nunca desaparecer, o status geral do pod está aparentemente incorreto:

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 

O que é interessante é observar o Estado e Pronto para o initContainer (Terminado, Concluído, Pronto = Verdadeiro) e o contêiner do aplicativo principal (Terminado, Concluído, Pronto = Falso). Isso parece estar levando ao estado de Pod Ready de False - na minha opinião, incorretamente. Isso está fazendo com que este pod seja sinalizado como tendo um problema em nossos painéis.

Tenho outro cliente que está enfrentando esse problema especificamente com o proxy do Cloud SQL. Eles gostariam de não ter que executá-lo como um serviço persistente para permitir que os cron jobs acessem o Cloud SQL.

@yuriatgoogle A solução mais fácil ainda é bash e emptyDir "mágica", como: https://github.com/kubernetes/kubernetes/issues/25908#issuecomment -365924958

É um hack, mas terá que servir. Sem querer ofender @phidah.

Definitivamente, parece que muitas pessoas querem isso por vários motivos. Seria bom ter algum apoio oficial. Tive o mesmo problema com nosso próprio sidecar e trabalhos, então fiz o sidecar usar a kube api para observar o status do outro contêiner no pod. Se encerrasse com completed o sidecar sairia 0, se errou que o sidecar sairia 1. Talvez não seja a solução mais elegante, mas funcionou sem precisar que nossos desenvolvedores mudassem muito. o código está aqui se alguém estiver interessado: https://github.com/uswitch/vault-creds/blob/master/cmd/main.go#L132.

Isso me lembra uma música do Gorillaz M1 A1 ...

Olá? Hellooooooo? Tem alguem ai

Sim, vamos conseguir um pouco de tração +1

Portanto, as soluções propostas que requerem mudanças upstream são:

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

Solução temporária para sidecar, um hacky (mas funciona):

  1. Por cloudsql-proxy sidecar por @phidah

Eu adoraria ver a resposta do mantenedor do Kubernetes em relação às soluções propostas e dê-nos uma recomendação sobre como resolver esse caso de uso usando a versão existente do Kubernetes. Obrigado!

Acabei de descobrir este thread depois de passar um dia tentando escrever um agente de log que carregaria o stdout / stderr da minha tarefa de renderização para um banco de dados, apenas para descobrir que a presença do agente no pod significaria que o trabalho nunca terminaria.

Das sugestões dadas acima, eu gosto do 'sidecar: true' o melhor, pois é simples e direto ao ponto - muito compreensível para um desenvolvedor como eu. Eu provavelmente o chamaria de algo um pouco diferente, já que 'sidecar' é realmente um padrão de design de pod que se aplica a mais do que apenas trabalhos e implica outras coisas além dos requisitos de conclusão. Se você me desculpar, eu provavelmente o chamaria de algo como 'ambiente: verdadeiro' para indicar que o trabalho pode ser considerado concluído, mesmo se essa tarefa ainda estiver em execução. Outras palavras podem ser 'auxiliar' ou 'suporte'.

Também me deparei com esse problema, para o mesmo fluxo de trabalho que muitos outros descreveram (um contêiner de arquivo secundário que é usado para conexões proxy ou coleta de métricas e não tem propósito depois que o outro contêiner no pod é encerrado com êxito).

Uma sugestão anterior era designar alguns contêineres como contêineres de "conclusão". Eu gostaria de propor o oposto - a capacidade de designar alguns contêineres como "side-cars". Quando o último contêiner não secundário em um pod termina, o pod deve enviar TERM para os sidecars.

Esta é minha solução ideal também. Eu poderia sugerir SIGHUP em vez de SIGTERM - este parece ser o caso de uso exato para o qual a semântica de SIGHUP é relevante! - mas ficaria feliz com qualquer um.

Do jeito que está, a execução de jobs no Kubernetes requer o patch manual de imagens do contêiner upstream para lidar com a comunicação entre contêineres específica do Kubernetes quando o contêiner não secundário terminar ou intervir manualmente para encerrar o arquivo secundário de cada trabalho para que o pod zumbi não andar por aí. Nenhum dos dois é particularmente agradável.

Eu estaria disposto a fazer um patch para isso, mas gostaria de alguma orientação de @ kubernetes / sig-apps-feature-requests antes de me aprofundar em qualquer código. Podemos adicionar um campo sidecar à especificação do pod para fazer isso funcionar? Hesito em fazer qualquer alteração nas especificações do pod sem ter certeza de que o queremos. Talvez use anotações por enquanto?

@andrewsykim Estou acompanhando esse problema há algum tempo (só não tentei resolver isso sozinho), mas gostaria de sugerir apenas o uso de anotações por enquanto.

Meu raciocínio é o seguinte:

  • Esse problema existe há quase 2 anos e não atraiu muita atenção do núcleo do kubernetes. Portanto, se esperarmos para fazer alterações nas especificações do pod, ou esperarmos por uma entrada direta, provavelmente ficaremos esperando por um longo tempo.
  • É muito mais fácil chamar a atenção para um RP viável do que para um problema antigo.
  • Deve ser muito bom mudar uma abordagem de anotação para usar um atributo de pod no futuro

Pensamentos?

Olá, conversei com alguns dos caras do sig-apps da kubecon sobre esse problema. Basicamente, não é algo que está em seu roteiro imediato, mas é algo que eles acham que é um caso de uso válido. Eles estão muito abertos a alguém da comunidade que está lidando com isso.

Eu criei um PR para uma proposta de melhoria para resolver isso, então espero que isso gere alguma discussão https://github.com/kubernetes/community/pull/2148.

Obrigado por colocar isso junto @Joseph-Irving! Parece que há mais detalhes que precisam ser resolvidos para isso, então vou adiar o trabalho até então :)

problema persistente a longo prazo :(

cc @ kow3ns @janetkuo

Sem querer complicar ainda mais o assunto, também seria útil ser capaz de executar um contêiner de estilo "sidecar" ao lado de initContainers .

Meu caso de uso é semelhante ao das pessoas aqui, eu preciso executar o proxy sql em nuvem ao mesmo tempo que um initContainer que executa migrações de banco de dados. Como initContainers são executados um de cada vez, não consigo ver uma maneira de fazer isso, exceto para executar o proxy como uma implantação + serviço, mas espero que haja outros casos de uso (gerenciamento de log, etc.) onde isso não seria um trabalho adequado por aí.

@mcfedr Existe uma proposta de aprimoramento razoavelmente ativa que pode apreciar essa observação sobre o comportamento do container init. Não está claro para mim se isso está no escopo desta proposta ou uma melhoria relacionada, mas acho que está suficientemente relacionado que faz sentido levantar para consideração.

Não obstante os possíveis problemas de implementação / compatibilidade, seu modelo ideal seria presumivelmente que contêineres init secundários executassem simultaneamente com contêineres init não secundários, que continuam a ser executados sequencialmente como agora, e que os contêineres secundários terminassem antes da inicialização dos contêineres de sequência principal.

pelo que vale a pena, eu também gostaria de expressar a necessidade de ignorar carros secundários ainda em execução como CloudSQL Proxy et.al.

Consegui matar o contêiner cloudsql após 30 segundos, pois sei que meu script não demoraria tanto. Aqui está minha abordagem:

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

E está funcionando para mim.
Vocês veem alguma desvantagem nessa abordagem?

Como acho que eles estão relacionados e também podem ser facilmente adaptados para CronJobs, esta é minha solução: https://github.com/GoogleCloudPlatform/cloudsql-proxy/issues/128#issuecomment -413444029

Ele é baseado em uma das soluções alternativas postadas aqui, mas usa preStop porque é destinado a implantações. Prender o sidecar funcionaria maravilhosamente bem.

Seguindo esta questão. Também usando o contêiner cloud_sql_proxy como carro lateral no cronjob
Usei a implementação de tempo limite de @stiko

Apenas adicionar à conversa a solução proposta por @ygen0211 sobre o uso de Substituir é uma solução decente por enquanto, certifique-se de verificar se você se deparar com esse problema como eu.

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

Temos este KEP aprovado provisoriamente https://github.com/kubernetes/community/pull/2148 , ainda temos algumas coisas que precisamos concordar, mas esperamos que chegue a um ponto onde o trabalho possa começar em relativamente breve . Observação Os KEPs serão transferidos para https://github.com/kubernetes/enhancements no dia 30, portanto, se você quiser acompanhar, estará lá.

Até que o suporte secundário chegue, você pode usar uma solução no nível do docker, que pode ser facilmente removida mais tarde: https://gist.github.com/janosroden/78725e3f846763aa3a660a6b2116c7da

Ele usa um contêiner privilegiado com um soquete docker montado e rótulos Kubernetes padrão para gerenciar contêineres no trabalho.

Estávamos tendo o mesmo problema com o Istio e seu carro lateral, e o que decidimos fazer é excluir o pod via curl + gancho preStop como este

dê ao seu trabalho uma regra RBAC mínima 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

e POD_NAME e POD_NAMESPACE ao seu ENV assim

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

e, finalmente, adicione um 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"

Meio confuso, mas um pouco mais seguro e menos complicado do que tentar matar o contêiner docker certo.

Só estou jogando isso aqui, mas eu montei um controlador há um tempo que deveria monitorar as mudanças de pod em execução e enviar um SIGTERM para contêineres secundários de forma adequada. Definitivamente não é o mais robusto e, honestamente, não o uso há algum tempo, mas pode ajudar.

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

Agradecimentos a @jpalomaki em https://github.com/kubernetes/kubernetes/issues/25908#issuecomment -371469801 pela sugestão de executar cloud_sql_proxy como uma implantação com ClusterIP serviço e para @ cvallance em https://github.com/kubernetes/kubernetes/issues/25908#issuecomment -364255363 pela dica sobre a configuração de tcp:0.0.0.0 no parâmetro cloud_sql_proxy instances para permitir não - conexões locais com o processo. Juntos, eles tornaram fácil permitir que os cron jobs usem o proxy.

problema de longo prazo (nota para mim)

O mesmo problema. Procurando uma maneira ou documentos oficiais sobre como usar GKE cron job com Cloud SQL

Nota:
O Google atualizou seu Cloud SQL -> Conectando a partir da documentação Connecting using the Cloud SQL Proxy Docker image você pode Connecting using a private IP address
Então, se você está aqui pelo mesmo motivo que estou aqui (por causa do cloud_sql_proxy), você pode usar agora o novo recurso de IP privado

Nota:
O Google atualizou seu Cloud SQL -> Conectando a partir da documentação Connecting using the Cloud SQL Proxy Docker image você pode Connecting using a private IP address
Então, se você está aqui pelo mesmo motivo que estou aqui (por causa do cloud_sql_proxy), você pode usar agora o novo recurso de IP privado

O recurso de IP privado parece precisar excluir todo o cluster e recriar um ........?

@cropse Isso só é necessário se seu cluster não for nativo de VPC.

Eu fiz uma solução alternativa para este problema, não a ótima solução, mas funcionou, espero que isso ajude antes de adicionar o recurso, e VPC é uma maneira de errar, mas excluir todo o cluster ainda é doloroso.

Só para adicionar meus dois centavos: os testes de leme também quebram se a injeção de istio sidecar ocorre porque o pod nunca termina.

@dansiviter você pode verificar minha solução alternativa, eu já testei em meu projeto com o helm.

ansioso para ver isso implementado! :)

Temos o mesmo problema com trabalhos normais quando um proxy Istio é injetado nele. Acima disso, também queremos isso porque queremos executar trabalhos de CI com Prow.
por exemplo, contêiner de aplicativo Rails + contêiner de banco de dados secundário para fins de teste.

@cropse Obrigado. Não tentei, pois precisaríamos configurar isso para todos os testes. Estamos apenas permitindo que o pod (os testes do Helm não permitem o trabalho, infelizmente) falhe e contando com a inspeção manual do log até que o problema seja corrigido em longo prazo. No entanto, também está se tornando um problema para outros Jobs, então podemos ter reconsiderado essa posição.

Para sua informação, o problema de rastreamento desse recurso está aqui https://github.com/kubernetes/enhancements/issues/753 se as pessoas quiserem acompanhar, temos um KEP, fizemos alguns protótipos (há um branch / vídeo POC ), ainda precisa resolver alguns dos detalhes de implementação antes que esteja em um estado implementável.

Nota:
O Google atualizou seu Cloud SQL -> Conectando a partir da documentação Connecting using the Cloud SQL Proxy Docker image você pode Connecting using a private IP address
Então, se você está aqui pelo mesmo motivo que estou aqui (por causa do cloud_sql_proxy), você pode usar agora o novo recurso de IP privado

Eu estava aqui pelo mesmo motivo, no entanto, nosso Cloud SQL foi provisionado antes que esse recurso estivesse pronto. Combinei sugestões anteriores e obtive isso (provavelmente não é o ideal, mas funciona) para meu gráfico de leme do migrador dbmate.

      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 "$@"

Seria um bom momento para ter uma noção dos contêineres secundários no Kubernetes e permitir a limpeza do pod com base no término dos contêineres não secundários?

@Willux Estou no meu telefone atm, então é mais difícil localizar links para referência, mas o que você acabou de propor já está bem encaminhado.

@krancour obrigado pela atualização. Devo ter perdido esse detalhe. Não houve muita atividade acontecendo aqui ultimamente, então só queria ter certeza de que algo está acontecendo :)

Para referência, fiz uma versão do arquivo secundário cloud-sql-proxy da solução alternativa de @jmillikin-stripe, em que um arquivo em um volume compartilhado comunica o estado ao arquivo secundário.

Funciona bem, mas é de longe o hack mais desagradável em minha configuração 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

Alguém interno do projeto pode comentar sobre o andamento desse problema?

É justo presumir que esta é a melhor opção para aqueles de nós que trabalham no canal de lançamento estável do GKE, que provavelmente não alcançará o Kubernetes 1.18 por alguns meses, no mínimo?

@Datamance neste ponto, o KEP para resolver esse problema parece estar indefinidamente em espera .

Postei um tempo atrás este comentário , que era minha solução anterior. Não estou tentando forçar minhas próprias coisas aqui, apenas aquele comentário foi perdido nos "100 mais comentários ..." do github e percebi que ressurgir pode ser útil novamente.

@nrmitchi, obrigado por

Descobrimos uma abordagem diferente, se você adicionar o seguinte aos seus contêineres de pod:

    securityContext:
            capabilities:
                   add:
                    - SYS_PTRACE

então você será capaz de executar grep no Pid em outros contêineres, executaremos o seguinte no final do nosso contêiner principal:
sql_proxy_pid=$(pgrep cloud_sql_proxy) && kill -INT $sql_proxy_pid

@krancour feliz por ter ajudado. Se você olhar para a rede nesse repositório, há alguns garfos que estão quase definitivamente em um lugar melhor do que o original e podem ser melhores para construir / usar.

IIRC, o garfo limonada-hq tinha alguns acréscimos úteis.

@nrmitchi , estive

Você pode comentar brevemente sobre quaisquer pré-requisitos que possam existir e não sejam mencionados no README?

Por exemplo, as imagens nas quais seus carros laterais são baseados requerem algum conhecimento especial desta solução alternativa? Por exemplo, eles precisam ouvir em uma porta específica para um sinal do controlador? Ou talvez eles devam incluir um certo shell (bash?)

@krancour Vou começar minha resposta com uma observação de que esta solução foi escrita alguns anos atrás e minha memória pode estar um pouco enferrujada.

Ele foi projetado na época de forma que os contêineres em questão não precisassem estar cientes da solução alternativa. Estávamos usando principalmente aplicativos de terceiros em sidecar (por exemplo, acredito que stripe / veneur era um) e não queríamos bifurcar / modificar.

O único requisito dos sidecars é que eles escutem corretamente um sinal SIGTERM e, em seguida, desliguem. Lembro-me de ter tido alguns problemas com código de terceiros rodando em sidecars que estavam esperando um sinal diferente e tiveram que ser contornados, mas na verdade o controlador deveria apenas ter permitido que o sinal enviado fosse especificado (isto é, SIGINT em vez de SIGTERM).

Eles não precisam ouvir nenhum sinal de nenhuma porta, já que o controlador usa um exec para sinalizar diretamente o processo principal do sidecar. IIRC no momento em que essa funcionalidade foi copiada do código do kubernetes porque não existia no cliente. Acredito que isso exista no cliente oficial agora e provavelmente deve ser atualizado.

Descobrimos uma abordagem diferente, se você adicionar o seguinte aos seus contêineres de pod:

    securityContext:
            capabilities:
                   add:
                    - SYS_PTRACE

então você será capaz de executar grep no Pid em outros contêineres, executaremos o seguinte no final do nosso contêiner principal:
sql_proxy_pid=$(pgrep cloud_sql_proxy) && kill -INT $sql_proxy_pid

@ ruiyang2015 obrigado por este hack.
Porém, se alguém o estiver implementando, certifique-se de entender as implicações de compartilhar um processo ns entre os contêineres

@nrmitchi

usa um exec para sinalizar o processo principal do sidecar diretamente

Essa é parte da razão pela qual perguntei ... Acho, especificamente, estou me perguntando se isso não funciona para contêineres baseados em imagens que são construídas FROM scratch .

@krancour Ponto justo, eu nunca fui e testei com contêineres que estavam fora de scratch . Olhando para o código (ou minha versão original; isso pode ter mudado para bifurcado), parece que vai depender de bash , mas deve poder ser modificado.

vai depender do bash, mas deve poder ser modificado

Claro, mas enquanto estiver em execução, sempre dependerá de algum binário presente no contêiner e, para um contêiner de rascunho, não há _nada_ lá, exceto o que você colocar explicitamente. 🤷‍♂

Dada essa limitação, não posso usar isso para um caso de uso em que os contêineres em execução podem ser totalmente arbitrários e especificados por terceiros. Oh - e então eu tenho contêineres do Windows em jogo também.

Vou mencionar o que vou resolver em vez disso. Provavelmente é muito pesado para a maioria dos casos de uso, mas estou mencionando-o no caso de o caso de uso de outra pessoa ser semelhante o suficiente ao meu para se safar com isso ...

Posso me dar ao luxo de simplesmente _excluir_ um pod cujo contêiner "principal" saiu, contanto que eu registre o status de saída primeiro. Portanto, vou acabar escrevendo um controlador que monitorará algum contêiner designado (por meio de anotação) para conclusão, registrará seu sucesso ou falha em um armazenamento de dados que já rastreia o status do "trabalho" e, em seguida, exclui o pod inteiramente.

Para uma boa medida, provavelmente colocarei um pequeno atraso na exclusão do pod para maximizar as chances de minha agregação de log central de obter as últimas linhas da saída do contêiner primário antes de ser torpedeado.

Pesado, mas pode funcionar para alguns.

@krancour Totalmente verdadeiro. Como está, o controlador não funcionará para bases de uso arbitrárias. Honestamente, nunca voltei atrás e tentei abstrair parte da implementação para dar suporte a outros casos, porque realmente pensei que o KEP mencionado anteriormente teria sido mesclado e tornado a necessidade dessa funcionalidade discutível.

Dado que este problema tem cerca de 4 anos, o KEP não foi a lugar nenhum ainda, e o estado da arte é um script de shell embutido em linha substituindo todos os pontos de entrada, decidi codificar o hack "padrão" (lápides em um volume compartilhado ) em um binário Go que pode ser facilmente incorporado em imagens de contêiner usando uma compilação de vários estágios.

https://github.com/karlkfi/kubexit

Existem algumas maneiras de usá-lo:

  1. Incorpore em suas imagens
  2. Carregue-o lateralmente usando um contêiner init e um volume efêmero.
  3. Provisione-o em cada nó e carregue-o lateralmente em contêineres usando uma montagem de ligação de host

Edit: v0.2.0 agora oferece suporte a “dependências de nascimento” (início atrasado) e “dependências de morte” (término automático).

Comentário de passagem: parece exatamente com https://github.com/kubernetes/enhancements/issues/753

@vanzin, como foi observado antes , que o KEP está em espera por tempo indeterminado.

Meu caso de uso para isso é que o Vault fornece credenciais para um CronJob ser executado. Assim que a tarefa for concluída, o arquivo secundário do Vault ainda está em execução com o trabalho em um estado pendente e isso aciona o sistema de monitoramento pensando que algo está errado. É uma pena o que aconteceu ao KEP.

Esta página foi útil?
0 / 5 - 0 avaliações