Sổ tay Kubernetes: Phương pháp triển khai bằng khai báo

Loạt bài viết sổ tay Kubernetes:

Thành thật mà nói, ví dụ hello-kube bạn vừa thấy trong phần trước không phải là cách lý tưởng để thực hiện triển khai với Kubernetes. Nếu bạn bỏ lỡ thì có thể xem lại ví dụ hello-kube ở bài viết sau:

Sổ tay Kubernetes: Các khái niệm cơ bản trong Kubernetes
Trong hướng dẫn trước bạn đã tìm hiểu về Kubernetes, cách cài đặt Kubernetes vàchạy ứng dụng đầu tiên sử dụng Kubernetes. Sổ tay Kubernetes: Giới thiệu về KubernetesHướng dẫn này giới thiệu về điềuphốicontainer và Kubernetes, cài đặt Kubernetes và chạy ứng dụng đầu tiên trongKubernetes.Trung Ng…

Cách tiếp cận mà bạn đã thực hiện trong phần đó là cách tiếp cận mệnh lệnh có nghĩa là bạn phải thực hiện từng lệnh một theo cách thủ công. Thực hiện một cách tiếp cận mệnh lệnh bất chấp toàn bộ quan điểm của Kubernetes.

Một cách tiếp cận lý tưởng để triển khai với Kubernetes là cách tiếp cận khai báo. Trong đó, bạn, với tư cách là nhà phát triển, hãy cho Kubernetes biết trạng thái mà bạn mong muốn máy chủ của mình ở trong đó và Kubernetes sẽ tìm ra cách để thực hiện điều đó.

Trong phần này, bạn sẽ triển khai cùng một ứng dụng hello-kube theo cách tiếp cận khai báo.

Trước khi bắt đầu, bạn hãy sao chép kho lưu trữ mã nguồn cho ví dụ hello-kube ở đây.

Khi bạn đã có mã nguồn, hãy vào bên trong thư mục hello-kube. Thư mục này chứa mã cho ứng dụng hello-kubeDockerfile để xây dựng image.

├── Dockerfile
├── index.html
├── package.json
├── public
└── src

2 directories, 3 files

Mã JavaScript nằm bên trong thư mục src nhưng bạn không cần quan tâm. Tệp bạn nên xem là Dockerfile vì nó có thể cung cấp cho bạn cái nhìn sâu sắc về cách bạn nên lập kế hoạch triển khai. Nội dung Dockerfile như sau:

FROM node as builder

WORKDIR /usr/app

COPY ./package.json ./
RUN npm install
COPY . .
RUN npm run build

EXPOSE 80

FROM nginx
COPY --from=builder /usr/app/dist /usr/share/nginx/html

Như bạn có thể thấy, đây là một quá trình xây dựng image gồm nhiều giai đoạn.

  • Giai đoạn đầu tiên sử dụng node làm image cơ sở và biên dịch ứng dụng JavaScript thành một loạt các tệp sẵn sàng cho sản xuất (production).
  • Giai đoạn thứ hai sao chép các tệp được tạo trong giai đoạn đầu tiên và dán chúng vào bên trong thư mục gốc mặc định của NGINX. Giả sử rằng image cơ sở cho giai đoạn thứ hai là nginx, image kết quả sẽ là image nginx phục vụ các tệp được xây dựng trong giai đoạn đầu tiên trên cổng 80 (cổng mặc định cho NGINX).

Bây giờ để triển khai ứng dụng này trên Kubernetes, bạn sẽ phải tìm cách chạy image dưới dạng container và làm cho cổng 80 có thể truy cập từ thế giới bên ngoài.

Viết bộ cấu hình đầu tiên của bạn

Trong cách tiếp cận khai báo, thay vì đưa ra các lệnh riêng lẻ trong terminal, bạn viết ra cấu hình cần thiết trong tệp YAML và đưa nó cho Kubernetes.

Trong thư mục dự án hello-kube, hãy tạo một thư mục khác có tên k8s. k8s là viết tắt của k (ubernete = 8 ký tự) s.

Bạn không cần phải đặt tên thư mục theo cách này, bạn có thể đặt bất cứ tên gì bạn muốn.

Thậm chí không cần thiết phải giữ nó trong thư mục dự án. Các tệp cấu hình này có thể tồn tại ở bất kỳ đâu trong máy tính của bạn, vì chúng không liên quan đến mã nguồn của dự án.

