Những điều cơ bản về Docker

image.png

Warning

Các hình ảnh và nội dung trình bày được lấy từ khoá học https://kodekloud.com/courses/docker-for-the-absolute-beginner

Docker là gì? Tại sao phải sử dụng docker?

Đặt vấn đề

image1.png

Vấn đề mà Docker giải quyết

image2.png

Docker là gì?

Docker là một chương trình command-line, lưu ý rằng bản thân nó không tự tạo ra container. Khái niệm container đã có tại hệ điều hành UNIX từ lâu cũng với mục đích nhằm cách ly (isolation) các ứng dụng, service nhưng do việc cấu hình container cần có sự hiểu biết sâu về cách thành phần lõi của OS, liên quan đến kernel nên dễ dẫn đến sai. Do đó, Docker ra đời, giúp đơn giản hoá công việc cấu hình container.

Note

Docker is a command-line program, a background daemon, and a set of remote services that take a logistical approach to solving common software problems and simplifying your experience installing, running, publishing, and removing software. It accomplishes this using a UNIX technology called containers.

Tuy nhiên, vì khái niệm container chỉ tồn tại trên hệ điều hành UNIX, vậy còn đối với các hệ điều hành khác như Windows, MAC, việc sử dụng docker sẽ như thế nào? Giải pháp chính là sử dụng máy ảo Linux làm docker host. Có 2 option cài đặt Docker cho Windows và MAC là Docker Toolbox và Docker Desktop.
Sự khác nhau giữa Docker và Virtual Machine:

image3.png

Docker image vs Docker container

Docker Image giống như một template chứa các file cần thiết cho việc chạy một process.
Docker Container chỉ chạy khi có một process chạy trong nó, nếu như process dừng thì container cũng dừng.
Sử dụng Image có thể tạo ra nhiều container chạy độc lập với nhau.

image4.png

Docker command cơ bản

Run - Chạy một container

 #Cơ bản
docker run <image_name>
 
 #Chạy image với tag (tham khảo các tag có sẵn với một image trên Docker Hub)
 docker run <image_name>:<tag>
 
 #Chạy docker mode attack cho phép nhập input
 docker run –it <image_name>
 docker run –p <host_port>:<container_port> <image_name>

image5.png

 docker run –v /opt/datadir:/var/lib/mysql mysql

PS - Liệt kê các container

 #Các container đang chạy
 docker ps
 
 #Tất cả các container bao gồm đã dừng và đang chạy 
 docker ps -a 

STOP - Dừng một container

 docker stop <container_name_list>

RM - Xoá một container

<container_id> không nhất thiết là toàn bộ dãy string mà chỉ cần vài ký tự đầu nhưng là unique trong danh sách Container ID hiện tại.

 docker rm <container_id_list>

RM - Xoá một image

 #Liệt kê danh sách images đã pull
 docker images
 
 #Xoá images
 docker rmi <image_list>

Pull - Tải xuống image

 #Liệt kê danh sách images đã pull
 docker pull nginx

Mở rộng command

 docker run ubuntu sleep 5

Exec - chạy một command trong container

docker exec distracted_mcclintock cat /etc/hosts

Mode attack và detach

#Mode detach tạo một process chạy background
docker run –d <image_name>

#Mode attack gắn process vào terminal hiện tại
docker attach <container_id>

Inpect Container

docker inspect <container_id>

Container Logs

docker logs <container_id>

Docker enviroment variables

docker run-e APP_COLOR=blue -e <variable>=<value> simple-webapp-color

Docker Image

Cách tạo docker image

Docker Image sẽ đi cùng với file Dockerfile.

Dockerfile hiểu đơn giản là một file dạng script chứa tất cả các bước để setup, cài đặt và chạy ứng dụng hoặc service, concept tương tự việc viết script để chạy automation, tuy nhiên các công việc này thực hiện trong container riêng biệt và độc lập.

image6.png

Với mỗi command dạng INSTRUCTION ARGUMENT trong Docker file sẽ tạo ra một layer, và khi kết hợp nhiều command lại, nó tạo thành một cấu trúc nhiều layer. Mỗi layer sẽ chiếm dung lượng bộ nhớ khác nhau, nhưng layer sau sẽ chỉ lưu dữ liệu mà layer trước chưa có, việc này giúp tối ưu hoá bộ nhớ lưu trữ.

