Как передать аргументы в сценарий оболочки через запуск докера


133

Я новичок в мире докеров. Мне нужно вызвать сценарий оболочки, который принимает аргументы командной строки через контейнер докера. Пример: мой сценарий оболочки выглядит так:

#!bin/bash
echo $1

Dockerfile выглядит так:

FROM ubuntu:14.04
COPY ./file.sh /
CMD /bin/bash file.sh

Я не уверен, как передавать аргументы при запуске контейнера

Ответы:


62

Используйте то же самое file.sh

#!/bin/bash
echo $1

Создайте образ, используя существующий файл Dockerfile:

docker build -t test .

Запустить образ с аргументами abcили xyzеще что-то.

docker run -ti test /file.sh abc

docker run -ti test /file.sh xyz

27
Я думаю, что ENTRYPOINT - это то, что вам нужно, если вы не хотите, чтобы конечный пользователь знал о file.sh напрямую.
greg.kindel

Как можно просто запустить такой скрипт docker run -ti test /file.sh abc. Я чувствую, что сценарий не запускается, потому что он должен быть docker run -ti test sh /file.sh abc. sh или / bin / sh запустит его правильно.
Vamsidhar Muggulla

1
Для всех, кто приезжает сюда. Уловка / usr / bin / env - это необязательный параметр стиля, а не требование для его работы. Так же #! Строка указывает, какой интерпретатор использовать по умолчанию. Так что его можно запустить, просто вызвав сценарий.
прибыло

167

с этим скриптом в file.sh

#!/bin/bash
echo Your container args are: "$@"

и это Dockerfile

FROM ubuntu:14.04
COPY ./file.sh /
ENTRYPOINT ["/file.sh"]

ты должен быть способен:

% docker build -t test .
% docker run test hello world
Your container args are: hello world

9
Если вы забудете "вокруг" /file.sh, как это сделал я, это не сработает.
kev

6
по какой-то причине это не работает сENTRYPOINT ./file.sh
phil294

6
Не забудьте chmod +x file.shустановить флаг исполняемого файла.
topskip

1
@kev, ты знаешь, почему это так? какая разница между ["/file.sh"]и /file.shили даже[/file.sh]
Ницанкин 03

1
@Nitzankin см. Мой ответ о том, почему необходимо правильное форматирование json.
BMitch

60

В Docker правильный способ передавать такую ​​информацию - через переменные среды.

Итак, с тем же файлом Dockerfile измените сценарий на

#!/bin/bash
echo $FOO

После сборки используйте следующую команду докера:

docker run -e FOO="hello world!" test

20
Почему этот ответ получил наибольшее количество голосов? Env vars - еще один способ передать информацию, но не то, о чем спрашивает OP. И, конечно, нет ничего неправильного в желании OP передавать аргументы в контейнер.
Небольшая

8
@PartlyCloudy Я думаю, людям это нравится, потому что он претендует на «правильный» ответ, несмотря на очевидную ошибку. Главный принцип разработки Docker - ставить догмы выше здравого смысла.
augurar

1
@augurar: Чтобы улучшить этот ответ, может быть, вы объясните, почему вы думаете, что этот ответ «явно неправильный»?
Эмиль Стенстрём

2
На SO задаются тонны проблем XY. Поскольку OP заявил, что они были новичками в Docker, вполне разумно, что ответ покажет рекомендуемый способ достижения цели. Таким образом, это отличный ответ.
colm.anseo

1
Самый простой способ выполнить работу вместо передачи переменных в качестве аргументов сборки и всего такого беспорядка. Очень полезно для передачи секретов в качестве переменных среды.
Арвинд Шридхаран

32

Здесь взаимодействуют несколько вещей:

  1. docker run your_image arg1 arg2заменит значение CMDс arg1 arg2. Это полная замена CMD, без добавления к нему дополнительных значений. Вот почему вы часто видите docker run some_image /bin/bashзапуск оболочки bash в контейнере.

  2. Когда у вас определены значения ENTRYPOINT и CMD, docker запускает контейнер, объединяя их и выполняя эту объединенную команду. Итак, если вы определите свою точку входа как file.sh, теперь вы можете запустить контейнер с дополнительными аргументами, которые будут переданы как аргументы в file.sh.

  3. Точки входа и команды в docker имеют два синтаксиса: строковый синтаксис, который запускает оболочку, и синтаксис json, который выполняет exec. Оболочка полезна для обработки таких вещей, как перенаправление ввода-вывода, объединение нескольких команд вместе (например, &&), подстановка переменных и т. Д. Однако эта оболочка мешает обработке сигналов (если вы когда-нибудь видели 10-секундную задержку для остановки контейнер, это часто является причиной) и с объединением точки входа и команды вместе. Если вы определите свою точку входа как строку, она будет работать /bin/sh -c "file.sh", что само по себе нормально. Но если у вас есть команда, определенная как строка, вы увидите что-то вроде того, /bin/sh -c "file.sh" /bin/sh -c "arg1 arg2"что команда запускается внутри вашего контейнера, что не так хорошо. См. Таблицу здесь, чтобы узнать, как взаимодействуют эти два варианта.

  4. Параметр оболочки -cпринимает только один аргумент. Все, что после этого, будет передано как $1, $2и т.д. в этот единственный аргумент, но не во встроенный сценарий оболочки, если вы явно не передали аргументы. Т.е. /bin/sh -c "file.sh $1 $2" "arg1" "arg2"будет работать, но /bin/sh -c "file.sh" "arg1" "arg2"не file.shбудет, поскольку будет вызываться без аргументов.

