Как передать аргумент командной строки при запуске 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
есть удаленная оболочка; вам также необходимо учитывать каждую неявную оболочку.