Bây giờ bên trong thư mục k8s đó, hãy tạo một tệp mới có tên hello-kube-pod.yaml. Tôi sẽ tiếp tục và viết mã cho tệp trước và sau đó tôi sẽ đi từng dòng một và giải thích cho bạn. Nội dung của tệp này như sau:

apiVersion: v1
kind: Pod
metadata:
  name: hello-kube-pod
  labels:
    component: web
spec:
  containers:
    - name: hello-kube
      image: fhsinchy/hello-kube
      ports:
        - containerPort: 80

Mọi tệp cấu hình Kubernetes hợp lệ đều có bốn trường bắt buộc. Chúng như sau:

  • apiVersion: Phiên bản nào của Kubernetes API bạn đang sử dụng để tạo đối tượng này. Giá trị này có thể thay đổi tùy thuộc vào loại đối tượng bạn đang tạo. Đối với việc tạo một Pod phiên bản bắt buộc là v1.
  • kind: Loại đối tượng bạn muốn tạo. Các đối tượng trong Kubernetes có thể có nhiều loại. Khi xem qua bài viết, bạn sẽ tìm hiểu về rất nhiều thứ trong số đó, nhưng hiện tại, hãy hiểu rằng bạn đang tạo một đối tượng Pod.
  • metadata: Dữ liệu giúp xác định duy nhất đối tượng. Trong trường này bạn có thể có các thông tin như name, labels, annotation, v.v. Trường metadata.name sẽ hiển thị trên các terminal và sẽ được sử dụng trong lệnh kubectl. Cặp khóa-giá trị trong trường metadata.labels không nhất thiết phải là components: web. Bạn có thể cho nó bất kỳ nhãn nào, chẳng hạn như app: hello-kube. Giá trị này sẽ được sử dụng làm bộ chọn ngay khi tạo dịch vụ LoadBalancer.
  • spec: chứa trạng thái bạn mong muốn cho đối tượng. Trường spec.containers chứa thông tin về các container sẽ chạy bên trong trường này Pod. Giá trị của trường spec.containers.name là những gì trình thực thi container bên trong node sẽ gán cho container mới được tạo ra. Trường spec.containers.image là image được sử dụng để tạo container này. Và trường spec.containers.ports chứa cấu hình liên quan đến cấu hình các cổng khác nhau. containerPort: 80 cho biết rằng bạn muốn để lộ cổng 80 từ container.

Bây giờ để cung cấp tệp cấu hình này cho Kubernetes, bạn sẽ sử dụng lệnh apply. Cú pháp chung cho lệnh như sau:

kubectl apply -f <configuration file>

Để chỉ định một tệp cấu hình có tên hello-kube-pod.yaml, lệnh sẽ như sau:

kubectl apply -f hello-kube-pod.yaml

# pod/hello-kube-pod created

Để đảm bảo rằng Pod đang hoạt động, hãy thực hiện lệnh sau:

kubectl get pod

# NAME         READY   STATUS    RESTARTS   AGE
# hello-kube   1/1     Running   0          3m3s

Bạn sẽ thấy Running trong cột STATUS. Nếu bạn thấy điều gì đó giống như ContainerCreating hãy đợi một hoặc hai phút và kiểm tra lại.

Sau khi thiết lập và chạy Pod, đã đến lúc bạn viết tệp cấu hình cho dịch vụ LoadBalancer.

Tạo một tệp khác bên trong thư mục k8s được gọi hello-kube-load-balancer-service.yaml và đặt mã sau vào đó:

apiVersion: v1
kind: Service
metadata:
  name: hello-kube-load-balancer-service
spec:
  type: LoadBalancer
  ports:
    - port: 80
      targetPort: 80
  selector:
    component: web

Giống như các tập tin cấu hình trước đó, các trường apiVersion, kindmetadata phục vụ cùng một mục đích ở đây. Như bạn có thể thấy không có trường labels nào bên trong metadata ở đây. Đó là bởi vì một service chọn các đối tượng khác bằng cách sử dụng labels, các đối tượng khác không chọn một service.

Hãy nhớ rằng, các service thiết lập chính sách truy cập cho các đối tượng khác, các đối tượng khác không thiết lập chính sách truy cập cho một service.

