Bài 1: Cẩm nang chuyển bến từ Docker sang Orchestration
Mục lục
Bước ngoặt từ chiếc hộp Docker lên một hệ thống thực thụ #
Tiếp nối câu chuyện dở khóc dở cười về đường truyền và những cổng mạng oái oăm ở phần mở đầu đợt trước, hôm nay chúng ta sẽ đi sâu vào “nhân vật chính” đang gánh vác hệ thống ở đằng sau: K3s.
Nếu bạn đã quen tay gõ lệnh chạy vài cái container Docker trên một con VPS, bạn sẽ thấy mọi thứ trơn tru. Nhưng khi ứng dụng phình to ra, cần chạy trên 3 đến 4 con server khác nhau, bạn sẽ tá hỏa nhận ra Docker thuần túy là không đủ. Đứt cáp, sập nguồn, hay đơn giản là một node bốc cháy — ai sẽ tự động dời ứng dụng của bạn sang một node khác đang khỏe mạnh? Đó là lúc chúng ta cần đến Orchestration, cụ thể là hệ sinh thái Kubernetes.
Nhưng cài Kubernetes bản full thì vã mồ hôi vì nó quá cồng kềnh. May thay, chúng ta có K3s. Bài viết này sẽ hệ thống lại toàn bộ các khái niệm cốt lõi nhất để bạn có thể tự tin bước vào thế giới này.
1. Tại sao lại là K3s? Và Docker đã đi đâu? #
Nói ngắn gọn, K3s là một bản phân phối siêu nhẹ của Kubernetes, được ép lại thành một file nhị phân duy nhất chưa tới 100MB. Nó loại bỏ các driver cloud cũ kỹ và thay thế hệ quản trị cơ sở dữ liệu etcd nặng nề bằng SQLite. Cực kỳ hoàn hảo cho những cụm homelab cá nhân, edge computing, hay các kiến trúc phân tán cần sự gọn gàng nhưng vẫn giữ nguyên sức mạnh chuẩn chỉ của Kubernetes.
Và có một sự thật trái ngược mà nhiều người mới chuyển từ Docker sang sẽ hơi sốc: K3s (hay Kubernetes hiện tại) không thèm dùng Docker nữa.
- Docker giờ đây chỉ nên làm nhiệm vụ build image ở máy cá nhân của bạn.
- Dưới hạ tầng K3s, thứ thực sự chạy các ứng dụng của bạn là Containerd.
- Bạn sẽ không còn gõ trực tiếp lệnh khởi tạo container nữa. Thay vào đó, bạn chỉ cần khai báo trạng thái mong muốn bằng file cấu hình YAML, K3s sẽ tự động gọi Containerd để kéo image về và chạy.
2. Điểm mặt gọi tên các Resource: Đừng để bị ngợp #
Để dễ nuốt, mình chia các khái niệm trong K3s thành 2 nhóm. Một nhóm bạn sẽ phải viết file cấu hình cọ xát hàng ngày, và một nhóm hệ thống tự lo, mình chỉ cần hiểu logic là đủ.
Nhóm 1: Dân Developer / Operator thao tác hàng ngày
- Pod: Thành phần nhỏ nhất. Một Pod có thể chứa nhiều container chạy chung với nhau, chia sẻ chung một mạng nội bộ. Tức là container A có thể gọi container B trong cùng một Pod thẳng qua cấu hình localhost.
- Deployment: Người quản lý vòng đời. Bạn bảo “tôi cần 3 bản sao của app này”, Deployment sẽ đảm bảo luôn có đủ 3 Pod chạy ngày đêm và lo luôn chuyện Rolling Update.
- Service (Svc): Bộ định tuyến nội bộ. Cấp IP tĩnh và tên miền nội bộ để các Pod gọi nhau mà không cần quan tâm IP thật của Pod vốn thay đổi liên tục.
- Ingress: Khái niệm định tuyến truyền thống làm nhiệm vụ cánh cổng vòng ngoài (Layer 7) để đón traffic. Ở cấu hình mặc định, K3s thường dùng Traefik cho thành phần này.
- Gateway API: Thế hệ tiêu chuẩn định tuyến mới của Kubernetes, khắc phục mọi yếu điểm của Ingress bằng cách cung cấp khả năng chia sẻ và quản trị routing mạnh mẽ hơn. Trong series này, thay vì xài Traefik cũ, mình sẽ sử dụng Envoy Gateway — một implementation xịn xò chuẩn Gateway API.
- ConfigMap & Secret: Tách rời cấu hình và mật khẩu ra khỏi image. Pod sẽ đọc các dữ liệu này khi khởi động.
- PersistentVolumeClaim (PVC): Yêu cầu không gian lưu trữ cứng để dữ liệu không bị bốc hơi khi Pod chết.
Nhóm 2: Chuyện hạ tầng và cấu hình nâng cao
- ReplicaSet: Đứng giữa Deployment và Pod để duy trì đúng số lượng bản sao.
- LoadBalancer (ServiceLB): Chịu trách nhiệm mở cánh cổng giao tiếp ở tầng mạng (Layer 4). Do server vật lý (bare-metal) không có sẵn Load Balancer như trên Cloud, K3s mặc định tích hợp sẵn công cụ ServiceLB (Klipper) để chữa cháy.
- MetalLB: Giải pháp Load Balancer thực thụ dành cho bare-metal. Để hệ thống chuyên nghiệp và kiểm soát IP tốt hơn, mình sẽ vô hiệu hóa (disable) ServiceLB mặc định và thay bằng MetalLB. Nó giúp cụm K3s có khả năng cấp phát IP thật độc lập trong mạng nội bộ y hệt như cơ chế của các nhà cung cấp Cloud lớn.
- Control Plane & Worker Node: Máy Master (Control Plane) là não bộ ra quyết định, máy Agent (Worker) là tay chân chạy các Pod.
3. Luồng đi của dữ liệu: Xâu chuỗi mọi thứ #
Hãy thử theo dấu một request từ trình duyệt web đi vào hệ thống. Điểm ăn tiền của toàn bộ thiết kế này là cách các gói tin lặn qua hầm Tailscale:
- Khách truy cập duyệt web, traffic đi qua Cloudflare và đập thẳng vào Public IP của máy Master ở ngoài Cloud.
- Tại Master, MetalLB tiếp nhận gói tin ở tầng mạng và lập tức chuyển giao cho Envoy Gateway.
- Envoy Gateway đọc Host Header, nhận diện khách muốn vào
vinhmdev.comvà chuyển lệnh xuống Service. - Đây là lúc phép màu xảy ra: Service phát hiện các Pod đang nằm ở một máy Worker tận trong nhà. Gói tin sẽ được mã hóa và chui qua hầm Tailscale (có sự hỗ trợ của DERP Server nếu cấu hình mạng chặn NAT quá ngặt nghèo) để “nhảy cóc” từ VPS về thẳng máy Home Worker ở nhà bạn và được xử lý an toàn.
4. Mạng lưới kết nối: Tailscale và DERP Server #
Trong kiến trúc Hybrid Cloud mà mình đang xây dựng, các server không phải lúc nào cũng nằm chung một chỗ. Để chúng “nhìn thấy” nhau an toàn mà không cần mở port bừa bãi ra internet, mình đưa Tailscale vào cuộc chơi.
- Tailscale: Tạo ra một mạng Mesh VPN phẳng, bảo mật. Mọi Node dù ở Sài Gòn hay Singapore đều có thể liên lạc như đang cắm chung một switch.
- DERP Server (Tailscale Relay): Để đảm bảo tốc độ và tránh bị ảnh hưởng bởi các lớp NAT khó chịu từ nhà mạng, mình tự dựng thêm DERP server riêng. Nó đóng vai trò trung chuyển gói tin, giúp các node kết nối với nhau ổn định nhất có thể, bất chấp rào cản địa lý hay hạ tầng mạng phức tạp.
5. Chuẩn bị đồ nghề cho chặng tiếp theo #
Bài tới, chúng ta sẽ bắt tay vào cài đặt. Ngoài các server chạy Ubuntu LTS sạch sẽ và SSH Keys, bạn cần lưu ý:
- Disable mặc định: Khi cài K3s, mình sẽ chủ động thêm tham số để vô hiệu hóa Traefik và ServiceLB ngay từ đầu để nhường chỗ cho Envoy Gateway và MetalLB.
- Swap: Nhớ chạy
sudo swapoff -ađể K3s không bị “lú” khi tính toán tài nguyên. - Kỹ năng Editor: Hãy sẵn sàng với vi hoặc nano. Việc SSH vào server và “múa” trên file cấu hình YAML bằng vi không chỉ giúp bạn sinh tồn tốt trong môi trường không có GUI, mà nó còn là một trải nghiệm rất thực chiến và “cuốn” (mặc dù chỉ copy và paste).
[!NOTE]
Điều gì sẽ xảy ra nếu máy Master (Control Plane) bốc cháy?
Về mặt bản chất Kubernetes: Nếu Master ngất lịm, bạn sẽ mất quyền điều khiển não bộ (chằng hạn không thể gõ sinh ra thêm Pod mới). Thế nhưng, những Pod đã được cấp lịch chạy trên các máy Agent (Worker Node) thì không hề chết. Chúng vẫn bám máy và chạy ngầm một cách khỏe mạnh.
Tuy nhiên, sự thật phũ phàng về mặt mạng lưới hiện tại: Trong kiến trúc series này, mình đang dùng Cloudflare trỏ trực tiếp tới public IP của máy Master (vì chúng ta không dùng LoadBalancer độc lập nằm ngoài). Điều đó dấn tới việc Master đồng thời cũng kiêm luôn cửa ngõ đón traffic. Thế nên nếu Master tắt thở, “cổng đình” sập, người dùng bên ngoài Internet sẽ không thể vào được web. Ứng dụng ở các con Worker Node bên trong rốt cuộc vẫn sống nhăn răng nhưng lại lâm vào cảnh “bơ vơ” không có đường mạng hướng ra ngoài. Sau này, để hóa giải điểm yếu chí mạng này (Single Point of Failure), chúng ta có thể nghiên cứu đắp thêm External LB hoặc tự động failover IP bằng các chiêu trò khác.
[!WARNING]
Lưu ý xương máu: KHÔNG cài chung Docker và K3s trên cùng một máy Master!
Tuyệt đối đừng cài song song cả Docker và K3s. Hai hệ sinh thái này sẽ quay ra cắn xé nhau, tranh giành cổng mạng, can thiệp vào bảng định tuyến và iptables của nhau. Việc đi gỡ mớ bòng bong phân giải xung đột này cực kỳ mệt mỏi và tốn thời gian vô ích. Ở tầng dưới, K3s vốn dĩ đã tích hợp sẵn và chạy Containerd siêu nhẹ rồi. Vì vậy, tốt nhất là bạn hãy chuẩn bị một cái server thật “sạch sẽ” (uninstall Docker) trước khi cài đặt. Về nguyên nhân kỹ thuật sâu xa tại sao chúng “chảng” nhau, nếu sau này có thời gian mình sẽ viết một bài mổ xẻ thêm nhé!
Hẹn gặp lại các bạn ở Bài 2: Thiết lập VPN với Tailscale.