Thứ Ba, 17 tháng 8, 2021

Bài 3: Tổng quan về docker

Xây dựng môi trường hỗ trợ làm việc nhóm với Docker

Bài 3: Tổng quan về docker

Nguyễn Lê Nhật Trường

 

Mục đích: Tiếp theo bài viết về “Tạo lập môi trường phát triển ứng dụng web có kết nối cơ sở dữ liệu”, chúng ta sẽ đi tìm hiểu nguyên lý hoạt động của docker. Qua 2 bài trước, ta thấy việc sử dụng docker container khiến cho việc cài đặt các công cụ phát triển và triển khai các kiến trúc dành cho 1 hệ thống phần mềm trở lên tinh gọn và nhanh chóng. Vậy docker container là gì, chúng hoạt động như thế nào, chúng có điểm tương đồng nào với hệ thống Virtual machine hay không, và nếu có thì Docker có phải là giải pháp thay thế cho Virtual machine. Chúng ta sẽ trả lời các câu hỏi này trong phần nội dung bài viết.

Yêu cầu về kiến thức cơ bản

·         Hiểu được cách hoạt động của hệ điều hành.

·         Hiểu được cách hoạt động của máy ảo Virtual Machine.

Để thuận lợi cho việc trình bày, chúng ta sẽ định nghĩa 1 số khái niệm dùng chung

Khái niệm

Diễn giải

Máy host

Máy tính/máy chủ/máy ảo đang cài đặt ứng dụng docker

Image

Docker image

Kernel

Phần nhân của hệ điều hành, chứa các tập lệnh xử lý.

horizontal scale

Một phương pháp tăng năng lực xử lý của hệ thống bằng cách nhân bản nhiều instance của web application và điều phối các request đến các instance nhằm chia nhỏ khối lượng xử lý cho mỗi instance.

swarm mode

Chế độ cho phép docker thực hiện horizontal scale cho các container.

 

1.       Docker Engine

a.       Mechanism

Về mặt cơ chế, chúng ta có thể tóm tắt docker engine qua các ý sau:

·         Docker là một phần mềm, chạy trên nền của hệ điều hành của máy host (có thể là Linux hoặc Window có hỗ trợ ảo hóa – Virtual Machine Platform hay Hyper-V). Docker sẽ đóng vai trò trung gian giao tiếp giữa các ứng dụng trong container và hệ điều hành của máy host.

·         Dựa trên các tập lệnh cơ bản của hệ điều hành hiện tại, Docker cung cấp cơ chế ảo hóa các tập lệnh này để sử dụng cho các container. Khi các ứng dụng trong container gọi các tập lệnh đã được ảo hóa, các lệnh này sẽ được xử lý ở phần kernel của máy host, sau đó điều chỉnh phần kết quả dựa theo context của container đó trước khi trả về cho chương trình.

·         Mỗi container được xem như là 1 sandbox, nơi cung cấp 1 môi trường hoàn toàn cô lập với máy host và các container khác. Mỗi 1 container sẽ chứa các resource được ảo hóa như các tập lệnh của hệ điều hành, đơn vị xử lý (CPU), bộ nhớ (RAM), nơi lưu trữ (storage), cấu hình mạng (network).

·         Docker cho phép kiểm soát việc sử dụng các resource được khai báo cho mỗi container như RAM, CPU, Storage, Network.

·         Mỗi container có thể tạo ra các docker image (1 dạng snapshot cho container) nhằm mục đích tái sử dụng container này.

·         Ngoài ra, docker còn cho phép horizontal scale cho các container thông qua swarm mode, từ đó tăng năng lực xử lý cho các service trong hệ thống. (các service phải được thiết kế theo hướng Decentralized).

b.      Docker vs Virtual machine

Sau khi đi qua phần cơ chế, ta thấy có khá nhiều điểm tương đồng giữa Docker và Virtual Machine (VM) như:

·         Cơ chế sandboxing: cho phép cô lập các môi trường chạy.

·         Cơ chế ảo hóa: cho phép ảo hóa các thành phần của môi trường thực thi.

·         Cho phép tạo các snapshot để tái sử dụng nhiều lần.

·         Cho phép kiểm soát các resource như CPU, RAM, storage, Network.

Bên cạnh đó, VM và docker vẫn có các đặc trưng rất riêng như:

VM