Bên trong trường spec, bạn có thể thấy một bộ giá trị mới. Không giống như Pod, service có bốn loại là ClusterIP, NodePort, LoadBalancerExternalName.

Trong ví dụ này, bạn đang sử dụng LoadBalancer, đây là cách tiêu chuẩn để hiển thị một service bên ngoài cụm. Service này sẽ cung cấp cho bạn một địa chỉ IP mà sau đó bạn có thể sử dụng để kết nối với các ứng dụng đang chạy bên trong cụm của bạn.

Cấu hình dịch vụ LoadBalancer trong Kubernetes

Service LoadBalancer yêu cầu hai giá trị cổng hoạt động tốt. Trong trường ports này, giá trị port là để truy cập chính pod và giá trị của nó có thể là bất kỳ thứ gì bạn muốn.

Giá trị targetPort là một cổng từ bên trong container và phải phù hợp với cổng mà bạn muốn để lộ từ bên trong container.

Tôi đã nói rằng ứng dụng hello-kube chạy trên cổng 80 bên trong container. Bạn thậm chí đã để lộ cổng này trong tệp cấu hình Pod, vì vậy targetPort sẽ là như vậy 80.

Trường selector được sử dụng để xác định các đối tượng sẽ được kết nối với dịch vụ này. Cặp khóa-giá trị component: web phải khớp với cặp khóa-giá trị trong trường labels trong tệp cấu hình Pod. Nếu bạn đã sử dụng một số cặp giá trị khóa khác như app: hello-kube trong tệp cấu hình đó, hãy sử dụng cặp giá trị đó để thay thế.

Để cung cấp tệp này cho Kubernetes, bạn sẽ lại sử dụng lệnh apply. Lệnh cung cấp tệp có tên hello-kube-load-balancer-service.yaml sẽ như sau:

kubectl apply -f hello-kube-load-balancer-service.yaml

# service/hello-kube-load-balancer-service created

Để đảm bảo bộ cân bằng tải đã được tạo thành công, hãy thực hiện lệnh sau:

kubectl get service

# NAME                               TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
# hello-kube-load-balancer-service   LoadBalancer   10.107.231.120   <pending>     80:30848/TCP   7s
# kubernetes                         ClusterIP      10.96.0.1        <none>        443/TCP        21h

Đảm bảo rằng bạn nhìn thấy tên hello-kube-load-balancer-service trong danh sách. Bây giờ bạn có một pod đang chạy được hiển thị, bạn có thể tiếp tục và truy cập pod đó. Thực thi lệnh sau để làm như vậy:

minikube service hello-kube-load-balancer-service

# |-----------|----------------------------------|-------------|-----------------------------|
# | NAMESPACE |           NAME                   | TARGET PORT |             URL             |
# |-----------|----------------------------------|-------------|-----------------------------|
# | default   | hello-kube-load-balancer-service |          80 | http://192.168.99.101:30848 |
# |-----------|----------------------------------|-------------|-----------------------------|
# ?  Opening service default/hello-kube-load-balancer in default browser...

Trình duyệt web mặc định của bạn sẽ tự động mở và bạn sẽ thấy một cái gì đó như sau:

Hello world trong Kubernetes

Bạn cũng có thể cấp dữ liệu cả hai tệp cùng nhau thay vì cấp từng tệp. Để làm điều đó, bạn có thể thay thế tên tệp bằng tên thư mục như sau:

kubectl apply -f k8s

# service/hello-kube-load-balancer-service created
# pod/hello-kube-pod created

Trong trường hợp này, hãy đảm bảo rằng terminal của bạn nằm ở thư mục cha của thư mục k8s.

Nếu bạn đang ở trong thư mục k8s, bạn có thể sử dụng dấu chấm (.) để tham chiếu đến thư mục hiện tại. Khi áp dụng hàng loạt các cấu hình, bạn nên loại bỏ các tài nguyên đã tạo trước đó. Bằng cách đó, khả năng xảy ra xung đột trở nên thấp hơn nhiều.

Phương pháp khai báo là phương pháp lý tưởng khi làm việc với Kubernetes. Ngoại trừ một số trường hợp đặc biệt, bạn sẽ thấy ở những phần sau.

Bảng điều khiển Kubernetes

Trong phần trước, bạn đã sử dụng lệnh delete để loại bỏ một đối tượng Kubernetes.

