Cách truyền đối số cho Shell Script thông qua chạy docker


131

Tôi mới đến thế giới docker. Tôi phải gọi một kịch bản shell lấy các đối số dòng lệnh thông qua một thùng chứa docker. Ví dụ: Kịch bản shell của tôi trông như:

#!bin/bash
echo $1

Dockerfile trông như thế này:

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

Tôi không chắc chắn làm thế nào để vượt qua các đối số trong khi chạy container

Câu trả lời:


61

Sử dụng tương tự file.sh

#!/bin/bash
echo $1

Xây dựng hình ảnh bằng Dockerfile hiện có:

docker build -t test .

Chạy hình ảnh với các đối số abchoặc xyzhoặc cái gì đó khác.

docker run -ti test /file.sh abc

docker run -ti test /file.sh xyz

27
Tôi nghĩ ENTRYPOINT là cách tốt nhất nếu bạn không muốn người dùng cuối biết trực tiếp về file.sh.
greg.kindel 15/03/2016

Làm thế nào bạn có thể chỉ cần bắt đầu một kịch bản như thế này docker run -ti test /file.sh abc. Tôi cảm thấy rằng kịch bản sẽ không chạy bởi vì nó nên được docker run -ti test sh /file.sh abc. sh hoặc / bin / sh sẽ chạy nó ngay.
Vamsidhar Muggulla

1
Đối với bất cứ ai khác đến đây. Thủ thuật / usr / bin / env là tùy chọn kiểu tùy chọn không phải là một yêu cầu để làm cho điều này hoạt động. Cũng là #! dòng cho biết thông dịch viên sẽ sử dụng mua mặc định. Vì vậy, nó có thể chạy chỉ bằng cách gọi kịch bản.
wheredidthatnamecome từ

162

với kịch bản này trong file.sh

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

và điều này Dockerfile

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

bạn sẽ có thể:

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

9
Nếu bạn quên "" xung quanh "/file.sh" như tôi đã làm, nó sẽ không hoạt động.
kev

6
vì một số lý do, điều này không hoạt động vớiENTRYPOINT ./file.sh
phil294 17/03/18

6
Đừng quên chmod +x file.shđặt cờ thực thi.
topskip

1
@kev, bạn có biết tại sao nó lại như vậy không? sự khác biệt giữa ["/file.sh"]/file.shthậm chí[/file.sh]
Nitzankin

1
@Nitzankin xem câu trả lời của tôi tại sao cần định dạng json thích hợp.
BMitch

60

Với Docker, cách thích hợp để truyền loại thông tin này là thông qua các biến môi trường.

Vì vậy, với cùng Dockerfile, hãy thay đổi tập lệnh thành

#!/bin/bash
echo $FOO

Sau khi xây dựng, sử dụng lệnh docker sau:

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

20
Tại sao đây là câu trả lời được bình chọn cao nhất? Env vars là một cách khác để truyền thông tin, nhưng không phải là những gì OP đang yêu cầu. Và tất nhiên, hoàn toàn không có gì không phù hợp về mong muốn của OP để chuyển các đối số vào container.
Một phần mây

8
@PartlyCloudy Tôi nghĩ mọi người thích điều này bởi vì nó có ý định đưa ra câu trả lời "đúng", mặc dù rõ ràng là sai. Một nguyên tắc thiết kế chính của Docker là ưu tiên giáo điều hơn lẽ thường.
tám

1
@augurar: Để cải thiện câu trả lời này, có thể bạn giải thích lý do tại sao bạn nghĩ câu trả lời này là "rõ ràng sai"?
Emil Stenström

2
Có rất nhiều vấn đề XY hỏi về SO. Vì OP tuyên bố họ là người mới đối với Docker, nên câu trả lời hoàn toàn hợp lý cho thấy cách được đề xuất để đạt được mục tiêu. Do đó làm cho điều này một câu trả lời tuyệt vời.
colm.anseo

1
Cách đơn giản nhất để hoàn thành công việc thay vì chuyển các biến như build args và tất cả những thứ lộn xộn đó. Rất hữu ích để truyền bí mật như các biến môi trường.
Arvind Sridharan

32

