Monday, 3 April 2017

Kubernetes - rồi cũng đến đít

Gần 1 tháng sau bài "từ đầu" ra đời http://www.familug.org/2017/03/kubernetes.html
mình vẫn chưa động vào Kubernetes. Vậy nên viết nhanh phần đến đít, không mai kia rơi vãi hết.

Bài này KHÔNG PHẢI HƯỚNG DẪN DÙNG K8s, ai cần hướng dẫn thì vào trang chủ xem.

Bài này tổng kết về kinh nghiệm sử dụng K8s: Khái niệm, kiến trúc, troubleshoot, ...
dựa trên trí nhớ mong manh còn sót lại chút ít sau những cơn lụt ở Sài Gòn...


Kubernetes

Các khái niệm trong K8s

K8s đưa ra một lô 1 lốc các khái niệm. Vậy nên muốn dùng k8s, phải nắm chắc các khái niệm.
Xem thì có vẻ nhiều, nhưng đó là những thứ mà nếu như k8s không đưa ra, thì một ngày nào đó, bạn cũng lại tự "phát minh" ra (và 99,96 % là tệ / tạm bợ hơn nhiều).

Pod

Pod là một khái niệm rộng hơn container, nhưng đa số trường hợp thì đánh đồng nó với container cũng không sao. Pod là 1 nhóm (1 trở lên) các container thực hiện một mục đích nào đó (chạy software nào đó - pod có nhiều container là khi các app có quan hệ rất chặt chẽ - theo ví dụ K8s đưa ra là trang upload ảnh và trang hiển thị ảnh.)

Nếu k8s chỉ có mỗi khái niệm pod, thì dùng k8s giống như dùng docker bình thường. Tức
muốn thêm tính năng gì thì ta phải tự kiến trúc/ thiết kế/ thực hiện.

96% thông tin bạn cần về pod, nằm trong output của lệnh : describe pod PODNAME
$ kubectl get pods --selector='app=audit'
NAME                                READY     STATUS    RESTARTS   AGE
audit-deployment-3585156150-mlcv3   1/1       Running   0          14d
$ kubectl describe pod audit-deployment-3585156150-mlcv3
Name:        audit-deployment-3585156150-mlcv3
Namespace:    default
...

Service (svc)

Service đưa ra khái niệm về - service 😂

Nếu như khi làm docker, bạn sẽ quá tập trung vào container, thì ở k8s, ta tập trung vào service.
Một service sẽ cung cấp một "dịch vụ" gì đó, có giá trị, và ta cố không tập trung vào chuyện bên dưới nó chạy thế nào, chỉ quan tâm rằng có một dịch vụ đang được cung cấp ở địa chỉ xyz.com port 2369...
Service là khái niệm được thực hiện bởi : domain name, và port. Service sẽ tự động "tìm" các pod được đánh label phù hợp (trùng với label của service), rồi chuyển các connection tới đó.
Nếu tìm được 5 pods thoả mã label, service sẽ thực hiện load-balancing: chia connection tới từng pod theo chiến lược được chọn (VD: round-robin: lần lượt vòng tròn).
Mỗi service sẽ được gán 1 domain do người dùng lựa chọn, khi ứng dụng cần kết nối đến service, ta chỉ cần dùng domain là xong. Domain được quản lý bởi hệ thống name server SkyDNS nội bộ của k8s - một thành phần sẽ được cài khi ta cài k8s.
$ kubectl get svc --namespace=kube-system | grep dns
kube-dns                10.3.240.10    <none>        53/UDP,53/TCP   38d
Nếu đã có kinh nghiệm sysadmin, ta sẽ thấy k8s service giải quyết rất nhiều bài toán mà khi hệ thống/dịch vụ của bạn to ra, bạn sẽ phải làm: service discovery, load balancing.

Tất nhiên, nếu chỉ có 1 máy chạy 1 dịch vụ, thì service chả có nghĩa lý gì. Vậy nên khi dùng k8s, hãy nhớ rằng nó được thiết kế và đưa vào các khái niệm để phục vụ cho hàng trăm, ngàn service/container, chứ không phải 1 cái. Nó phức tạp vì nó có lý do để phức tạp. Và bạn/công ty của bạn không phải Google (ở đây không hạ thấp bạn hay công ty của bạn), không phải công ty nào cũng chạy dịch vụ software cung cấp cho cả thế giới.

Namespace (ns)

