Wie setze ich mit Kubernetes mehrere Befehle in einer Yaml-Datei?

89

In diesem offiziellen Dokument kann der Befehl in einer yaml-Konfigurationsdatei ausgeführt werden:

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}\""]

Wie gehe ich vor, wenn ich mehr als einen Befehl ausführen möchte?

scho
quelle

Antworten:

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

Erläuterung: Der command ["/bin/sh", "-c"]Befehl "Führen Sie eine Shell aus und führen Sie die folgenden Anweisungen aus". Die Argumente werden dann als Befehle an die Shell übergeben. Beim Shell-Scripting trennt ein Semikolon Befehle und &&führt den folgenden Befehl bedingt aus, wenn der erste erfolgreich ist. Im obigen Beispiel wird immer command onegefolgt von command twound nur dann ausgeführt, command threewenncommand two erfolgreich war.

Alternative: In vielen Fällen richten einige der Befehle, die Sie ausführen möchten, wahrscheinlich den endgültigen auszuführenden Befehl ein. In diesem Fall ist das Erstellen einer eigenen Docker-Datei der richtige Weg. Schau dir den RUN an Direktive an.

Tim Allclair
quelle
1
Ja, sehr gültig, aber ich denke, es gibt auch gute Anwendungsfälle, die erweitert werden müssen, commandda sie die Docker-Dateien überschreiben Entrypoint;)
Michael Hausenblas
1
Haben Sie eine Idee, wie dies mit dem Container-Lebenszyklus geschehen soll? Es hat keine
Argumente
1
@aclokay Sie können die Argumente einfach als zusätzliche Befehlszeichenfolgen angeben. Die Trennung zwischen Befehl und Argumenten im Container dient lediglich dazu, das Überschreiben der Argumente zu vereinfachen. Sie sind funktional gleichwertig.
Tim Allclair
was -c macht hier
Abdul
1
@Abdul bedeutet, dass das als Argument bereitgestellte Skript ausgeführt wird, anstatt eine interaktive Shell zu starten oder das Skript aus einer Datei zu laden.
Tim Allclair
68

Ich bevorzuge es, die Argumente mehrzeilig zu machen. Dies ist am einfachsten und am einfachsten zu lesen. Außerdem kann das Skript geändert werden, ohne das Image zu beeinträchtigen. Sie müssen lediglich den Pod neu starten. Für einen MySQL-Dump könnte die Containerspezifikation beispielsweise so aussehen:

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

Der Grund dafür ist, dass yaml tatsächlich alle Zeilen nach dem "-" zu einer verkettet und sh eine lange Zeichenfolge "echo starting; ls ...; echo done;" ausführt.

Oliver
quelle
Schön, aber wenn Sie eine Bearbeitung mit kubectl anfordern, wird diese wieder in einer Zeile stehen. :)
sekrett
@sekrett oh nein! :(
aclokay
1
Das hat ganz gut funktioniert - der Schlüssel ist das Semikolon in jeder Zeile. Dies ist eine besonders gute Lösung, wenn die Befehle viele sind und mit der obigen Lösung mehrzeilig wären. Macht git diff zum Kinderspiel
kellyfj
Das habe ich gesucht. Die Verwendung der Umgebungsvariablen als Argumente mit dieser Lösung funktioniert gut.
Jingpeng Wu
+1 Schöne und mehrzeilige Befehle funktionieren perfekt: command: ['/bin/bash', '-c'] args: - exec &> /path/to/redirected/program.output;`python / program.py`` --key1 = val1` `--key2 = val2`` --key3 = val3`
nelsonspbr
42

Wenn Sie bereit sind, ein Volume und eine ConfigMap zu verwenden, können Sie ConfigMap-Daten als Skript bereitstellen und dann dieses Skript ausführen:

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

Dies bereinigt Ihre Pod-Spezifikation ein wenig und ermöglicht komplexere Skripte.

$ kubectl logs my-pod
Do this
Do that
Dhulihan
quelle
1
Sehr cool, aber ich denke, es ist einfacher, das Skript inline zu haben, verwenden Sie einfach die mehrzeilige Syntax. Ich zeige dies in einer separaten Antwort.
Oliver
Was ist, wenn ich doppelte Anführungszeichen geben muss? Stellen Sie sich zum Beispiel diesen Befehl vor: printf '% s @% s \ n' "$ (echo 'user')" "$ (echo 'host')"
L3K0V
15

Wenn Sie vermeiden möchten, dass alle Befehle zu einem einzigen Befehl verkettet werden, ;oder &&wenn Sie mithilfe eines Heredocs auch echte mehrzeilige Skripte erhalten möchten:

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

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

   EOF

Dies ist praktisch, um vorhandene Bash-Skripte auszuführen, hat jedoch den Nachteil, dass zum Einrichten des Heredocs sowohl eine innere als auch eine äußere Shell-Instanz erforderlich sind.

bluenote10
quelle
2

IMHO ist die beste Option, die nativen Blockskalare von YAML zu verwenden . Speziell in diesem Fall ist das gefaltet Stilblock.

Durch Aufrufen können sh -cSie Argumente als Befehle an Ihren Container übergeben. Wenn Sie sie jedoch elegant durch Zeilenumbrüche trennen möchten, möchten Sie den gefalteten Stilblock verwenden , damit YAML Zeilenumbrüche in Leerzeichen konvertiert und die Befehle effektiv verkettet.

Ein voll funktionsfähiges Beispiel:

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
quelle
0

So können Sie mehrere Befehle und Argumente in einer YAML-Datei mit Kubernetes übergeben:

# 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"]

Vollständiger Containerblock aus Yaml-Datei:

    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
quelle
0

Um eine weitere mögliche Option zu bieten, können Geheimnisse verwendet werden, wenn sie dem Pod als Bände präsentiert werden:

Geheimes Beispiel:

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

Yaml-Extrakt:

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

Ich weiß, dass viele argumentieren werden, dass dies nicht das ist, wofür Geheimnisse verwendet werden müssen, aber es ist eine Option.

Nacht
quelle