¿Cómo configurar varios comandos en un archivo yaml con Kubernetes?

96

En este documento oficial, puede ejecutar el comando en un archivo de configuración 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}\""]

Si quiero ejecutar más de un comando, ¿cómo hacerlo?

scho
fuente

Respuestas:

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

Explicación: El command ["/bin/sh", "-c"]dice "Ejecutar una cáscara, y ejecutar las siguientes instrucciones". Luego, los argumentos se pasan como comandos al shell. En la secuencia de comandos de shell, un punto y coma separa los comandos y &&ejecuta condicionalmente el siguiente comando si el primero tiene éxito. En el ejemplo anterior, siempre se ejecuta command oneseguido de command two, y solo se ejecuta command threesi se realiza command twocorrectamente.

Alternativa: en muchos casos, algunos de los comandos que desea ejecutar probablemente estén configurando el comando final para que se ejecute. En este caso, construir su propio Dockerfile es el camino a seguir. Mire la directiva RUN en particular.

Tim Allclair
fuente
1
Sí, muy válido, sin embargo, creo que también hay buenos casos de uso para extender, commandya que anula el Dockerfile Entrypoint;)
Michael Hausenblas
1
¿Alguna idea de cómo hacer esto con el ciclo de vida del contenedor? No tiene
argumentos
1
@aclokay, puede especificar los argumentos como cadenas de comandos adicionales. La separación entre comando y argumentos en el contenedor es solo para facilitar la anulación de los argumentos. Son funcionalmente equivalentes.
Tim Allclair
¿Qué hace -c aquí?
Abdul
1
@Abdul significa ejecutar el script provisto como argumento, en lugar de iniciar un shell interactivo o cargar el script desde un archivo.
Tim Allclair
77

Mi preferencia es multilínea de argumentos, esto es más simple y fácil de leer. Además, el script se puede cambiar sin afectar la imagen, solo es necesario reiniciar el pod. Por ejemplo, para un volcado de mysql, la especificación del contenedor podría ser algo como esto:

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:
      - ...

La razón por la que esto funciona es que yaml en realidad concatena todas las líneas después del "-" en una, y sh ejecuta una cadena larga "echo comenzando; ls ...; echo hecho;".

Oliver
fuente
Bien, pero cuando solicite una edición con kubectl, estará en una línea nuevamente. :)
sekrett
@sekrett ¡oh no! :(
aclokay
1
Esto funcionó bastante bien: la clave es el punto y coma en cada línea. Esta es una solución particularmente buena cuando los comandos son muchos y serían multilínea con la solución anterior. Hace que git diff sea muy fácil
kellyfj
Esto es lo que estaba buscando. Usar la variable de entorno como argumentos con esta solución funciona bien.
Jingpeng Wu
+1 Hermoso, además los comandos de varias líneas funcionan perfectamente: command: ['/bin/bash', '-c'] args: - exec &> /path/to/redirected/program.output;`python / program.py`` --key1 = val1` `--key2 = val2`` --key3 = val3`
nelsonspbr
46

Si está dispuesto a utilizar un Volumen y un ConfigMap, puede montar los datos de ConfigMap como un script y luego ejecutar ese 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

Esto limpia un poco la especificación de su pod y permite scripts más complejos.

$ kubectl logs my-pod
Do this
Do that
dhulihan
fuente
1
Muy bueno, pero creo que es más simple tener el script en línea, solo use sintaxis multilínea. Muestro esto en una respuesta separada.
Oliver
¿Qué pasa cuando necesito pasar comillas dobles? Por ejemplo, imagine este comando: printf '% s @% s \ n' "$ (echo 'usuario')" "$ (echo 'host')"
L3K0V
16

Si desea evitar la concatenación de todos los comandos en un solo comando con ;o &&también puede obtener verdaderos scripts de varias líneas usando un heredoc:

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

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

   EOF

Esto es útil para ejecutar scripts bash existentes, pero tiene la desventaja de requerir una instancia de shell tanto interna como externa para configurar el heredoc.

bluenote10
fuente
4

En mi humilde opinión, la mejor opción es usar los escalares de bloques nativos de YAML . Concretamente en este caso, el bloque estilo plegado .

Al invocar sh -c, puede pasar argumentos a su contenedor como comandos, pero si desea separarlos elegantemente con líneas nuevas, querrá usar el bloque de estilo plegado , de modo que YAML sepa convertir las líneas nuevas en espacios en blanco, concatenando los comandos de manera efectiva.

Un ejemplo de trabajo completo:

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
fuente
1

No estoy seguro de si la pregunta aún está activa, pero debido al hecho de que no encontré la solución en las respuestas anteriores, decidí escribirla.

Utilizo el siguiente enfoque:

readinessProbe:
  exec:
    command:
    - sh
    - -c
    - |
      command1
      command2 && command3

Sé que mi ejemplo está relacionado con readinessProbe, livenessProbe, etc. pero sospecho que el mismo caso es para los comandos del contenedor. Esto proporciona flexibilidad, ya que refleja una escritura de script estándar en Bash.

tmetodie
fuente
0

Así es como puede pasar múltiples comandos y argumentos en un archivo YAML con 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"]

Bloque de contenedores completo del archivo 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
fuente
0

Solo para traer otra opción posible, los secretos se pueden usar a medida que se presentan al pod como volúmenes:

Ejemplo secreto:

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

Extracto de ñame:

....
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

Sé que muchos argumentarán que esto no es para lo que deben usarse los secretos, pero es una opción.

noche
fuente
0

Aquí está mi carrera exitosa

apiVersion: v1
kind: Pod
metadata:
  labels:
    run: busybox
  name: busybox
spec:
  containers:
  - command:
    - /bin/sh
    - -c
    - |
      echo "running below scripts"
      i=0; 
      while true; 
      do 
        echo "$i: $(date)"; 
        i=$((i+1)); 
        sleep 1; 
      done
    name: busybox
    image: busybox
brajesh jaishwal
fuente