Tuy nhiên, trong phần này, tôi nghĩ rằng việc giới thiệu bảng điều khiển sẽ là một ý tưởng tuyệt vời. Bảng điều khiển Kubernetes (Kubernetes Dashboard) là một giao diện đồ họa người dùng mà bạn có thể sử dụng để quản lý khối lượng công việc, dịch vụ của mình và hơn thế nữa.

Để khởi chạy bảng điều khiển Kubernetes, hãy thực hiện lệnh sau trong terminal của bạn:

minikube dashboard

# ? Verifying dashboard health ...
# ? Launching proxy ...
# ? Verifying proxy health ...
# ? Opening http://127.0.0.1:52393/api/v1/namespaces/kubernetes-dashboard/services/http:kubernetes-dashboard:/proxy/ in your default browser...

Trang tổng quan sẽ tự động mở trong trình duyệt mặc định của bạn:

Bảng điều khiển Kubernetes (Kubernetes Dashboard)

Giao diện người dùng khá thân thiện với người dùng và bạn có thể thoải mái di chuyển xung quanh đây. Mặc dù hoàn toàn có thể tạo, quản lý và xóa các đối tượng khỏi giao diện người dùng này, nhưng tôi sẽ sử dụng CLI cho phần còn lại của bài viết này.

Ở đây là danh sách Pods, bạn có thể sử dụng menu ba dấu chấm ở bên phải để xóa Pod. Bạn cũng có thể làm như vậy với dịch vụ LoadBalancer. Trong thực tế,  danh sách Service được đặt thuận tiện ngay sau khi danh sách Pods.

Bạn có thể đóng bảng điều khiển Kubernetes bằng cách nhấn tổ hợp phím Ctrl + C hoặc đóng cửa sổ dòng lệnh.

Ở bài viết tiếp theo, bạn sẽ tìm hiểu cách triển khai ứng dụng trên nhiều container. Bạn cũng sẽ tiếp xúc với Deployment, ClusterIP, PersistentVolume, PersistentVolumeClaim và một số lỗi thường gặp khi triển khai.

Sổ tay Kubernetes: Triển khai ứng dụng đa container (p1)
Trong phần này, bạn sẽ tìm hiểu về Deployment, ClusterIP, PersistentVolume, PersistentVolumeClaim để triển khai một ứng dụng bao gồm hai container.

Hướng dẫn này được dịch từ sách Kubernetes Handbook của Farhan Hasin Chowdhury:

The Kubernetes Handbook
Kubernetes [https://kubernetes.io/] is an open-source container orchestrationplatform that automates the deployment, management, scaling, and networking ofcontainers. It was developed by Google [https://opensource.google/projects/kubernetes] usingthe Go Programming Language [https://golang.org/…
KubernetesDevOps
Bài Viết Liên Quan:
Sổ tay Kubernetes: làm việc với Ingress Controller (p2)
Trung Nguyen 30/05/2021
Sổ tay Kubernetes: làm việc với Ingress Controller (p2)

Trong phần này, bạn sẽ tìm hiểu cách sử dụng Secret, ConfigMap để lưu trữ thông tin cấu hình, phát hành các bản cập nhật và xử lý sự cố trong Kubernetes.

Sổ tay Kubernetes: làm việc với Ingress Controller (p1)
Trung Nguyen 30/05/2021
Sổ tay Kubernetes: làm việc với Ingress Controller (p1)

Trong hướng dẫn này, bạn sẽ tìm hiểu về Ingress Controller và cách sử dụng NGINX Ingress Controller để cấu hình định tuyến trong Kubernetes.

Sổ tay Kubernetes: Triển khai ứng dụng đa container (p3)
Trung Nguyen 30/05/2021
Sổ tay Kubernetes: Triển khai ứng dụng đa container (p3)

Ở phần 3 này, chúng ta sẽ tìm hiểu cách cung cấp động Persistent Volume, kết nối volume với pod và kết nối các thành phần trong cụm với nhau.

Sổ tay Kubernetes: Triển khai ứng dụng đa container (p2)
Trung Nguyen 30/05/2021
Sổ tay Kubernetes: Triển khai ứng dụng đa container (p2)

Ở phần 2 này, chúng ta sẽ tìm cách khắc phục những lỗi xảy ra khi triển khai. Chúng ta cũng tìm hiểu thêm về Persistent Volume, Persistent Volume Claim.