Để sử dụng Docker thì bạn có thể bở qua bài này.Để thực sự master một thứ gì đó, bạn cần hiểu rõ cơ chế hoạt động của nó. Đây là bài lý thuyết, không có bài tập thực hành.
- Docker engine là nhân phần mềm để chạy và quản lý container. Nó gần giống với ESXi ở VMware. Docker engine là thiết kế module với nhiều bộ phận có thể thay đổi.
- Docker engine như là một động cơ xe ô tô- đều được tạo bởi nhiều bộ phận chuyên biêt:
- Động cơ ô tô được tạo từ nhiều phần chuyên biệt hoạt động cùng nhau để xe có thể đi đươc - Động cơ xi lanh, Bugi, van, trục cam,....
- Docker engine cũng được tạo từ các tool chuyên biệt mà chạy cùng nhau để chạy và quản lý container - APIs, runtime, shim, .....
- Các thành phần chính cấu tạo nên Docker Engine là : Docker Client, Docker daemon, containerd, runc.
- Bản phân phối đầu tiên của Docker engine có 2 phần chính:
- Docker daemon
- LXC
- Docker daemon là một khối nhị phân thống nhất chứa tất cả code của Docker client, Docker API, container runtime, image build, và nhiều thứ khác.
- LXC cung cấp cho Docker daemon quyền truy cập vào các building-block cơ bản của container mà tồn tại trong Linux Kernel như Cgroup và namespace.
- Thứ nhất, LXC dành riêng cho Linux nên nó trở thành vấn đề lớn với dự án đa nền tảng của Docker.
- Thứ hai, việc phụ thuộc vào một công cụ bên ngoài cho một phần cốt lõi của dự án là một rủi ro lớn có thể ảnh hưởng đến sự phát triển của dự án.
- Do đó, công ty Docker đã phát triển công cụ riêng của họ là libcontainer để thay thế LXC. Mục tiêu của libcontainer là một công cụ không cần biết nền tảng, cung cấp cho Docker quyền truy cập vào các container building-block thay thế LXC trong Docker 0.9.
- Bản chất nguyên khối của Docker deamon dẫn có những hạn chế:
- Khó phát triển.
- Ngày càng chậm hơn.
- Nó không phải là những gì mà thệ sinh thái Docker mong muốn
- Docker .Inc tiến hành mô-dun hóa nó. Mục đích của họ là tách docker daemon ra thành nhiều chức năng nhất có thể và rồi thực hiện các chức năng đó qua các công cụ chuyên dụng nhỏ hơn. Các công cụ nhỏ có thể tháo lắp
OCI định nghĩa hai thông số liên quan đến container:
- Image spec
- Container runtime spec Docker sử dụng runc để chứa container runtime code. runc là bản phân phối tham chiếu cho OCI container-runtime-spec. runc và containerd đều là các thành phần của Docker engine với mục đích là phù hợp với các thông số OCI.
- Docker inc tham gia rất nhiều để xác định các thông số và phát triển runc theo các thông số đó
- runc được coi là một trình command-line wrapper nhỏ, nhẹ cho libcontainer.
- runc dùng để tạo container nhanh, là một công cụ container runtime độc lập. Nó tạo, chạy contaner tốt nhưng lại không có nhiều chức năng.
- runc là low-level container runtime
- containerd (phát âm container-dee) là một công cụ dùng để quản lý vòng đời của các container:
start | stop | pause | rm ...
. - containerd có sẵn như một daemon cho Linux và Window.
- containerd nằm giữa Docker daemon và runc trong các tầng OCI.
- containerd không chỉ quản lý vòng đời của container, sau này nó được phát triển để làm được nhiều nhứ khác, như là quản lý image. Lý do là để containerd dễ sử dụng trong các sự án khác. Tuy nhiên, các chức năng khác của containerd là dạng mô đun có thể dùng hoặc không.
- containerd là high-level container runtime
- Lệnh
docker container run
sau chạy một container từalpine
image:docker container run --name vidu -it alpine sh
- Khi bạn gõ lệnh như trên vào Docker CLI, Docker client sẽ convert chúng thành API payload phù hợp và post chúng vào các API endpoint đúng,
- API được triển khai trên Docker daemon sau khi nhận lệnh tạo một container, nó liên hệ đến containerd thông qua CRUD-style API qua gRPC. Lưu ý, Docker daemon không chứa bất kì một đoạn code nào để chạy container.
- containerd không thể tạo container mà nó convert image thành một gói OCI và yêu cầu runc dùng nó để tạo container.
- runc giao tiếp với OS kernel để tập hợp các cấu trúc cần thiết để tạo một container( namespace, cgroup,... ). Container process sẽ khởi động như một process con của runc và ngay sau khi nó hoạt động, runc sẽ thoát.
- quá trình tạo container được tóm tắt ở hình sau.
- Container runtime tách biệt với Docker daemon nên có thể bảo trì và nâng cấp Docker daemon mà không ảnh hưởng đến những container đang chạy
- Trước đây khi mà container runtime được triển khai trên daemon thì mỗi khi cập nhật Docker (cập nhật thường xuyên), docker daemon cập nhật sẽ kill hết các container đang chạy.
- shim quan trọng trong quá trình tách biệt một container đang chạy với daemon.
- Khi tạo một một container nghĩa là tạo ra một runc process mới để chạy container process như process con của runc. Nhưng ngay sau khi container được tạo thì runc process sẽ thoát.
- Khi runc thoát, container shim process thay thế runc trở thành process cha cho container. Nhiệm vụ của shim:
- giữ bất kì STDIN và STDOUT mở cho đến khi daemon khởi động lại, do đó container không bị đóng
- báo cáo trạng thái thoát của container cho daemon
- dockerd (the Docker daemon)
- docker-containerd (containerd)
- docker-container-shim (shim)
- docker-runc (runc)
The Docker engine is modular in design and based heavily on open-standards from the OCI. The Docker daemon implements the Docker API which is currently a rich, versioned, HTTP API that has developed alongside the rest of the Docker project. Container execution is handled by containerd. containerd was written by Docker, Inc. and contributed to the CNCF. You can think of it as a container supervisor that handles container lifecycle operations. It is small and lightweight and can be used by other projects and third-party tools. For example, it’s poised to become the default, and most common, container runtime in Kubernetes. containerd needs to talk to an OCI-compliant container runtime to actually create containers. By default, Docker uses runc as its default container runtime. runc is the de facto implementation of the OCI container-runtime-spec and expects to start containers from OCI-compliant bundles. containerd talks to runc and ensures Docker images are presented to runc as OCI-compliant bundles. runc can be used as a standalone CLI tool to create containers. It’s based on code from libcontainer, and can also be used by other projects and third-party tools. There is still a lot of functionality implemented in the Docker daemon. More of this may be broken out over time. Functionality currently still inside of the Docker daemon include, but is not limited to: the API, image management, authentication, security features, core networking, and volumes. The work of modularizing the Docker engine is ongoing