Como definir vários comandos em um arquivo yaml com Kubernetes?

91

Neste documento oficial, ele pode executar o comando em um arquivo de configuração yaml:

https://kubernetes.io/docs/tasks/configure-pod-container/

apiVersion: v1
kind: Pod
metadata:
  name: hello-world
spec:  # specification of the pod’s contents
  restartPolicy: Never
  containers:
  - name: hello
    image: "ubuntu:14.04"
    env:
    - name: MESSAGE
      value: "hello world"
    command: ["/bin/sh","-c"]
    args: ["/bin/echo \"${MESSAGE}\""]

Se eu quiser executar mais de um comando, como fazer?

escola
fonte

Respostas:

144
command: ["/bin/sh","-c"]
args: ["command one; command two && command three"]

Explicação: A command ["/bin/sh", "-c"]mensagem diz "execute um shell e execute as seguintes instruções". Os args são então passados ​​como comandos para o shell. No script de shell, um ponto-e-vírgula separa os comandos e &&executa condicionalmente o seguinte comando se o primeiro for bem-sucedido. No exemplo acima, ele sempre é executado command oneseguido por command twoe só é executado command threese for command twobem-sucedido.

Alternativa: em muitos casos, alguns dos comandos que você deseja executar provavelmente estão configurando o comando final a ser executado. Nesse caso, construir seu próprio Dockerfile é o caminho a percorrer. Observe a diretiva RUN em particular.

Tim Allclair
fonte
1
Sim, muito válido, no entanto, acho que também há bons casos de uso para estender, uma commandvez que substitui o Dockerfile Entrypoint;)
Michael Hausenblas
1
Alguma ideia de como fazer isso com o ciclo de vida do contêiner? Não tem argumentos
aclokay
1
@aclokay você pode apenas especificar os argumentos como strings de comando adicionais. A separação entre command & args no Container é apenas para facilitar a substituição dos argumentos. Eles são funcionalmente equivalentes.
Tim Allclair
o que -c faz aqui?
Abdul
1
@Abdul significa executar o script fornecido como argumento, em vez de iniciar um shell interativo ou carregar o script de um arquivo.
Tim Allclair
69

Minha preferência é multilinha os argumentos, isso é mais simples e fácil de ler. Além disso, o script pode ser alterado sem afetar a imagem, basta reiniciar o pod. Por exemplo, para um dump do mysql, a especificação do contêiner pode ser algo assim:

containers:
  - name: mysqldump
    image: mysql
    command: ["/bin/sh", "-c"]
    args:
      - echo starting;
        ls -la /backups;
        mysqldump --host=... -r /backups/file.sql db_name;
        ls -la /backups;
        echo done;
    volumeMounts:
      - ...

A razão para isso funcionar é que yaml na verdade concatena todas as linhas após o "-" em uma, e sh executa uma longa string "echo started; ls ...; echo done;".