Собирая все это вместе, общий дизайн таков:

FROM ubuntu:14.04
COPY ./file.sh /
RUN chmod 755 /file.sh
# Note the json syntax on this next line is strict, double quotes, and any syntax
# error will result in a shell being used to run the line.
ENTRYPOINT ["file.sh"]

И затем вы запускаете это с помощью:

docker run your_image arg1 arg2

Подробнее об этом можно узнать по адресу:


1
Я экспериментировал с установкой моей точки входа, чтобы ["bash", "--login", "-c"]получить источник / etc / profile в образе, но позже мне стало интересно, почему никакие аргументы не будут переданы в сценарий оболочки, переданный в docker run ... Ваш ответ прояснил это, спасибо !
Apteryx

23

У меня есть файл сценария, который действительно запускает вещи. Этот файл сценария может быть относительно сложным. Назовем его run_container. Этот сценарий принимает аргументы из командной строки:

run_container p1 p2 p3

Простой run_container может быть:

#!/bin/bash
echo "argc = ${#*}"
echo "argv = ${*}"

Что я хочу сделать, так это после "стыковки" этого я хотел бы иметь возможность запускать этот контейнер с параметрами в командной строке докера следующим образом:

docker run image_name p1 p2 p3

и запустить сценарий run_container с параметрами p1 p2 p3.

Это мое решение:

Dockerfile:

FROM docker.io/ubuntu
ADD run_container /
ENTRYPOINT ["/bin/bash", "-c", "/run_container \"$@\"", "--"]

7
Замена третьего значения в ENTRYPOINTмассиве на "/run_container \"$@\""аргументы, содержащие пробелы, обрабатываются правильно (например, docker run image_name foo 'bar baz' quux).
davidchambers

После добавления операторов switch / case в мой файл bash ENTRYPOINT ["run_container.sh"] больше не работал у меня, но ENTRYPOINT ["sh", "-c", "run_container.sh"] больше не принимал мои параметры. Это решение (с предложением @davidchambers) сработало для меня.
Рэмилтон 01

10

Если вы хотите запустить его @build time:

CMD /bin/bash /file.sh arg1

если вы хотите запустить его @ время выполнения:

ENTRYPOINT ["/bin/bash"]
CMD ["/file.sh", "arg1"]

Затем в оболочке хоста

docker build -t test .
docker run -i -t test

2
ENTRYPOINT- хороший ответ для OP, которому, как мне кажется, нужна среда выполнения, но если вам действительно нужны переменные времени сборки, этот ответ просто не работает. Используйте ARGи docker build --build-arg docs.docker.com/engine/reference/builder/#arg
greg.kindel

0

Другой вариант...

Чтобы это работало

docker run -d --rm $IMG_NAME "bash:command1&&command2&&command3"

в dockerfile

ENTRYPOINT ["/entrypoint.sh"]

в entrypoint.sh

#!/bin/sh

entrypoint_params=$1
printf "==>[entrypoint.sh] %s\n" "entry_point_param is $entrypoint_params"

PARAM1=$(echo $entrypoint_params | cut -d':' -f1) # output is 1 must be 'bash' it     will be tested    
PARAM2=$(echo $entrypoint_params | cut -d':' -f2) # the real command separated by     &&

printf "==>[entrypoint.sh] %s\n" "PARAM1=$PARAM1"
printf "==>[entrypoint.sh] %s\n" "PARAM2=$PARAM2"

if [ "$PARAM1" = "bash" ];
then
    printf "==>[entrypoint.sh] %s\n" "about to running $PARAM2 command"
    echo $PARAM2 | tr '&&' '\n' | while read cmd; do
        $cmd
    done    
fi

некоторые замечания и ограничения .... команда с ":" требует изменений в cut -d ':' и такие команды, как docker run -d --rm $ IMG_NAME "bash: echo $ PATH" покажет значение пути к хосту вместо хоста one
wagnermarques 01
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.