Khi mà kỷ nguyên điện toán đám mây trở nên phổ biến, cũng là lúc mà các doanh nghiệp bắt đầu thực hiện một cuộc di dời cơ sở hạ tầng và kiến trúc của họ sang các nền tảng này, và là thời điểm mà các lập trình viên phải quan tâm đến các vấn đề container hoá và điều phối container. Và khi mà xu hướng này ngày càng phát triển mạnh mẽ, thì những cái tên lớn đã xuất hiện để làm tiêu chuẩn chung cho devops như Docker và Kubernetes, hai cái tên này đã tạo nên một cuộc cách mạng cho phát triển phần mềm trên quy mô lớn.

Bất kể bạn đang là một lập trình web, phân tích dữ liệu, quản lý dự án hay gì đi nữa thì bạn cũng cần đến kiến thức về Docker và Kubernetes.

Docker là một nền tảng cho container hoá, còn Kubernetes là nền tảng cho điều phối container, cả hai đều là những công cụ cơ bản cho phát triển phần mềm.

Hôm nay chúng ta sẽ tìm hiểu về:

  • Docker là gì, container là gì và tại sao phải dùng chúng?
  • Kubernetes là gì và tại sao phải dùng nó?
  • Sự khác biệt giữa Docker và Kubernetes
  • Docker và Kubernetes: Tốt hơn khi kết hợp với nhau
  • Sử dụng Docker
  • Sử dụng Kubernetes

Docker là gì và tại sao phải dùng nó

docker

Dễ hiểu thì, Docker giúp mọi người dễ dàng triển khai một ứng dụng trên cùng một môi trường mà không cần lo về các phụ thuộc (dependencies) hay các vấn đề về hệ điều hành vì Docker cung cấp hệ điều hành của riêng nó. Ví dụ:

  • Trước khi có Docker: bạn xây dựng một trang web Laravel + Vue + MySQL, thì khi phía tester muốn kiểm thử ứng dụng này, họ phải cài đặt PHP, node.js và MySQL. Nếu không ứng dụng sẽ không hoạt động.
  • Sử dụng Docker: lúc này tester sẽ chạy trên container của Docker, nó sẽ tải tất các phụ thuộc cần thiết để ứng dụng hoạt động, tuy nhiên nó làm điều đó trên Docker chứ không phải hệ điều hành máy của bạn.

Có thể nói Docker hoạt động giống như một VM nhưng gọn nhẹ và linh hoạt hơn.

Chi tiết hơn

Docker là một nền tảng container hoá, nó đóng gói ứng dụng của bạn và tất cả phụ thuộc của nó thành một docker container. Nó là một tập hợp các sản phẩm platform-as-a-service được thiết kế để giải quyết các vấn đề trong xu hướng phát triển DevOps. Docker giúp dễ dàng tạo, triển khai và chạy ứng dụng bằng cách dụng container.

Container là thứ giúp Docker trở nên phổ biến với các dev. Nó tạo ra một lớp ứng dụng trừu tượng đóng gói ứng dụng và tất cả phụ thuộc cần thiết để chạy nó: hệ điều hành, công cụ, thư viện hệ thống, runtime, ...

Container chiếm ít dung lượng hơn so với VM, nhưng có thể xử lý nhiều ứng dụng hơn với yêu cầu ít hơn so với VM và hệ điều hành.

docker

Kubernetes là gì và tại sao phải dùng nó

kubernetes