Docker cũng hỗ trợ tính năng cache dữ liệu, đảm bảo khi dữ liệu của một layer build thất bại, dữ liệu các layer trước vẫn được giữ nguyên trong bộ nhớ cache, và khi build lại image, không cần phải tốn thời gian pull dữ liệu các layer này.

image7.png

CMD và ENTRYPOINT

CMD và ENTRYPOINT đều là instruction cho phép chạy command/process ở thời điểm container bắt đầu chạy.

Warning

Lưu ý rằng cách instruction khác như RUN hay COPY trong ví dụ trên cũng đều thực hiện command nhưng là trong quá trình build image, sau khi build image và tạo container, các lệnh này sẽ không được thực thi nữa, thay vào đó là CMD và ENTRYPOINT.

CMD: các command và variable được định nghĩa có thể bị ghi đè trong quá trình chạy container, thường được sử dụng để định nghĩa mặc định. Trong ví dụ sau:

FROM ubuntu
CMD ["echo", "Hello World"]

ENTRYPOINT: các command và variable được định nghĩa không thể bị ghi đè trong quá trình chạy container.Trong ví dụ sau:

FROM ubuntu
ENTRYPOINT ["echo"]

Kết hợp việc sử dụng CMD và ENTRYPOINT:

FROM ubuntu
ENTRYPOINT ["echo"]
CMD ["Hello, World!"]

Lưu ý, có hai cách để định nghĩa command cho CMD và ENTRYPOINT:

image8.png

Docker Networking

Default networks

Có 3 dạng network chính trong docker host:

image9.png

User-defined networks

Tạo network mới:

docker network create –-driver bridge -–subnet 182.18.0.0/16 custom-isolated-network
Note

Theo mặc định, các brigde network là cách ly hoàn toàn ( tức là không kết nối với nhau).

DNS server

Docker Host có một DNS server mặc định có IP 127.0.0.11 để diễn giải IP của các container. Việc sử dụng IP để kết nối đến các service chạy trong container khá bất tiện vì IP có thể thay đổi bất cứ lúc nào, do đó với DNS server, trong cùng một mạng, các container có thể kết nối với nhau thông qua container name thay vì IP.

Theo mặc định, tất cả user-defined bridge network sử dụng một DNS server duy nhất có IP là 127.0.0.11

image10.png

Docker Storage

Cấu trúc thư mục của Docker

 /var/lib/docker
 |__aufs
 |__containers
 |__image
 |__volumes

Storage driver và Layered architecture

