So sánh đúng cách áp dụng, thay thế và vá lỗi Kubernetes

Kubernetes có một số tùy chọn để cập nhật tài nguyên: áp dụng, chỉnh sửa, vá lỗi và thay thế. Có sự nhầm lẫn về những gì mỗi người làm và khi nào nên sử dụng chúng. Hãy tìm ra nó.

So sánh đúng cách áp dụng, thay thế và vá lỗi Kubernetes

Nếu tìm kiếm trên Google cụm từ "kubernetes áp dụng và thay thế" được đặt trả lời StackOverflow, điều đó không đúng. Khi tìm kiếm "kubernetes áp dụng và bản vá" liên kết đầu tiên là tài liệu về kubectl patch, không bao gồm so sánh apply и patch. Bài viết này sẽ xem xét các tùy chọn khác nhau, cũng như cách sử dụng hợp lý từng tùy chọn.

Trong vòng đời của tài nguyên Kubernetes (dịch vụ, triển khai, xâm nhập, v.v.), đôi khi bạn cần thay đổi, thêm hoặc xóa một số thuộc tính của tài nguyên này. Ví dụ: thêm ghi chú, tăng hoặc giảm số lượng bản sao.

Kubernetes CLI

Nếu bạn đang làm việc với các cụm Kubernetes thông qua CLI thì bạn đã quen với apply и edit. Đội apply đọc đặc tả tài nguyên từ tệp và tạo "upsert" cho cụm Kubernetes, tức là. tạo tài nguyên nếu nó không tồn tại và cập nhật nó nếu nó tồn tại. Đội edit đọc tài nguyên thông qua API, sau đó ghi đặc tả tài nguyên vào tệp cục bộ, sau đó tệp này được mở trong trình soạn thảo văn bản. Sau khi chỉnh sửa và lưu file, kubectl sẽ gửi lại những thay đổi được thực hiện thông qua API, API này sẽ áp dụng cẩn thận những thay đổi này cho tài nguyên.

Không phải ai cũng biết lệnh patch и replace. Đội patch cho phép bạn thay đổi một phần đặc tả tài nguyên, chỉ cung cấp phần đã thay đổi trên dòng lệnh. Đội replace hoạt động tương tự như edit, nhưng mọi thứ cần phải được thực hiện thủ công: bạn cần tải xuống phiên bản hiện tại của đặc tả tài nguyên, ví dụ: sử dụng kubectl get -o yaml, chỉnh sửa nó rồi sử dụng replace để cập nhật tài nguyên theo thông số kỹ thuật đã thay đổi. Đội replace sẽ không hoạt động nếu có bất kỳ thay đổi nào xảy ra giữa việc đọc và thay thế tài nguyên.

API Kubernetes

Có lẽ bạn đã quen với các phương pháp CoreV1().Pods().Update(), replaceNamespacedService hoặc patch_namespaced_deployment, nếu bạn làm việc với các cụm thông qua thư viện ứng dụng khách cho API Kubernetes sử dụng một số ngôn ngữ lập trình. Thư viện xử lý các phương thức này thông qua các yêu cầu HTTP bằng các phương thức PUT и PATCH... Trong đó update и replace sử dụng PUTpatch, cho dù nó tầm thường đến đâu, hãy sử dụng PATCH.

Cần lưu ý rằng kubectl cũng hoạt động với các cụm thông qua API. Nói cách khác, kubectllà một trình bao bọc bên trên thư viện máy khách dành cho ngôn ngữ Go, phần lớn cung cấp khả năng cung cấp các lệnh phụ ở dạng nhỏ gọn và dễ đọc hơn bên cạnh các khả năng API tiêu chuẩn. Ví dụ, như bạn có thể đã nhận thấy, phương pháp apply đã không được đề cập ở trên trong đoạn trước. Hiện tại (tháng 2020 năm XNUMX, khoảng người phiên dịch) tất cả logic kubectl apply, I E. tạo tài nguyên không tồn tại và cập nhật tài nguyên hiện có, hoạt động hoàn toàn ở phía mã kubectl. Những nỗ lực đang được thực hiện về chuyển giao logic apply về phía API, nhưng nó vẫn đang trong giai đoạn thử nghiệm. Tôi sẽ viết chi tiết hơn ở bên dưới.

Bản vá theo mặc định

Sử dụng tốt nhất patch, nếu bạn muốn cập nhật tài nguyên. Đây là cách cả hai thư viện máy khách hoạt động dựa trên API Kubernetes và kubectl (không có gì đáng ngạc nhiên, vì nó là một trình bao bọc cho thư viện máy khách, khoảng người phiên dịch).

Làm việc có chiến lược

Tất cả các đội kubectl apply, edit и patch sử dụng phương pháp PATCH trong các yêu cầu HTTP để cập nhật tài nguyên hiện có. Nếu bạn đi sâu vào việc thực hiện các lệnh chi tiết hơn thì tất cả chúng đều sử dụng phương pháp vá lỗi hợp nhất chiến lược để cập nhật tài nguyên, mặc dù lệnh patch có thể sử dụng các phương pháp khác (xem thêm về điều này bên dưới). Phương pháp vá lỗi hợp nhất chiến lược cố gắng "làm đúng" bằng cách hợp nhất đặc tả được cung cấp với đặc tả hiện có. Cụ thể hơn, nó cố gắng kết hợp cả đối tượng và mảng, có nghĩa là những thay đổi có xu hướng mang tính bổ sung. Ví dụ: chạy lệnh patch với một biến môi trường mới trong đặc tả vùng chứa nhóm, biến môi trường đó sẽ được thêm vào các biến môi trường hiện có thay vì ghi đè chúng. Để loại bỏ việc sử dụng phương pháp này, bạn phải buộc giá trị tham số thành null trong thông số kỹ thuật được cung cấp. Đội nào trong số các đội kubectl Tốt nhất là sử dụng để cập nhật?

Nếu bạn tạo và quản lý tài nguyên của mình bằng cách sử dụng kubectl apply, khi cập nhật, tốt hơn hết là luôn sử dụng kubectl applyĐể kubectl có thể quản lý cấu hình và theo dõi chính xác các thay đổi được yêu cầu từ ứng dụng này sang ứng dụng khác. Ưu điểm luôn sử dụng apply là nó theo dõi đặc tả được áp dụng trước đó, cho phép nó biết khi nào các thuộc tính đặc tả và phần tử mảng bị loại bỏ rõ ràng. Điều này cho phép bạn sử dụng apply để loại bỏ các thuộc tính và phần tử mảng, trong khi việc hợp nhất chiến lược thông thường sẽ không hoạt động. Đội edit и patch không cập nhật ghi chú rằng kubectl apply sử dụng để theo dõi các thay đổi của nó, do đó, mọi thay đổi được theo dõi và thực hiện thông qua API Kubernetes nhưng được thực hiện thông qua các lệnh edit и patch, vô hình với các lệnh tiếp theo applyĐó là, apply không loại bỏ chúng ngay cả khi chúng không xuất hiện trong đặc tả đầu vào cho apply (Tài liệu nói rằng edit и patch cập nhật các ghi chú được sử dụng apply, nhưng trong thực tế - không).

Nếu bạn không sử dụng lệnh apply, có thể được sử dụng như editpatch, chọn lệnh phù hợp nhất với thay đổi đang được thực hiện. Khi thêm và thay đổi thuộc tính BOM, cả hai cách tiếp cận đều gần giống nhau. Khi xóa thuộc tính đặc tả hoặc phần tử mảng edit hoạt động giống như khởi chạy một lần apply, bao gồm cả việc theo dõi đặc tả như thế nào trước và sau khi được chỉnh sửa, do đó bạn có thể loại bỏ rõ ràng các thuộc tính và phần tử mảng khỏi tài nguyên. Bạn cần đặt rõ ràng giá trị thuộc tính thành null trong thông số kỹ thuật cho patchđể loại bỏ nó khỏi tài nguyên. Việc loại bỏ một phần tử mảng bằng cách sử dụng bản vá hợp nhất chiến lược phức tạp hơn vì nó yêu cầu sử dụng các lệnh hợp nhất. Xem các phương pháp nâng cấp khác bên dưới để có các lựa chọn thay thế khả thi hơn.

Để triển khai các phương thức cập nhật trong thư viện máy khách hoạt động tương tự như các lệnh trên kubectl, nên được đặt trong yêu cầu content-type в application/strategic-merge-patch+json. Nếu bạn muốn loại bỏ các thuộc tính trong một đặc tả, bạn cần đặt rõ ràng giá trị của chúng thành null theo cách tương tự kubectl patch. Nếu cần loại bỏ các phần tử mảng, bạn nên đưa các lệnh hợp nhất vào đặc tả cập nhật hoặc sử dụng một cách tiếp cận khác để cập nhật.

Các cách tiếp cận khác để cập nhật

Kubernetes hỗ trợ hai phương pháp cập nhật khác: Bản vá hợp nhất JSON и Bản vá JSON. Phương pháp vá lỗi hợp nhất JSON lấy thông số kỹ thuật Kubernetes một phần làm đầu vào và hỗ trợ việc hợp nhất các đối tượng tương tự như phương pháp vá lỗi hợp nhất chiến lược. Sự khác biệt giữa hai loại này là nó chỉ hỗ trợ thay thế mảng, bao gồm cả mảng chứa trong đặc tả nhóm. Điều này có nghĩa là khi sử dụng bản vá hợp nhất JSON, bạn cần cung cấp thông số kỹ thuật đầy đủ cho tất cả các vùng chứa trong trường hợp bất kỳ thuộc tính nào của bất kỳ vùng chứa nào thay đổi. Vì vậy, cách tiếp cận này rất hữu ích để loại bỏ các phần tử khỏi một mảng trong BOM. Trên dòng lệnh, bạn có thể chọn bản vá hợp nhất JSON bằng cách sử dụng kubectl patch --type=merge. Khi làm việc với Kubernetes API, bạn nên sử dụng phương thức request PATCH và cài đặt content-type в application/merge-patch+json.

Cách tiếp cận bản vá JSON, thay vì cung cấp thông số kỹ thuật một phần của tài nguyên, sử dụng việc cung cấp các thay đổi bạn muốn thực hiện cho tài nguyên dưới dạng một mảng, trong đó mỗi phần tử của mảng thể hiện mô tả về thay đổi được thực hiện đối với tài nguyên. Cách tiếp cận này là một cách linh hoạt và mạnh mẽ hơn để thể hiện những thay đổi đang được thực hiện, nhưng phải trả giá bằng việc liệt kê những thay đổi được thực hiện ở định dạng riêng biệt, không phải Kubernetes, thay vì gửi thông số tài nguyên một phần. TRONG kubectl bạn có thể chọn bản vá JSON bằng cách sử dụng kubectl patch --type=json. Khi sử dụng API Kubernetes, phương pháp này hoạt động bằng phương thức yêu cầu PATCH và cài đặt content-type в application/json-patch+json.

Chúng tôi cần sự tự tin - sử dụng thay thế

Trong một số trường hợp, bạn cần chắc chắn rằng không có thay đổi nào được thực hiện đối với tài nguyên trong khoảng thời gian tài nguyên được đọc và khi tài nguyên được cập nhật. Nói cách khác, bạn nên đảm bảo rằng mọi thay đổi sẽ được thực hiện nguyên tử. Trong trường hợp này, để cập nhật tài nguyên bạn nên sử dụng replace. Ví dụ: nếu bạn có ConfigMap với bộ đếm được cập nhật bởi nhiều nguồn, bạn nên đảm bảo rằng hai nguồn không cập nhật bộ đếm cùng lúc, khiến bản cập nhật bị mất. Để chứng minh, hãy tưởng tượng một chuỗi các sự kiện bằng cách sử dụng phương pháp patch:

  • A và B lấy trạng thái hiện tại của tài nguyên từ API
  • Mỗi cái cập nhật cục bộ thông số kỹ thuật bằng cách tăng bộ đếm lên một và cũng thêm "A" hoặc "B" tương ứng vào ghi chú "được cập nhật bởi"
  • Và nó cập nhật tài nguyên nhanh hơn một chút
  • B cập nhật tài nguyên

Kết quả là bản cập nhật A bị mất. Hoạt động cuối cùng patch thắng, bộ đếm được tăng lên một thay vì hai và giá trị của ghi chú "được cập nhật bởi" kết thúc bằng "B" và không chứa "A". Hãy so sánh những điều trên với những gì xảy ra khi cập nhật được thực hiện bằng cách sử dụng phương pháp này replace:

  • A và B lấy trạng thái hiện tại của tài nguyên từ API
  • Mỗi cái cập nhật cục bộ thông số kỹ thuật bằng cách tăng bộ đếm lên một và cũng thêm "A" hoặc "B" tương ứng vào ghi chú "được cập nhật bởi"
  • Và nó cập nhật tài nguyên nhanh hơn một chút
  • B cố gắng cập nhật tài nguyên nhưng bản cập nhật bị API từ chối vì phiên bản tài nguyên nằm trong thông số kỹ thuật replace không khớp với phiên bản hiện tại của tài nguyên trong Kubernetes vì ​​phiên bản của tài nguyên đã được tăng lên nhờ hoạt động thay thế của A.

Trong trường hợp trên, B sẽ phải tìm nạp lại tài nguyên, thay đổi trạng thái mới và thử lại replace. Điều này sẽ khiến bộ đếm tăng lên hai và ghi chú "được cập nhật bởi" sẽ bao gồm "AB" ở cuối.

Ví dụ trên ngụ ý rằng khi thực hiện replace Toàn bộ tài nguyên được thay thế hoàn toàn. Đặc điểm kỹ thuật được sử dụng cho replace, không được một phần hoặc từng phần như trong apply, nhưng đầy đủ, bao gồm cả phần bổ sung resourceVersion vào siêu dữ liệu đặc tả. Nếu bạn chưa kích hoạt resourceVersion hoặc phiên bản bạn cung cấp không phải là phiên bản hiện hành, việc thay thế sẽ bị từ chối. Vì vậy cách tốt nhất để sử dụng là replace – đọc tài nguyên, cập nhật và thay thế nó ngay lập tức. sử dụng kubectl, nó có thể trông như thế này:

$ kubectl get deployment my-deployment -o json 
    | jq '.spec.template.spec.containers[0].env[1].value = "new value"' 
    | kubectl replace -f -

Điều đáng lưu ý là hai lệnh sau đây, được thực hiện tuần tự, sẽ thực thi thành công, vì deployment.yaml không chứa tài sản .metadata.resourceVersion

$ kubectl create -f deployment.yaml
$ kubectl replace -f deployment.yaml

Điều này dường như mâu thuẫn với những gì đã nói ở trên, tức là "thêm resourceVersion vào siêu dữ liệu đặc tả." Nói như vậy có sai không? Không, không phải vậy, bởi vì nếu kubectl thông báo mà bạn không chỉ định resourceVersion, nó sẽ đọc nó từ tài nguyên và thêm nó vào thông số kỹ thuật mà bạn đã chỉ định và chỉ sau đó mới thực thi nó replace. Bởi vì điều này tiềm ẩn nguy hiểm nếu bạn dựa vào tính nguyên tử, nên phép thuật hoàn toàn có tác dụng kubectl, bạn không nên dựa vào nó khi sử dụng thư viện máy khách hoạt động với API. Trong trường hợp này, bạn sẽ phải đọc đặc tả tài nguyên hiện tại, cập nhật nó rồi thực thi PUT lời yêu cầu.

Bạn không thể thực hiện bản vá - chúng tôi thực hiện thay thế

Đôi khi bạn cần thực hiện một số thay đổi mà API không thể xử lý được. Trong những trường hợp này, bạn có thể buộc thay thế tài nguyên bằng cách xóa và tạo lại tài nguyên đó. Việc này được thực hiện bằng cách sử dụng kubectl replace --force. Việc chạy lệnh sẽ ngay lập tức loại bỏ các tài nguyên rồi tạo lại chúng từ thông số kỹ thuật được cung cấp. Không có trình xử lý "bắt buộc thay thế" trong API và để thực hiện điều đó thông qua API, bạn cần thực hiện hai thao tác. Đầu tiên bạn cần xóa tài nguyên bằng cách thiết lập cho nó gracePeriodSeconds về không (0) và propagationPolicy trong “Nền” rồi tạo lại tài nguyên này với thông số kỹ thuật mong muốn.

Cảnh báo: Cách tiếp cận này có khả năng nguy hiểm và có thể dẫn đến trạng thái không xác định.

Áp dụng ở phía máy chủ

Như đã đề cập ở trên, các nhà phát triển Kubernetes đang nỗ lực triển khai logic apply của kubectl trong API Kubernetes. Logic apply có sẵn trong Kubernetes 1.18 thông qua kubectl apply --server-side hoặc thông qua API bằng phương thức PATCH с content-type application/apply-patch+YAML.

Lưu ý: JSON cũng là YAML hợp lệ, vì vậy bạn có thể gửi thông số kỹ thuật dưới dạng JSON ngay cả khi content-type sẽ application/apply-patch+yaml.

Bên cạnh logic đó kubectl trở nên có sẵn cho mọi người thông qua API, apply về phía máy chủ, theo dõi xem ai chịu trách nhiệm về các trường trong đặc tả, do đó cho phép nhiều quyền truy cập an toàn để chỉnh sửa không có xung đột. Nói cách khác, nếu apply về phía máy chủ sẽ trở nên phổ biến hơn, một giao diện quản lý tài nguyên an toàn phổ quát sẽ xuất hiện cho các máy khách khác nhau, chẳng hạn như kubectl, Pulumi hoặc Terraform, GitOps, cũng như các tập lệnh tự viết bằng thư viện máy khách.

Kết quả

Tôi hy vọng phần tổng quan ngắn gọn này về các cách khác nhau để cập nhật tài nguyên theo cụm sẽ hữu ích cho bạn. Thật tốt khi biết rằng nó không chỉ là áp dụng hay thay thế; còn có thể cập nhật tài nguyên bằng cách sử dụng áp dụng, chỉnh sửa, vá lỗi hoặc thay thế. Xét cho cùng, về nguyên tắc, mỗi phương pháp đều có lĩnh vực ứng dụng riêng. Đối với những thay đổi nguyên tử, thay thế là thích hợp hơn; nếu không, bạn nên sử dụng bản vá hợp nhất chiến lược thông qua áp dụng. Ít nhất, tôi mong bạn hiểu rằng bạn không thể tin tưởng vào Google hoặc StackOerflow khi tìm kiếm "kubernetes áp dụng so với thay thế". Ít nhất cho đến khi bài viết này thay thế câu trả lời hiện tại.

So sánh đúng cách áp dụng, thay thế và vá lỗi Kubernetes

Nguồn: www.habr.com

Thêm một lời nhận xét