Các khái niệm về Docker và Docker Compose
Việc sử dụng Docker Compose đòi hỏi bạn phải kết hợp nhiều khái niệm khác nhau của Docker trong một lúc, vì vậy trước khi bắt đầu, hãy dành chút thời gian để ôn lại các khái niệm liên quan. Nếu bạn đã quen thuộc với các khái niệm của Docker như volumes, links và port forwarding thì có thể chuyển sang phần tiếp theo ngay.
Docker Images
Mỗi container Docker là một phiên bản cục bộ của một Docker image. Bạn có thể nghĩ về Docker image như một cài đặt Linux hoàn chỉnh. Thông thường, một cài đặt tối giản chỉ chứa những gói cơ bản cần thiết để chạy image. Các image này sử dụng kernel của hệ thống chủ, nhưng vì chúng chạy bên trong container Docker và chỉ nhìn thấy hệ thống tập tin của riêng mình, nên hoàn toàn có thể chạy một bản phân phối như CentOS trên hệ thống Ubuntu (hoặc ngược lại).
Hầu hết các Docker image được phân phối qua Docker Hub, được duy trì bởi đội ngũ Docker. Phần lớn các dự án mã nguồn mở phổ biến đều có một image tương ứng được tải lên Docker Registry, cho phép bạn triển khai phần mềm. Khi có thể, tốt nhất là sử dụng các image “official”, vì chúng được đội ngũ Docker đảm bảo tuân thủ các thực hành tốt nhất của Docker.
Giao tiếp giữa các Docker Images
Theo mặc định, các container Docker được cô lập khỏi máy chủ, có nghĩa là máy chủ không có quyền truy cập vào hệ thống tập tin bên trong container, cũng như không có cách nào giao tiếp với nó qua mạng. Điều này có thể gây khó khăn trong việc cấu hình và làm việc với image chạy bên trong container.
Docker có ba cách chính để khắc phục vấn đề này:
-
Sử dụng biến môi trường (environment variables):
Docker cho phép chỉ định các biến môi trường sẽ được thiết lập bên trong container. Mã chạy trong container sẽ kiểm tra các giá trị của biến môi trường này khi khởi động và sử dụng chúng để tự cấu hình. -
Docker data volume:
Docker volumes có hai dạng – nội bộ (internal) và chia sẻ (shared).-
Một volume nội bộ có nghĩa là đối với một thư mục cụ thể trong container, dữ liệu sẽ được lưu lại ngay cả khi container bị xóa. Ví dụ, nếu bạn muốn giữ lại các file log, bạn có thể chỉ định một volume nội bộ cho
/var/log
. -
Volume chia sẻ ánh xạ một thư mục bên trong container sang một thư mục trên máy chủ, giúp bạn dễ dàng chia sẻ tập tin giữa container và máy chủ. (Xem thêm bài viết về Docker data volume để biết thêm chi tiết.)
-
-
Giao tiếp qua mạng:
Docker cho phép giao tiếp giữa các container thông qua các liên kết (links) cũng như chuyển tiếp cổng (port forwarding). Ví dụ, bạn có thể tạo liên kết cho phép container WordPress và MariaDB giao tiếp với nhau, và sử dụng port forwarding để mở cổng cho WordPress ra ngoài, giúp người dùng có thể kết nối.
Yêu cầu tiên quyết
Để theo dõi bài viết này, bạn cần có:
-
Một Droplet Ubuntu 14.04
-
Một người dùng không phải root với quyền sudo (bài viết Thiết lập máy chủ ban đầu với Ubuntu 14.04 đã giải thích cách thiết lập điều này.)
Bước 1 – Cài đặt Docker
Trước tiên, nếu bạn chưa cài Docker, hãy tiến hành cài đặt. Cách nhanh nhất để cài Docker là tải và chạy script cài đặt của họ (bạn sẽ được yêu cầu nhập mật khẩu sudo).
wget -qO- https://get.docker.com/ | sh
Lệnh trên sẽ tải về và thực thi một script cài đặt nhỏ được viết bởi đội ngũ Docker. Nếu bạn không tin tưởng vào các script của bên thứ ba hoặc muốn biết chi tiết hơn về những gì script đang làm.
Việc làm việc với Docker sẽ gặp khó khăn nếu người dùng của bạn không được cấu hình đúng. Do đó, hãy thêm người dùng của bạn vào nhóm docker bằng lệnh sau:
sudo usermod -aG docker $(whoami)
Sau đó, đăng xuất và đăng nhập lại vào máy chủ để kích hoạt các nhóm mới.
Bước 2 – Cài đặt Docker Compose
Sau khi đã cài Docker, hãy tiến hành cài đặt Docker Compose. Đầu tiên, cài đặt python-pip
như một yêu cầu tiên quyết:
sudo apt-get -y install python-pip
Tiếp theo, cài đặt Docker Compose:
sudo pip install docker-compose
Bước 3 – Chạy một Container với Docker Compose
Docker Hub, registry công khai của Docker, bao gồm một image Hello World đơn giản. Giờ đây, khi bạn đã cài đặt Docker Compose, hãy kiểm tra nó với một ví dụ cực kỳ đơn giản này.
Đầu tiên, tạo một thư mục cho file YAML:
mkdir hello-world
Sau đó, chuyển vào thư mục:
cd hello-world
Tiếp theo, tạo file YAML sử dụng trình soạn thảo văn bản yêu thích (ở đây chúng ta sử dụng nano):
nano docker-compose.yml
Nhập nội dung sau vào file, sau đó lưu file và thoát trình soạn thảo:
docker-compose.yml my-test: image: hello-world
Dòng đầu tiên sẽ được sử dụng như một phần của tên container. Dòng thứ hai chỉ định image nào sẽ được sử dụng để tạo container. Image này sẽ được tải từ kho lưu trữ chính thức của Docker Hub.
Trong thư mục ~/hello-world
, thực thi lệnh sau để tạo container:
docker-compose up
Kết quả đầu ra sẽ bắt đầu như sau:
Output of docker-compose up Creating helloworld_my-test_1... Attaching to helloworld_my-test_1 my-test_1 | my-test_1 | Hello from Docker. my-test_1 | This message shows that your installation appears to be working correctly. my-test_1 |
Kết quả đầu ra sau đó giải thích những gì Docker đang thực hiện:
-
Docker client đã liên hệ với Docker daemon.
-
Docker daemon đã tải image “hello-world” từ Docker Hub.
-
Docker daemon đã tạo một container mới từ image đó, container chạy chương trình xuất ra kết quả mà bạn đang xem.
-
Docker daemon đã truyền dòng kết quả đó đến Docker client, và Docker client chuyển nó tới terminal của bạn.
Nếu quá trình không tự động kết thúc, nhấn CTRL-C.
Bài kiểm tra đơn giản này không thể hiện một trong những lợi ích chính của Docker Compose – khả năng khởi động và tắt một nhóm các container Docker cùng lúc. Các bài viết Cách Cài Đặt WordPress và PhpMyAdmin bằng Docker Compose trên Ubuntu 14.04 sẽ chỉ cho bạn cách sử dụng Docker Compose để chạy ba container như một nhóm ứng dụng.
Bước 4 – Học các lệnh của Docker Compose
Hãy cùng điểm qua các lệnh mà công cụ docker-compose
hỗ trợ.
Lệnh docker-compose
hoạt động trên cơ sở từng thư mục. Bạn có thể chạy nhiều nhóm container Docker trên một máy chủ – chỉ cần tạo một thư mục cho mỗi nhóm container và một file docker-compose.yml
cho mỗi nhóm container đó trong thư mục của nó.
Cho đến nay, chúng ta đã chạy docker-compose up
bằng tay và sử dụng CTRL-C
để tắt nó. Cách này cho phép hiển thị thông báo debug trên cửa sổ terminal. Tuy nhiên, khi chạy trong môi trường production, bạn sẽ muốn docker-compose
hoạt động giống như một service. Một cách đơn giản để làm điều này là thêm tham số -d
khi khởi động phiên:
docker-compose up -d
Sau đó, docker-compose
sẽ chạy ở chế độ nền.
Để hiển thị danh sách các container Docker trong nhóm (bao gồm cả container đang dừng và đang chạy), sử dụng lệnh:
docker-compose ps
Ví dụ, lệnh dưới đây cho thấy container helloworld_my-test_1
đang ở trạng thái dừng:
Output of `docker-compose ps` Name Command State Ports ----------------------------------------------- helloworld_my-test_1 /hello Exit 0
Một container đang chạy sẽ hiển thị trạng thái Up
:
Output of `docker-compose ps` Name Command State Ports --------------------------------------------------------------- nginx_nginx_1 nginx -g daemon off; Up 443/tcp, 80/tcp
Để dừng tất cả các container Docker đang chạy trong một nhóm ứng dụng, hãy thực hiện lệnh sau trong cùng thư mục chứa file docker-compose.yml
đã sử dụng để khởi động nhóm container:
docker-compose stop
Lưu ý: Lệnh
docker-compose kill
cũng có sẵn nếu bạn cần tắt các container một cách cưỡng bức.
Trong một số trường hợp, các container Docker sẽ lưu trữ thông tin cũ của chúng trong một volume nội bộ. Nếu bạn muốn bắt đầu lại từ đầu, bạn có thể sử dụng lệnh rm
để xóa hoàn toàn tất cả các container tạo nên nhóm container của bạn:
docker-compose rm
Nếu bạn thực hiện bất kỳ lệnh nào trong một thư mục khác với thư mục chứa container và file .yml
, hệ thống sẽ thông báo lỗi và không hiển thị container của bạn:
Output from wrong directory Can't find a suitable configuration file in this directory or any parent. Are you in the right directory? Supported filenames: docker-compose.yml, docker-compose.yaml, fig.yml, fig.yaml
Bước 5 – Truy cập hệ thống tập tin bên trong Container Docker
Nếu bạn cần làm việc trên dòng lệnh bên trong một container, bạn có thể sử dụng lệnh docker exec
.
Ví dụ Hello World! đã tự thoát sau khi chạy, vì vậy chúng ta cần khởi động một container giữ trạng thái chạy để có thể sử dụng docker exec
truy cập vào hệ thống tập tin của container. Hãy xem xét image Nginx từ Docker Hub.
Tạo một thư mục mới cho Nginx và chuyển vào đó:
mkdir ~/nginx && cd $_
Tạo file docker-compose.yml
trong thư mục mới:
nano docker-compose.yml
Dán nội dung sau vào file:
~/nginx/docker-compose.yml nginx: image: nginx
Sau đó, lưu file và thoát.
Chỉ cần khởi động container Nginx ở chế độ nền bằng lệnh:
docker-compose up -d
Image Nginx sẽ được tải xuống và container sẽ được khởi động ở chế độ nền. Giờ chúng ta cần lấy CONTAINER ID
của container. Liệt kê tất cả các container đang chạy:
docker ps
Bạn sẽ thấy một kết quả tương tự:
Output of `docker ps` CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e90e12f70418 nginx "nginx -g 'daemon off" 6 minutes ago Up 5 minutes 80/tcp, 443/tcp nginx_nginx_1
Lưu ý: Chỉ những container đang chạy mới được liệt kê với lệnh
docker ps
.
Nếu bạn muốn thực hiện thay đổi trong hệ thống tập tin của container, hãy lấy ID của container (ví dụ: e90e12f70418
) và sử dụng lệnh docker exec
để mở một shell bên trong container:
docker exec -it e90e12f70418 /bin/bash
Tham số -t
mở một terminal, và -i
cho phép tương tác. Tùy chọn /bin/bash
mở một shell bash trong container đang chạy. Hãy chắc chắn sử dụng ID của container của bạn.
Bạn sẽ thấy một prompt bash trong container như sau:
root@e90e12f70418:/#
Từ đây, bạn có thể làm việc với dòng lệnh. Tuy nhiên, hãy lưu ý rằng, trừ khi bạn đang làm việc trong một thư mục được lưu trữ trong volume dữ liệu, các thay đổi của bạn sẽ bị mất ngay khi container khởi động lại. Ngoài ra, hầu hết các image Docker được tạo ra với cài đặt Linux tối giản, vì vậy một số tiện ích và công cụ dòng lệnh mà bạn quen dùng có thể không có sẵn.