Kubernetes(k8's) là một làn sóng mới trong điện toán đám mây, nó là một công cụ quản lý container mạnh mẽ có thể tự động triển khai và quản lý container.

Khi nói đến việc vận hành các container trong thực tế, bạn có thể làm việc với hàng chục, thậm chí hàng nghìn container. Các container này cần được triển khai, quản lý, kết nối và cập nhật; nếu bạn phải làm điều này theo cách thủ công, sẽ phải cần có cả một nhóm chuyên trách việc này.

Và để chạy được các container, bạn cần có khả năng:

  • Tích hợp và sắp xếp các phần module.
  • Mở rộng hay thu hẹp quy mô dựa trên yêu cầu.
  • Tạo dung sai phân vùng.
  • Cung cấp khả năng giao tiếp trên cụm.

Ở đây ta có thể hỏi: không phải một container sẽ làm tất cả những điều đó sao? Câu trả lời là các container chỉ là một phần nhỏ của toàn bộ vấn đề. Thứ thực sự đem lại giá trị là những công cụ phía trên các container đó, ví dụ như Kubernetes. Những công cụ này được gọi chung là container schedulers.

Sự khác biệt giữa Docker và Kubernetes

docker-kubernetes

Điều đầu tiên cần phải làm rõ rằng chúng là hai công nghệ khác nhau được thiết kế để hoạt động cùng nhau. Chúng không phải là những công cụ cạnh tranh vì vậy không nên có nhầm lẫn rằng "tôi có nên dùng cái này thay cho cái kia" hay "cái nào tốt hơn". Cả hai đều có vai trò riêng biệt trong DevOps và thường được kết hợp sử dụng cùng nhau:

  • Docker được dùng để chuyển đổi ứng dụng của bạn thành container. Nó dùng cho đóng gói và chuyển đổi ứng dụng.
  • Kubernetes mặt khác dùng như một container scheduler. Được sử dụng để triển khai và tuỳ chỉnh quy mô ứng dụng.

Docker và Kubernetes: tốt hơn khi đi cùng nhau

docker-kubernetes

Hai công nghệ được thiết kế để hoạt động cùng nhau và khi chúng làm điều đó thì đấy chính là giấc mơ của các DevOps. Như đã đề cập trước đó, chỉ chạy các contaienr trong quá trình production là chưa đủ, chúng cần phải được quản lý và Kubernetes cung cấp một số tính năng tuyệt vời giúp làm việc với các container dễ dàng hơn. Kubernetes cung cấp những thứ như tự động mở rộng quy mô, kiểm tra tình trạng và cân bằng tải, những thứ rất quan trọng để quản lý vòng đời của container.

Bắt đầu với Docker

Các khái niệm cơ bản trong Docker

Có một vài khái niệm cơ bạn mà bạn cần học trong Docker:

  • Container
  • Image
  • Registry

Containers

Một container là thứ cuối cùng mà bạn muốn chạy và lưu trữ trong Docker. Bạn có thể xen nó như một máy ảo nếu bạn muốn.

Từ quan điểm chung, một container chạy bên trong máy chủ Docker tách biệt với các container khác và thậm chí cả hệ điều hành máy chủ. Nó không thể nhìn thấy các container khác, bộ nhớ vật lý hoặc nhận các kết nối đến trừ khi được bạn thiết lập. Nó chứa mọi thứ cần thiết để chạy ứng dụng của bản: thông tin về hệ điều hành, package, runtime, file, biến môi trường, đầu vào và đầu ra tiêu chuẩn.

Máy chủ Docker thông thường của bạn sẽ trông giống như thế này - một máy chủ cho nhiều container:

container

Như trên hình, việc có có hai container app2 là bình thường; trường hợp này thường là khi máy chủ lưu trữ một bản phát hành (release) và một phiên bản thử nghiệm (dev). Có nghĩa là bạn có thể lưu trữ cả hai phiên bản trên cùng một máy chủ.

Images

Bất kỳ container nào đang chạy đều được tạo từ một image. Image mô tả mọi thứ cần thiết để tạo container; nó là một mẫu cho các container. Bạn có thể tạo nhiều container chỉ từ một image duy nhất.

Registries

Image được lưu trữ trong một registry. Trong ví dụ trên, image app2 được sử dụng để tạo hai container. Mỗi container có vòng đời riêng và cả hai đều có chung một gốc: image của chúng từ registry. Bức tranh tổng quan như sau:

registry

Thiết lập và chạy Docker

Chọn Docker dựa trên yêu cầu

Trong môi trường production chạy các container lưu trữ các ứng dụng quan trọng, bạn muốn các quản trị viên của mình cài đặt Docker Enterprise.

Tuy nhiên, trên máy dev của bạn hoặc máy CD/CI, bạn có thể sử dụng Docker Engine Community hoặc Docker Desktop miễn phí tùy thuộc vào loại máy của bạn. Nói ngắn gọn:

Sử dụng Sản phẩm
Máy dev Docker Engine Community/Docker Desktop
Server nhỏ Docker Engine Community
Ứng dụng quan trọng/cốt lõi Docker Engine Enterprise/Kubernetes

Hello World

Dù bạn cài đặt phiên bản nào, bạn cũng có thể kiểm tra cài đặt của mình bằng cách chạy lệnh sau trong một dòng lệnh (terminal của bạn trên Linux hoặc PowerShell trên Windows):

docker run hello-world

Nó sẽ pull một image và hiển thị văn bản output như sau:

Hello from Docker!
This message shows that your installation appears to be working correctly.

Cài đặt Docker - Window, Linux, Mac

Thiết lập Docker trên Windows 10

Docker Desktop yêu cầu phiên bản Windows 10 64-bit Professional hoặc Enterprise, vì nó dựa trên Hyper-V. Nếu bạn có phiên bản Windows dành cho máy tính để bàn không đáp ứng các yêu cầu, bạn có thể sử dụng Docker Toolbox cũ hơn dựa trên VirtualBox. Trước khai cài đặt Docker Desktop cần nhớ các điều quan chạy:

  • enable Hyper-V
  • enable ảo hoá phần cứng trên BIOS
  • Sau đó thực hiện theo đường link dưới đây

Trong khi cài đặt, bạn sẽ được nhắc sử dụng Windows hay Linux container. Nên dùng các Linux container vì:

  • Bạn có thể thay đổi quyết định của mình bất kỳ lúc nào sau đó, chỉ cần click chuột phải vào biểu tượng Docker trên thanh công cụ và chọn “Switch to Windows containers…”
  • Hiện tại, hầu hết các container image đều dựa trên Linux.

Thiết lập Docker trên Linux

Ở đây có nhiều Docker package khả dụng khác nhau mà bạn có thể cài đặt:

Dù bạn sử dụng hệ điều hành Linux nào thì cũng có các bước sau cài đặt phổ biến ở đây. Hãy chắc chắn rằng bạn đọc chúng một cách cẩn thận. Kiểm tra kỹ chúng nếu bạn không thể chạy thử nghiệm hello-world thành công.

Thiết lập Docker trên Mac

Docker Desktop yêu cầu Mac OS Sierra 10.12 trở lên. Nếu bạn có phiên bản macOS cũ hơn, bạn có thể sử dụng Docker Toolbox cũ hơn dựa trên VirtualBox.

Tạo Docker image đầu tiên

Như chúng ta đã nói trước đó, các container được tạo từ các image. Hãy cùng khám phá cách bạn có thể tạo container cho riêng mình. Bên trong image, chúng ta có thể đặt các chương trình của mình và các phụ thuộc của chúng để có thể tạo ra nhiều container từ những image đó.

Tạo một Docker image đơn giản

image

Dockerfile

Docker Image được tạo bằng lệnh docker build và file Dockerfile. Dockerfile chứa các hướng dẫn về cách tạo image.

Dockerfile có thể có bất kỳ cái tên nào. Đặt tên cho nó là Dockerfile giúp người khác hiểu mục đích của nó dễ dàng hơn khi họ nhìn thấy file đó trong dự án của bạn. Điều đó cũng có nghĩa là bạn không cần phải nêu tên file khi sử dụng lệnh docker build.

Bây giờ, hãy tạo image cơ bản cho container hiển thị thông báo “hello world” khi container chạy.

Trước tiên, hãy tạo một file có tên Dockerfile mô tả cách image của bạn sẽ được tạo. Dockerfile luôn bắt đầu bằng lệnh FROM vì mọi image đều dựa trên một image cơ sở khác. Đây là một tính năng mạnh mẽ vì nó cho phép bạn mở rộng các image có thể đã phức tạp.

Vì ở đây chỉ cần một kết xuất văn bản đơn giản, ta có thể sử dụng image Debian Linux. Đây là Dockerfile:

FROM debian:8

Nó chưa đủ. Mặc dù ta đã có được nền tảng Debian Linux, nhưng ta chưa chạy bất kỳ lệnh nào có thể hiển thị “hello world”. Điều này có thể thực hiện bằng cách sử dụng lệnh CMD. Lệnh CMD chỉ định file thực thi nào được chạy khi một container được tạo bằng image của bạn và cung cấp các đối số tùy chọn.

Dưới đây là một Dockerfile được cải tiến tạo image dựa trên Debian Linux và hướng dẫn nó chào người dùng của khi một container được tạo:

FROM debian:8

CMD ["echo", 'Hello world']

Lưu ý rằng cả chương trình sẽ chạy và các đối số của nó đều được cung cấp dưới dạng một mảng chuỗi JSON. Để tạo image từ Dockerfile, ta cần chạy lệnh docker build. Để thực hiện việc này, ta nhập lệnh sau vào terminal của mình trong thư mục chứa Dockerfile:

docker build -t hello .

Ở đây -t được sử dụng ở phía trước của image mong muốn. Một image có thể được tạo mà không có tên, nó sẽ có một ID duy nhất được tạo tự động, vì vậy nó là một tham số tùy chọn trên lệnh docker build.

Lưu ý dấu chấm ở cuối lệnh trên. Nó chỉ định đường dẫn nào được sử dụng làm bối cảnh để build (sẽ nói thêm về điều này ở phần sau) và nơi dự kiến sẽ tìm thấy Dockerfile. Nếu Dockerfile của chúng ta có tên khác hoặc ở ở nơi khác, ta có thể thêm chuyển đổi -f để cung cấp đường dẫn.

Lệnh docker build vừa tạo một image có tên là hello. Image đó được lưu trữ cục bộ trên máy tính và bạn có thể chạy nó như cách bạn làm với bất kỳ image nào khác:

docker run --rm hello

Bây giờ, bạn có thể public image của mình để những người khác chạy các container dựa trên nó. Chúng ta sẽ xem cách thực hiện điều đó sau nhưng hiện tại, hãy tập trung vào việc tạo image.

Cho đến hiện tại đây là những gì chúng ta đã được thực hiện:

  • Đã tạo một image
  • Đã tạo một file có tên Dockerfile
  • Chạy lệnh docker build
  • Chạy một container từ image đã tạo

Vậy điều này có ý nghĩa là gì; chạy một container tương đương với việc khởi động một máy hoàn toàn mới và sau đó chuyển nó vào thùng rác. Để hiển thị thông báo “Hello world”, về cơ bản, chúng ta có một máy tính mới, yêu cầu nó thực hiện lệnh echo, sau đó chuyển nó vào thùng rác. Docker làm cho máy tính ghi-và-quên trở nên dễ dàng. Tất nhiên, điều này là quá mức cần thiết cho một mục đích đơn giản như vậy, nhưng nó vẫn đúng ngay cả khi chúng ta cài đặt các framework hoặc di chuyển các file xung quanh bên trong các container của chúng ta; đó là một tính năng tuyệt vời. Hầu hết sức mạnh Docker sẽ đến khi bạn hiểu bạn có thể tạo và dọn rác các máy tính ảo được cô lập dễ dàng như thế nào.

Publish Docker Image

Một Docker Registry về cơ bản là một nơi lưu trữ image để cung cấp các tính năng sau:

  • Khả dụng để lưu trữ nhiều image khác nhau.
  • Khả dụng để lưu trữ các tag khác nhau cho cùng một image.
  • Một HTTP API cho phép push image từ một máy để tạo nó, hoặc pull image đến một máy để chạy container từ các image này.
  • Kết nối TLS-secured đến API theo trật tự đến tránh tấn công MITM (Man in the middle).

Có rất nhiều registry có sẵn. Bạn có thể sử dụng Docker Hub hoặc sử dụng registry riêng của bạn. Trong mọi trường hợp, quy trình gắn tag và public image của bạn vẫn giống nhau đối với mọi regitry.

Cho dù bạn chọn registry nào, việc public image là một quá trình gồm ba bước:

  1. Build image của bạn (docker build) với tên tiền tố thích hợp hoặc tag (docker tag) hiện có một cách thích hợp.
  2. Đăng nhập vào Registry (docker login).
  3. Push image vào Registry (docker push).

registry

Bắt đầu với Kubernetes

Pods

Một pod là một đơn vị nhỏ nhất trong một ứng dụng Kubernetes. Ở đây có một điều cần phải làm rõ là một pod không phải là một container. Một pod có thể là nhiều container, nếu bạn đến với Kubernetes từ Docker, thì điều này có thể sẽ khó hiểu với bạn. Một pod có thể là một hoặc nhiều container. Song nó có giới hạn mà ta cần biết. Một pod có thể là

  • Một địa chỉ IP duy nhất
  • Localhost dùng chung
  • Không gian IPC dùng chung
  • Phạm vi cổng mạng dùng chung
  • Dung lượng dùng chung

Các container trong một pod giao tiếp với nhau thông qua localhost, trong khi đó giao tiếp pod-to-pod được thực hiện thông qua các services

ReplicaSets

Ở phần này, chúng ta cần lưu ý về trường hợp mà các pod ngừng hoạt động (hay có thể gọi là chết), chúng ta sẽ cần một cơ chế nào đó để đảm bảo tính khả dụng của hệ thống.

Ở đây chúng ta sử dụng trình điều khiển dự phòng (replication controller).

Trách nhiệm chính của trình điều khiển dự phòng là ngăn chặn tình trạng sập (failure), nó bao gồm việc đặt tất cả kiểu tài nguyên pod và điều khiển chúng. Ta lấy ví dụ, một tập dự phòng bao gồm một số lượng các pod cần chạy, ở đây là 4. Nếu một trong số các pod sập, trình điều khiển dự phòng sẽ chạy một pod mới và một lần nữa, ta có 4 pod đang chạy. Thế nên chức năng này là rất cần thiết trước khi một pod nào đó gặp vấn đề.

Services

Nếu ta muốn kết nối với các pod của chúng ta, ta sẽ cần tạo một service. Trong kubernetes, một service là mạng trừu tượng bao trùm toàn bộ pod. Nó cho phép quản lý lưu lượng truy cập để cân bằng tải. Một service cho phép Kubernetes thiết lập một bảng ghi DNS duy nhất cho các pod.

Deployment

Kiểu tài nguyên deployment bao gồm một tập dự phòng mà chúng có thể quản lý. Vậy tại sao lại cần quản lý tập dự phòng ? Trong trường hợp chúng ta cần cập nhật, ta sẽ thay thế một tập dự phòng và điều này sẽ gây ra downtime (thời gian chết) cho hệ thống.

Khi sử dụng Kubernetes, ta có lợi thế là tính khả dụng cao. Deployment cung cấp cho chúng ta chức năng cập nhật mà không phải có downtime. Vì khi thực hiện với tập dự phòng, bạn chỉ dụng số pod cụ thể mà bạn muốn chạy. Sau đó khi bạn kích hoạt một cập nhật, một deployment sẽ thực hiện cập nhật lên toàn pod, tất cả sẽ đảm bảo rằng pod đó cập nhật thành công trước khi chuyển sang bước kế tiếp.

Lưu ý rằng: kiểu deployment điều khiển tập dự phòng, còn tập dự phòng điều khiển các pod. Khi sử dụng kiểu tài nguyên deployment bạn không thể quên rằng mình đang sử dụng services nào để truy cập chúng.

Thiết lập Kubernetes và triển khai cụm cục bộ

Triển khai kubectl

Kubernetes có một công cụ command-line là kubectl, được dùng cho quản lý cụm và các ứng dụng chạy trong nó. Ở đây là các cách đề cài đặt trên Windows, Linux và Mac:

Windows

curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/windows/amd64/kubectl.exe

Linux

curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl
chmod +x ./kubectl
sudo mv ./kubectl /usr/local/bin/kubectl

Mac

curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/darwin/amd64/kubectl
chmod +x ./kubectl
sudo mv ./kubectl /usr/local/bin/kubectl

Cách xác nhận đã thiết lập

kubectl version --output=yaml

Cài đặt Minikube

Minikube hỗ trợ ảo hoá cho nhiều thiết bị. Ta có thể sử dụng VirtualBox nếu chỉ cần ảo hoá cho toàn bộ hệ điều hành. Nhưng hãy nhớ dù cho có dùng VirtualBox hay HyperV, thì ảo hoá cần được cho phép ở BIOS.

Windows

Để cài đặt minikube trên Windows bạn tải file minikube theo link này đổi tên nó thành minikube.exe và đặt nó vào đường dẫn của bạn.

Linux

curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/

Mac

brew cask install minikube

Tạo cụm cục bộ với Minikube

Minikube tạo một cụm vô cùng dễ dàng. Tất cả những gì bạn cần làm chỉ là thực thi một dòng lệnh duy nhất. Minikube sẽ bắt đầu một chạy cục bộ một máy ảo và triển khai các thành phần cần thiết vào nó. VM sẽ được cấu hình với Docker và Kubernetes thông qua một binary gọi là localkube.

minikube start --vm-driver=virtualbox

Khi chúng ta thực hiện lệnh bắt đầu Minikube, nó đã tạo một máy ảo mới dựa trên image Minikube. Image đó chứa một số file binary. Nó có cả Docker và rkt container engine cũng như thư viện localkube.

rkt là một công cụ chứa ứng dụng được phát triển cho các môi trường đám mây production hiện đại.

Thư viện localkube bao gồm tất cả các thành phần cần thiết để chạy Kubernetes. Hiện tại, điều quan trọng là localkube cung cấp mọi thứ chúng ta cần để chạy một cụm Kubernetes cục bộ.

Hãy nhớ rằng đây là một cụm nút đơn chỉ chạy cục bộ trên máy của chúng ta. Như đã nói, đây vẫn là cách dễ dàng nhất để “thử” với Kubernetes tại cục bộ và làm quen với công cụ này.

Tạo một pod thông qua cú pháp khai báo

Đầu tiên tạo một cụm sử dụng Minikube như hình bên dưới:

minikube start --vm-driver=virtualbox
kubectl get nodes

Hãy cùng xem một Pod đơn giản bằng cách truy cập file db.yml từ git repo này. Bây giờ, hãy tạo Pod được xác định trong file db.yml.

kubectl create -f pod/db.yml

Bây giờ ta hãy xem các Pod trong cụm

kubectl get pods

Kết quả như sau, bạn có thể xem pod của chúng ta đã up và đang chạy

NAME READY STATUS  RESTARTS AGE
db   1/1   Running 0        11s

Tạo services thông qua cú pháp khai báo

Tạo một service:

kubectl create -f svc/go-demo-2-svc.yml
kubectl get -f svc/go-demo-2-svc.yml

Ta tạo service và nhận thong tin của nó từ API server. Kết quả là lệnh bên dưới:

NAME      TYPE     CLUSTER-IP EXTERNAL-IP PORT(S)         AGE
go-demo-2 NodePort 10.0.0.129 <none>      28017:30001/TCP 10m

Bây giờ service đang chạy, bạn có thể double-check nó để nó hoạt động như mong đợi bằng truy cập đến giao diện MongoDB.

open "http://$IP:30001"

Triển khai bản phát hành

Ta sẽ tạo một cụm một lần nữa:

cd k8s-specs
git pull
minikube start --vm-driver=virtualbox
kubectl config current-context

Ta sẽ tạo một triển khai

kubectl create \
    -f deploy/go-demo-2-db.yml \
    --record
kubectl get -f deploy/go-demo-2-db.yml

Kết quả của dòng lệnh như sau:

NAME           READY   UP-TO-DATE   AVAILABLE   AGE
go-demo-2-db   0/1     1            0           4s

Tổng kết

Trên đây là một vài kiến thức tổng quan về Docker và Kubernetes. Cả hai công nghệ này đều đang là những công nghệ được yêu cầu nhiều nhất trên thị trường hiện tại. Nắm bắt các khái niệm và làm chủ nó ngay bây giờ sẽ giúp bạn tạo ra các phần mềm tốt hơn, nâng cao kỹ năng của bạn và phát triển sự nghiệp nhanh chóng.

Tham khảo