Как передать аргумент командной строки в командный интерпретатор kubectl при запуске по ssh

Как передать аргумент командной строки в командный интерпретатор kubectl при запуске по ssh
Как передать аргумент командной строки в командный интерпретатор kubectl при запуске по ssh - jrkorpa @ Unsplash

Как передать аргумент командной строки при запуске kubectl по ssh? Аргумент -l для ls передается оболочке pod shell, если я запускаю ее без ssh. Я пробовал экранировать, заключать в кавычки и т.д., но ничего не помогло.

ssh  [email protected]  kubectl exec -it mypod -n mynamespace -- sh -c ls -l

Полезные ресурсы:

Если вы знаете точную команду, которую хотите выполнить в удаленной оболочке, вы можете создать команду для локальной оболочки. Я думаю, что команда для удаленной оболочки не должна быть:

# wrong
kubectl exec -it mypod -n mynamespace -- sh -c ls -l

потому что он будет работать kubectl, который будет работать sh -c ls -l. Попробуйте последний код локально, и вы увидите, что он не запускается ls -l. Это потому, что -l не относится к коду sh, который нужно запустить. Код для sh должен быть одним аргументом опции после -c; дальнейшие аргументы (если есть) разные (сравните этот вопрос).

Это означает, что в конечном итоге вам нужна команда, которая в оболочке будет выглядеть так: sh -c 'ls -l'. Ваш kubectl exec запустит это, если ls -l является единственный аргумент к этому. Итак, вам нужно это в удаленной оболочке:

kubectl exec -it mypod -n mynamespace -- sh -c 'ls -l'
# or
kubectl exec -it mypod -n mynamespace -- sh -c "ls -l"

(Давайте выберем последний вариант.) Теперь вы знаете точную команду, которую хотите выполнить в удаленной оболочке. Передайте его местному ssh в качестве одного аргумента:

ssh [email protected] 'kubectl exec -it mypod -n mynamespace -- sh -c "ls -l"'

Внешние (одинарные) кавычки будут удалены локальной оболочкой, но благодаря им ssh получит большую строку кода (kubectl … "ls -l") в качестве одного аргумента. Код будет содержать внутренние (двойные) кавычки. Они будут удалены удаленной оболочкой (созданной сервером SSH), но благодаря им kubectl получит небольшую строку кода (ls -l) в качестве единственного аргумента; поэтому он будет порождать sh, который получит код в качестве одного аргумента.

В этом случае не имеет значения, в каких кавычках используются одинарные кавычки, а в каких — двойные. Важно то, что пары кавычек разные (в отличие, например, от a "b "c"", где кавычки не внутренние и внешние, это две отдельные пары, где c не заключен в кавычки).


Обратите внимание, что разные инструменты обрабатывают свои аргументы и строят «код» для следующего шага по-разному:

  • ssh может объединять несколько аргументов для сборки кода для удаленной оболочки (поэтому ваша попытка сработала); затем удаленная оболочка интерпретирует одну строку. Когда мне нужно защитить что-то (например, кавычки) от локальной оболочки (и это имеет место здесь), я предпочитаю цитировать весь код локально и передавать его ssh в качестве одного аргумента; но это мой выбор.

    Итак, ssh строит одну строку из одного или нескольких аргументов.

  • kubectl exec обрабатывает аргументы после -- как массив. В нашем случае выполняется sh с аргументами -c и ls -l (в вашей попытке аргументы были -c, ls и -l).

    Итак, kubectl exec не создает никакой строки. Из массива аргументов он строит массив для выполнения.

  • sh -c интерпретирует только один аргумент после -c как шелл-код. Он не объединяет несколько аргументов, как это может сделать ssh.

Представьте sh -c как интерфейс для запуска кода в локальной оболочке; и ssh …@… как интерфейс для запуска кода в удаленной оболочке. Они похожи, каждый порождает оболочку, которая интерпретирует код, написанный как одна строка. И все же они разные, разница в том, как создается строка: sh -c берет код ровно из одного аргумента, ssh строит код, возможно, из многих аргументов. kubectl exec — это интерфейс для запуска исполняемого файла в контейнере. Он больше всего отличается от двух других интерфейсов тем, что использует свои аргументы непосредственно как массив.


Вам действительно нужно sh -c? думаю в этом случае

ssh [email protected] 'kubectl exec -it mypod -n mynamespace -- ls -l'

достаточно. Обратите внимание, что если вы использовали "ls -l" (все еще внутри кода в одинарных кавычках) здесь, то kubectl exec попытается запустить исполняемый файл с именем ls -l (вместо ls с -l в качестве аргумента). Здесь вы не хотите применять внутренние кавычки к ls -l.

OTOH любой из этих:

ssh [email protected] kubectl exec -it mypod -n mynamespace -- ls -l
ssh [email protected] kubectl exec -it mypod -n mynamespace -- "ls -l"
ssh [email protected] kubectl exec -it "mypod -n mynamespace -- ls" -l

будет работать, потому что ssh создаст одну и ту же строку для удаленной оболочки (хотя и из разного количества разных аргументов). Последний пример особенно причудлив; он локально собирает несколько «окончательных» аргументов в один, по-видимому, нарушая логику (я имею в виду, что ls имеет больше общего с -l, чем с -n, верно?). Тем не менее это работает, и причина в том, что ssh строит одну строку из многих.

sh -c является обязательным в тех случаях, когда вместо ls -l у вас есть что-то, что действительно нуждается в оболочке (например, конвейер с |, команда с перенаправлениями, например >file, синтаксис оболочки, например if).


Ваша команда (или моя фиксированная команда) состоит из нескольких вложенных инструментов. На каждом этапе один (внешний) инструмент каким-то образом обрабатывает свои аргументы и каким-то образом порождает другой (внутренний) инструмент на том же или другом хосте. Окончательный вывод: вам нужно знать все инструменты, которые вы используете, способы, которыми они анализируют свои аргументы и вызывают следующий инструмент. Обратите внимание, что в нашем примере перед ssh есть локальная оболочка, а между демоном SSH на сервере и kubectl есть удаленная оболочка; вам также необходимо учитывать каждую неявную оболочку.


NevaDev, 30 января 2023 г., 02:49