Docker RUN vs CMD vs ENTRYPOINT
Hiểu ngắn gọn là: RUN thực thi (các) lệnh trong một layer mới và tạo một image mới. Ví dụ: nó thường được sử dụng để cài đặt các gói phần mềm. CMD đặt lệnh và/hoặc là đặt các tham số mặc định trong dockerfile, lệnh hoặc các tham số mặc định này có thể được ghi đè từ dòng lệnh khi docker ...
Hiểu ngắn gọn là:
- RUN thực thi (các) lệnh trong một layer mới và tạo một image mới. Ví dụ: nó thường được sử dụng để cài đặt các gói phần mềm.
- CMD đặt lệnh và/hoặc là đặt các tham số mặc định trong dockerfile, lệnh hoặc các tham số mặc định này có thể được ghi đè từ dòng lệnh khi docker container chạy.
- ENTRYPOINT cấu hình một container sẽ chạy như một executable.
Tóm tắt thì là như vậy, còn để hiểu sau thì mời mọi người cùng đọc phần bên dưới, với một vài ví dụ khá dễ hiểu )
Docker images and layers
Khi Docker chạy một container, nó chạy một image bên trong nó. Image này thường được xây dựng bằng cách thực hiện các hướng dẫn (instruction) trong dockerfile, nó sẽ thêm các layer mới trên một base image đã tồn tại tạo ra một image mới.
Shell and Exec forms
Cả ba lệnh (RUN, CMD và ENTRYPOINT) có thể được chỉ định ở dạng shell form hoặc dạng exec form. Trước tiên ta cùng làm quen với các biểu mẫu này:
Shell form<instruction> <command>
Ex:
RUN apt-get install python3 CMD echo "Hello world" ENTRYPOINT echo "Hello world"
Khi instruction được thực thi trong shell form nó sẽ gọi xử lý /bin/sh -c <command> bên dưới và xử lý shell xảy ra. Ví dụ một đoạn mẫu trong dockerfile như sau
ENV name John Dow ENTRYPOINT echo "Hello, $name" # executed shell
khi run docker run -it < image > sẽ cho ra output:
Hello, John Dow
Biến $name được thay thế bằng giá trị set trong ENV
Exec formExec form được ưa thích sử dụng hơn với các hướng dẫn CMD và ENTRYPOINT
<instruction> ["executable", "param1", "param2", ...]
Ex:
RUN ["apt-get", "install", "python3"] CMD ["/bin/echo", "Hello world"] ENTRYPOINT ["/bin/echo", "Hello world"]
Khi lệnh thực thi ở dạng exec form, nó gọi thực thi trực tiếp và xử lý shell không xảy ra. Ví dụ: đoạn mã sau trong Dockerfile
ENV name John Dow ENTRYPOINT ["/bin/echo", "Hello, $name"]
khi container chạy docker run -it < image > sẽ cho output
Hello, $name
Biến $name không được thay thế
How to run bash?
Nếu muốn run bash thì ta sử dụng exec form với /bin/bash như một executable. Khi đó xử lý shell bình thường sẽ được thực thi. Ví dụ
ENV name John Dow ENTRYPOINT ["/bin/bash", "-c", "echo Hello, $name"]
khi container chạy output sẽ in ra biến $name
Hello, John Dow
RUN
Run cho phép ta cài đặt ứng dụng (các layer cần thiết cho ứng dụng) trên image ban đầu và tạo ra image mới bằng cách commit các layer mới được cài đặt thêm (refer docker commit).
Thường thì ta sẽ thấy nhiều lệnh RUN trong dockerfile. RUN có 2 cấu trúc
- RUN < command > (shell form) - RUN ["executable", "param1", "param2"] (exec form)
Một minh họa tốt về hướng dẫn RUN cài đặt nhiều package:
RUN apt-get update && apt-get install -y bzr cvs git mercurial subversion
Note: apt-get update và apt-get install được thực thi trong cùng một lệnh RUN. Điều này đảm bảo rằng các package mới nhất sẽ được cài đặt. Nếu apt-get install được chạy ở một lệnh RUN riêng thì nó sẽ sử dụng lại một layer được thêm bởi lệnh apt-get update, mà có thể đã được tạo ra từ trước đó. Lên lưu ý là hãy sử dụng apt-get update và apt-get install trong cùng một lệnh RUN.
CMD
CMD cho phép ta set default command, có nghĩa là command này sẽ chỉ được chạy khi run container mà không chỉ định một command.
Nếu docker run với một command thì default command sẽ được ignore. Nếu dockerfile có nhiều hơn một lệnh CMD thì tất cả sẽ bị ignore ngoại trừ lệnh CMD cuối cùng.
CMD có 3 dạng form:
- CMD ["executable", "param1", "param2"] (exec forrm, preferred) - CMD ["param1", "param2"] (đặt các tham số mặc định cho ENTRYPOINT ở dạng exec form) - CMD command param1 param2 (shell form)
Cách thứ 2 được sử dụng cùng với ENTRYPOINT trong exec form. Nó set default parameters được thêm vào ENTRYPOINT nếu container chạy mà không truyền đối số nào, ngược lại nó sẽ bị ignore. Ví dụ sử dụng đoạn mã dưới trong dockerfile
CMD echo "Hello world"
khi container chạy docker run -it < image > sẽ ra output
Hello world
nhưng khi chạy docker run -it < image > /bin/bash, CMD sẽ bị ignored và bash sẽ được thay thế, output:
[email protected]:/#
ENTRYPOINT
Lệnh ENTRYPOINT cho phép ta cấu hình container sẽ chạy dưới dạng thực thi. Nó tương tự như CMD, vì nó cũng cho phép ta chỉ định một lệnh với các tham số. Sự khác biệt là lệnh ENTRYPOINT và các tham số không bị ignore khi Docker container chạy với các tham số dòng lệnh. (Có một cách để bỏ qua ENTTRYPOINT, mọi người google search nhé)
ENTRYPOINT có 2 dạng form:
- ENTRYPOINT ["executable", "param1", "param2"] (exec form, preferred) - ENTRYPOINT command param1 param2 (shell form)
Exec form của ENTRYPOINT cho phép ta đặt các lệnh và tham số và sau đó sử dụng một trong hai dạng : một là CMD để đặt các tham số bổ sung (có nhiều khả năng sẽ được thay đổi), hai là các đối số ENTRYPOINT (luôn được sử dụng), trong khi các đối số CMD có thể được ghi đè bằng các tham số dòng lệnh được cung cấp khi Docker container chạy. Ví dụ sử dụng đoạn mã dưới trong dockerfile
ENTRYPOINT ["/bin/echo", "Hello"] CMD ["world"]
khi chạy docker với lệnh docker run -it < image > sẽ cho output:
Hello world
nhưng khi chạy với lệnh docker run -it < image > John sẽ cho output:
Hello John
đối số dòng lệnh John đã thay thế đối số world được set ở CMD
Shell form của ENTRYPOINT ignore tất CMD và các tahm số dòng lệnh
Tổng kết
RUN được sử dụng để cài đặt các layer, build image mới theo nhu cầu của ứng dụng.
ENTRYPOINT và CMD sử dụng khi ta cần một lệnh luôn được thực thi. Ngoài ra, hãy sử dụng CMD kết hợp với ENTRYPOINT nếu ta cần cung cấp thêm các đối số mặc định có thể được ghi đè từ dòng lệnh khi docker container chạy.
Chọn CMD nếu ta cần cung cấp một lệnh mặc định và / hoặc các tham số có thể được ghi đè từ dòng lệnh khi docker container chạy.