Sổ tay Docker: Thao tác Docker Container cơ bản
Trong phần trước, bạn đã tìm hiểu về kiến trúc của Docker, ba khái niệm cơ bản của Docker là Container, Image, Registry và bạn cũng đã chạy một container bằng lệnh docker run
. Nếu bỏ lỡ thì bạn có thể xem lại bài viết này ở dưới đây:
Trong phần này, bạn sẽ tìm hiểu về các thao tác container một cách chi tiết hơn. Thao tác container là một trong những nhiệm vụ phổ biến nhất mà bạn sẽ thực hiện mỗi ngày, vì vậy việc hiểu đúng về các lệnh khác nhau là rất quan trọng.
Tuy nhiên, hãy nhớ rằng đây không phải là danh sách đầy đủ tất cả các lệnh bạn có thể thực thi trên Docker. Tôi sẽ chỉ nói về những lệnh phổ biến nhất. Bất cứ khi nào bạn muốn tìm hiểu thêm về các lệnh có sẵn, chỉ cần truy cập tài liệu tham khảo chính thức của Docker.
Làm thế nào để chạy một Container
Ở bài viết trước, bạn đã sử dụng lệnh docker run
để tạo và chạy một container bằng image hello-world
. Cú pháp chung cho lệnh này như sau:
docker run <image name>
Mặc dù đây là một lệnh hoàn toàn hợp lệ, nhưng có một cách tốt hơn để gửi lệnh tới docker
daemon.
Trước phiên bản 1.13
, Docker chỉ có cú pháp lệnh được đề cập ở trên. Sau này, câu lệnh đã được cấu trúc lại để có cú pháp sau:
docker <object> <command> <options>
Trong cú pháp này:
object
cho biết loại đối tượng Docker mà bạn sẽ thao tác. Đây có thể là mộtcontainer
,image
,network
hoặcvolume
.command
cho biết lệnh được thực hiện bởi daemon, đó là lệnhrun
.options
có thể là bất kỳ tham số hợp lệ nào có thể ghi đè hành vi mặc định của lệnh, như tùy chọn--publish
ánh xạ cổng.
Bây giờ, theo cú pháp này, lệnh run
có thể được viết như sau:
docker container run <image name>
Trong đó image name
có thể là bất kỳ image nào từ Registry hoặc hệ thống cục bộ của bạn. Ví dụ: bạn có thể thử chạy một container bằng image fhsinchy/hello-dock. Image này chứa một ứng dụng Vue.js đơn giản chạy trên cổng 80 bên trong container.
Để chạy container bằng image này, hãy thực hiện lệnh sau trên thiết bị đầu cuối của bạn:
docker container run --publish 8080:80 fhsinchy/hello-dock
# /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
# /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
# /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
# 10-listen-on-ipv6-by-default.sh: Getting the checksum of /etc/nginx/conf.d/default.conf
# 10-listen-on-ipv6-by-default.sh: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
# /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
# /docker-entrypoint.sh: Configuration complete; ready for start up
Lệnh này khá dễ hiểu. Phần duy nhất có thể yêu cầu một số lời giải thích là phần --publish 8080:80
sẽ được giải thích trong phần tiếp theo.
Làm thế nào để publish port cho Container
Container là môi trường cô lập. Hệ thống máy chủ của bạn không biết bất cứ điều gì về những gì đang xảy ra bên trong một container. Do đó, các ứng dụng chạy bên trong container không thể truy cập được từ bên ngoài.
Để cho phép truy cập từ bên ngoài container, bạn phải publish port thích hợp bên trong container tới một port trên mạng cục bộ của bạn. Cú pháp chung cho tùy chọn --publish
hoặc -p
như sau:
--publish <host port>:<container port>
Khi bạn đã viết --publish 8080:80
trong phần trước, điều đó có nghĩa là bất kỳ yêu cầu nào được gửi đến cổng 8080 của hệ thống máy chủ của bạn sẽ được chuyển tiếp đến cổng 80 bên trong container.
Bây giờ để truy cập ứng dụng trên trình duyệt của bạn, hãy truy cập http://127.0.0.1:8080
.
Bạn có thể dừng tùy chọn bằng cách nhấn tổ hợp phím ctrl + c
trong terminal hoặc đóng terminal.
Cách sử dụng chế độ Detached
Một tùy chọn rất phổ biến khác của lệnh run
là tùy chọn --detach
hoặc -d
. Trong ví dụ trên, để container tiếp tục chạy, bạn phải giữ cửa sổ terminal mở. Đóng cửa sổ terminal cũng sẽ dừng container đang chạy.
Điều này là do, theo mặc định, các container chạy ở chế độ bình thường và tự gắn vào terminal giống như bất kỳ chương trình bình thường nào khác được gọi từ terminal.
Để ghi đè hành vi này và giữ cho container chạy nền, bạn có thể thêm tùy chọn --detach
cho lệnh run
như sau:
docker container run --detach --publish 8080:80 fhsinchy/hello-dock
# 9f21cb77705810797c4b847dbd330d9c732ffddba14fb435470567a7a3f46cdc
Không giống như ví dụ trước, bạn sẽ không nhận được nhiều thông điệp trên terminal ở lần này. Thay vào đó, những gì bạn sẽ nhận được là ID của container mới được tạo.
Thứ tự của các tùy chọn bạn cung cấp không thực sự quan trọng. Nếu bạn đặt tùy chọn --publish
trước tùy chọn --detach
, nó sẽ hoạt động giống nhau.
Một điều mà bạn phải ghi nhớ trong trường hợp lệnh run
là tên image phải đứng sau cùng. Nếu bạn đặt bất kỳ thứ gì sau tên image, điều đó sẽ được chuyển làm đối số cho điểm vào image (được giải thích chi tiết trong phần Thực thi lệnh bên trong container) và có thể dẫn đến các tình huống không mong muốn.
Cách liệt kê các container
Lệnh container ls
có thể được sử dụng để liệt kê danh sách container hiện đang chạy. Để làm như vậy, hãy thực hiện lệnh sau:
docker container ls
# CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
# 9f21cb777058 fhsinchy/hello-dock "/docker-entrypoint.…" 5 seconds ago Up 5 seconds 0.0.0.0:8080->80/tcp gifted_sammet
Một container có tên gifted_sammet
đang chạy. Nó đã được tạo 5 seconds ago
và trạng thái Up 5 seconds
cho biết rằng container đã hoạt động tốt kể từ khi nó được tạo.
Cột CONTAINER ID
có giá trị 9f21cb777058
đó là 12 ký tự đầu tiên của Container ID đầy đủ. Container ID đầy đủ dài 64 ký tự như sau: 9f21cb77705810797c4b847dbd330d9c732ffddba14fb435470567a7a3f46cdc
. Container ID đầy đủ này đã được in dưới dạng đầu ra của lệnh docker container run
trong phần trước.
Được liệt kê dưới cột PORTS
, cổng 8080 từ mạng cục bộ của bạn đang hướng tới cổng 80 bên trong container. Tên gifted_sammet
được tạo bởi Docker và có thể là một cái gì đó hoàn toàn khác trong máy tính của bạn.
Lệnh container ls
chỉ liệt kê các container hiện đang chạy trên hệ thống của bạn. Để liệt kê tất cả các container đã chạy trước đây, bạn có thể sử dụng tùy chọn --all
hoặc -a
.
docker container ls --all
# CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
# 9f21cb777058 fhsinchy/hello-dock "/docker-entrypoint.…" 2 minutes ago Up 2 minutes 0.0.0.0:8080->80/tcp gifted_sammet
# 6cf52771dde1 fhsinchy/hello-dock "/docker-entrypoint.…" 3 minutes ago Exited (0) 3 minutes ago reverent_torvalds
# 128ec8ceab71 hello-world "/hello" 4 minutes ago Exited (0) 4 minutes ago exciting_chebyshev
Như bạn có thể thấy, container thứ hai trong danh sách reverent_torvalds
đã được tạo trước đó và đã thoát với mã trạng thái 0, cho biết rằng không có lỗi nào được tạo ra trong thời gian chạy của container.
Cách đặt tên hoặc đổi tên container
Theo mặc định, mỗi container có hai định danh sau:
CONTAINER ID
– một chuỗi dài 64 ký tự ngẫu nhiên.NAME
– sự kết hợp của hai từ ngẫu nhiên, được nối bằng dấu gạch dưới.
Chỉ định một container dựa trên hai định danh ngẫu nhiên này là một điều bất tiện. Sẽ thật tuyệt nếu các container có thể được gọi bằng tên do bạn xác định.
Đặt tên cho container có thể đạt được bằng cách sử dụng tùy chọn --name
. Để chạy một tùy chọn khác bằng cách sử dụng image fhsinchy/hello-dock
với tên hello-dock-container
bạn có thể thực hiện lệnh sau:
docker container run --detach --publish 8888:80 --name hello-dock-container fhsinchy/hello-dock
# b1db06e400c4c5e81a93a64d30acc1bf821bed63af36cab5cdb95d25e114f5fb
Cổng 8080 trên mạng cục bộ bị tùy chọn gifted_sammet
(container đã tạo trong phần trước) chiếm giữ. Đó là lý do tại sao bạn sẽ phải sử dụng một số cổng khác, chẳng hạn như 8888. Bây giờ để xác minh, hãy chạy lệnh container ls
:
docker container ls
# CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
# b1db06e400c4 fhsinchy/hello-dock "/docker-entrypoint.…" 28 seconds ago Up 26 seconds 0.0.0.0:8888->80/tcp hello-dock-container
# 9f21cb777058 fhsinchy/hello-dock "/docker-entrypoint.…" 4 minutes ago Up 4 minutes 0.0.0.0:8080->80/tcp gifted_sammet
Một container mới có tên là hello-dock-container
đã được khởi chạy.
Bạn thậm chí có thể đổi tên các container cũ bằng lệnh container rename
. Cú pháp của lệnh như sau:
docker container rename <container identifier> <new name>
Để đổi tên container gifted_sammet
thành hello-dock-container-2
, hãy thực hiện lệnh sau:
docker container rename gifted_sammet hello-dock-container-2
Lệnh không in ra bất kỳ đầu ra nào nhưng bạn có thể kiểm tra bằng cách sử dụng lệnh container ls
. Lệnh rename
làm việc với container cả trong trạng thái đang chạy và trạng thái đã dừng.
Làm thế nào để dừng hoặc hủy một container đang chạy
Có thể dừng các container đang chạy ở chế độ bình thường bằng cách chỉ cần đóng cửa sổ terminal hoặc nhấn ctrl + c
. Tuy nhiên, các container đang chạy nền không thể bị dừng lại theo cách tương tự.
Có hai lệnh xử lý tác vụ này. Đầu tiên là lệnh container stop
. Cú pháp chung cho lệnh như sau:
docker container stop <container identifier>
Trong đó container identifier
có thể là id hoặc tên của container.
Tôi hy vọng rằng bạn nhớ container mà bạn đã bắt đầu trong phần trước. Nó vẫn đang chạy trong nền. Lấy mã định danh cho container đó bằng cách sử dụng lệnh docker container ls
(Tôi sẽ sử dụng container hello-dock-container
để minh họa). Bây giờ thực hiện lệnh sau để dừng container:
docker container stop hello-dock-container
# hello-dock-container
Nếu bạn sử dụng tên làm định danh, bạn sẽ nhận được tên trả lại cho bạn dưới dạng đầu ra. Lệnh stop
dừng một container một cách nhẹ nhàng bằng cách gửi một tín hiệu SIGTERM
. Nếu container không dừng lại trong một khoảng thời gian nhất định, một tín hiệu SIGKILL
sẽ được gửi để hủy container ngay lập tức.
Trong trường hợp bạn muốn gửi tín hiệu SIGKILL
thay vì tín hiệu SIGTERM
, bạn có thể sử dụng lệnh container kill
để thay thế. Lệnh container kill
có cú pháp tương tự như lệnh stop
.
docker container kill hello-dock-container-2
# hello-dock-container-2
Cách khởi động lại container
Khi tôi nói khởi động lại, nó có nghĩa là hai tình huống cụ thể. Chúng như sau:
- Khởi động lại container đã bị dừng hoặc bị hủy trước đó.
- Khởi động lại một container đang chạy.
Như bạn đã tìm hiểu từ phần trước, các container đã dừng vẫn còn trong hệ thống của bạn. Nếu bạn muốn, bạn có thể khởi động lại chúng. Lệnh container start
có thể được sử dụng để khởi động bất kỳ container bị dừng hoặc bị hủy. Cú pháp của lệnh như sau:
docker container start <container identifier>
Bạn có thể lấy danh sách tất cả các container bằng cách thực hiện lệnh container ls --all
. Sau đó, tìm kiếm các container có trạng thái Exited
.
docker container ls --all
# CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
# b1db06e400c4 fhsinchy/hello-dock "/docker-entrypoint.…" 3 minutes ago Exited (0) 47 seconds ago hello-dock-container
# 9f21cb777058 fhsinchy/hello-dock "/docker-entrypoint.…" 7 minutes ago Exited (137) 17 seconds ago hello-dock-container-2
# 6cf52771dde1 fhsinchy/hello-dock "/docker-entrypoint.…" 7 minutes ago Exited (0) 7 minutes ago reverent_torvalds
# 128ec8ceab71 hello-world "/hello" 9 minutes ago Exited (0) 9 minutes ago exciting_chebyshev
Bây giờ để khởi động lại container hello-dock-container
, bạn có thể thực hiện lệnh sau:
docker container start hello-dock-container
# hello-dock-container
Bây giờ bạn có thể đảm bảo rằng container đang chạy bằng cách xem danh sách các container đang chạy bằng lệnh container ls
.
Lệnh container start
khởi động bất kỳ container trong chế độ detached theo mặc định và giữ lại bất kỳ cấu hình cổng thực hiện trước đó. Vì vậy, nếu bạn truy cập http://127.0.0.1:8080
ngay bây giờ, bạn sẽ có thể truy cập ứng dụng hello-dock
giống như trước đây.
Bây giờ, trong các tình huống mà bạn muốn khởi động lại một container đang chạy, bạn có thể sử dụng lệnh container restart
. Lệnh container restart
có cú pháp tương tự lệnh container start
.
docker container restart hello-dock-container-2
# hello-dock-container-2
Sự khác biệt chính giữa hai lệnh là lệnh container restart
cố gắng dừng container đích và sau đó khởi động lại, trong khi lệnh container start
chỉ khởi động một container đã dừng.
Trong trường hợp container bị dừng, cả hai lệnh đều hoàn toàn giống nhau. Nhưng trong trường hợp container đang chạy, bạn phải sử dụng lệnh container restart
.
Cách tạo container mà không cần chạy
Cho đến phần này, bạn đã biết khởi động các container bằng cách sử dụng lệnh container run
. Trên thực tếcontainer run
là sự kết hợp của hai lệnh riêng biệt. Các lệnh này như sau:
container create
lệnh tạo một container từ một image nhất định.container start
lệnh khởi động một container đã được tạo.
Bây giờ, chúng ta sẽ làm lại ví dụ trong phần Làm thế nào để chạy container bằng cách sử dụng hai lệnh này, bạn có thể làm như sau:
docker container create --publish 8080:80 fhsinchy/hello-dock
# 2e7ef5098bab92f4536eb9a372d9b99ed852a9a816c341127399f51a6d053856
docker container ls --all
# CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
# 2e7ef5098bab fhsinchy/hello-dock "/docker-entrypoint.…" 30 seconds ago Created hello-dock
Rõ ràng là ở đầu ra của lệnh container ls --all
, một container có tên là hello-dock
đã được tạo bằng cách sử dụng image fhsinchy/hello-dock
. Trạng thái của container ở thời điểm hiện tại đang là Created
và do nó không chạy, nó sẽ không được liệt kê nếu không sử dụng tùy chọn --all
.
Khi container đã được tạo, nó có thể được khởi động bằng cách sử dụng lệnh container start
.
docker container start hello-dock
# hello-dock
docker container ls
# CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
# 2e7ef5098bab fhsinchy/hello-dock "/docker-entrypoint.…" About a minute ago Up 29 seconds 0.0.0.0:8080->80/tcp hello-dock
Trạng thái của container đã thay đổi từ Created
sang Up 29 seconds
chỉ ra rằng container hiện đang ở trạng thái chạy. Cấu hình cổng cũng đã hiển thị trong cột PORTS
mà trước đó là trống .
Mặc dù bạn có thể sử dụng lệnh container run
trong phần lớn các tình huống, nhưng sẽ có một số tình huống sau này yêu cầu bạn sử dụng lệnh container create
.
Làm thế nào để xóa một container
Như bạn đã thấy, các container đã bị dừng hoặc bị hủy vẫn còn trong hệ thống. Các container treo lơ lửng này có thể chiếm dung lượng hoặc có thể xung đột với các container mới hơn.
Để loại bỏ một container đã dừng, bạn có thể sử dụng lệnh container rm
. Cú pháp chung như sau:
docker container rm <container identifier>
Để biết container nào không chạy, hãy sử dụng lệnh container ls --all
và tìm container có trạng thái Exited
.
docker container ls --all
# CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
# b1db06e400c4 fhsinchy/hello-dock "/docker-entrypoint.…" 6 minutes ago Up About a minute 0.0.0.0:8888->80/tcp hello-dock-container
# 9f21cb777058 fhsinchy/hello-dock "/docker-entrypoint.…" 10 minutes ago Up About a minute 0.0.0.0:8080->80/tcp hello-dock-container-2
# 6cf52771dde1 fhsinchy/hello-dock "/docker-entrypoint.…" 10 minutes ago Exited (0) 10 minutes ago reverent_torvalds
# 128ec8ceab71 hello-world "/hello" 12 minutes ago Exited (0) 12 minutes ago exciting_chebyshev
Như có thể thấy trong đầu ra, container có Container ID 6cf52771dde1
và 128ec8ceab71
không chạy. Để xóa container 6cf52771dde1
bạn có thể thực hiện lệnh sau:
docker container rm 6cf52771dde1
# 6cf52771dde1
Bạn có thể kiểm tra xem container đã bị xóa hay chưa bằng cách sử dụng lệnh container ls --all
. Bạn cũng có thể xóa nhiều container cùng một lúc bằng cách truyền nhiều định danh của các container được phân tách bằng khoảng trắng.
Hoặc, thay vì xóa các container riêng lẻ, nếu bạn muốn xóa tất cả các container đã dừng cùng một lúc, bạn có thể sử dụng lệnh container prune
.
Bạn có thể kiểm tra danh sách container bằng lệnh container ls --all
để đảm bảo rằng các container đã dừng đã được loại bỏ:
docker container ls --all
# CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
# b1db06e400c4 fhsinchy/hello-dock "/docker-entrypoint.…" 8 minutes ago Up 3 minutes 0.0.0.0:8888->80/tcp hello-dock-container
# 9f21cb777058 fhsinchy/hello-dock "/docker-entrypoint.…" 12 minutes ago Up 3 minutes 0.0.0.0:8080->80/tcp hello-dock-container-2
Trong hướng dẫn này chúng ta có 2 container là hello-dock-container
và hello-dock-container-2
trong danh sách. Tôi sẽ đề nghị bạn dừng và xóa cả hai container này trước khi chuyển sang phần tiếp theo.
Ngoài ra còn có tùy chọn --rm
cho lệnh container run
và container start
mà chỉ ra rằng bạn muốn xóa container ngay khi nó dừng lại. Để bắt đầu một container hello-dock
khác với tùy chọn --rm
, hãy thực hiện lệnh sau:
docker container run --rm --detach --publish 8888:80 --name hello-dock-volatile fhsinchy/hello-dock
# 0d74e14091dc6262732bee226d95702c21894678efb4043663f7911c53fb79f3
Bạn có thể sử dụng lệnh container ls
để xác minh rằng container đang chạy:
docker container ls
# CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
# 0d74e14091dc fhsinchy/hello-dock "/docker-entrypoint.…" About a minute ago Up About a minute 0.0.0.0:8888->80/tcp hello-dock-volatile
Bây giờ nếu bạn dừng container và sau đó kiểm tra lại bằng lệnh container ls --all
:
docker container stop hello-dock-volatile
# hello-dock-volatile
docker container ls --all
# CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
Container đã được gỡ bỏ tự động. Từ bây giờ tôi sẽ sử dụng tùy chọn --rm
cho hầu hết các container. Tôi sẽ đề cập rõ ràng những chỗ không cần thiết.
Cách chạy Container trong chế độ tương tác
Cho đến nay, bạn chỉ chạy các container được tạo từ image hello-world hoặc image fhsinchy/hello-dock. Những image này được tạo ra để thực hiện các chương trình đơn giản không tương tác.
Chà, hầu hết các image không đơn giản như vậy. Image có thể đóng gói toàn bộ bản phân phối Linux bên trong chúng.
Các bản phân phối phổ biến như Ubuntu, Fedora và Debian đều có Docker image chính thức có sẵn trên Docker Hub. Các ngôn ngữ lập trình như python, php, go hoặc trình thực thi như node và de đều có image chính thức của chúng.
Những image này không chỉ chạy một số chương trình được cấu hình sẵn. Thay vào đó, chúng được cấu hình để chạy một shell theo mặc định. Trong trường hợp image hệ điều hành, nó có thể giống như sh
hoặc bash
và trong trường hợp ngôn ngữ lập trình hoặc trình thực thi, nó thường là shell ngôn ngữ mặc định của chúng.
Như bạn có thể đã học được từ kinh nghiệm trước đây của mình với máy tính, shell là các chương trình tương tác. Một image được cấu hình để chạy một chương trình như vậy là một image tương tác. Những image này yêu cầu một tùy chọn đặc biệt -it
được truyền trong lệnh container run
.
Ví dụ: nếu bạn chạy một container bằng cách sử dụng image ubuntu
bằng cách thực thi lệnh docker container run ubuntu
, bạn sẽ thấy không có gì xảy ra. Nhưng nếu bạn thực hiện cùng lệnh trên với tùy chọn -it
, bạn sẽ truy cập trực tiếp vào bash bên trong container Ubuntu.
docker container run --rm -it ubuntu
# root@dbb1f56b9563:/# cat /etc/os-release
# NAME="Ubuntu"
# VERSION="20.04.1 LTS (Focal Fossa)"
# ID=ubuntu
# ID_LIKE=debian
# PRETTY_NAME="Ubuntu 20.04.1 LTS"
# VERSION_ID="20.04"
# HOME_URL="https://www.ubuntu.com/"
# SUPPORT_URL="https://help.ubuntu.com/"
# BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
# PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
# VERSION_CODENAME=focal
# UBUNTU_CODENAME=focal
Như bạn có thể thấy từ đầu ra của lệnh cat /etc/os-release
, tôi thực sự đang tương tác với bash chạy bên trong container Ubuntu.
Tùy chọn -it
cho phép bạn có thể tương tác với bất kỳ chương trình tương tác bên trong một container. Tùy chọn này thực sự là hai tùy chọn riêng biệt được trộn với nhau.
- Tùy chọn
-i
hoặc--interactive
kết nối bạn với các luồng đầu vào của các container, do đó bạn có thể gửi lệnh cho bash. - Tùy chọn
-t
hoặc--tty
đảm bảo rằng bạn nhận được một vài định dạng tốt và một terminal thực sự bằng cách phân bổ một pseudo-tty.
Bạn cần sử dụng tùy chọn -it
này bất cứ khi nào bạn muốn chạy một container ở chế độ tương tác. Một ví dụ khác có thể chạy image node
như sau:
docker container run -it node
# Welcome to Node.js v15.0.0.
# Type ".help" for more information.
# > ['farhan', 'hasin', 'chowdhury'].map(name => name.toUpperCase())
# [ 'FARHAN', 'HASIN', 'CHOWDHURY' ]
Bất kỳ mã JavaScript hợp lệ nào đều có thể được thực thi trong shell của Node. Thay vì viết -it
, bạn có thể viết dài dòng hơn bằng cách viết --interactive --tty
.
Cách thực thi các lệnh bên trong container
Trong phần trước, bạn đã thấy tôi thực thi một lệnh bên trong container Alpine Linux. Nó trông như thế này:
docker run alpine uname -a
# Linux f08dbbe9199b 5.8.0-22-generic #23-Ubuntu SMP Fri Oct 9 00:34:40 UTC 2020 x86_64 Linux
Trong lệnh này, tôi đã thực hiện lệnh uname -a
bên trong container Alpine Linux. Các tình huống như thế này (trong đó tất cả những gì bạn muốn làm là thực hiện một lệnh nhất định bên trong một container nhất định) khá phổ biến.
Giả sử rằng bạn muốn mã hóa một chuỗi bằng chương trình base64
. Đây là thứ có sẵn trong hầu hết mọi hệ điều hành dựa trên Linux hoặc Unix (nhưng không có trên Windows).
Trong tình huống này, bạn có thể nhanh chóng chạy một container bằng cách sử dụng các image như busybox và để nó thực hiện công việc.
Cú pháp chung để mã hóa một chuỗi bằng cách sử dụng base64
như sau:
echo -n my-secret | base64
# bXktc2VjcmV0
Và cú pháp chung để truyền một lệnh đến một container không chạy như sau:
docker container run <image name> <command>
Để thực hiện mã hóa base64 bằng image busybox, bạn có thể thực hiện lệnh sau:
docker container run --rm busybox echo -n my-secret | base64
# bXktc2VjcmV0
Điều xảy ra ở đây là, trong một lệnh container run
, bất cứ thứ gì bạn truyền sau tên image được chuyển đến điểm vào mặc định của image.
Một điểm vào giống như một cổng vào image. Hầu hết các image ngoại trừ các image thực thi (được giải thích trong phần tiếp theo) sử dụng shell hoặc sh
làm điểm vào mặc định. Vì vậy, bất kỳ lệnh shell hợp lệ nào cũng có thể được chuyển cho chúng dưới dạng đối số.
Cách làm việc với image thực thi
Trong phần trước, tôi đã đề cập ngắn gọn đến các image thực thi (Executable Images). Những image này được thiết kế để hoạt động giống như các chương trình thực thi.
Lấy ví dụ dự án rmbyext. Đây là một tập lệnh Python đơn giản có khả năng xóa đệ quy các tệp có phần mở rộng nhất định. Để tìm hiểu thêm về dự án, bạn có thể kiểm tra kho: https://github.com/fhsinchy/rmbyext.
Nếu bạn đã cài đặt cả Git và Python, bạn có thể cài đặt tập lệnh này bằng cách thực hiện lệnh sau:
pip install git+https://github.com/fhsinchy/rmbyext.git#egg=rmbyext
Giả sử Python đã được thiết lập đúng cách trên hệ thống của bạn, tập lệnh sẽ có sẵn ở mọi nơi thông qua terminal. Cú pháp chung để sử dụng tập lệnh này như sau:
rmbyext <file extension>
Để kiểm tra, hãy mở terminal của bạn bên trong một thư mục trống và tạo một số tệp trong đó với các phần mở rộng khác nhau. Bạn có thể sử dụng lệnh touch
để làm như vậy. Bây giờ, tôi có một thư mục trên máy tính của mình với các tệp sau:
touch a.pdf b.pdf c.txt d.pdf e.txt
ls
# a.pdf b.pdf c.txt d.pdf e.txt
Để xóa tất cả các tệp pdf
khỏi thư mục này, bạn có thể thực hiện lệnh sau:
rmbyext pdf
# Removing: PDF
# b.pdf
# a.pdf
# d.pdf
Một image thực thi cho chương trình này sẽ có thể lấy phần mở rộng của tệp làm đối số và xóa chúng giống như chương trình rmbyext
đã làm.
Image fhsinchy/rmbyext cũng thực thi một cách tương tự. Image này chứa một bản sao của tập lệnh rmbyext
và được cấu hình để chạy tập lệnh trên một thư mục /zone
bên trong container.
Bây giờ vấn đề là các container bị cô lập với hệ thống cục bộ của bạn, vì vậy chương trình rmbyext
chạy bên trong container không có bất kỳ quyền truy cập nào vào hệ thống tệp cục bộ của bạn. Vì vậy, nếu bằng cách nào đó bạn có thể ánh xạ thư mục cục bộ chứa các tệp pdf
vào thư mục /zone
bên trong container, thì các tệp sẽ có thể truy cập được từ container.
Một cách để cấp cho container quyền truy cập trực tiếp vào hệ thống tệp cục bộ của bạn là sử dụng bind mount (liên kết ràng buộc).
Liên kết ràng buộc cho phép bạn hình thành liên kết dữ liệu hai chiều giữa nội dung của thư mục hệ thống tệp cục bộ (nguồn) và một thư mục khác bên trong container (đích). Bằng cách này, bất kỳ thay đổi nào được thực hiện trong thư mục đích sẽ có hiệu lực trên thư mục nguồn và ngược lại.
Hãy xem một liên kết ràng buộc hoạt động như thế nào. Để xóa tệp bằng container này thay vì chính chương trình, bạn có thể thực hiện lệnh sau:
docker container run --rm -v $(pwd):/zone fhsinchy/rmbyext pdf
# Removing: PDF
# b.pdf
# a.pdf
# d.pdf
Như bạn có thể đã đoán khi xem phần -v $(pwd):/zone
trong lệnh, tùy chọn -v
hoặc --volume
được sử dụng để tạo một liên kết ràng buộc cho một container. Tùy chọn này có thể có ba trường được phân tách bằng dấu hai chấm (:
). Cú pháp chung cho tùy chọn như sau:
--volume <local file system directory absolute path>:<container file system directory absolute path>:<read write access>
Trường thứ ba là tùy chọn nhưng bạn phải truyền đường dẫn tuyệt đối của thư mục cục bộ và đường dẫn tuyệt đối của thư mục bên trong container.
Thư mục nguồn trong trường hợp của tôi là /home/fhsinchy/the-zone
. Terminal của tôi được mở bên trong thư mục $(pwd)
sẽ được thay thế bằng thư mục /home/fhsinchy/the-zone
chứa tệp .pdf
và tệp .txt
đã đề cập trước đó .
Tùy chọn --volume
hoặc -v
có giá trị trong các lệnh container run
cũng như container create
. Chúng ta sẽ khám phá chi tiết hơn trong các phần sắp tới, vì vậy đừng lo lắng nếu bạn không hiểu rõ về chúng ở đây.
Sự khác biệt giữa image thông thường và image thực thi là điểm vào cho image thực thi được đặt thành một chương trình tùy chỉnh thay vì sh
, trong trường hợp này là chương trình rmbyext
. Và như bạn đã tìm hiểu trong phần trước, bất cứ thứ gì bạn viết sau tên image trong lệnh container run
sẽ được chuyển đến điểm vào của image.
Vì vậy, kết thúc lệnh docker container run --rm -v $(pwd):/zone fhsinchy/rmbyext pdf
sẽ chuyển sang lệnh rmbyext pdf
bên trong container. Image thực thi không phổ biến trong thực tế nhưng có thể rất hữu ích trong một số trường hợp nhất định.
Ở bài viết tiếp theo, bạn sẽ tìm hiểu về các thao tác Docker Image cơ bản:
Bài viết này được dịch từ cuốn sách The Docker Handbook của Farhan Hasin Chowdhury: