Friday, November 1, 2024

[Kustomize] Tạo ứng dụng Kubernetes

-

Kustomize là một trong những công cụ hữu ích nhất trong hệ sinh thái Kubernetes để đơn giản hóa việc triển khai, cho phép bạn tạo toàn bộ ứng dụng Kubernetes từ các manifest có sẵn mà không cần chỉnh sửa vào các file cấu hình YAML gốc cho nhiều mục đích khác nhau.

Trong hướng dẫn này, chúng ta sẽ thiết lập Kustomize và khám phá cách nó hoạt động bằng cách triển khai WordPress và sau đó, chúng ta sẽ xem việc sử dụng Kustomize với kubectl để xem lợi ích của Kustomize đối với việc triển khai trên quy mô lớn nó có lợi như thế nào.

Lưu ý : Nếu bạn đang sử dụng phiên bản mới nhất của kubectl, thì bạn đã tích hợp sẵn Kustomize. Nếu bạn đang sử dụng phiên bản kubectl 1.14 trở về trước hoặc chỉ muốn sử dụng công cụ Kustomize độc ​​lập, bạn có thể làm theo hướng dẫn bên dưới. Trong một số trường hợp, các lệnh sẽ khác nhau giữa phiên bản độc lập và phiên bản tích hợp — mình chắc chắn sẽ chỉ ra những khác biệt đó nếu nó phát sinh.

1. Cài đặt Kustomize.

opsys=linux # hoặc darwin hoặc windows 
curl -s https://api.github.com/repos/kubernetes-sigs/kustomize/releases/latest |\ 
  grep browser_download |\ 
  grep $opsys |\ 
  cut -d '"' -f 4 |\ 
  xargs curl -O -L 
mv kustomize_*_${opsys}_amd64 kustomize 
chmod u+x kustomize

Hoặc nếu bạn sử dụng snap, hãy chạy lệnh.

snap install kustomize

2. Triển khai môi trường ứng dụng.

Một trong những cách sử dụng phổ biến nhất của Kustomize là lấy nhiều đối tượng và kết hợp chúng thành một tài nguyên duy nhất dựa vào các label chung, đầu tiên hãy tạo thư mục làm việc cho WordPress trước.

KUSTOM_HOME=$(mktemp -d) 
BASE=$KUSTOM_HOME/base 
mkdir $BASE 
WORDPRESS_HOME=$BASE/wordpress 
mkdir $WORDPRESS_HOME 
cd $WORDPRESS_HOME

Bây giờ chúng ta hãy tạo manifest deployment.yaml theo đường dẫn $WORDPRESS_HOME/deployment.yaml .

cat > $WORDPRESS_HOME/deployment.yaml << 'OEF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: wordpress
  labels:
    app: wordpress
spec:
  selector:
    matchLabels:
      app: wordpress
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: wordpress
    spec:
      containers:
      - image: wordpress:4.8-apache
        name: wordpress
        ports:
        - containerPort: 80
          name: wordpress
        volumeMounts:
        - name: wordpress-persistent-storage
          mountPath: /var/www/html
      volumes:
      - name: wordpress-persistent-storage
        emptyDir: {}
OEF

Tiếp theo hãy tạo manifest của services vào đường dẫn $WORDPRESS_HOME/service.yaml

cat > $WORDPRESS_HOME/service.yaml << 'OEF'
apiVersion: v1
kind: Service
metadata:
  name: wordpress
  labels:
    app: wordpress
spec:
  ports:
    - port: 80
  selector:
    app: wordpress
  type: LoadBalancer
OEF

Theo cách bình thường thì bạn sẽ sử dụng lệnh dưới để tạo ứng dụng.

$ kubectl apply -f $WORDPRESS_HOME
deployment.apps/wordpress created
service/wordpress created
$ kubectl get pod,svc
NAME                             READY   STATUS    RESTARTS   AGE
pod/wordpress-5d9f64987b-98l7b   1/1     Running   0          70s

NAME                 TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)        AGE
service/wordpress    LoadBalancer   10.97.120.115   192.168.13.224   80:30709/TCP   71s

Bây giờ nếu bạn xem các định nghĩa, bạn sẽ nhận thấy rằng cả hai tài nguyên đều hiển thị label ứng dụng là wordpress . Nếu bạn muốn triển khai chúng và sử dụng label để phân biệt giữa các ứng dụng, chẳng hạn như app:my-wordpress1 hoặc app:my-wordpress2,… bạn sẽ phải vào thêm tham số label trong cả 2 file manifest deployment.yaml và service.yaml. Nếu như vậy rất mất thời gian và không tiện trong việc triển khai nhiều dự án lớn.

Thay vào đó, chúng ta có thể sử dụng Kustomize để kết hợp chúng thành một manifest duy nhất — bao gồm label ứng dụng mong muốn — mà không thay đổi manifest gốc. Do lúc nãy mình đã triển khai thử nên bây giờ trước khi chúng ta tiếp tục, bạn cần dọn dẹp nó trước.

$ kubectl delete -f $WORDPRESS_HOME
deployment.apps "wordpress" deleted
service "wordpress" deleted

Sau khi dọn dẹp nó xong chúng ta sẽ bắt đầu bằng cách tạo file $WORDPRESS_HOME/kustomization.yaml và thêm file này nội dung sau:

cat >  $WORDPRESS_HOME/kustomization.yaml << 'OEF'
commonLabels:
  app: my-wordpress

resources:
- deployment.yaml
- service.yaml
OEF

Đây là một file rất đơn giản chỉ đơn giản là thêm 1 label chung — app: my-wordpress — vào các tài nguyên được xác định trong 2 file manifest deployment.yaml và service.yaml . Bây giờ chúng ta có thể sử dụng lệnh kustomize build để build 1 YAML mới. Nếu bạn đang sử dụng Kustomize độc ​​lập, bạn sẽ chạy:

kustomize build $WORDPRESS_HOME

Nếu bạn đang sử dụng kubectl kustomize bạn hãy chạy:

kubectl kustomize $WORDPRESS_HOME

Đầu ra là sự kết hợp của 2 file manifest deployment.yaml và nó chỉ thay đổi label mà chúng ta đã định nghĩa trong file kustomization.yaml

$ kubectl kustomize $WORDPRESS_HOME
apiVersion: v1
kind: Service
metadata:
  labels:
    app: my-wordpress
  name: wordpress
spec:
  ports:
  - port: 80
  selector:
    app: my-wordpress
  type: LoadBalancer
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: my-wordpress
  name: wordpress
spec:
  selector:
    matchLabels:
      app: my-wordpress
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: my-wordpress
    spec:
      containers:
      - image: wordpress:4.8-apache
        name: wordpress
        ports:
        - containerPort: 80
          name: wordpress
        volumeMounts:
        - mountPath: /var/www/html
          name: wordpress-persistent-storage
      volumes:
      - emptyDir: {}
        name: wordpress-persistent-storage

Bạn có thể export nội dung này thành file hoặc chuyển file trực tiếp vào kubectl — mình sẽ đề cập đến cả hai phương pháp trong giây lát.

Quản lý nhiều thư mục

Để WordPress chạy bạn cần có thêm cơ sở dữ liệu như MySQL hoặc MariaDB. Đề làm được điều này mình sẽ tạo một tập hợp các file tương tự để thiết lập MySQL nhưng thật không may là chúng sẽ trùng tên với các file của WordPress và bạn hãy nhớ rằng mình không muốn thay đổi bất kỳ file nào của WordPress vì vậy để làm được điều này mình sẽ tạo thêm 1 thư mục mới để lưu các file manifest cho MySQL.

MYSQL_HOME=$BASE/mysql
mkdir $MYSQL_HOME
cd $MYSQL_HOME

File đầu tiên mình cần thêm là $MYSQL_HOME/deployment.yaml

cat > $MYSQL_HOME/deployment.yaml << 'OEF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
  labels:
    app: mysql
spec:
  selector:
    matchLabels:
      app: mysql
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - image: mysql:5.6
        name: mysql
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-pass
              key: password
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-persistent-storage
        emptyDir: {}
OEF

Tiếp theo thêm file $MYSQL_HOME/service.yaml

cat > $MYSQL_HOME/service.yaml << 'OEF'
apiVersion: v1
kind: Service
metadata:
  name: mysql
  labels:
    app: mysql
spec:
  ports:
    - port: 3306
  selector:
    app: mysql
OEF

Và cuối cùng $MYSQL_HOME/secret.yaml để giữ tên người dùng và mật khẩu cơ sở dữ liệu.

cat > $MYSQL_HOME/secret.yaml << 'OEF'
apiVersion: v1
kind: Secret
metadata:
  name: mysql-pass
type: Opaque
data:
  # Default password is "admin".
  password: YWRtaW4=
OEF

Và giống như WordPress chúng ta sẽ thêm một file kustomization, $MYSQL_HOME/kustomization.yaml để custom resource manifest cho MySQL.

cat > $MYSQL_HOME/kustomization.yaml << 'OEF'
resources:
- deployment.yaml
- service.yaml
- secret.yaml
OEF

Bây giờ chúng ta cần thêm một file kustomization mới vào thư mục base tại $BASE/kustomization.yaml, chúng ta sẽ khai báo thông tin label tại file kustomization.yaml này luôn để thông tin label có sẽ được áp dụng cho cả 2 resource WordPress và MySQL.

cat > $BASE/kustomization.yaml << 'OEF'
commonLabels:
  app: my-wordpress
bases:
- ./wordpress
- ./mysql
OEF

Ở bước trên lúc này chúng ta có thử triển khai Kustomize cho WordPress nên đã thêm nội dung label vào file $WORDPRESS_HOME/kustomization.yaml rồi nên giờ bạn hãy xoá label trong file này nhé.

commonLabels: -> xoá phần này
  app: my-wordpress -> xoá phần này

resources: -> giữ nguyên
- deployment.yaml -> giữ nguyên
- service.yaml -> giữ nguyên

Tất cả đã sẵn sàng, hãy thử build nó bằng lệnh kubectl kustomize $BASE hoặc kustomize build $BASE. Chúng ta có thể thấy cả 2 thành phần là WordPress và MySQL đã được cập nhật label.

$ kubectl kustomize $BASE
apiVersion: v1
data:
  password: YWRtaW4=
kind: Secret
metadata:
  labels:
    app: my-wordpress
  name: mysql-pass
type: Opaque
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: my-wordpress
  name: mysql
spec:
  ports:
  - port: 3306
  selector:
    app: my-wordpress
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: my-wordpress
  name: wordpress
spec:
  ports:
  - port: 80
  selector:
    app: my-wordpress
  type: LoadBalancer
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: my-wordpress
  name: wordpress
spec:
  selector:
    matchLabels:
      app: my-wordpress
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: my-wordpress
    spec:
      containers:
      - image: wordpress:4.8-apache
        name: wordpress
        ports:
        - containerPort: 80
          name: wordpress
        volumeMounts:
        - mountPath: /var/www/html
          name: wordpress-persistent-storage
      volumes:
      - emptyDir: {}
        name: wordpress-persistent-storage
---
apiVersion: apps/v1beta2
kind: Deployment
metadata:
  labels:
    app: my-wordpress
  name: mysql
spec:
  selector:
    matchLabels:
      app: my-wordpress
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: my-wordpress
    spec:
      containers:
      - env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              key: password
              name: mysql-pass
        image: mysql:5.6
        name: mysql
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - mountPath: /var/lib/mysql
          name: mysql-persistent-storage
      volumes:
      - emptyDir: {}
        name: mysql-persistent-storage

OK, vậy bây giờ chúng ta đã thay đổi được nhiều thành phần… nhưng điều gì sẽ xảy ra nếu chúng ta cần thay đổi điều gì đó?

Thay đổi tham số cho một thành phần bằng cách sử dụng Kustomize Overlays.

Bây giờ, chúng ta gần như đã sẵn sàng triển khai được ứng dụng WordPress, nhưng chúng ta có một vấn đề là nếu các manifest trên chúng ta triển khai cho hệ thống có tích hợp sẵn LoadBalancer ví dụ như các cloud provider thì nó sẽ hoạt động tốt nhưng nếu chúng ta triển khai demo trên máy tính cá nhân của mình chẳng hạn mà không có sẵn tính năng loadbalancer thì dịch vụ sẽ không chạy. Vì vậy mình đã nghĩ ra nếu rơi vào trường hợp demo thì sẽ chạy service là NodePort. Chúng ta có thể giải quyết vấn đề này bằng Kustomize.

Kustomize cho phép chúng ta lấy YAML base và thay đổi một số nội dung mong muốn. Ví dụ: chúng ta sẽ tạo một bản vá để thay đổi service từ các manifest base thành các service loại NodePort.

Creating a kustomize patch

Mình sẽ tạo 1 thư mục có tên là overlay và điều quan trọng là thư mục overlay không được nằm trong cùng thư mục với các file base, vì vậy chúng ta sẽ tạo thư mục overlay song song với thư mục base, sau đó thêm thư mục con dev vào thư mục overlay.

OVERLAY_HOME=$BASE/../overlays
mkdir $OVERLAY_HOME
DEV_HOME=$OVERLAY_HOME/dev
mkdir $DEV_HOME
cd $DEV_HOME

Tiếp theo, chúng ta sẽ tạo 1 manifest như là 1 bản vá cho service $DEV_HOME/localserv.yaml

cat > $DEV_HOME/localserv.yaml << 'OEF'
apiVersion: v1
kind: Service
metadata:
  name: wordpress
spec:
  type: NodePort
---
apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  type: NodePort
OEF

Lưu ý rằng chúng ta đã có các thông tin tối thiểu ở đây; vừa đủ để xác định từng dịch vụ mà chúng ta muốn thay đổi, sau đó chỉ định thay đổi mà chúng ta muốn thực hiện — trong trường hợp này là service type. Bây giờ chúng ta cần tạo file $DEV_HOME/kustomization.yaml để liên kết tất cả những thứ này lại với nhau:

cat > $DEV_HOME/kustomization.yaml << 'OEF'
bases:
- ../../base

patchesStrategicMerge:
- localserv.yaml
OEF

Lưu ý rằng điều này thực sự rất đơn giản; chúng ta đang chỉ vào thư mục base khởi tạo lúc ban đầu có chứa 2 thư mục của 2 thành phần đó là WordPress bà MySQL và chỉ định (các) bản vá mà chúng ta muốn thêm.

Bây giờ chúng ta có thể tiếp tục và xây dựng $BASE ban đầu và đảm bảo rằng nó không bị ảnh hưởng.

Sau khi tạo xong các thành phần, bạn sẽ có cây thư mục như thế này.

.
├── overlays
│   └── dev
│       ├── kustomization.yaml
│       └── localserv.yaml
└── base
    ├── kustomization.yaml
    ├── mysql
    │   ├── deployment.yaml
    │   ├── kustomization.yaml
    │   ├── secret.yaml
    │   └── service.yaml
    └── wordpress
        ├── deployment.yaml
        ├── kustomization.yaml
        └── service.yaml

Chúng ta vẫn có các dịch vụ LoadBalancer nếu build chúng tại thư mục base:

$ kustomize build $BASE
apiVersion: v1
data:
  password: YWRtaW4=
kind: Secret
metadata:
  labels:
    app: my-wordpress
  name: mysql-pass
type: Opaque
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: my-wordpress
  name: mysql
spec:
  ports:
  - port: 3306
  selector:
    app: my-wordpress
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: my-wordpress
  name: wordpress
spec:
  ports:
  - port: 80
  selector:
    app: my-wordpress
  type: LoadBalancer
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: my-wordpress
  name: wordpress
spec:
  selector:
    matchLabels:
      app: my-wordpress
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: my-wordpress
    spec:
      containers:
      - image: wordpress:4.8-apache
        name: wordpress
        ports:
        - containerPort: 80
          name: wordpress
        volumeMounts:
        - mountPath: /var/www/html
          name: wordpress-persistent-storage
      volumes:
      - emptyDir: {}
        name: wordpress-persistent-storage
---
apiVersion: apps/v1beta2
kind: Deployment
metadata:
  labels:
    app: my-wordpress
  name: mysql
spec:
  selector:
    matchLabels:
      app: my-wordpress
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: my-wordpress
    spec:
      containers:
      - env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              key: password
              name: mysql-pass
        image: mysql:5.6
        name: mysql
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - mountPath: /var/lib/mysql
          name: mysql-persistent-storage
      volumes:
      - emptyDir: {}
        name: mysql-persistent-storage

Nhưng nếu chúng ta build các manifest từ thư mục dev, bạn sẽ có kết qu service type loadbalancer đã được thay thế bằng NodePort. Hãy sử dụng kubectl kustomize $DEV_HOME hoặc kustomize build $DEV_HOME. Bạn sẽ thấy mọi thứ không thay đổi ngoại trừ service type:

$ kustomize build $DEV_HOME
apiVersion: v1
data:
  password: YWRtaW4=
kind: Secret
metadata:
  labels:
    app: my-wordpress
  name: mysql-pass
type: Opaque
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: my-wordpress
  name: mysql
spec:
  ports:
  - port: 3306
  selector:
    app: my-wordpress
  type: NodePort
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: my-wordpress
  name: wordpress
spec:
  ports:
  - port: 80
  selector:
    app: my-wordpress
  type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: my-wordpress
  name: wordpress
spec:
  selector:
    matchLabels:
      app: my-wordpress
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: my-wordpress
    spec:
      containers:
      - image: wordpress:4.8-apache
        name: wordpress
        ports:
        - containerPort: 80
          name: wordpress
        volumeMounts:
        - mountPath: /var/www/html
          name: wordpress-persistent-storage
      volumes:
      - emptyDir: {}
        name: wordpress-persistent-storage
---
apiVersion: apps/v1beta2
kind: Deployment
metadata:
  labels:
    app: my-wordpress
  name: mysql
spec:
  selector:
    matchLabels:
      app: my-wordpress
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: my-wordpress
    spec:
      containers:
      - env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              key: password
              name: mysql-pass
        image: mysql:5.6
        name: mysql
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - mountPath: /var/lib/mysql
          name: mysql-persistent-storage
      volumes:
      - emptyDir: {}
        name: mysql-persistent-storage

Sử dụng Kustomize với Kubectl
Tất cả những điều này thật tuyệt vời, nhưng việc lưu nó vào một file rồi chạy file đó có vẻ hơi quá mức cần thiết. May mắn cho chúng ta là có hai cách để chúng ta có thể cung cấp trực tiếp thông tin này.

$ kustomize build . | kubectl apply -f -
secret/mysql-pass created
service/mysql created
service/wordpress created
deployment.apps/mysql created
deployment.apps/wordpress created

Hoặc nếu đang sử dụng Kubernetes 1.14 trở lên, bạn chỉ cần sử dụng tham số -k:

$ kubectl apply -k $DEV_HOME
secret/mysql-pass created
service/mysql created
service/wordpress created
deployment.apps/mysql created
deployment.apps/wordpress created

Như đã khai báo dịch vụ của bạn sau khi triển khai tại thư mục $DEV_HOME đang ở loại NodePort.

$ kubectl get svc -A | grep 'wordpress'
default                wordpress                                 NodePort    10.96.65.38      <none>        80:32680/TCP                 8m30s

Một ví dụ Secret Generator với Kustomize

với cách làm cũ bạn sẽ phải chạy lệnh như dưới.

$ kubectl create secret docker-registry myregistrykey --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL
secret/myregistrykey created.

Nhưng nếu sử dụng Kustomize bạn chỉ cần tạo ta file như thế này.

secretGenerator:
- name: myregistrykey
 type: docker-registry
 literals:
 - docker-server=DOCKER_REGISTRY_SERVER
 - docker-username=DOCKER_USER
 - docker-password=DOCKER_PASSWORD
 - docker-email=DOCKER_EMAIL

Sau đó, chỉ cần tham chiếu nó bằng tham số -k:

$ kubectl apply -k .
secret/myregistrykey-66h7d4d986 created

Kết luận.

Khi bạn đang làm việc trên nhiều môi trường với các yêu cầu riêng biệt, Kustomize có thể giúp nhóm của bạn chia sẻ cùng một file cơ sở chỉ với những thay đổi cần thiết được đặt chồng lên nhau một cách đơn giản và có chọn lọc. Chúng ta có thể tiếp tục công việc của mình trên ứng dụng đó với sự tự tin rằng các cấu hình của chúng ta vẫn giống nhau trên các môi trường .

Kết hợp điều này với sự tích hợp của Kustomize vào kubectl tất cả đều hoàn toàn phù hợp với bộ công cụ K8s — và rõ ràng là Kustomize có thể đóng vai trò là một công cụ mạnh mẽ để triển khai cơ sở hạ tầng Kubernetes của chúng ta nhanh chóng và gọn gàng hơn.

LEAVE A REPLY

Please enter your comment!
Please enter your name here

4,956FansLike
256FollowersFollow
223SubscribersSubscribe
spot_img

Related Stories