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:

Sổ tay Docker: Giới thiệu khái niệm cơ bản của Docker
Trong hướng dẫn này, bạn sẽ làm quen với kiến trúc Docker và ba khái niệm rất cơ bản về container hóa là Container, Image và Registry.

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ột container, image, network hoặc volume.
  • command cho biết lệnh được thực hiện bởi daemon, đó là lệnh run.
  • 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.

Làm thế nào để publish port cho Container

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.

Cách khởi động lại container

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 6cf52771dde1128ec8ceab71 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-containerhello-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, FedoraDebian đề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ư nodede đề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:

Sổ tay Docker: Thao tác Docker Image cơ bản
Trong hướng dẫn này, bạn sẽ tìm hiểu các thao tác Docker Image cơ bản như: tạo image, xem danh sách image, xóa image, tối ưu image, hiểu về các lớp của image, ...

Bài viết này được dịch từ cuốn sách The Docker Handbook của Farhan Hasin Chowdhury:

The Docker Handbook – 2021 Edition
The concept of containerization itself is pretty old. But the emergence of the Docker Engine [https://docs.docker.com/get-started/overview/#docker-engine] in2013 has made it much easier to containerize your applications. According to the Stack Overflow Developer Survey - 2020[https://insights.stackoverflow.com/survey/2020#overview…
DockerDevOps
Bài Viết Liên Quan:
Deploy ứng dụng ASP.NET Core bằng Docker
Trung Nguyen 29/03/2021
Deploy ứng dụng ASP.NET Core bằng Docker

Bài viết này sẽ hướng dẫn bạn chi tiết cách deploy ứng dụng ASP.NET Core bằng Docker.

Sổ tay Docker: Cách sử dụng Docker Compose
Trung Nguyen 20/03/2021
Sổ tay Docker: Cách sử dụng Docker Compose

Trong hướng dẫn này, bạn sẽ tìm hiểu các kiến thức cơ bản về Docker Compose, cách chạy và quản lý các dịch vụ sử dụng Docker Compose.

Sổ tay Docker: Cách chạy ứng dụng JavaScript trên nhiều Container
Trung Nguyen 20/03/2021
Sổ tay Docker: Cách chạy ứng dụng JavaScript trên nhiều Container

Trong hướng dẫn này, bạn sẽ học cách triển khai ứng dụng trên nhiều container trong Docker.

Sổ tay Docker: Thao tác Docker Network cơ bản
Trung Nguyen 19/03/2021
Sổ tay Docker: Thao tác Docker Network cơ bản

Bạn sẽ tìm hiểu các kiến thức cơ bản về Docker Network, các thao tác mạng cơ bản như: tạo và xóa mạng, gắn container vào mạng, gỡ container khỏi mạng.