Nếu tôi đặt service này là "web" lúc chạy production, còn lúc dev thì tôi chạy nó ở đâu? không nhẽ phải đổi tên service?
Namespace giải quyết vấn đề này. Mặc định các dịch vụ sẽ sử đụng namespace "default", nhưng ta muốn tạo namespace nào thì tuỳ ý. K8s sử dụng 1 namespace riêng : kube-system, vì vậy nhớ đừng quên namespace khi gọi câu lệnh: VD:
$ kubectl get svc --namespace=kube-system
NAME                    CLUSTER-IP     EXTERNAL-IP   PORT(S)         AGE
default-http-backend    10.3.246.86    <nodes>       80:31031/TCP    38d
elasticsearch-logging   10.3.251.158   <none>        9200/TCP        33d
heapster                10.3.242.120   <none>        80/TCP          33d
kibana-logging          10.3.245.215   <none>        5601/TCP        33d
kube-dns                10.3.240.10    <none>        53/UDP,53/TCP   38d
kubernetes-dashboard    10.3.243.251   <none>        80/TCP          38d
monitoring-grafana      10.3.243.34    <none>        80/TCP          33d
monitoring-influxdb     10.3.253.47    <none>        8086/TCP        33d
tiller-deploy           10.3.240.33    <none>        44134/TCP       38d
namespace - luôn là một ý tưởng tuyệt vời, Python cũng nói vậy:
$ python -c 'import this' | grep -i namespace
Namespaces are one honking great idea -- let's do more of those!

Port-forward

Không phải dịch vụ nào cũng cần show ra cho cả thế giới xem, ví dụ như hệ thống logging hay monitoring thì chỉ cần "người nhà mình" biết là đủ. Hoặc khi dev, chưa có domain để expose ra ngoài, ta sẽ truy cập các service bằng port-forward khi đã biết tên pod (get pods):
$ kubectl port-forward monitoring-grafana-3730655072-sbcst 3000:3000 --namespace=kube-system
Forwarding from 127.0.0.1:3000 -> 3000
Forwarding from [::1]:3000 -> 3000
Handling connection for 3000
Handling connection for 3000
...
Và ta có thể truy cập vào pod này qua port 3000 mà nó đang listen thông qua localhost:3000

Dashboard

Dashboard cho phép xem tổng quan về cluster k8s đang dùng, nó được cài vào k8s như một add-on https://github.com/kubernetes/dashboard Nói chung là để xem thôi, còn tương tác gì thì cứ câu lệnh kubectl mà chọc.
Kiểm tra xem đã cài dashboard chưa:
$ kubectl get svc --namespace=kube-system | grep -i dashboard
kubernetes-dashboard    10.3.243.251   <none>        80/TCP          38d
Truy cập:
$ kubectl proxy
Starting to serve on 127.0.0.1:8001
Vào trình duyệt qua 127.0.0.1:8001/ui/

K8s dashboard

Persistent volume (PV) - Persistent volume claim (PVC)

Bất kỳ ai làm container cũng cần hiểu rằng, ta không lưu dữ liệu trên container mà phải lưu nó vào một chỗ nào đó. Bởi khi container restart / bị die thì dữ liệu cũng sẽ mất theo nó. Đây là chuyện dù dùng docker trực tiếp hay giải pháp khác K8s thì bạn vẫn phải tính. Việc lưu dữ liệu của app trên container trực tiếp trên máy host là một giải pháp nhỏ lẻ. Vì nếu ta cho dữ liệu của pod của app A vào /var/lib/app/A, mà có 2 pod cho app A cùng được chạy trên máy đó thì chuyện gì xảy ra?
Giải pháp k8s sử dụng là các hệ thống lưu trữ "network". Tức lưu vào một hệ thống storage khác. Như NFS, GlusterFS, Ceph ...
PV, là khái niệm để đưa ra một dung lượng lưu trữ THỰC TẾ 1GB, 10GB ...
PVC là khái niệm ảo, đưa ra một dung lượng CẦN THIẾT, mà ứng dụng yêu cầu.
Khi 1 PV thoả mãn yêu cầu của 1 PVC thì chúng "match" nhau, rồi "bound" (buộc / kết nối) lại với nhạu. Nếu tự cài K8s, hãy chuẩn bị sẵn giải pháp lưu trữ của bạn. Nếu dùng sẵn Google cloud hay AWS, sẵn sàng để trả tiền.

ConfigMap (cm) - Secret