Docker

Dung lượng lưu trữ 1 snapshot lớn do phải kèm cả phần hệ điều hành lần phần ứng dụng chạy trong VM

Dung lượng lưu trữ cho 1 snapshot (docker image) nhỏ hơn do chỉ chứa các file cần thiết để thực thi ứng dụng

Thời gian khởi động chương trình lâu hơn do phải chờ khởi động xong hệ điều hành

Thời gian khởi động chương trình nhanh hơn do hệ điều hành đã được load sẵn

Không phụ thuộc vào hệ điều hành của máy host. Hỗ trợ ảo hóa hoàn toàn các phần cứng cần thiết.

Phụ thuộc vào hệ điều hành của máy host để chạy các tập lệnh ảo hóa. Hiểu cách khác là không thể chạy các container windows trên nền hệ điều hành linux.

Mức độ cô lập giữa các VM cao hơn, đảm bảo hơn về bảo mật.

Mức độ cô lập giữa các container trong cùng 1 host thấp hơn.

Hướng về xây dựng Infrastructure as a Service

Hướng về xây dựng Platform as a service

Tiếp cận theo hướng infrastructure centric

Tiếp cận theo hướng application centric

Tốn nhiều thời gian để setup hỗ trợ horizontal scale

Dể dàng triển khai horizontal scale trong thời gian thực.

Như vậy, VM và docker mặc dù có nhiều điểm giống nhau, nhưng đây là 2 thành phần riêng biệt khi triển khai hệ thống phần mềm. Chúng không thể hoàn toàn thay thế nhau và có mối quan hệ tương hỗ lẫn nhau. Chúng ta có thể setup 1 hệ thống VM để tối ưu hóa việc sử dụng phần cứng. Tuy nhiên trên mỗi VM, chúng ta có thể cài đặt docker và tạo ra môi trường deployment nhanh chóng và tiện lợi.

c.       Docker architecture

The Docker daemon: Cung cấp các API để quản lý các container và các thành phần khác trong docker engine như: image, network, volume. Các daemon có thể giao tiếp với nhau để cùng quản lý các services trong docker.

The Docker client: một command line interface (CLI) dành cho lập trình viên tương tác với docker daemon.

Docker registries: Nơi dùng để lưu trữ, quản lý và chia sẻ các docker image.

 

2.       Docker image

Docker image là một snapshot các thành phần lưu trữ (file và folder) của 1 container kèm với các tập lệnh chỉ định để khởi chạy container đó. Thông thường, một Docker image sẽ được xây dựng (build) dựa trên một Docker image có sẵn.

Docker sử dụng định dạng dữ liệu AUFS (Advance multi-layered Unification File System) để lưu trữ các image. Mỗi 1 image sẽ được cấu thành từ nhiều lớp dữ liệu (layer), mỗi lớp dữ liệu chứa các file đã thay đổi so với lớp trước đó. Khi chúng ta build một image mới dựa trên 1 image có sẵn, chúng ta sẽ có 1 image mới với các lớp dữ liệu mới dựa trên các lớp dữ liệu của image cũ. Như vậy, thay vì chúng ta tốn bộ nhớ để lưu trữ 2 bộ dữ liệu như nhau, chúng ta sẽ sử dụng bộ nhớ để lưu trữ các image tối ưu hơn.

Theo thông thường, chúng ta  2 cách để tạo ra 1 Docker image:

·         Build image từ 1 file Dockerfile: Mỗi một tập lệnh trong Dockerfile sau khi thực thi sẽ trở thành 1 lớp dữ liệu trong docker image mới. Trong 2 bài trước, chúng ta đã thực hiện tạo dockerfile để build image cho 2 thành phần db và web container.

·         Snapshot từ 1 container: Docker sẽ hỗ trợ biến các thay đổi về file trong container hiện tại so với image của nó và tạo ra 1 lớp dữ liệu mới. Để thực hiện tạo snapshot từ 1 container, chúng ta có thể dùng lệnh docker commit để tạo ra docker image.

Mỗi lớp dữ liệu trong image sẽ được đại diện bằng 1 mã hash (tương tự như git). Mã hash của lớp cuối cùng trong image sẽ đại diện cho image đó. Chúng ta có thể dùng tag để đặt tên cho mã hash của image nhằm tạo sự thuận lợi trong việc quản lý và sử dụng image sau này. Một docker image có thể có nhiều tag khác nhau tùy theo mục đích.