Oliver
fonte
Legal, mas quando você solicitar uma edição com kubectl, ela estará em uma linha novamente. :)
sekrett
@sekrett oh não! :(
aclokay
1
Isso funcionou muito bem - a chave é o ponto-e-vírgula em cada linha. Esta é uma solução particularmente boa quando os comandos são muitos e seriam multilinhas com a solução acima. Torna o git diff uma brisa
kellyfj
Isso é o que eu estava procurando. usar a variável de ambiente como argumentos com esta solução funciona bem.
Jingpeng Wu de
+1 Bonito, além de comandos multi-linhas funcionam perfeitamente: command: ['/bin/bash', '-c'] args: - exec &> /path/to/redirected/program.output;`python / program.py`` --key1 = val1` `--key2 = val2`` --key3 = val3`
nelsonspbr
44

Se você deseja usar um Volume e um ConfigMap, pode montar os dados do ConfigMap como um script e, em seguida, executar esse script:

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: my-configmap
data:
  entrypoint.sh: |-
    #!/bin/bash
    echo "Do this"

    echo "Do that"
---
apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: my-container
    image: "ubuntu:14.04"
    command:
    - /bin/entrypoint.sh
    volumeMounts:
    - name: configmap-volume
      mountPath: /bin/entrypoint.sh
      readOnly: true
      subPath: entrypoint.sh
  volumes:
  - name: configmap-volume
    configMap:
      defaultMode: 0700
      name: my-configmap

Isso limpa um pouco as especificações do pod e permite scripts mais complexos.

$ kubectl logs my-pod
Do this
Do that
dhulihan
fonte
1
Muito legal, mas acho mais simples ter o script embutido, basta usar a sintaxe multilinha. Eu mostro isso em uma resposta separada.
Oliver
E quando eu preciso passar aspas duplas. Por exemplo, imagine este comando: printf '% s @% s \ n' "$ (echo 'usuário')" "$ (echo 'host')"
L3K0V
15

Se você deseja evitar a concatenação de todos os comandos em um único comando com ;ou &&também pode obter verdadeiros scripts de várias linhas usando um heredoc:

command: 
 - sh
 - "-c"
 - |
   /bin/bash <<'EOF'

   # Normal script content possible here
   echo "Hello world"
   ls -l
   exit 123

   EOF

Isso é útil para executar scripts bash existentes, mas tem a desvantagem de exigir uma instância de shell interno e externo para configurar o heredoc.

bluenote10
fonte
2

IMHO, a melhor opção é usar os escalares de bloco nativos do YAML . Especificamente neste caso, o bloco de estilo dobrado .

Ao invocar, sh -cvocê pode passar argumentos para seu contêiner como comandos, mas se quiser separá-los elegantemente com novas linhas, use o bloco de estilo dobrado , para que YAML saiba como converter novas linhas em espaços em branco, concatenando efetivamente os comandos.

Um exemplo completo de trabalho:

apiVersion: v1
kind: Pod
metadata:
  name: myapp
  labels:
    app: myapp
spec:
  containers:
  - name: busy
    image: busybox:1.28
    command: ["/bin/sh", "-c"]
    args:
    - >
      command_1 &&
      command_2 &&
      ... 
      command_n
Piscesgeek
fonte
0

Veja como você pode passar vários comandos e argumentos em um arquivo YAML com kubernetes:

# Write your commands here
command: ["/bin/sh", "-c"]
# Write your multiple arguments in args
args: ["/usr/local/bin/php /var/www/test.php & /usr/local/bin/php /var/www/vendor/api.php"]

Bloco completo de contêineres do arquivo yaml:

    containers:
      - name: widc-cron # container name
        image: widc-cron # custom docker image
        imagePullPolicy: IfNotPresent # advisable to keep
        # write your command here
        command: ["/bin/sh", "-c"]
        # You can declare multiple arguments here, like this example
        args: ["/usr/local/bin/php /var/www/tools/test.php & /usr/local/bin/php /var/www/vendor/api.php"]
        volumeMounts: # to mount files from config-map generator
          - mountPath: /var/www/session/constants.inc.php
            subPath: constants.inc.php
            name: widc-constants
Yogi Ghorecha
fonte
0

Apenas para trazer outra opção possível, os segredos podem ser usados ​​conforme são apresentados ao pod como volumes:

Exemplo secreto:

apiVersion: v1
kind: Secret 
metadata:
  name: secret-script
type: Opaque
data:
  script_text: <<your script in b64>>

Extrato de Yaml:

....
containers:
    - name: container-name
      image: image-name
      command: ["/bin/bash", "/your_script.sh"]
      volumeMounts:
        - name: vsecret-script
          mountPath: /your_script.sh
          subPath: script_text
....
  volumes:
    - name: vsecret-script
      secret:
        secretName: secret-script

Sei que muitos argumentarão que não é para isso que os segredos devem ser usados, mas é uma opção.

noite
fonte