Comment définir plusieurs commandes dans un fichier yaml avec Kubernetes?

91

Dans ce document officiel, il peut exécuter la commande dans un fichier de configuration 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 je veux exécuter plus d'une commande, comment faire?

scho
la source

Réponses:

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

Explication: Le command ["/bin/sh", "-c"]dit "exécuter un shell et exécuter les instructions suivantes". Les arguments sont ensuite passés sous forme de commandes au shell. Dans les scripts shell, un point-virgule sépare les commandes et &&exécute conditionnellement la commande suivante si la première réussit. Dans l'exemple ci-dessus, il s'exécute toujours command onesuivi de command twoet ne s'exécute qu'en command threecas de command tworéussite.

Alternative: dans de nombreux cas, certaines des commandes que vous souhaitez exécuter définissent probablement la commande finale à exécuter. Dans ce cas, la création de votre propre Dockerfile est la voie à suivre. Regardez la directive RUN en particulier.

Tim Allclair
la source
1
Oui, très valide, cependant, je pense qu'il y a aussi de bons cas d'utilisation à étendre commandcar il remplace le Dockerfile Entrypoint;)
Michael Hausenblas
1
Une idée sur la façon de faire cela avec le cycle de vie des conteneurs? Il n'a pas d'
arguments
1
@aclokay vous pouvez simplement spécifier les arguments sous forme de chaînes de commande supplémentaires. La séparation entre la commande et les arguments dans le conteneur est juste pour rendre plus facile le remplacement des arguments. Ils sont fonctionnellement équivalents.
Tim Allclair
que fait -c ici?
Abdul
1
@Abdul cela signifie exécuter le script fourni en argument, plutôt que de démarrer un shell interactif ou de charger le script à partir d'un fichier.
Tim Allclair
69

Ma préférence est de multiligner les arguments, c'est le plus simple et le plus facile à lire. En outre, le script peut être modifié sans affecter l'image, il suffit de redémarrer le pod. Par exemple, pour un vidage mysql, la spécification du conteneur pourrait être quelque chose comme ceci:

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 raison pour laquelle cela fonctionne est que yaml concatène en fait toutes les lignes après le "-" en une seule, et sh exécute une longue chaîne "echo starting; ls ...; echo done;".

Oliver
la source
Bien, mais lorsque vous demandez une modification avec kubectl, ce sera à nouveau sur une ligne. :)
sekrett
@sekrett oh non! :(
aclokay
1
Cela fonctionnait très bien - la clé est le point-virgule sur chaque ligne. C'est une solution particulièrement bonne lorsque les commandes sont nombreuses et seraient multilignes avec la solution ci-dessus. Fait git diff un jeu d'enfant
kellyfj
C'est ce que je cherchais. l'utilisation de la variable d'environnement comme arguments avec cette solution fonctionne bien.
Jingpeng Wu
+1 Belle, plus les commandes multilignes fonctionnent parfaitement: command: ['/bin/bash', '-c'] args: - exec &> /path/to/redirected/program.output;`python / program.py`` `--key1 = val1`` --key2 = val2` `--key3 = val3`
nelsonspbr
44

Si vous souhaitez utiliser un volume et un ConfigMap, vous pouvez monter les données ConfigMap en tant que script, puis exécuter ce 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

Cela nettoie un peu les spécifications de votre pod et permet des scripts plus complexes.

$ kubectl logs my-pod
Do this
Do that
Dhulihan
la source
1
Très cool, mais je pense qu'il est plus simple d'avoir le script en ligne, utilisez simplement la syntaxe multiligne. Je montre cela dans une réponse séparée.
Oliver
Et quand je dois passer des guillemets doubles. Par exemple, imaginez cette commande: printf '% s @% s \ n' "$ (echo 'user')" "$ (echo 'host')"
L3K0V
15

Si vous voulez éviter de concaténer toutes les commandes en une seule commande avec ;ou &&vous pouvez également obtenir de vrais scripts multilignes en utilisant un heredoc:

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

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

   EOF

Ceci est pratique pour exécuter des scripts bash existants, mais présente l'inconvénient de nécessiter à la fois une instance interne et externe du shell pour configurer heredoc.

bluenote10
la source
2

À mon humble avis, la meilleure option est d'utiliser les scalaires de bloc natifs de YAML . Plus précisément dans ce cas, le bloc de style plié .

En invoquant, sh -cvous pouvez passer des arguments à votre conteneur sous forme de commandes, mais si vous souhaitez les séparer élégamment avec des retours à la ligne, vous voudrez utiliser le bloc de style plié , afin que YAML sache convertir les retours à la ligne en espaces blancs, concaténant efficacement les commandes.

Un exemple de travail complet:

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
la source
0

Voici comment vous pouvez transmettre plusieurs commandes et arguments dans un fichier YAML avec 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"]

Blocage complet des conteneurs du fichier 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
la source
0

Juste pour apporter une autre option possible, les secrets peuvent être utilisés car ils sont présentés au pod sous forme de volumes:

Exemple secret:

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

Extrait 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

Je sais que beaucoup diront que ce n'est pas pour cela que les secrets doivent être utilisés, mais c'est une option.

nuit
la source