Bài 39.2: Docker architecture và components

Bài 39.2: Docker architecture và components
Trong thế giới phát triển web hiện đại, Docker đã trở thành một công cụ không thể thiếu. Nó giúp chúng ta đóng gói ứng dụng và môi trường chạy của chúng vào các đơn vị nhỏ gọn, dễ dàng di chuyển và nhất quán - gọi là containers. Nhưng đằng sau sự tiện lợi đó là một kiến trúc mạnh mẽ với các thành phần hoạt động nhịp nhàng cùng nhau. Hiểu rõ kiến trúc này sẽ giúp bạn sử dụng Docker hiệu quả hơn, đặc biệt là khi triển khai các ứng dụng web phức tạp.
Hãy cùng đi sâu vào kiến trúc và các thành phần chính của Docker!
Kiến trúc Client-Server của Docker
Về cơ bản, Docker hoạt động dựa trên kiến trúc Client-Server. Đây là cách các thành phần tương tác với nhau:
- Docker Daemon (dockerd): Đây là "trái tim" của Docker, chạy ngầm trên hệ điều hành của bạn (hoặc trên một máy chủ từ xa). Docker Daemon lắng nghe các yêu cầu từ Docker Client và quản lý các đối tượng Docker như images, containers, volumes, và networks. Daemon chịu trách nhiệm xây dựng (build), chạy (run), và phân phối (distribute) các Docker container của bạn.
- Docker Client: Đây là cách người dùng tương tác với Docker. Client (thường là giao diện dòng lệnh CLI - Command Line Interface) gửi các lệnh đến Docker Daemon thông qua REST API. Khi bạn gõ
docker run
haydocker build
trong terminal, bạn đang sử dụng Docker Client để nói chuyện với Daemon. Client có thể chạy trên cùng một máy với Daemon hoặc trên một máy khác.
Mối quan hệ này cho phép sự linh hoạt: bạn có thể điều khiển một Docker Daemon đang chạy trên máy chủ cloud từ máy tính xách tay của mình thông qua Docker Client.
Các Thành phần Cốt lõi của Docker
Bây giờ, hãy tìm hiểu sâu hơn về các đối tượng chính mà Docker Daemon quản lý:
1. Docker Images
- Docker Images là các template (khuôn mẫu) chỉ đọc (read-only). Chúng chứa tất cả mọi thứ cần thiết để chạy một ứng dụng cụ thể: mã nguồn, thư viện, công cụ hệ thống, môi trường chạy, cấu hình, v.v. Tưởng tượng một image như một "bản chụp" (snapshot) của một hệ thống file và cấu hình sẵn sàng để chạy.
- Images được xây dựng từ một tệp tin đặc biệt gọi là Dockerfile. Mỗi lệnh trong Dockerfile tạo ra một lớp (layer) chỉ đọc mới trong image. Khi chạy một container, các lớp này được xếp chồng lên nhau.
Tại sao lại quan trọng cho web dev? Bạn có thể tạo ra các image chứa sẵn môi trường chạy cho ứng dụng web của mình, ví dụ: một image có Node.js và tất cả dependencies cho ứng dụng React/NextJs backend, hoặc một image có Nginx để phục vụ các file tĩnh của frontend.
Ví dụ đơn giản về cách tạo image: Giả sử bạn có một Dockerfile (chúng ta sẽ nói về nó kỹ hơn sau). Để xây dựng một image từ Dockerfile đó, bạn dùng lệnh:
docker build -t ten_image_cua_ban:latest .
- Giải thích:
docker build
: Lệnh nói với Docker Client rằng bạn muốn xây dựng một image.-t ten_image_cua_ban:latest
: Gắn thẻ (tag) cho image vừa tạo.ten_image_cua_ban
là tên bạn đặt,:latest
là phiên bản (tag)..
: Chỉ ra đường dẫn đến thư mục chứa Dockerfile (trong trường hợp này là thư mục hiện tại). Docker Daemon sẽ đọc Dockerfile ở đây để thực hiện các bước xây dựng image.
- Giải thích:
2. Docker Containers
- Docker Containers là các thể hiện đang chạy (running instances) của một Docker Image. Khi bạn chạy một image, Docker tạo ra một container từ image đó. Khác với image chỉ đọc, container có một lớp ghi được (writable layer) ở trên cùng. Mọi thay đổi bạn thực hiện khi container đang chạy (ghi file mới, thay đổi cấu hình...) đều được lưu vào lớp này.
- Mỗi container là một môi trường cô lập (isolated). Nó có hệ thống file riêng, mạng riêng, quy trình riêng, tách biệt hoàn toàn với hệ điều hành gốc và các container khác (trừ khi bạn cấu hình cho chúng giao tiếp).
Tại sao lại quan trọng cho web dev? Bạn có thể chạy nhiều instance của ứng dụng web (ví dụ: nhiều server Node.js), hoặc chạy database (MySQL, PostgreSQL) trong một container riêng biệt, thậm chí chạy một container Nginx/Apache để làm reverse proxy, tất cả trên cùng một máy nhưng hoàn toàn cô lập với nhau. Điều này giúp tránh xung đột môi trường và dễ dàng quản lý.
Ví dụ đơn giản về cách chạy container: Để chạy một container từ image bạn vừa build (hoặc từ một image có sẵn trên Docker Hub):
docker run -p 80:80 --name ten_container_cua_ban ten_image_cua_ban:latest
- Giải thích:
docker run
: Lệnh nói với Docker Client rằng bạn muốn chạy một container.-p 80:80
: Ánh xạ cổng (port mapping). Cổng80
trên máy chủ (host) sẽ được ánh xạ tới cổng80
bên trong container. Điều này cho phép bạn truy cập ứng dụng web đang chạy trong container từ trình duyệt của máy chủ.--name ten_container_cua_ban
: Đặt tên cho container để dễ quản lý hơn sau này.ten_image_cua_ban:latest
: Chỉ định image mà container sẽ chạy từ đó.
- Giải thích:
3. Dockerfile
- Dockerfile là một tệp tin văn bản chứa các lệnh (instructions) mà Docker Daemon sử dụng để xây dựng một Docker Image. Mỗi lệnh trong Dockerfile (như
FROM
,RUN
,COPY
,CMD
,EXPOSE
, v.v.) thực hiện một hành động cụ thể và tạo ra một lớp mới trong image. - Dockerfile mô tả từng bước để thiết lập môi trường và cài đặt ứng dụng của bạn một cách tự động. Điều này giúp đảm bảo quá trình xây dựng image luôn nhất quán và có thể lặp lại.
Tại sao lại quan trọng cho web dev? Dockerfile chính là "công thức" để đóng gói ứng dụng web của bạn. Bạn viết Dockerfile một lần và có thể sử dụng nó để tạo ra image chạy được ở bất cứ đâu có Docker, đảm bảo môi trường phát triển, staging, và production là giống nhau.
Ví dụ đơn giản về Dockerfile cho ứng dụng Node.js:
# Sử dụng image Node.js chính thức làm nền tảng FROM node:18 # Tạo thư mục làm việc bên trong container WORKDIR /app # Sao chép file package*.json để cài đặt dependencies COPY package*.json ./ # Cài đặt dependencies RUN npm install # Sao chép toàn bộ mã nguồn ứng dụng COPY . . # Mở cổng mà ứng dụng Node.js lắng nghe EXPOSE 3000 # Lệnh mặc định để chạy ứng dụng khi container khởi động CMD ["npm", "start"]
- Giải thích:
FROM node:18
: Bắt đầu từ một image Node.js version 18 đã có sẵn (tải từ Docker Hub).WORKDIR /app
: Đặt thư mục/app
làm thư mục làm việc mặc định cho các lệnh tiếp theo.COPY package*.json ./
: Sao chép các filepackage.json
vàpackage-lock.json
(hoặcyarn.lock
) từ máy chủ vào thư mục/app
trong image.RUN npm install
: Chạy lệnhnpm install
để cài đặt các thư viện cần thiết (được định nghĩa trongpackage.json
). Bước này tạo ra một lớp riêng, và Docker sẽ cache nó nếupackage*.json
không thay đổi, giúp quá trình build nhanh hơn.COPY . .
: Sao chép toàn bộ các file còn lại trong thư mục hiện tại của máy chủ vào thư mục/app
trong image.EXPOSE 3000
: Thông báo rằng container sẽ lắng nghe trên cổng 3000 khi chạy (chỉ là tài liệu, cần kết hợp với-p
khidocker run
để ánh xạ ra ngoài).CMD ["npm", "start"]
: Thiết lập lệnh mặc định sẽ được chạy khi container khởi động.
- Giải thích:
4. Docker Registry (e.g., Docker Hub)
- Docker Registry là nơi lưu trữ các Docker Images. Nó hoạt động như một kho chứa tập trung, cho phép bạn tải về (pull) các image có sẵn do người khác tạo ra và đẩy lên (push) các image của riêng bạn để chia sẻ hoặc lưu trữ.
- Docker Hub là Registry công cộng lớn nhất và phổ biến nhất. Ngoài ra, các công ty có thể thiết lập Registry riêng (Private Registry) để lưu trữ các image nội bộ.
Tại sao lại quan trọng cho web dev? Bạn có thể dễ dàng sử dụng các image nền tảng chuẩn (như
node
,nginx
,ubuntu
,mysql
) từ Docker Hub mà không cần tự xây dựng từ đầu. Bạn cũng có thể đẩy image ứng dụng web của mình lên Registry để nhóm làm việc cùng sử dụng hoặc để hệ thống CI/CD/triển khai tự động kéo về.Ví dụ đơn giản về kéo và đẩy image: Để tải một image từ Docker Hub:
docker pull nginx:latest
Để đẩy image của bạn lên Docker Hub (sau khi đã đăng nhập và đặt tên image theo định dạng
your_dockerhub_username/ten_image_cua_ban:tag
):docker push your_dockerhub_username/ten_image_cua_ban:latest
- Giải thích:
docker pull nginx:latest
: Tải image Nginx phiên bảnlatest
từ Docker Hub về máy cục bộ của bạn.docker push ...
: Đẩy imageten_image_cua_ban
với taglatest
từ máy cục bộ của bạn lên kho lưu trữ trên Docker Hub dưới tài khoảnyour_dockerhub_username
.
- Giải thích:
Cách các thành phần hoạt động cùng nhau trong một quy trình điển hình
Một quy trình làm việc thông thường với Docker cho ứng dụng web sẽ diễn ra như sau:
- Bạn viết mã nguồn ứng dụng web của mình (ví dụ: code React, code Node.js backend).
- Bạn tạo một Dockerfile mô tả cách xây dựng môi trường cho ứng dụng đó (dựa trên image nền tảng từ Docker Registry, sao chép code, cài đặt dependencies, cấu hình...).
- Sử dụng Docker Client, bạn chạy lệnh
docker build
để gửi Dockerfile và các file cần thiết tới Docker Daemon. - Docker Daemon đọc Dockerfile, thực hiện từng lệnh để tạo ra các lớp, và cuối cùng đóng gói chúng lại thành một Docker Image mới.
- Bạn có thể tùy chọn sử dụng Docker Client chạy lệnh
docker push
để đẩy image vừa tạo lên một Docker Registry (như Docker Hub) để lưu trữ hoặc chia sẻ. - Để chạy ứng dụng, bạn dùng Docker Client chạy lệnh
docker run
. Nếu image chưa có trên máy cục bộ, Docker Daemon sẽ tự động kéo (pull) image đó từ Docker Registry về. - Docker Daemon tạo ra một Docker Container từ image và chạy ứng dụng của bạn bên trong môi trường cô lập đó.
Hiểu được các thành phần này và cách chúng tương tác là nền tảng vững chắc để bạn có thể khai thác tối đa sức mạnh của Docker trong quá trình phát triển và triển khai các ứng dụng web. Docker không chỉ giúp đơn giản hóa môi trường mà còn mở ra cánh cửa cho các kiến trúc hiện đại hơn như microservices và CI/CD (Tích hợp Liên tục / Triển khai Liên tục).
Comments