Phần tag của 1 image sẽ gồm 2 thành phần <tên tag>:<version>. Phần tên tag và version là các chuỗi string viết liền, không dấu cách, chỉ chứa ký tự, số, dấu – và dấu _. Đối với các image được quản lý bởi registry, tên tag phải chứa domain/username của registry đó. VD: image muốn publish lên private registry của google cloud thì sẽ dạng như sau: gcr.io/project-id/image-name:v1.1, image muốn publish lên docker hub thì sẽ có dạng như sau: docker-hub-username/image-name:v1.1.

Nhược điểm lớn nhất khi sử dụng định dạng AUFS đó là 1 image càng nhiều lớp thì image đó càng lưu trữ thiếu hiệu quả. Đôi lúc, dung lượng của image sẽ lớn hơn tổng dung lượng các file và folder có trong image. Lúc đó, chúng ta sẽ cần phải giảm bớt số lượng lớp trong image để tối ưu hóa cho việc lưu trữ image và thực thi các container.

Để chia sẻ các image giữa các máy host khác nhau, chúng ta có thể publish image lên 1 registry (VD: docker hub, cloud registry, self-host registry…) hoặc xuất image ra thành 1 file bằng lệnh docker save và gửi chia sẻ file này cho các máy khác (đây là giải pháp không khuyến khích do không tối ưu về mặt lưu trữ cũng như quản lý phiên bản).

3.       Docker container

Docker container là một instance của 1 docker image. Instance này chứa các file và folder trong image tạo ra một môi trường thực thi (execute environment) cho ứng dụng bên trong container.

Các tập lệnh chỉ định trong container (CMD hoặc ENDPOINT trong docker file) sẽ được docker thực thi khi container được start. Phần output của các lệnh này sẽ được ghi thành log của container này. Sau khi thực thi xong các tập lệnh này, container sẽ tự động stop.

Docker container tương tự như docker image, sử dụng AUFS để lưu trữ các dữ liệu trong container. Cụ thể, từ các layer của image, docker sẽ khởi tạo một layer mới dành cho container để lưu trữ các file đã thay đổi theo cơ chế copy-on-write (CoW). Với cơ chế CoW, container muốn thay đổi nội dung 1 file có trong docker image sẽ phải copy file đó vào container layer trước, sau đó thay đổi file có trong container layer.

 

Cơ chế này của docker cho phép hệ điều hành tối ưu hóa về lưu trữ khi chạy nhiều container thuộc cùng 1 image. Tuy nhiên, phần container layer này chỉ là phần lưu trữ tạm thời, khi container bị xóa khỏi docker thì layer này cũng sẽ bị xóa theo.

Mặc định, các container hoạt động độc lập (isolate) so với các container khác trong cùng 1 docker engine. Đồng nghĩa, một container sẽ không thể tương tác với các container khác. Để các container giao tiếp được với nhau, chúng ta cần phải xây dựng một mạng dùng chung kết nối các container cùng với nhau. Với cơ chế này, chúng ta có thể giao tiếp giữa các container thông qua tên của các container hoặc thông qua các alias được khai báo trong network. Chúng ta sẽ được tìm hiểu cụ thể hơn về cách khai báo và giao tiếp giữa các container trong phần Docker network.

Ngoại trừ cơ chế lưu trữ trên định dạng AUFS, docker còn hỗ trợ khai báo các vùng nhớ trong container với các định dạng khác như btrfs, zfs, vfs,… Chúng ta sẽ tìm hiểu cụ thể hơn về các vùng nhớ này trong phần Docker volume.

Chúng ta có thể tạo ra 1 container bằng các cách sau:

·         Dùng lệnh docker run

·         Dùng lệnh docker create

·         Dùng các tập lệnh của docker-compose

 

Như vậy chúng ta đã đi qua được phần cơ chế hoạt động của docker cũng như 2 thành phần cơ bản nhất của docker là container và image. Trong bài tiếp theo, chung ta sẽ tìm hiểu thêm về các thành phần còn lại trong docker như volume, network, log và swarm trong docker.

Rất mong sự góp ý chân thành và chia sẻ của quí vị về loạt series này.

 

Không có nhận xét nào:

Đăng nhận xét