Tôi nhận thấy rằng nhiều tập lệnh entrypoint.sh cho docker thực hiện một số việc như sau:
#!/bin/bash
set -e
... code ...
exec "$@"
Cái gì set -e
và cái exec "$@"
gì?
Câu trả lời:
Về cơ bản, nó nhận bất kỳ đối số dòng lệnh nào được chuyển đến entrypoint.sh
và thực thi chúng dưới dạng một lệnh. Về cơ bản, ý định là "Làm mọi thứ trong tập lệnh .sh này, sau đó trong cùng một trình bao chạy lệnh mà người dùng chuyển vào trên dòng lệnh".
Xem:
exec "$@"
sẽ thay thế quy trình hiện đang chạy bằng quy trình mới được tạo ra cho các đối số đã truyền. Quan trọng đối với tín hiệu Docker: stackoverflow.com/a/32261019/99717
set -e
đặt tùy chọn trình bao để thoát ngay lập tức nếu bất kỳ lệnh nào đang chạy thoát với mã thoát khác 0. Tập lệnh sẽ trả về với mã thoát của lệnh thất bại. Từ trang người đàn ông bash:
set -e:
Thoát ngay lập tức nếu một đường dẫn (có thể bao gồm một lệnh đơn giản), một danh sách hoặc một lệnh ghép (xem SHELL GRAMMAR ở trên), thoát với trạng thái khác không. Trình bao không thoát nếu lệnh bị lỗi là một phần của danh sách lệnh ngay sau từ khóa while hoặc Until, một phần của kiểm tra theo sau các từ dành riêng if hoặc elif, một phần của bất kỳ lệnh nào được thực thi trong && hoặc || liệt kê ngoại trừ lệnh theo sau && hoặc || cuối cùng, bất kỳ lệnh nào trong một đường dẫn nhưng là lệnh cuối cùng hoặc nếu giá trị trả về của lệnh đang được đảo ngược với !. Nếu một lệnh ghép không phải là vỏ con trả về trạng thái khác 0 vì lệnh bị lỗi trong khi -e đang bị bỏ qua, thì trình bao sẽ không thoát. Một bẫy trên ERR, nếu được đặt, sẽ được thực thi trước khi trình bao thoát ra.
Nếu một lệnh ghép hoặc hàm shell thực thi trong ngữ cảnh mà -e đang bị bỏ qua, thì không lệnh nào được thực thi trong phần thân hàm hoặc lệnh ghép sẽ bị ảnh hưởng bởi cài đặt -e, ngay cả khi -e được đặt và một lệnh trả về tình trạng hỏng hóc. Nếu lệnh ghép hoặc hàm shell đặt -e trong khi thực thi trong ngữ cảnh mà -e bị bỏ qua, thì cài đặt đó sẽ không có bất kỳ tác dụng nào cho đến khi lệnh ghép hoặc lệnh chứa lệnh gọi hàm hoàn tất.
exec "$@"
thường được sử dụng để làm cho entrypoint đi qua sau đó chạy lệnh docker. Nó sẽ thay thế shell đang chạy hiện tại bằng lệnh "$@"
được trỏ tới. Theo mặc định, biến đó trỏ đến các đối số dòng lệnh.
Nếu bạn có một hình ảnh có điểm nhập trỏ đến entrypoint.sh và bạn chạy vùng chứa của mình với tư cách là docker run my_image server start
, điều đó sẽ chuyển sang chạy entrypoint.sh server start
trong vùng chứa. Tại dòng thực thi entrypoint.sh
, trình bao chạy dưới dạng pid 1 sẽ thay thế chính nó bằng lệnh server start
.
Điều này rất quan trọng đối với việc xử lý tín hiệu. Nếu không sử dụng exec
, server start
ví dụ trên sẽ chạy dưới dạng pid khác và sau khi thoát, bạn sẽ quay lại tập lệnh shell của mình. Với shell trong pid 1, SIGTERM sẽ bị bỏ qua theo mặc định. Điều đó có nghĩa là quá trình docker stop
sẽ không bao giờ nhận được tín hiệu dừng duyên dáng gửi đến vùng chứa của bạn server
. Sau 10 giây (theo mặc định), docker stop
sẽ từ bỏ việc tắt máy có duyên và gửi một SIGKILL sẽ buộc ứng dụng của bạn thoát ra, nhưng với khả năng mất dữ liệu hoặc kết nối mạng bị đóng, nhà phát triển ứng dụng đó có thể đã viết mã nếu họ nhận được tín hiệu. Điều đó cũng có nghĩa là vùng chứa của bạn sẽ luôn mất 10 giây để dừng lại.
Lưu ý rằng với các lệnh shell như shift
và set --
, bạn có thể thay đổi giá trị của "$@"
. Ví dụ: đây là một phần ngắn của tập lệnh loại bỏ lệnh /bin/sh -c "..."
khỏi lệnh có thể xuất hiện nếu bạn sử dụng cú pháp trình bao của docker cho CMD
:
# convert `/bin/sh -c "server start"` to `server start`
if [ $# -gt 1 ] && [ x"$1" = x"/bin/sh" ] && [ x"$2" = x"-c" ]; then
shift 2
eval "set -- $1"
fi
....
exec "$@"
test
, được đánh dấu là -a
lỗi thời. [ "$#" -gt 1 ] && [ "$1" = /bin/sh ]
là sự thay thế chính xác (không cần x"$1"
hack khi chỉ sử dụng cú pháp không lỗi thời).
shift 2; set -- $1
không giống với cách eval
sẽ phân tích cú pháp chuỗi. Hãy xem xét /bin/sh -c 'printf "%s\n" "hello world" "goodbye world"'
, nếu bạn muốn một trường hợp thử nghiệm cụ thể và thấy Bash không phân tích cú pháp dấu ngoặc kép khi chuyển đổi một chuỗi thành đối số .
eval
, tôi tin rằng tôi vẫn muốn điều đó phản ánh hành vi của /bin/sh -c
sẽ có trên chuỗi, nhưng hãy cho tôi biết nếu tôi thiếu thứ gì đó.
set -e
- thoát script nếu bất kỳ lệnh nào không thành công (giá trị khác 0)
exec "$@"
- sẽ chuyển hướng các biến đầu vào, xem thêm tại đây
exec
chắc chắn có một chế độ sử dụng nơi nó thực hiện chuyển hướng, nhưng đây không phải là chế độ đó.
set -e
được coi là dễ xảy ra lỗi hơn nhiều so với xử lý lỗi viết tay. (Nếu vội vàng, hãy bỏ qua phần tương tự ở trên cùng cho các bài tập bên dưới).