Jak ustawić wiele poleceń w jednym pliku yaml w Kubernetes?

95

W tym oficjalnym dokumencie może uruchomić polecenie w pliku konfiguracyjnym 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}\""]

Jeśli chcę uruchomić więcej niż jedno polecenie, jak to zrobić?

scho
źródło

Odpowiedzi:

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

Objaśnienie:command ["/bin/sh", "-c"] mówi „uruchom powłokę i wykonać następujące instrukcje”. Argumenty są następnie przekazywane jako polecenia do powłoki. W skryptach powłoki średnik oddziela polecenia i &&warunkowo uruchamia następujące polecenie, jeśli pierwsze powiedzie się. W powyższym przykładzie zawsze jest uruchamiany, command onepo którym następuje command two, i działa tylko command threewtedy, gdy się command twopowiedzie.

Alternatywa: w wielu przypadkach niektóre polecenia, które chcesz uruchomić, prawdopodobnie konfigurują ostatnie polecenie do wykonania. W takim przypadku najlepszym rozwiązaniem jest zbudowanie własnego pliku Dockerfile . W szczególności spójrz na dyrektywę RUN .

Tim Allclair
źródło
1
Tak, bardzo ważne, ale myślę, że są też dobre przypadki użycia do rozszerzenia, commandponieważ zastępuje plik Dockerfile Entrypoint;)
Michael Hausenblas
1
Masz pomysł, jak to zrobić z cyklem życia kontenera? Nie ma żadnych argumentów
aclokay
1
@aclokay możesz po prostu określić argumenty jako dodatkowe ciągi poleceń. Oddzielenie poleceń i argumentów w kontenerze ma na celu ułatwienie zastępowania argumentów. Są funkcjonalnie równoważne.
Tim Allclair
co tu robi -c?
Abdul,
1
@Abdul oznacza to uruchomienie skryptu dostarczonego jako argument, zamiast uruchamiania interaktywnej powłoki lub ładowania skryptu z pliku.
Tim Allclair,
77

Wolę multilinię argumentów, to jest najprostsze i najłatwiejsze do odczytania. Ponadto skrypt można zmienić bez wpływu na obraz, wystarczy ponownie uruchomić kapsułę. Na przykład w przypadku zrzutu mysql specyfikacja kontenera może wyglądać następująco:

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

Powodem, dla którego to działa, jest fakt, że yaml faktycznie łączy wszystkie wiersze po znaku „-” w jeden, a sh uruchamia jeden długi ciąg „rozpoczynający się echo; ls ...; echo done;”.

Oliver
źródło
Fajnie, ale kiedy zażądasz edycji za pomocą kubectl, znowu będzie ona w jednej linii. :)
sekrett
@sekrett oh no! :(
aclokay
1
To działało całkiem nieźle - kluczem jest średnik w każdym wierszu. Jest to szczególnie dobre rozwiązanie, gdy poleceń jest wiele i przy powyższym rozwiązaniu byłoby to wielowierszowe. Sprawia, że ​​git diff jest
prosty
To jest to, czego szukałem. użycie zmiennej środowiskowej jako argumentów w tym rozwiązaniu działa dobrze.
Jingpeng Wu
+1 Piękne plus polecenia wieloliniowe działają doskonale: command: ['/bin/bash', '-c'] args: - exec &> /path/to/redirected/program.output;`python / program.py`` --key1 = val1` `--key2 = val2`` --key3 = val3`
nelsonspbr
46

Jeśli chcesz użyć woluminu i mapy ConfigMap, możesz zamontować dane ConfigMap jako skrypt, a następnie uruchomić ten skrypt:

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

To trochę czyści specyfikację kapsuły i pozwala na bardziej złożone skrypty.

$ kubectl logs my-pod
Do this
Do that
dhulihan
źródło
1
Bardzo fajnie, ale myślę, że łatwiej jest mieć wbudowany skrypt, po prostu użyj składni wielowierszowej. Pokażę to w osobnej odpowiedzi.
Oliver
A co, kiedy muszę podawać podwójne cudzysłowy. Na przykład wyobraź sobie to polecenie: printf '% s @% s \ n' "$ (echo 'user')" "$ (echo 'host')"
L3K0V
16

Jeśli chcesz uniknąć łączenia wszystkich poleceń w jedno polecenie za pomocą ;lub &&możesz również uzyskać prawdziwe skrypty wieloliniowe za pomocą heredoc:

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

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

   EOF

Jest to przydatne do uruchamiania istniejących skryptów bash, ale ma tę wadę, że wymaga zarówno wewnętrznej, jak i zewnętrznej instancji powłoki do skonfigurowania heredoc.

bluenote10
źródło
3

IMHO najlepszą opcją jest użycie natywnych skalarów blokowych YAML . W szczególności w tym przypadku złożony blok stylu.

Wywołując sh -cmożesz przekazać argumenty do swojego kontenera jako polecenia, ale jeśli chcesz elegancko oddzielić je nowymi liniami, powinieneś użyć bloku w stylu zawiniętym , aby YAML wiedział, że konwertuje znaki nowej linii na białe spacje, skutecznie łącząc polecenia.

Pełny przykład działania:

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
źródło
1

Nie jestem pewien, czy pytanie jest nadal aktywne, ale ze względu na to, że nie znalazłem rozwiązania w powyższych odpowiedziach, postanowiłem je zapisać.

Stosuję następujące podejście:

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

Wiem, że mój przykład jest związany z readinessProbe, livenessProbe itp., Ale podejrzewam, że ten sam przypadek dotyczy poleceń kontenera. Zapewnia to elastyczność, ponieważ odzwierciedla standardowy skrypt napisany w Bash.

tmetodie
źródło
0

Oto jak możesz przekazać wiele poleceń i argumentów w jednym pliku YAML za pomocą 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"]

Pełny blok kontenerów z pliku 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
źródło
0

Aby zapewnić inną możliwą opcję, sekrety mogą być używane, ponieważ są prezentowane w kapsule jako tomy:

Tajny przykład:

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

Ekstrakt z Yamla:

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

Wiem, że wielu będzie argumentować, że nie do tego trzeba wykorzystywać sekrety, ale jest to opcja.

Nocne
źródło
0

Oto mój udany bieg

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
źródło