Một software ít khi chạy luôn mà không cần config.
ConfigMap là giải pháp để nhét 1 file config / đặt các ENVironment var hay set các argument khi gọi câu lệnh. ConfigMap là một cục config, mà pod nào cần, thì chỉ định là nó cần - giúp dễ dàng chia sẻ file cấu hình.
Ít ai muốn đặt mật khẩu vào file cấu hình, và chỉ có lập trình viên "tồi" mới hardcode mật khẩu vào code. Vậy nên K8s có "secret", để lưu trữ các mật khẩu, token, ... hay những gì cần giữ bí mật.

Nodes

là các máy trong k8s cluster.
$ kubectl get nodes
NAME                                       STATUS    AGE
gke-cluster-1-default-pool-xxx-7f9v   Ready     23d
gke-cluster-1-default-pool-xxx-8k6t   Ready     39d
gke-cluster-1-default-pool-xxx-hc0d   Ready     39d
gke-cluster-1-default-pool-xxx-xpcc   Ready     39d

Deployment/ StatefulSets / DaemonSet / Static Pod

Các "khái niệm" khác nhau cho các loại dịch vụ khác nhau.
Deployment là loại chung nhất, khi ta muốn "deploy" một dịch vụ nào đó. Ta tạo ra pod bằng cách tạo ra một deployment (hoặc statefulSets, hoặc các khái niệm tương đương).
StatefulSets được dùng khi ta cần các service bật lên theo tứ tự nhất định.
DaemonSets thường dành cho các dịch vụ cần chạy trên tất cả các node. Ví dụ như fluentd để collect log trên tất cả các node.
Static Pod là 1 file "manifest" đặt trong thư mục chỉ định bởi kubelet, các pod này sẽ được chạy khi kubelet chạy. Không thể điều khiển chúng bằng kubectl. Đây là một khái niệm đang dần bị xa lánh bởi sự thiếu linh động và khó kiểm soát.

kubectl get để xem tất cả những khái niệm resource mà k8s sử dụng, và cách gọi ngắn gọn cho từng khái niệm (svc cho service, deploy cho deployment, cm cho configmap ...).

Helm - K8s package manager

Trên Ubuntu, ta dùng APT để cài package, thì trên K8s, Helm dùng để cài các "chart", muốn chạy một hệ thống CI ?
Install ngay bằng câu lệnh của helm.
helm install something
VD:
$ helm install stable/concourse # cài concourse CI

Monitoring

Monitoring trên K8s rất dễ dàng, chỉ cần cài 1 phần mềm có khả năng tích hợp với k8s, nó sẽ hỏi
K8s để lấy thông tin về tất cả các pod trong hệ thống.Hãy tưởng tượng ta có hệ thống monitoring tự động cho mọi pod được tạo - mà không cần làm gì :3
Xem thêm tại https://kubernetes.io/docs/concepts/cluster-administration/resource-usage-monitoring/

Create

Mọi file cấu hình cho pod/svc/cm/ ... đều là file ở định dạng YAML.
Chỉ cần chạy
kubectl create -f filename # hoặc . để cài hết các file trong thư mục hiện tại
để "deploy" chúng.

Kiến trúc

K8s cluster bao gồm nhiều node, trên mỗi node sẽ cần chạy một "kubelet", đây là chương trình
để chạy k8s. Cần một máy để làm "chủ" cluster, trên đó sẽ cài API server, scheduler ...
Các máy còn lại sẽ chạy kubelet để sinh ra các container.

Network

Có nhiều loại phần mềm để triển khai container network, như Flannel, Weaver ...
nếu bạn dùng Google Cloud, vấn đề này không cần quan tâm.

Tổng kết

- Nếu bạn sẵn sàng chi tiền để mua K8s chạy trên một hệ thống dựng sẵn nào đó: như GCE hay OpenShift, thì mọi vấn đề liên quan đến cài đặt k8s cùng các thành phần khác sẽ được bỏ qua, bạn chỉ cần quan tâm tới việc vận hành các pod/service của mình, và trả tiền.
- CoreOS có nhiều đóng góp và doc khá tốt để giới thiệu và tự cài 1 hệ thống K8s: https://coreos.com/kubernetes/docs/latest/

Đến đây, tình nghĩa với K8s chấm dứt... cho tới khi nào ta lại cần.
PS: hoá đơn dùng k8s 1 tháng để test (GKE 4 vCPU), không phải trả đồng nào vì GCE khuyến mãi 300$ mỗi user.


Hết.
HVN at http://www.familug.org/ and http://pymi.vn

Đăng ký học #Python , lớp tại chi nhánh #HàNội khai giảng giữa tháng 4, 2017: https://pymi.vn/

Nhập email vào http://invite.pymi.vn/ để nhận thư mời tham gia forum hỏi đáp Python, Django, Golang, Linux ...