Kubernetes มีตัวเลือกมากมายสำหรับการอัปเดตทรัพยากร: ใช้ แก้ไข แก้ไข และแทนที่ มีความสับสนว่าแต่ละคนทำอะไรและควรใช้เมื่อใด ลองคิดดูสิ
ถ้า kubectl patch
ซึ่งไม่รวมการเปรียบเทียบ apply
и patch
. บทความนี้จะกล่าวถึงตัวเลือกต่างๆ รวมถึงการใช้งานที่เหมาะสมของแต่ละตัวเลือก
ในช่วงวงจรชีวิตของทรัพยากร Kubernetes (บริการ การนำไปใช้งาน ทางเข้า ฯลฯ) บางครั้งคุณจำเป็นต้องเปลี่ยนแปลง เพิ่ม หรือลบคุณสมบัติบางอย่างของทรัพยากรนี้ เช่น เพิ่มบันทึก เพิ่มหรือลดจำนวนแบบจำลอง
Kubernetes CLI
หากคุณทำงานกับคลัสเตอร์ Kubernetes ผ่าน CLI อยู่แล้ว แสดงว่าคุณคุ้นเคยอยู่แล้ว apply
и edit
. ทีม apply
อ่านข้อกำหนดทรัพยากรจากไฟล์และสร้าง "upsert" ไปยังคลัสเตอร์ Kubernetes เช่น สร้างทรัพยากรหากไม่มีอยู่และอัปเดตหากมีอยู่ ทีม edit
อ่านทรัพยากรผ่าน API จากนั้นเขียนข้อกำหนดทรัพยากรลงในไฟล์ในเครื่อง ซึ่งจากนั้นจะเปิดในโปรแกรมแก้ไขข้อความ หลังจากที่คุณแก้ไขและบันทึกไฟล์แล้ว kubectl
จะส่งการเปลี่ยนแปลงที่ทำกลับผ่าน API ซึ่งจะนำการเปลี่ยนแปลงเหล่านี้ไปใช้กับทรัพยากรอย่างระมัดระวัง
ไม่ใช่ทุกคนที่รู้คำสั่ง patch
и replace
. ทีม patch
อนุญาตให้คุณเปลี่ยนส่วนหนึ่งของข้อกำหนดคุณสมบัติทรัพยากร โดยระบุเฉพาะส่วนที่เปลี่ยนแปลงในบรรทัดคำสั่ง ทีม replace
ทำงานเหมือนกับ edit
แต่ทุกอย่างจะต้องดำเนินการด้วยตนเอง: คุณต้องดาวน์โหลดเวอร์ชันปัจจุบันของข้อกำหนดทรัพยากร เช่น การใช้ kubectl get -o yaml
แก้ไขแล้วจึงใช้งาน replace
เพื่ออัปเดตทรัพยากรตามข้อกำหนดที่เปลี่ยนแปลง ทีม replace
จะไม่ทำงานหากมีการเปลี่ยนแปลงใดๆ เกิดขึ้นระหว่างการอ่านและการแทนที่ทรัพยากร
Kubernetes API
คุณคงคุ้นเคยกับวิธีการต่างๆ CoreV1().Pods().Update()
, replaceNamespacedService
หรือ patch_namespaced_deployment
หากคุณทำงานกับคลัสเตอร์ผ่าน PUT
и PATCH
... โดยที่ update
и replace
ใช้ PUT
และ patch
ไม่ว่าจะเล็กน้อยแค่ไหนก็ใช้ PATCH
.
มันเป็นที่น่าสังเกตว่า kubectl
ยังทำงานร่วมกับคลัสเตอร์ผ่าน API ได้อีกด้วย กล่าวอีกนัยหนึ่ง kubectl
เป็น wrapper ที่อยู่ด้านบนของไลบรารีไคลเอนต์สำหรับภาษา Go ซึ่งส่วนใหญ่ให้ความสามารถในการจัดเตรียมคำสั่งย่อยในรูปแบบที่กะทัดรัดและอ่านง่ายขึ้น นอกเหนือจากความสามารถมาตรฐานของ API ตัวอย่างเช่น ดังที่คุณอาจสังเกตเห็นแล้วว่าวิธีการนี้ apply
ไม่ได้กล่าวไว้ข้างต้นในย่อหน้าก่อนหน้า ปัจจุบัน (พฤษภาคม 2020, ประมาณ นักแปล) ตรรกะทั้งหมด kubectl apply
, เช่น. การสร้างทรัพยากรที่ไม่มีอยู่จริงและการอัปเดตทรัพยากรที่มีอยู่ ทำงานบนฝั่งโค้ดทั้งหมด kubectl
. กำลังพยายามอยู่ apply
ไปทางด้าน API แต่ก็ยังอยู่ในช่วงเบต้า ฉันจะเขียนรายละเอียดเพิ่มเติมด้านล่าง
แพทช์ตามค่าเริ่มต้น
ใช้ดีที่สุด patch
หากคุณต้องการอัปเดตทรัพยากร นี่คือวิธีที่ไลบรารีไคลเอ็นต์ทั้งสองทำงานบน Kubernetes API และ kubectl
(ไม่น่าแปลกใจ เนื่องจากเป็น wrapper สำหรับไลบรารีไคลเอ็นต์ ประมาณ นักแปล).
ทำงานอย่างมีกลยุทธ์
ทุกทีม kubectl
apply
, edit
и patch
ใช้วิธีการ PATCH
ในคำขอ HTTP เพื่ออัปเดตทรัพยากรที่มีอยู่ หากคุณเจาะลึกการใช้งานคำสั่งโดยละเอียดมากขึ้น คำสั่งทั้งหมดก็ใช้วิธีการนั้น patch
อาจใช้วิธีการอื่น (เพิ่มเติมด้านล่างนี้) วิธีการแก้ไขแบบผสานเชิงกลยุทธ์พยายามที่จะ "ทำให้ถูกต้อง" โดยการผสานข้อกำหนดที่ให้มาเข้ากับข้อกำหนดที่มีอยู่ โดยเฉพาะอย่างยิ่ง พยายามรวมทั้งอ็อบเจ็กต์และอาร์เรย์ ซึ่งหมายความว่าการเปลี่ยนแปลงมีแนวโน้มที่จะเป็นการบวก เช่น การรันคำสั่ง patch
ด้วยตัวแปรสภาพแวดล้อมใหม่ในข้อกำหนดเฉพาะของคอนเทนเนอร์พ็อด จะทำให้ตัวแปรสภาพแวดล้อมนั้นถูกเพิ่มลงในตัวแปรสภาพแวดล้อมที่มีอยู่แทนที่จะเขียนทับ หากต้องการลบโดยใช้วิธีนี้ คุณต้องบังคับให้ค่าพารามิเตอร์เป็นโมฆะในข้อกำหนดที่ให้ไว้ ของทีมไหน. kubectl
ควรใช้สำหรับการอัพเดตหรือไม่?
หากคุณสร้างและจัดการทรัพยากรของคุณโดยใช้ kubectl apply
เมื่ออัปเดตจะเป็นการดีกว่าถ้าใช้เสมอ kubectl apply
ถึง kubectl
สามารถจัดการการกำหนดค่าและติดตามการเปลี่ยนแปลงที่ร้องขอจากแอปพลิเคชันไปยังแอปพลิเคชันได้อย่างถูกต้อง ข้อดีใช้เสมอ apply
คือการติดตามข้อกำหนดที่ใช้ก่อนหน้านี้ ทำให้สามารถทราบเมื่อคุณสมบัติข้อกำหนดและองค์ประกอบอาร์เรย์ถูกลบออกอย่างชัดเจน นี้ช่วยให้คุณสามารถใช้ apply
เพื่อลบคุณสมบัติและองค์ประกอบอาร์เรย์ ในขณะที่การผสานเชิงกลยุทธ์ตามปกติจะไม่ทำงาน ทีม edit
и patch
อย่าอัพเดตบันทึกย่อนั้น kubectl apply
ใช้เพื่อติดตามการเปลี่ยนแปลง ดังนั้นการเปลี่ยนแปลงใด ๆ ที่ถูกติดตามและทำผ่าน Kubernetes API แต่ทำผ่านคำสั่ง edit
и patch
มองไม่เห็นคำสั่งต่อมา apply
นั่นคือ apply
จะไม่ลบออกแม้ว่าจะไม่ปรากฏในข้อกำหนดอินพุตก็ตาม apply
(เอกสารบอกว่า edit
и patch
อัปเดตบันทึกย่อที่ใช้ apply
แต่ในทางปฏิบัติ - ไม่)
ถ้าไม่ใช้คำสั่ง apply
,สามารถใช้เป็น edit
และ patch
โดยเลือกคำสั่งที่เหมาะสมกับการเปลี่ยนแปลงที่เกิดขึ้นมากที่สุด เมื่อเพิ่มและเปลี่ยนแปลงคุณสมบัติ BOM ทั้งสองวิธีจะใกล้เคียงกัน เมื่อลบคุณสมบัติข้อกำหนดหรือองค์ประกอบอาร์เรย์ edit
ทำตัวเหมือนการเปิดตัวครั้งเดียว apply
รวมถึงการติดตามว่าข้อกำหนดนั้นเป็นอย่างไรก่อนและหลังการแก้ไข เพื่อให้คุณสามารถลบคุณสมบัติและองค์ประกอบอาร์เรย์ออกจากทรัพยากรได้อย่างชัดเจน คุณต้องตั้งค่าคุณสมบัติเป็นโมฆะอย่างชัดเจนในข้อกำหนดสำหรับ patch
เพื่อลบออกจากทรัพยากร การลบองค์ประกอบอาร์เรย์โดยใช้การแพตช์ผสานเชิงกลยุทธ์นั้นซับซ้อนกว่าเนื่องจากต้องใช้คำสั่งผสาน ดูวิธีการอัปเกรดอื่นๆ ด้านล่างเพื่อดูทางเลือกที่มีประสิทธิภาพมากขึ้น
เพื่อใช้วิธีการอัพเดตในไลบรารีไคลเอนต์ที่ทำงานคล้ายกับคำสั่งด้านบน kubectl
ควรตั้งค่าไว้ในคำขอ content-type
в application/strategic-merge-patch+json
. หากคุณต้องการลบคุณสมบัติในข้อกำหนด คุณต้องตั้งค่าคุณสมบัติให้เป็น null อย่างชัดเจนในลักษณะเดียวกัน kubectl patch
. หากคุณต้องการลบองค์ประกอบอาร์เรย์ คุณควรรวมคำสั่งการผสานไว้ในข้อกำหนดการอัปเดต หรือใช้แนวทางอื่นในการอัปเดต
แนวทางอื่นๆ ในการอัปเดต
Kubernetes รองรับวิธีอัปเดตอีกสองวิธี: kubectl patch --type=merge
. เมื่อทำงานกับ Kubernetes API คุณควรใช้วิธีการร้องขอ PATCH
และการติดตั้ง content-type
в application/merge-patch+json
.
วิธีการแพตช์ JSON แทนที่จะระบุข้อกำหนดเฉพาะบางส่วนของทรัพยากร จะใช้การให้การเปลี่ยนแปลงที่คุณต้องการทำกับทรัพยากรในรูปแบบอาร์เรย์ ซึ่งแต่ละองค์ประกอบของอาร์เรย์จะแสดงคำอธิบายของการเปลี่ยนแปลงที่เกิดขึ้นกับทรัพยากร แนวทางนี้เป็นวิธีที่ยืดหยุ่นและมีประสิทธิภาพมากกว่าในการแสดงการเปลี่ยนแปลงที่กำลังดำเนินการ แต่ต้องเสียค่าใช้จ่ายในการแสดงรายการการเปลี่ยนแปลงที่ทำในรูปแบบแยกต่างหากที่ไม่ใช่ Kubernetes แทนที่จะส่งข้อกำหนดเฉพาะทรัพยากรบางส่วน ใน kubectl
คุณสามารถเลือกแพตช์ JSON ได้โดยใช้ kubectl patch --type=json
. เมื่อใช้ Kubernetes API วิธีการนี้จะใช้ได้กับวิธีการร้องขอ PATCH
และการติดตั้ง content-type
в application/json-patch+json
.
เราต้องการความมั่นใจ - ใช้การแทนที่
ในบางกรณี คุณต้องแน่ใจว่าไม่มีการเปลี่ยนแปลงใดๆ กับทรัพยากรระหว่างเวลาที่อ่านทรัพยากรและเมื่อมีการอัปเดต กล่าวอีกนัยหนึ่ง คุณควรตรวจสอบให้แน่ใจว่าการเปลี่ยนแปลงทั้งหมดจะเป็นไปตามนั้น อะตอม. ในกรณีนี้ เพื่ออัปเดตทรัพยากรที่คุณควรใช้ replace
. ตัวอย่างเช่น หากคุณมี ConfigMap ที่มีตัวนับที่อัปเดตจากหลายแหล่ง คุณควรแน่ใจว่าทั้งสองแหล่งไม่อัปเดตตัวนับพร้อมกัน ส่งผลให้การอัปเดตสูญหาย เพื่อสาธิต ลองจินตนาการถึงลำดับเหตุการณ์โดยใช้แนวทางนี้ patch
:
- A และ B รับสถานะปัจจุบันของทรัพยากรจาก API
- แต่ละรายการจะอัปเดตข้อกำหนดในเครื่องโดยเพิ่มตัวนับทีละรายการและเพิ่ม "A" หรือ "B" ตามลำดับในบันทึกย่อ "อัปเดตโดย"
- และจะอัปเดตทรัพยากรเร็วขึ้นเล็กน้อย
- B อัพเดตทรัพยากร
เป็นผลให้การอัปเดต A หายไป การดำเนินการครั้งสุดท้าย patch
ชนะ ตัวนับจะเพิ่มขึ้นทีละหนึ่งแทนที่จะเป็นสอง และค่าของบันทึกย่อ "อัปเดตโดย" จะลงท้ายด้วย "B" และไม่มี "A" ลองเปรียบเทียบข้างต้นกับสิ่งที่เกิดขึ้นเมื่อการอัปเดตเสร็จสิ้นโดยใช้แนวทางนี้ replace
:
- A และ B รับสถานะปัจจุบันของทรัพยากรจาก API
- แต่ละรายการจะอัปเดตข้อกำหนดในเครื่องโดยเพิ่มตัวนับทีละรายการและเพิ่ม "A" หรือ "B" ตามลำดับในบันทึกย่อ "อัปเดตโดย"
- และจะอัปเดตทรัพยากรเร็วขึ้นเล็กน้อย
- B พยายามอัปเดตทรัพยากร แต่การอัปเดตถูกปฏิเสธโดย API เนื่องจากเวอร์ชันของทรัพยากรอยู่ในข้อกำหนด
replace
ไม่ตรงกับเวอร์ชันปัจจุบันของทรัพยากรใน Kubernetes เนื่องจากเวอร์ชันของทรัพยากรเพิ่มขึ้นตามการดำเนินการแทนที่ของ A
ในกรณีข้างต้น B จะต้องดึงทรัพยากรอีกครั้ง ทำการเปลี่ยนแปลงสถานะใหม่ และลองอีกครั้ง replace
. สิ่งนี้จะทำให้ตัวนับเพิ่มขึ้นทีละสองและบันทึกย่อ "อัปเดตโดย" จะรวม "AB" ที่ท้าย
ตัวอย่างข้างต้นบอกเป็นนัยว่าเมื่อดำเนินการ replace
ทรัพยากรทั้งหมดถูกแทนที่โดยสมบูรณ์ ข้อมูลจำเพาะที่ใช้สำหรับ replace
จะต้องไม่เป็นบางส่วนหรือเป็นบางส่วนเหมือนใน apply
แต่ครบถ้วนรวมถึงการต่อเติมด้วย resourceVersion
ลงในข้อมูลเมตาของข้อกำหนด หากคุณไม่ได้เปิดใช้งาน resourceVersion
หรือเวอร์ชันที่คุณระบุไม่ใช่เวอร์ชันปัจจุบัน เวอร์ชันทดแทนจะถูกปฏิเสธ ดังนั้นแนวทางการใช้ที่ดีที่สุดคือ replace
– อ่านทรัพยากร อัปเดต และแทนที่ทันที โดยใช้ kubectl
อาจมีลักษณะดังนี้:
$ kubectl get deployment my-deployment -o json
| jq '.spec.template.spec.containers[0].env[1].value = "new value"'
| kubectl replace -f -
เป็นที่น่าสังเกตว่าคำสั่งสองคำสั่งต่อไปนี้ซึ่งดำเนินการตามลำดับจะดำเนินการได้สำเร็จตั้งแต่นั้นมา deployment.yaml
ไม่มีทรัพย์สิน .metadata.resourceVersion
$ kubectl create -f deployment.yaml
$ kubectl replace -f deployment.yaml
สิ่งนี้ดูเหมือนจะขัดแย้งกับสิ่งที่กล่าวไว้ข้างต้นนั่นคือ "เพิ่ม resourceVersion
ลงในข้อกำหนดเมตาดาต้า" พูดแบบนั้นผิดไหม ไม่ใช่ ไม่ใช่ เพราะถ้า kubectl
สังเกตว่าคุณไม่ได้ระบุ resourceVersion
มันจะอ่านจากทรัพยากรและเพิ่มลงในข้อกำหนดที่คุณระบุ จากนั้นจึงดำเนินการเท่านั้น replace
. เนื่องจากสิ่งนี้อาจเป็นอันตรายได้หากคุณอาศัยอะตอมมิกซิตี เวทมนตร์จึงทำงานที่ด้านข้างทั้งหมด kubectl
คุณไม่ควรเชื่อถือเมื่อใช้ไลบรารีไคลเอ็นต์ที่ทำงานร่วมกับ API ในกรณีนี้ คุณจะต้องอ่านข้อกำหนดทรัพยากรปัจจุบัน อัปเดต จากนั้นจึงดำเนินการ PUT
ขอ.
คุณไม่สามารถทำการแพตช์ได้ - เราจะทำการแทนที่
บางครั้งคุณจำเป็นต้องทำการเปลี่ยนแปลงบางอย่างที่ API ไม่สามารถจัดการได้ ในกรณีเหล่านี้ คุณสามารถบังคับให้เปลี่ยนทรัพยากรได้โดยการลบและสร้างใหม่ นี้จะเสร็จสิ้นโดยใช้ kubectl replace --force
. การรันคำสั่งจะลบรีซอร์สทันที จากนั้นสร้างใหม่จากข้อกำหนดที่ให้มา ไม่มีตัวจัดการ "บังคับแทนที่" ใน API และเพื่อที่จะดำเนินการดังกล่าวผ่าน API คุณจะต้องดำเนินการสองอย่าง ขั้นแรกคุณต้องลบทรัพยากรโดยการตั้งค่า gracePeriodSeconds
ถึงศูนย์ (0) และ propagationPolicy
ใน "พื้นหลัง" จากนั้นสร้างทรัพยากรนี้ใหม่ตามข้อกำหนดที่ต้องการ
คำเตือน: วิธีการนี้อาจเป็นอันตรายและอาจนำไปสู่สภาวะที่ไม่ได้กำหนดไว้
สมัครบนฝั่งเซิร์ฟเวอร์
ตามที่กล่าวไว้ข้างต้น นักพัฒนา Kubernetes กำลังทำงานเพื่อนำตรรกะไปใช้ apply
ของ kubectl
ใน Kubernetes API ลอจิก apply
มีอยู่ใน Kubernetes 1.18 ผ่าน kubectl apply --server-side
หรือผ่าน API โดยใช้วิธี PATCH
с content-type
application/apply-patch+YAML
.
หมายเหตุ: JSON ก็เป็น YAML ที่ถูกต้องเช่นกัน ดังนั้นคุณจึงสามารถส่งข้อกำหนดเป็น JSON ได้แม้ว่าจะเป็นเช่นนั้นก็ตาม
content-type
จะapplication/apply-patch+yaml
.
นอกจากตรรกะนั้นแล้ว kubectl
เปิดให้ทุกคนใช้งานได้ผ่าน API apply
ทางฝั่งเซิร์ฟเวอร์ ติดตามผู้ที่รับผิดชอบฟิลด์ในข้อกำหนด จึงทำให้สามารถเข้าถึงหลายรายการได้อย่างปลอดภัยสำหรับการแก้ไขที่ปราศจากข้อขัดแย้ง กล่าวอีกนัยหนึ่งถ้า apply
ทางฝั่งเซิร์ฟเวอร์จะแพร่หลายมากขึ้น อินเทอร์เฟซการจัดการทรัพยากรที่ปลอดภัยสากลจะปรากฏขึ้นสำหรับไคลเอนต์ที่แตกต่างกัน เช่น kubectl, Pulumi หรือ Terraform, GitOps รวมถึงสคริปต์ที่เขียนเองโดยใช้ไลบรารีไคลเอนต์
ผลของการ
ฉันหวังว่าภาพรวมสั้นๆ ของวิธีต่างๆ ในการอัปเดตทรัพยากรในคลัสเตอร์จะเป็นประโยชน์กับคุณ เป็นเรื่องดีที่รู้ว่าไม่เพียงแต่ใช้เทียบกับการแทนที่เท่านั้น แต่ยังสามารถอัปเดตทรัพยากรโดยใช้ใช้ แก้ไข แก้ไข หรือแทนที่ได้ โดยหลักการแล้วแต่ละวิธีมีพื้นที่การใช้งานของตัวเอง สำหรับการเปลี่ยนแปลงแบบอะตอมมิก ควรแทนที่ มิฉะนั้น คุณควรใช้แพตช์ผสานเชิงกลยุทธ์ผ่านการใช้ อย่างน้อยที่สุด ฉันคาดหวังให้คุณเข้าใจว่าคุณไม่สามารถเชื่อถือ Google หรือ StackOerflow เมื่อค้นหา "kubernetes Apply vs แทนที่" อย่างน้อยก็จนกว่าบทความนี้จะแทนที่คำตอบปัจจุบัน
ที่มา: will.com