Có một vài điều tương tác ở đây:

  1. docker run your_image arg1 arg2sẽ thay thế giá trị của CMDvới arg1 arg2. Đó là sự thay thế hoàn toàn của CMD, không gắn thêm các giá trị vào nó. Đây là lý do tại sao bạn thường thấy docker run some_image /bin/bashđể chạy bash shell trong container.

  2. Khi bạn có cả giá trị ENTRYPOINT và giá trị CMD được xác định, docker sẽ khởi động bộ chứa bằng cách nối hai cái đó và chạy lệnh nối đó. Vì vậy, nếu bạn xác định điểm vào của mình là file.sh, bây giờ bạn có thể chạy container với các đối số bổ sung sẽ được chuyển như đối số file.sh.

  3. Điểm truy cập và lệnh trong docker có hai cú pháp, cú pháp chuỗi sẽ khởi chạy shell và cú pháp json sẽ thực hiện lệnh exec. Shell này rất hữu ích để xử lý những thứ như chuyển hướng IO, kết hợp nhiều lệnh với nhau (với những thứ như &&), thay thế biến đổi, v.v. Tuy nhiên, shell đó cản trở việc xử lý tín hiệu (nếu bạn đã thấy độ trễ 10 giây dừng một container, đây thường là nguyên nhân) và với việc kết hợp một điểm vào và lệnh cùng nhau. Nếu bạn xác định điểm vào của bạn là một chuỗi, nó sẽ chạy /bin/sh -c "file.sh", một mình là ổn. Nhưng nếu bạn cũng có một lệnh được định nghĩa là một chuỗi, bạn sẽ thấy một cái gì đó giống /bin/sh -c "file.sh" /bin/sh -c "arg1 arg2"như lệnh được khởi chạy bên trong container của bạn, không tốt lắm. Xem bảng ở đây để biết thêm về cách hai tùy chọn này tương tác

  4. -cTùy chọn shell chỉ mất một đối số duy nhất. Tất cả mọi thứ sau đó sẽ được thông qua như $1, $2, vv, với đối số duy nhất, nhưng không phải vào một shell script nhúng trừ khi bạn thông qua một cách rõ ràng args. Tức là /bin/sh -c "file.sh $1 $2" "arg1" "arg2"sẽ làm việc, nhưng /bin/sh -c "file.sh" "arg1" "arg2"sẽ không file.shđược gọi mà không có đối số.

Đặt tất cả lại với nhau, thiết kế chung là:

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

Và sau đó bạn chạy nó với:

docker run your_image arg1 arg2

Có một chút chi tiết hơn về điều này tại:


1
Tôi đã thử nghiệm thiết lập điểm truy cập của mình ["bash", "--login", "-c"]để lấy nguồn / etc / profile trong ảnh, nhưng sau đó lại tự hỏi tại sao không có đối số nào được chuyển đến một tập lệnh shell được chuyển đến docker chạy ... Câu trả lời của bạn đã xóa nó, cảm ơn bạn !
Apterx

23

Những gì tôi có là một tập tin kịch bản thực sự chạy mọi thứ. Tập tin scrip này có thể tương đối phức tạp. Hãy gọi nó là "run_container". Kịch bản lệnh này lấy các đối số từ dòng lệnh:

run_container p1 p2 p3

Một run_container đơn giản có thể là:

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

Những gì tôi muốn làm là, sau khi "neo" cái này, tôi muốn có thể khởi động container này với các tham số trên dòng lệnh docker như thế này:

docker run image_name p1 p2 p3

và có tập lệnh run_container được chạy với p1 p2 p3 làm tham số.

Đây là giải pháp của tôi:

Dockerfile:

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

7
Thay thế giá trị thứ ba trong ENTRYPOINTmảng bằng các "/run_container \"$@\""đối số có nghĩa là khoảng trắng được xử lý chính xác (ví dụ docker run image_name foo 'bar baz' quux).
davidchambers 6/2/2017

Sau khi thêm các câu lệnh switch / case vào tệp bash của tôi, ENTRYPOINT ["run_container.sh"] không còn hoạt động với tôi nữa, nhưng ENTRYPOINT ["sh", "-c", "run_container.sh"] sẽ không còn chấp nhận các tham số của tôi nữa. Giải pháp này (với đề xuất @davidchambers) đã làm việc cho tôi.
rhamilton

10

Nếu bạn muốn chạy nó @build time:

CMD /bin/bash /file.sh arg1

nếu bạn muốn chạy nó @ thời gian:

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

Sau đó trong vỏ máy chủ

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

2
ENTRYPOINTlà một câu trả lời tốt cho OP, người mà tôi nghĩ muốn có thời gian chạy, nhưng nếu bạn thực sự muốn xây dựng các biến thời gian thì câu trả lời này đã bị hỏng. Sử dụng ARGdocker build --build-arg docs.docker.com/engine/reference/builder/#arg
greg.kindel 15/03/2016

0

Một lựa chọn khác ...

Để làm việc này

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

trong dockerfile

ENTRYPOINT ["/entrypoint.sh"]

trong 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

một số lưu ý và giới hạn .... lệnh với ":" cần thay đổi trong cut -d ':' và các lệnh như docker run -d --rm $ IMG_NAME "bash: echo $ PATH" sẽ hiển thị giá trị đường dẫn máy chủ thay vì máy chủ một
wagnermarques
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.