ในปีนี้ การประชุม Kubernetes หลักแห่งยุโรป - KubeCon + CloudNativeCon Europe 2020 - เป็นแบบเสมือนจริง อย่างไรก็ตาม การเปลี่ยนแปลงรูปแบบดังกล่าวไม่ได้ขัดขวางเราจากการส่งรายงานที่วางแผนไว้ระยะยาว “ไปเหรอ? ทุบตี! พบกับผู้ดำเนินการเชลล์” ที่อุทิศให้กับโครงการโอเพ่นซอร์สของเรา
บทความนี้ได้รับแรงบันดาลใจจากการพูดคุย นำเสนอแนวทางในการทำให้กระบวนการสร้างตัวดำเนินการสำหรับ Kubernetes ง่ายขึ้น และแสดงให้เห็นว่าคุณสามารถสร้างตัวดำเนินการของคุณเองโดยใช้ความพยายามเพียงเล็กน้อยโดยใช้ตัวดำเนินการเชลล์ได้อย่างไร
แนะนำตัว
ที่ Flant เราปรับปรุงและทำให้ทุกอย่างเป็นอัตโนมัติอย่างต่อเนื่อง วันนี้เราจะมาพูดถึงแนวคิดที่น่าตื่นเต้นอีกอย่างหนึ่ง พบปะ: การเขียนสคริปต์เชลล์แบบคลาวด์เนทีฟ!
อย่างไรก็ตาม เรามาเริ่มด้วยบริบทที่เกิดเหตุการณ์ทั้งหมดนี้กันก่อน: Kubernetes
Kubernetes API และตัวควบคุม
API ใน Kubernetes สามารถแสดงเป็นไฟล์เซิร์ฟเวอร์ประเภทหนึ่งพร้อมไดเร็กทอรีสำหรับออบเจ็กต์แต่ละประเภท ออบเจ็กต์ (ทรัพยากร) บนเซิร์ฟเวอร์นี้แสดงด้วยไฟล์ YAML นอกจากนี้ เซิร์ฟเวอร์ยังมี API พื้นฐานที่ให้คุณทำสามสิ่ง:
- รับ ทรัพยากรตามชนิดและชื่อ
- เปลี่ยน ทรัพยากร (ในกรณีนี้เซิร์ฟเวอร์จะเก็บเฉพาะวัตถุที่ "ถูกต้อง" เท่านั้น - วัตถุที่มีรูปแบบไม่ถูกต้องหรือมีไว้สำหรับไดเรกทอรีอื่นทั้งหมดจะถูกละทิ้ง)
- ติดตาม สำหรับทรัพยากร (ในกรณีนี้ ผู้ใช้จะได้รับเวอร์ชันปัจจุบัน/อัปเดตทันที)
ดังนั้น Kubernetes จึงทำหน้าที่เป็นเซิร์ฟเวอร์ไฟล์ประเภทหนึ่ง (สำหรับรายการ YAML) โดยมีวิธีการพื้นฐานสามวิธี (ใช่ จริงๆ แล้วยังมีวิธีอื่นๆ อยู่ แต่ตอนนี้เราจะละเว้นไว้)
ปัญหาคือเซิร์ฟเวอร์สามารถเก็บข้อมูลได้เท่านั้น เพื่อให้มันได้ผลคุณต้องมี ตัวควบคุม - แนวคิดที่สำคัญและพื้นฐานเป็นอันดับสองในโลกของ Kubernetes
คอนโทรลเลอร์มีสองประเภทหลัก รายการแรกรับข้อมูลจาก Kubernetes ประมวลผลตามตรรกะที่ซ้อนกัน และส่งคืนไปยัง K8 ส่วนที่สองรับข้อมูลจาก Kubernetes แต่ต่างจากประเภทแรกตรงที่เปลี่ยนสถานะของทรัพยากรภายนอกบางส่วน
มาดูกระบวนการสร้าง Deployment ใน Kubernetes กันดีกว่า:
- ตัวควบคุมการปรับใช้ (รวมอยู่ใน
kube-controller-manager
) รับข้อมูลเกี่ยวกับการปรับใช้และสร้าง ReplicaSet - ReplicaSet สร้างแบบจำลองสองรายการ (สองพ็อด) โดยอิงตามข้อมูลนี้ แต่ยังไม่ได้กำหนดเวลาพ็อดเหล่านี้
- ตัวกำหนดเวลากำหนดเวลาพ็อดและเพิ่มข้อมูลโหนดให้กับ YAML
- Kubelets ทำการเปลี่ยนแปลงทรัพยากรภายนอก (พูด Docker)
จากนั้นลำดับทั้งหมดนี้จะถูกทำซ้ำในลำดับย้อนกลับ: kubelet จะตรวจสอบคอนเทนเนอร์ คำนวณสถานะของพ็อด และส่งกลับ ตัวควบคุม ReplicaSet ได้รับสถานะและอัพเดตสถานะของชุดแบบจำลอง สิ่งเดียวกันนี้เกิดขึ้นกับ Deployment Controller และผู้ใช้จะได้รับสถานะที่อัปเดต (ปัจจุบัน) ในที่สุด
ผู้ประกอบการเชลล์
ปรากฎว่า Kubernetes ขึ้นอยู่กับการทำงานร่วมกันของตัวควบคุมต่างๆ (ตัวดำเนินการ Kubernetes ก็เป็นผู้ควบคุมเช่นกัน) คำถามเกิดขึ้น จะสร้างตัวดำเนินการของคุณเองโดยใช้ความพยายามเพียงเล็กน้อยได้อย่างไร? และนี่คือสิ่งที่เราพัฒนาขึ้นมาเพื่อช่วยเหลือ
ตัวอย่างง่ายๆ: การคัดลอกความลับ
ลองดูตัวอย่างง่ายๆ
สมมติว่าเรามีคลัสเตอร์ Kubernetes มันมีเนมสเปซ default
พร้อมความลับบางอย่าง mysecret
. นอกจากนี้ ยังมีเนมสเปซอื่นๆ ในคลัสเตอร์อีกด้วย บางส่วนมีป้ายกำกับเฉพาะติดอยู่ด้วย เป้าหมายของเราคือการคัดลอก Secret ลงในเนมสเปซด้วยป้ายกำกับ
งานมีความซับซ้อนเนื่องจากเนมสเปซใหม่อาจปรากฏในคลัสเตอร์และบางส่วนอาจมีป้ายกำกับนี้ ในทางกลับกัน เมื่อลบป้ายกำกับแล้ว ข้อมูลลับก็ควรถูกลบไปด้วย นอกจากนี้ ข้อมูลลับยังสามารถเปลี่ยนแปลงได้: ในกรณีนี้ ข้อมูลลับใหม่จะต้องถูกคัดลอกไปยังเนมสเปซทั้งหมดที่มีป้ายกำกับ หาก Secret ถูกลบในเนมสเปซใดๆ โดยไม่ได้ตั้งใจ โอเปอเรเตอร์ของเราควรกู้คืนทันที
ตอนนี้งานได้รับการกำหนดแล้ว ก็ถึงเวลาที่จะเริ่มใช้งานโดยใช้ตัวดำเนินการเชลล์ แต่ก่อนอื่นควรพูดสักสองสามคำเกี่ยวกับตัวดำเนินการเชลล์ก่อน
วิธีการทำงานของตัวดำเนินการเชลล์
เช่นเดียวกับปริมาณงานอื่นๆ ใน Kubernetes ตัวดำเนินการเชลล์จะทำงานในพ็อดของตัวเอง ในพ็อดนี้ในไดเร็กทอรี /hooks
ไฟล์ปฏิบัติการจะถูกจัดเก็บ สิ่งเหล่านี้อาจเป็นสคริปต์ใน Bash, Python, Ruby ฯลฯ เราเรียกไฟล์ปฏิบัติการดังกล่าวว่า hooks (ตะขอ).
ผู้ดำเนินการเชลล์สมัครรับกิจกรรม Kubernetes และเรียกใช้ hooks เหล่านี้เพื่อตอบสนองต่อเหตุการณ์เหล่านั้นที่เราต้องการ
Shell-Operator รู้ได้อย่างไรว่า hook ใดที่จะรันและเมื่อใด? ประเด็นก็คือตะขอทุกอันมีสองขั้นตอน ในระหว่างการเริ่มต้น ตัวดำเนินการเชลล์จะรัน hooks ทั้งหมดพร้อมอาร์กิวเมนต์ --config
นี่คือขั้นตอนการกำหนดค่า และหลังจากนั้น hooks จะถูกปล่อยในลักษณะปกติ - เพื่อตอบสนองต่อเหตุการณ์ที่ติดอยู่ ในกรณีหลัง hook ได้รับบริบทการผูก (บริบทที่มีผลผูกพัน) - ข้อมูลในรูปแบบ JSON ซึ่งเราจะพูดถึงรายละเอียดเพิ่มเติมด้านล่าง
สร้างโอเปอเรเตอร์ใน Bash
ตอนนี้เราพร้อมสำหรับการใช้งานแล้ว ในการทำเช่นนี้ เราจำเป็นต้องเขียนฟังก์ชันสองรายการ (โดยวิธีการที่เราแนะนำ ห้องสมุด
- สิ่งแรกจำเป็นสำหรับขั้นตอนการกำหนดค่า - จะแสดงบริบทการเชื่อมโยง
- ส่วนที่สองประกอบด้วยตรรกะหลักของเบ็ด
#!/bin/bash
source /shell_lib.sh
function __config__() {
cat << EOF
configVersion: v1
# BINDING CONFIGURATION
EOF
}
function __main__() {
# THE LOGIC
}
hook::run "$@"
ขั้นตอนต่อไปคือการตัดสินใจว่าเราต้องการวัตถุอะไร ในกรณีของเรา เราต้องติดตาม:
- ความลับของแหล่งที่มาสำหรับการเปลี่ยนแปลง
- เนมสเปซทั้งหมดในคลัสเตอร์ เพื่อให้คุณทราบว่าอันไหนมีป้ายกำกับติดอยู่
- ข้อมูลลับเป้าหมายเพื่อให้แน่ใจว่าข้อมูลทั้งหมดซิงค์กับข้อมูลลับต้นทาง
สมัครสมาชิกแหล่งความลับ
การกำหนดค่าการเชื่อมโยงนั้นค่อนข้างง่าย เราระบุว่าเราสนใจ Secret ด้วยชื่อ mysecret
ในเนมสเปซ default
:
function __config__() {
cat << EOF
configVersion: v1
kubernetes:
- name: src_secret
apiVersion: v1
kind: Secret
nameSelector:
matchNames:
- mysecret
namespace:
nameSelector:
matchNames: ["default"]
group: main
EOF
เป็นผลให้ฮุกจะถูกทริกเกอร์เมื่อความลับของแหล่งที่มาเปลี่ยนแปลง (src_secret
) และรับบริบทการผูกต่อไปนี้:
อย่างที่คุณเห็น มันมีชื่อและวัตถุทั้งหมด
การติดตามเนมสเปซ
ตอนนี้คุณต้องสมัครสมาชิกเนมสเปซ เมื่อต้องการทำเช่นนี้ เราระบุการกำหนดค่าการผูกต่อไปนี้:
- name: namespaces
group: main
apiVersion: v1
kind: Namespace
jqFilter: |
{
namespace: .metadata.name,
hasLabel: (
.metadata.labels // {} |
contains({"secret": "yes"})
)
}
group: main
keepFullObjectsInMemory: false
อย่างที่คุณเห็นฟิลด์ใหม่ปรากฏขึ้นในการกำหนดค่าพร้อมชื่อ jqFilter. ตามชื่อของมันบ่งบอกว่า jqFilter
กรองข้อมูลที่ไม่จำเป็นออกทั้งหมดและสร้างออบเจ็กต์ JSON ใหม่พร้อมฟิลด์ที่เราสนใจ hook ที่มีการกำหนดค่าคล้ายกันจะได้รับบริบทการเชื่อมโยงต่อไปนี้:
มันมีอาร์เรย์ filterResults
สำหรับแต่ละเนมสเปซในคลัสเตอร์ ตัวแปรบูลีน hasLabel
บ่งชี้ว่ามีการแนบป้ายกำกับกับเนมสเปซที่กำหนดหรือไม่ ตัวเลือก keepFullObjectsInMemory: false
แสดงว่าไม่จำเป็นต้องเก็บวัตถุที่สมบูรณ์ไว้ในหน่วยความจำ
ติดตามความลับของเป้าหมาย
เราสมัครรับข้อมูลลับทั้งหมดที่มีการระบุคำอธิบายประกอบ managed-secret: "yes"
(นี่คือเป้าหมายของเรา dst_secrets
):
- name: dst_secrets
apiVersion: v1
kind: Secret
labelSelector:
matchLabels:
managed-secret: "yes"
jqFilter: |
{
"namespace":
.metadata.namespace,
"resourceVersion":
.metadata.annotations.resourceVersion
}
group: main
keepFullObjectsInMemory: false
ในกรณีนี้ jqFilter
กรองข้อมูลทั้งหมดยกเว้นเนมสเปซและพารามิเตอร์ resourceVersion
. พารามิเตอร์สุดท้ายถูกส่งไปยังคำอธิบายประกอบเมื่อสร้างข้อมูลลับ: ช่วยให้คุณสามารถเปรียบเทียบเวอร์ชันของข้อมูลลับและอัปเดตข้อมูลให้ทันสมัยอยู่เสมอ
hook ที่กำหนดค่าด้วยวิธีนี้จะได้รับบริบทการเชื่อมโยงสามประการที่อธิบายไว้ข้างต้นเมื่อดำเนินการ พวกเขาสามารถมองได้ว่าเป็นภาพรวมประเภทหนึ่ง (ภาพรวม) กลุ่ม.
จากข้อมูลทั้งหมดนี้ สามารถพัฒนาอัลกอริธึมพื้นฐานได้ มันวนซ้ำเนมสเปซทั้งหมดและ:
- ถ้า
hasLabel
เรื่องtrue
สำหรับเนมสเปซปัจจุบัน:- เปรียบเทียบความลับระดับโลกกับความลับในท้องถิ่น:
- ถ้าเหมือนกันก็ไม่ทำอะไรเลย
- หากแตกต่าง - ดำเนินการ
kubectl replace
หรือcreate
;
- เปรียบเทียบความลับระดับโลกกับความลับในท้องถิ่น:
- ถ้า
hasLabel
เรื่องfalse
สำหรับเนมสเปซปัจจุบัน:- ตรวจสอบให้แน่ใจว่า Secret ไม่ได้อยู่ในเนมสเปซที่กำหนด:
- หากมีความลับในเครื่องอยู่ ให้ลบออกโดยใช้
kubectl delete
; - หากตรวจไม่พบข้อมูลลับในเครื่อง ก็จะไม่ทำอะไรเลย
- หากมีความลับในเครื่องอยู่ ให้ลบออกโดยใช้
- ตรวจสอบให้แน่ใจว่า Secret ไม่ได้อยู่ในเนมสเปซที่กำหนด:
นั่นคือวิธีที่เราสามารถสร้างคอนโทรลเลอร์ Kubernetes ง่ายๆ โดยใช้การกำหนดค่า YAML 35 บรรทัดและโค้ด Bash ในจำนวนที่เท่ากัน! หน้าที่ของผู้ปฏิบัติงานเชลล์คือการเชื่อมโยงพวกมันเข้าด้วยกัน
อย่างไรก็ตามการคัดลอกความลับไม่ใช่เพียงการใช้งานยูทิลิตี้นี้เท่านั้น นี่เป็นตัวอย่างเพิ่มเติมบางส่วนที่แสดงให้เห็นว่าเขามีความสามารถอะไร
ตัวอย่างที่ 1: การเปลี่ยนแปลง ConfigMap
มาดู Deployment ที่ประกอบด้วย 1 พ็อดกัน พ็อดใช้ ConfigMap เพื่อจัดเก็บการกำหนดค่าบางอย่าง เมื่อพ็อดถูกเปิดใช้งาน ConfigMap อยู่ในสถานะหนึ่ง (ขอเรียกว่าเวอร์ชัน XNUMX) ดังนั้น พ็อดทั้งหมดจึงใช้ ConfigMap เวอร์ชันเฉพาะนี้
ตอนนี้ สมมติว่า ConfigMap มีการเปลี่ยนแปลง (v.2) อย่างไรก็ตาม พ็อดจะใช้ ConfigMap เวอร์ชันก่อนหน้า (v.1):
ฉันจะทำให้พวกเขาเปลี่ยนไปใช้ ConfigMap (v.2) ใหม่ได้อย่างไร คำตอบนั้นง่าย: ใช้เทมเพลต มาเพิ่มคำอธิบายประกอบการตรวจสอบในส่วนนี้กัน template
การกำหนดค่าการปรับใช้:
ด้วยเหตุนี้ การตรวจสอบนี้จะถูกลงทะเบียนในพ็อดทั้งหมด และจะเหมือนกับการตรวจสอบการทำให้ใช้งานได้ ตอนนี้ คุณเพียงแค่ต้องอัปเดตคำอธิบายประกอบเมื่อ ConfigMap เปลี่ยนแปลง และตัวดำเนินการเชลล์ก็มีประโยชน์ในกรณีนี้ สิ่งที่คุณต้องทำคือโปรแกรม เบ็ดที่จะสมัครรับ ConfigMap และอัปเดตเช็คซัม.
หากผู้ใช้ทำการเปลี่ยนแปลง ConfigMap ตัวดำเนินการเชลล์จะสังเกตเห็นการเปลี่ยนแปลงเหล่านั้นและคำนวณผลรวมตรวจสอบใหม่ หลังจากนั้นความมหัศจรรย์ของ Kubernetes จะเข้ามามีบทบาท: ผู้เรียบเรียงจะฆ่าพ็อดสร้างอันใหม่รอให้มันกลายเป็น Ready
และไปยังเรื่องถัดไป ด้วยเหตุนี้ Deployment จะซิงโครไนซ์และเปลี่ยนไปใช้ ConfigMap เวอร์ชันใหม่
ตัวอย่างที่ 2: การทำงานกับคำจำกัดความทรัพยากรที่กำหนดเอง
ดังที่คุณทราบ Kubernetes อนุญาตให้คุณสร้างประเภทออบเจ็กต์แบบกำหนดเองได้ ตัวอย่างเช่น คุณสามารถสร้างชนิด MysqlDatabase
. สมมติว่าประเภทนี้มีพารามิเตอร์ข้อมูลเมตา XNUMX รายการ: name
и namespace.
apiVersion: example.com/v1alpha1
kind: MysqlDatabase
metadata:
name: foo
namespace: bar
เรามีคลัสเตอร์ Kubernetes ที่มีเนมสเปซต่างกันซึ่งเราสามารถสร้างฐานข้อมูล MySQL ได้ ในกรณีนี้ สามารถใช้ตัวดำเนินการเชลล์เพื่อติดตามทรัพยากรได้ MysqlDatabase
โดยเชื่อมต่อกับเซิร์ฟเวอร์ MySQL และซิงโครไนซ์สถานะที่ต้องการและสังเกตได้ของคลัสเตอร์
ตัวอย่างที่ 3: การตรวจสอบเครือข่ายคลัสเตอร์
อย่างที่คุณทราบ การใช้ ping เป็นวิธีที่ง่ายที่สุดในการตรวจสอบเครือข่าย ในตัวอย่างนี้ เราจะแสดงวิธีการใช้การตรวจสอบดังกล่าวโดยใช้ตัวดำเนินการเชลล์
ก่อนอื่น คุณจะต้องสมัครสมาชิกโหนดก่อน ตัวดำเนินการเชลล์ต้องการชื่อและที่อยู่ IP ของแต่ละโหนด ด้วยความช่วยเหลือของพวกเขา เขาจะ ping โหนดเหล่านี้
configVersion: v1
kubernetes:
- name: nodes
apiVersion: v1
kind: Node
jqFilter: |
{
name: .metadata.name,
ip: (
.status.addresses[] |
select(.type == "InternalIP") |
.address
)
}
group: main
keepFullObjectsInMemory: false
executeHookOnEvent: []
schedule:
- name: every_minute
group: main
crontab: "* * * * *"
พารามิเตอร์ executeHookOnEvent: []
ป้องกันไม่ให้ hook ทำงานเพื่อตอบสนองต่อเหตุการณ์ใดๆ (นั่นคือ เพื่อตอบสนองต่อการเปลี่ยนแปลง เพิ่ม และการลบโหนด) อย่างไรก็ตามเขา จะวิ่ง (และอัพเดตรายการโหนด) กำหนดเวลาแล้ว - ทุกนาทีตามที่สนามกำหนด schedule
.
ตอนนี้คำถามเกิดขึ้น เราจะรู้ได้อย่างไรเกี่ยวกับปัญหาเช่นการสูญหายของแพ็คเก็ต? มาดูโค้ดกัน:
function __main__() {
for i in $(seq 0 "$(context::jq -r '(.snapshots.nodes | length) - 1')"); do
node_name="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.name')"
node_ip="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.ip')"
packets_lost=0
if ! ping -c 1 "$node_ip" -t 1 ; then
packets_lost=1
fi
cat >> "$METRICS_PATH" <<END
{
"name": "node_packets_lost",
"add": $packets_lost,
"labels": {
"node": "$node_name"
}
}
END
done
}
เราวนซ้ำรายการโหนด รับชื่อและที่อยู่ IP ของพวกเขา ping และส่งผลลัพธ์ไปยัง Prometheus ผู้ปฏิบัติงานเชลล์สามารถส่งออกหน่วยวัดไปยัง Prometheus ได้โดยบันทึกลงในไฟล์ที่อยู่ในเส้นทางที่ระบุในตัวแปรสภาพแวดล้อม $METRICS_PATH
.
กลไกการเข้าคิว
บทความนี้จะไม่สมบูรณ์หากไม่มีการอธิบายกลไกสำคัญอื่นๆ ที่สร้างไว้ในตัวดำเนินการเชลล์ ลองนึกภาพว่ามันดำเนินการ hook บางอย่างเพื่อตอบสนองต่อเหตุการณ์ในคลัสเตอร์
- จะเกิดอะไรขึ้นหากในขณะเดียวกัน มีบางอย่างเกิดขึ้นในคลัสเตอร์? อีกหนึ่ง เหตุการณ์?
- ตัวดำเนินการเชลล์จะเรียกใช้อินสแตนซ์ของ hook อื่นหรือไม่
- จะเกิดอะไรขึ้นถ้ามีเหตุการณ์ห้าเหตุการณ์เกิดขึ้นในคลัสเตอร์พร้อมกัน?
- ผู้ปฏิบัติงานเชลล์จะประมวลผลสิ่งเหล่านั้นพร้อมกันหรือไม่?
- แล้วทรัพยากรที่ใช้ไปเช่นหน่วยความจำและ CPU ล่ะ?
โชคดีที่ตัวดำเนินการเชลล์มีกลไกการเข้าคิวในตัว กิจกรรมทั้งหมดจะถูกจัดคิวและประมวลผลตามลำดับ
เรามาอธิบายเรื่องนี้ด้วยตัวอย่างกัน สมมติว่าเรามีตะขอสองอัน เหตุการณ์แรกไปที่ฮุกแรก เมื่อการประมวลผลเสร็จสิ้น คิวจะเคลื่อนไปข้างหน้า สามเหตุการณ์ถัดไปจะถูกเปลี่ยนเส้นทางไปยังฮุกที่สอง - กิจกรรมเหล่านั้นจะถูกลบออกจากคิวและป้อนลงใน "บันเดิล" นั่นคือ hook ได้รับอาร์เรย์ของเหตุการณ์ — หรือที่เจาะจงกว่านั้นคืออาร์เรย์ของบริบทที่มีผลผูกพัน
เหล่านี้ด้วย เหตุการณ์สามารถนำมารวมกันเป็นงานใหญ่ได้. พารามิเตอร์มีหน้าที่รับผิดชอบในเรื่องนี้ group
ในการกำหนดค่าการเชื่อมโยง
คุณสามารถสร้างคิว/ฮุคและชุดค่าผสมต่างๆ ได้จำนวนเท่าใดก็ได้ ตัวอย่างเช่น หนึ่งคิวสามารถทำงานกับสอง hooks หรือในทางกลับกัน
สิ่งที่คุณต้องทำคือกำหนดค่าฟิลด์ให้เหมาะสม queue
ในการกำหนดค่าการผูก หากไม่ได้ระบุชื่อคิว hook จะทำงานบนคิวเริ่มต้น (default
). กลไกการจัดคิวนี้ช่วยให้คุณแก้ไขปัญหาการจัดการทรัพยากรทั้งหมดได้อย่างสมบูรณ์เมื่อทำงานกับ hooks
ข้อสรุป
เราได้อธิบายว่าตัวดำเนินการเชลล์คืออะไร แสดงให้เห็นว่าสามารถใช้ตัวดำเนินการดังกล่าวเพื่อสร้างตัวดำเนินการ Kubernetes ได้อย่างรวดเร็วและง่ายดายได้อย่างไร และยกตัวอย่างการใช้งานหลายตัวอย่าง
ข้อมูลโดยละเอียดเกี่ยวกับเชลล์โอเปอเรเตอร์ ตลอดจนบทช่วยสอนสั้นๆ เกี่ยวกับวิธีการใช้งาน มีอยู่ในข้อมูลที่เกี่ยวข้อง
และหากคุณชอบ เรายินดีเสมอที่ได้เห็นประเด็นใหม่ๆ/ประชาสัมพันธ์/ดาวบน GitHub ซึ่งคุณสามารถหาคนอื่นๆ ได้
วิดีโอและสไลด์
วิดีโอจากการแสดง (~23 นาที):
การนำเสนอรายงาน:
PS
อ่านเพิ่มเติมในบล็อกของเรา:
- «
สร้างตัวดำเนินการ Kubernetes ได้อย่างง่ายดายด้วยตัวดำเนินการเชลล์: ความคืบหน้าของโครงการตลอดทั้งปี "; - «
ขอแนะนำตัวดำเนินการเชลล์: การสร้างตัวดำเนินการสำหรับ Kubernetes กลายเป็นเรื่องง่ายยิ่งขึ้น "; - «
การเตรียมคลัสเตอร์ Kubernetes ง่ายและสะดวกหรือไม่ ประกาศตัวดำเนินการ addon "; - «
การขยายและการเสริม Kubernetes" (ตรวจสอบและรายงานวิดีโอ) .
ที่มา: will.com