Như đã trình bày ở phần [[#Cách tạo docker image]], Docker Image có kiến trúc dạng layer, tuy nhiên tuỳ thuộc vào cấu hình storage driver sẽ có cách sử dụng và các tính năng lưu trữ dữ liệu khác nhau giữa các layer khác nhau.

Các loại storage driver:

Type Mô tả
AUFS • Kém hiệu quả với nhiều layer, hỗ trợ bởi các phiên bản Docker cũ
ZFS • Cung cấp hiệu suất cao và các tính năng nâng cao như kiểm tra tính toàn vẹn dữ liệu, snapshot và replication.
• Yêu cầu ZFS phải được cài đặt và cấu hình trên hệ thống máy chủ.
BTRFS • Có thêm tính năng snapshot và subvolume
• Khó quản lý
Device Mapper • Sử dụng LVM (Logical Volume Manager)
• Có thể chạy nhiều container nhưng không hiệu quả bằng Overlay2 và BTRFS
VFS • Sử dụng cho testing và debugging
• Không sử dụng trong môi trường production
Overlay2 • Driver mặc định cho hầu hết các hệ điều hành Linux
• Hiệu suất tốt và tối ưu hoá được việc sử dụng bộ nhớ
• Cho phép chia phân vùng bộ nhớ read-only và write khác nhau
• Cho phép sử dụng chung bộ nhớ cho nhiều layer

Sau đây, sẽ trình bày cách hoạt động cơ bản của Overlay2 Driver:

Layered architecture: Overlay2 cho phép sử dụng lại dữ liệu của các layer được build sẵn trong bộ nhớ cache giữa các image. Ví dụ, Dockerfile dưới đây sẽ build image my-custom-app và có 5 layers, Dockerfile2 sẽ build image my-custom-app có 5 layers nhưng có 3 layers giống với my-custom-app. Nếu như ta build my-custom-app trước, sau đó build my-custom-app-2, thì thay vì Docker pull thêm dữ liệu của 3 layer giống nhau trước đó, nó sẽ sử dụng lại dữ liệu trong bộ nhớ cache. Từ đó, tiết kiệm được dung lượng bộ nhớ.

image11.png

Mặc định các layer sau khi build image sẽ ở mode read-only. Và khi container được tạo từ image, Docker sẽ thêm một layer bên trên ở mode read-write, layer này sẽ lưu tất cả các dữ liệu phát sinh trong quá trình chạy của container. Nhưng nếu container bị xoá thì các dữ liệu ở layer read-write cũng sẽ biến mất.

image12.png

Để ngăn các dữ liệu phát sinh trong quá trình chạy container không bị mất đi, cần tạo volume và mount nó vào container. Có hai kiểu mount chính là BIND và VOLUME.

 docker volume create data_volume
 docker run –-mount source=data_volume,target=/var/lib/mysql mysql
 docker run –-mount type=bind,source=/data/mysql,target=/var/lib/mysql mysql

Docker Compose

Docker Compose có 3 version:

Trong ví dụ dưới đây, một ứng dụng voting đơn giản được xây dựng tại Github.

Các container trên được deploy trên một Docker Host duy nhất với hai network là front-endback-end, front-end là nơi giao tiếp giữa user và web interface, back-end là nơi giao tiếp giữa các thành phần internal của ứng dụng.

image13.png

Docker Registry

Ta có thể tạo các docker image bằng Dockerfile, sau đó build image dưới local và chạy container hoặc sử dụng image có sẵn trên Docker Hub. Vậy quá trình khi một image không có sẵn ở local và phải tiến hành pull từ Docker Hub diễn ra như thế nào? Việc này được thực hiện thông qua API server của Docker Hub, có thể giống như lệnh curl và URI path được gọi là Docker Registry.

Docker Hub chỉ là party lưu trữ image mặc định, chúng ta có thể pull image từ các party khác như Google, AWS,…

image14.png

Sử dụng Private Registry trên Docker Hub

docker login private-registry.io
docker run private-registry.io/apps/internal-app

Deploy Private Registry

#Chạy container xây dựng một registry server local
docker run -d -p 5000:5000 --name registry registry:2

#Tag image muốn push
docker image tag my-image localhost:5000/my-image
 
#Push Image lên Registry Server
docker push localhost:5000/my-image

#Pull Image từ Registry Server
docker pull localhost:5000/my-image

Docker Engine

Khi một host có cài đặt Docker thì gọi là Docker Host hay Docker Engine, các thành phần của Docker Engine bao gồm:

image15.png

Containerization

Về mặt concept, container có tính chất cô lập, Docker sử dụng các Namespace như Process ID, Unix Timesharing, Network, Mount, InterProcess để định nghĩa tính chất này. Network, Mount đã được thể hiện trong các phần trước.

image16.png

Process PID: Mỗi process trong hệ thống đều có Process ID (PID) riêng. Trong Docker, mỗi container chạy các process bên trong một không gian tên PID riêng biệt, nghĩa là PID trong container có thể khác với PID trên Docker Host. Các container Docker chạy dưới dạng các process bị cô lập, nhưng các tiến trình đó vẫn có các PID tương ứng trên Docker Host.

image17.png

Cgroups (Control Groups) là một tính năng cơ bản trong Linux mà Docker và các công nghệ container khác sử dụng để quản lý và giới hạn tài nguyên hệ thống (như CPU, bộ nhớ, I/O đĩa và mạng) được phân bổ cho các process. Cgroups cho phép Docker cô lập và phân bổ tài nguyên cho các container theo cách được kiểm soát.

image18.png

Container Orchestration

Đặt vấn đề

Các giải pháp Container Orchestration được sử dụng để giải quyết vấn đề này. Về mặt concept, các giải pháp này đều xoay quanh môi trường cluster, với một node là manager, các node còn lại là worker, nhận lệnh từ manager để deploy container một cách tự động.

image19.png

Docker Swarm

Docker Swarm yêu cầu setup thủ công Manager Node để join các Docker Host vào Cluster.

image20.png

image21.png

Kubernetes (k8s)

Có thêm nhiều option scaling số lượng container dựa vào hiện trạng truy cập, lượng traffic, có thể deploy container với số lượng rất lớn.

image22.png