ปรับใช้แอปพลิเคชันบนคลัสเตอร์ Kubernetes หลายคลัสเตอร์ด้วย Helm

Dailymotion ใช้ Kubernetes อย่างไร: การปรับใช้แอปพลิเคชัน

พวกเราที่ Dailymotion เริ่มใช้ Kubernetes ในการผลิตเมื่อ 3 ปีที่แล้ว แต่การนำแอปพลิเคชันไปใช้งานในหลายคลัสเตอร์เป็นเรื่องสนุก ดังนั้นในช่วงไม่กี่ปีที่ผ่านมา เราจึงพยายามปรับปรุงเครื่องมือและขั้นตอนการทำงานของเรา

มันเริ่มต้นที่ไหน

เราจะกล่าวถึงวิธีการปรับใช้แอปพลิเคชันของเราในคลัสเตอร์ Kubernetes หลายแห่งทั่วโลกในที่นี้

ในการปรับใช้ออบเจ็กต์ Kubernetes หลายรายการพร้อมกัน เราใช้ หางเสือและแผนภูมิทั้งหมดของเราถูกจัดเก็บไว้ในที่เก็บ git เดียว หากต้องการปรับใช้สแต็กแอปพลิเคชันแบบเต็มจากบริการต่างๆ เราใช้สิ่งที่เรียกว่าแผนภูมิสรุป โดยพื้นฐานแล้ว นี่คือแผนภูมิที่ประกาศการขึ้นต่อกันและช่วยให้คุณสามารถเริ่มต้น API และบริการต่างๆ ได้ด้วยคำสั่งเดียว

นอกจากนี้เรายังเขียนสคริปต์ Python ขนาดเล็กไว้บน Helm เพื่อตรวจสอบ สร้างแผนภูมิ เพิ่มความลับ และปรับใช้แอปพลิเคชัน งานทั้งหมดนี้ดำเนินการบนแพลตฟอร์ม CI ส่วนกลางโดยใช้อิมเมจนักเทียบท่า

มาเข้าประเด็นกันดีกว่า

บันทึก. ในขณะที่คุณอ่านข้อความนี้ ผู้สมัครรุ่นแรกสำหรับ Helm 3 ได้รับการประกาศแล้ว เวอร์ชันหลักประกอบด้วยการปรับปรุงมากมายเพื่อแก้ไขปัญหาบางอย่างที่เราพบในอดีต

ขั้นตอนการพัฒนาแผนภูมิ

เราใช้การแยกสาขาสำหรับแอปพลิเคชัน และเราตัดสินใจที่จะใช้วิธีการเดียวกันกับแผนภูมิ

  • สาขา dev ใช้เพื่อสร้างแผนภูมิที่จะทดสอบบนคลัสเตอร์การพัฒนา
  • เมื่อมีการส่งคำขอดึงไปที่ เจ้านายพวกมันจะถูกตรวจสอบในการจัดเตรียม
  • สุดท้ายนี้ เราสร้างคำขอดึงเพื่อยืนยันการเปลี่ยนแปลงในสาขา แยง และนำไปใช้ในการผลิต

แต่ละสภาพแวดล้อมมีพื้นที่เก็บข้อมูลส่วนตัวของตัวเองซึ่งจัดเก็บแผนภูมิของเราและเราใช้ Chartmuseum ด้วย API ที่มีประโยชน์มาก ด้วยวิธีนี้เรารับประกันการแยกอย่างเข้มงวดระหว่างสภาพแวดล้อมและการทดสอบแผนภูมิในโลกแห่งความเป็นจริงก่อนที่จะนำไปใช้ในการผลิต

ที่เก็บแผนภูมิในสภาพแวดล้อมที่แตกต่างกัน

เป็นที่น่าสังเกตว่าเมื่อนักพัฒนาพุชสาขา dev เวอร์ชันของแผนภูมิจะถูกส่งไปยัง dev Chartmuseum โดยอัตโนมัติ ดังนั้น นักพัฒนาทุกคนจึงใช้พื้นที่เก็บข้อมูล dev เดียวกัน และคุณต้องระบุเวอร์ชันของแผนภูมิอย่างระมัดระวัง เพื่อไม่ให้ใช้การเปลี่ยนแปลงของผู้อื่นโดยไม่ตั้งใจ

นอกจากนี้ สคริปต์ Python เล็กๆ ของเราจะตรวจสอบออบเจ็กต์ Kubernetes กับข้อกำหนด Kubernetes OpenAPI โดยใช้ คูเบวาลก่อนที่จะเผยแพร่บน Chartmusem

คำอธิบายทั่วไปของขั้นตอนการพัฒนาแผนภูมิ

  1. ตั้งค่างานไปป์ไลน์ตามข้อกำหนด gazr.io สำหรับการควบคุมคุณภาพ (ผ้าสำลี, การทดสอบหน่วย)
  2. การพุชอิมเมจนักเทียบท่าด้วยเครื่องมือ Python ที่ใช้งานแอปพลิเคชันของเรา
  3. การตั้งค่าสภาพแวดล้อมตามชื่อสาขา
  4. กำลังตรวจสอบไฟล์ Kubernetes yaml โดยใช้ Kubeval
  5. เพิ่มเวอร์ชันของแผนภูมิและแผนภูมิหลักโดยอัตโนมัติ (แผนภูมิที่ขึ้นอยู่กับแผนภูมิที่มีการเปลี่ยนแปลง)
  6. การส่งแผนภูมิไปยัง Chartmuseum ที่ตรงกับสภาพแวดล้อม

การจัดการความแตกต่างระหว่างคลัสเตอร์

สหพันธ์คลัสเตอร์

มีอยู่ช่วงหนึ่งที่เราเคยใช้ สหพันธ์คลัสเตอร์ Kubernetesโดยที่วัตถุ Kubernetes สามารถประกาศได้จากจุดสิ้นสุด API เดียว แต่ปัญหาก็เกิดขึ้น ตัวอย่างเช่น ไม่สามารถสร้างอ็อบเจ็กต์ Kubernetes บางอย่างในจุดสิ้นสุดการรวม ซึ่งทำให้ยากต่อการรักษาอ็อบเจ็กต์รวมและอ็อบเจ็กต์อื่นๆ สำหรับแต่ละคลัสเตอร์

เพื่อแก้ไขปัญหา เราเริ่มจัดการคลัสเตอร์อย่างเป็นอิสระ ซึ่งทำให้กระบวนการง่ายขึ้นอย่างมาก (เราใช้เวอร์ชันแรกของการรวมศูนย์ บางอย่างอาจมีการเปลี่ยนแปลงในวินาที)

แพลตฟอร์มกระจายทางภูมิศาสตร์

ปัจจุบันแพลตฟอร์มของเรากระจายอยู่ใน 6 ภูมิภาค - 3 แห่งในพื้นที่และ 3 แห่งในระบบคลาวด์


การปรับใช้แบบกระจาย

ค่า Helm ทั่วโลก

ค่า Helm ทั่วโลก 4 ค่าช่วยให้คุณสามารถระบุความแตกต่างระหว่างคลัสเตอร์ได้ แผนภูมิทั้งหมดของเรามีค่าขั้นต่ำที่เป็นค่าเริ่มต้น

global:
  cloud: True
  env: staging
  region: us-central1
  clusterName: staging-us-central1

ค่านิยมสากล

ค่าเหล่านี้ช่วยกำหนดบริบทสำหรับแอปพลิเคชันของเราและใช้เพื่อวัตถุประสงค์ต่างๆ: การตรวจสอบ การติดตาม การบันทึก การโทรภายนอก การปรับขนาด ฯลฯ

  • "คลาวด์": เรามีแพลตฟอร์ม Kubernetes แบบไฮบริด ตัวอย่างเช่น มีการปรับใช้ API ของเราในโซน GCP และในศูนย์ข้อมูลของเรา
  • "env": ค่าบางค่าอาจมีการเปลี่ยนแปลงสำหรับสภาพแวดล้อมที่ไม่ใช้งานจริง เช่น คำจำกัดความของทรัพยากรและการกำหนดค่าการปรับขนาดอัตโนมัติ
  • "ภูมิภาค": ข้อมูลนี้ช่วยระบุตำแหน่งของคลัสเตอร์และสามารถใช้เพื่อระบุตำแหน่งข้อมูลใกล้เคียงสำหรับบริการภายนอก
  • "clusterName": ถ้าและเมื่อใดที่เราต้องการกำหนดค่าสำหรับแต่ละคลัสเตอร์

นี่เป็นตัวอย่างที่เฉพาะเจาะจง:

{{/* Returns Horizontal Pod Autoscaler replicas for GraphQL*/}}
{{- define "graphql.hpaReplicas" -}}
{{- if eq .Values.global.env "prod" }}
{{- if eq .Values.global.region "europe-west1" }}
minReplicas: 40
{{- else }}
minReplicas: 150
{{- end }}
maxReplicas: 1400
{{- else }}
minReplicas: 4
maxReplicas: 20
{{- end }}
{{- end -}}

ตัวอย่างเทมเพลตหมวกกันน็อค

ตรรกะนี้ถูกกำหนดไว้ในเทมเพลตตัวช่วยเพื่อหลีกเลี่ยงความยุ่งเหยิงของ Kubernetes YAML

ประกาศรับสมัคร

เครื่องมือการปรับใช้ของเราอิงจากไฟล์ YAML หลายไฟล์ ด้านล่างนี้คือตัวอย่างวิธีที่เราประกาศบริการและโทโพโลยีการปรับขนาด (จำนวนเรพลิกา) ในคลัสเตอร์

releases:
  - foo.world

foo.world:                # Release name
  services:               # List of dailymotion's apps/projects
    foobar:
      chart_name: foo-foobar
      repo: [email protected]:dailymotion/foobar
      contexts:
        prod-europe-west1:
          deployments:
            - name: foo-bar-baz
              replicas: 18
            - name: another-deployment
              replicas: 3

คำจำกัดความของบริการ

นี่คือโครงร่างของขั้นตอนทั้งหมดที่กำหนดเวิร์กโฟลว์การปรับใช้ของเรา ขั้นตอนสุดท้ายจะปรับใช้แอปพลิเคชันกับกลุ่มผู้ปฏิบัติงานหลายกลุ่มพร้อมกัน


ขั้นตอนการปรับใช้เจนกินส์

แล้วความลับล่ะ?

ในส่วนของความปลอดภัย เราติดตามความลับทั้งหมดจากสถานที่ต่างๆ และจัดเก็บไว้ในห้องนิรภัยที่ไม่เหมือนใคร หกคะเมน ในปารีส.

เครื่องมือการปรับใช้ของเราจะดึงค่าลับจาก Vault และเมื่อถึงเวลาปรับใช้ ให้แทรกค่าเหล่านั้นลงใน Helm

ในการดำเนินการนี้ เราได้กำหนดการแมประหว่างข้อมูลลับในห้องนิรภัยกับข้อมูลลับที่แอปพลิเคชันของเราต้องการ:

secrets:                                                                                                                                                                                                        
     - secret_id: "stack1-app1-password"                                                                                                                                                                                  
       contexts:                                                                                                                                                                                                   
         - name: "default"                                                                                                                                                                                         
           vaultPath: "/kv/dev/stack1/app1/test"                                                                                                                                                               
           vaultKey: "password"                                                                                                                                                                                    
         - name: "cluster1"                                                                                                                                                                           
           vaultPath: "/kv/dev/stack1/app1/test"                                                                                                                                                               
           vaultKey: "password"

  • เราได้กำหนดกฎทั่วไปที่ต้องปฏิบัติเมื่อบันทึกความลับในห้องนิรภัย
  • ถ้าความลับมีผล ไปยังบริบทหรือคลัสเตอร์เฉพาะคุณต้องเพิ่มรายการเฉพาะ (ที่นี่บริบทคลัสเตอร์1 มีค่าของตัวเองสำหรับความลับ stack-app1-password)
  • มิฉะนั้นจะใช้ค่า โดยค่าเริ่มต้น.
  • สำหรับแต่ละรายการในรายการนี้ค่ะ ความลับของ Kubernetes มีการแทรกคู่คีย์-ค่า ดังนั้นเทมเพลตลับในแผนภูมิของเราจึงเรียบง่ายมาก

apiVersion: v1
data:
{{- range $key,$value := .Values.secrets }}
  {{ $key }}: {{ $value | b64enc | quote }}
{{ end }}
kind: Secret
metadata:
  name: "{{ .Chart.Name }}"
  labels:
    chartVersion: "{{ .Chart.Version }}"
    tillerVersion: "{{ .Capabilities.TillerVersion.SemVer }}"
type: Opaque

ปัญหาและข้อจำกัด

การทำงานกับที่เก็บข้อมูลหลายแห่ง

ตอนนี้เราแยกการพัฒนาแผนภูมิและแอปพลิเคชันออกจากกัน ซึ่งหมายความว่านักพัฒนาจะต้องทำงานในที่เก็บ git สองแห่ง: หนึ่งแห่งสำหรับแอปพลิเคชัน และอีกหนึ่งแห่งสำหรับการกำหนดการปรับใช้กับ Kubernetes พื้นที่เก็บข้อมูล 2 git หมายถึง 2 เวิร์กโฟลว์ และเป็นเรื่องง่ายสำหรับมือใหม่ที่จะสับสน

การจัดการแผนภูมิทั่วไปเป็นเรื่องยุ่งยาก

ดังที่เราได้กล่าวไปแล้ว แผนภูมิทั่วไปมีประโยชน์อย่างมากในการระบุการขึ้นต่อกันและปรับใช้หลายแอปพลิเคชันได้อย่างรวดเร็ว แต่เราใช้ --reuse-valuesเพื่อหลีกเลี่ยงการส่งผ่านค่าทั้งหมดทุกครั้งที่เราปรับใช้แอปพลิเคชันที่เป็นส่วนหนึ่งของแผนภูมิทั่วไปนี้

ในเวิร์กโฟลว์การจัดส่งอย่างต่อเนื่อง เรามีเพียงสองค่าที่เปลี่ยนแปลงเป็นประจำ คือ จำนวนเรพลิกา และแท็กรูปภาพ (เวอร์ชัน) ค่าอื่น ๆ ที่เสถียรกว่านั้นจะถูกเปลี่ยนด้วยตนเองซึ่งค่อนข้างยาก ยิ่งไปกว่านั้น ข้อผิดพลาดประการหนึ่งในการปรับใช้แผนภูมิทั่วไปอาจนำไปสู่ความล้มเหลวร้ายแรง ดังที่เราได้เห็นจากประสบการณ์ของเราเอง

การอัพเดตไฟล์การกำหนดค่าหลายไฟล์

เมื่อนักพัฒนาเพิ่มแอปพลิเคชันใหม่ เขาจะต้องเปลี่ยนไฟล์หลายไฟล์: การประกาศแอปพลิเคชัน รายการความลับ การเพิ่มแอปพลิเคชันเป็นการขึ้นต่อกันหากรวมอยู่ในแผนภูมิทั่วไป

สิทธิ์ของ Jenkins ขยายออกไปในห้องนิรภัยมากเกินไป

ตอนนี้เรามีอันหนึ่ง AppRoleซึ่งอ่านความลับทั้งหมดจากห้องนิรภัย

กระบวนการย้อนกลับไม่ได้เป็นแบบอัตโนมัติ

หากต้องการย้อนกลับ คุณต้องรันคำสั่งบนหลายคลัสเตอร์ ซึ่งเต็มไปด้วยข้อผิดพลาด เราดำเนินการนี้ด้วยตนเองเพื่อให้แน่ใจว่ามีการระบุรหัสเวอร์ชันที่ถูกต้อง

เรากำลังก้าวไปสู่ ​​GitOps

เป้าหมายของพวกเรา

เราต้องการคืนแผนภูมิไปยังพื้นที่เก็บข้อมูลของแอปพลิเคชันที่ปรับใช้

ขั้นตอนการทำงานจะเหมือนกับการพัฒนา ตัวอย่างเช่น เมื่อแบรนช์ถูกพุชไปที่มาสเตอร์ การปรับใช้จะถูกทริกเกอร์โดยอัตโนมัติ ความแตกต่างที่สำคัญระหว่างแนวทางนี้กับขั้นตอนการทำงานปัจจุบันก็คือ ทุกอย่างจะถูกจัดการในคอมไพล์ (ตัวแอปพลิเคชันและวิธีการปรับใช้ใน Kubernetes)

มีข้อดีหลายประการ:

  • มาก ชัดเจนยิ่งขึ้น สำหรับนักพัฒนา การเรียนรู้วิธีใช้การเปลี่ยนแปลงในแผนภูมิท้องถิ่นทำได้ง่ายกว่า
  • สามารถระบุข้อกำหนดการปรับใช้บริการได้ สถานที่เดียวกันกับรหัส บริการ.
  • การจัดการการลบแผนภูมิทั่วไป. บริการนี้จะมีการเปิดตัว Helm ของตัวเอง ซึ่งจะช่วยให้คุณสามารถจัดการวงจรการใช้งานของแอปพลิเคชัน (ย้อนกลับ อัปเกรด) ในระดับที่เล็กที่สุด เพื่อไม่ให้ส่งผลกระทบต่อบริการอื่นๆ
  • ประโยชน์ของคอมไพล์ สำหรับการจัดการแผนภูมิ: เลิกทำการเปลี่ยนแปลง บันทึกการตรวจสอบ ฯลฯ หากคุณต้องการเลิกทำการเปลี่ยนแปลงในแผนภูมิ คุณสามารถทำได้โดยใช้ git การปรับใช้เริ่มต้นโดยอัตโนมัติ
  • คุณอาจพิจารณาปรับปรุงขั้นตอนการพัฒนาของคุณด้วยเครื่องมือเช่น นั่งร้านซึ่งนักพัฒนาสามารถทดสอบการเปลี่ยนแปลงในบริบทที่ใกล้เคียงกับการใช้งานจริงได้

การโยกย้ายสองขั้นตอน

นักพัฒนาของเราใช้ขั้นตอนการทำงานนี้มาเป็นเวลา 2 ปีแล้ว ดังนั้นเราจึงต้องการให้การย้ายข้อมูลไม่ยุ่งยากเท่าที่จะเป็นไปได้ ดังนั้นเราจึงตัดสินใจเพิ่มขั้นกลางระหว่างทางไปสู่เป้าหมาย
ขั้นตอนแรกนั้นง่าย:

  • เราคงโครงสร้างที่คล้ายกันสำหรับการตั้งค่าการปรับใช้งานแอปพลิเคชัน แต่อยู่ในออบเจ็กต์เดียวที่เรียกว่า DailymotionRelease

apiVersion: "v1"
kind: "DailymotionRelease"
metadata:
  name: "app1.ns1"
  environment: "dev"
  branch: "mybranch"
spec:
  slack_channel: "#admin"
  chart_name: "app1"
  scaling:
    - context: "dev-us-central1-0"
      replicas:
        - name: "hermes"
          count: 2
    - context: "dev-europe-west1-0"
      replicas:
        - name: "app1-deploy"
          count: 2
  secrets:
    - secret_id: "app1"
      contexts:
        - name: "default"
          vaultPath: "/kv/dev/ns1/app1/test"
          vaultKey: "password"
        - name: "dev-europe-west1-0"
          vaultPath: "/kv/dev/ns1/app1/test"
          vaultKey: "password"

  • 1 รุ่นต่อแอปพลิเคชัน (ไม่มีแผนภูมิทั่วไป)
  • แผนภูมิในพื้นที่เก็บข้อมูล git ของแอปพลิเคชัน

เราได้พูดคุยกับนักพัฒนาซอฟต์แวร์ทุกคนแล้ว กระบวนการย้ายข้อมูลจึงได้เริ่มต้นขึ้นแล้ว ระยะแรกยังคงควบคุมโดยใช้แพลตฟอร์ม CI ฉันจะเขียนโพสต์อีกครั้งเกี่ยวกับระยะที่สองในเร็วๆ นี้: วิธีที่เราย้ายไปยังเวิร์กโฟลว์ GitOps ด้วย การไหล. ฉันจะบอกคุณว่าเราตั้งค่าทุกอย่างอย่างไรและพบปัญหาใดบ้าง (ที่เก็บข้อมูลหลายแห่ง ความลับ ฯลฯ) ติดตามข่าวสาร

ที่นี่เราได้พยายามอธิบายความคืบหน้าของเราในเวิร์กโฟลว์การปรับใช้แอปพลิเคชันในช่วงหลายปีที่ผ่านมา ซึ่งนำไปสู่ความคิดเกี่ยวกับแนวทาง GitOps เรายังไม่ถึงเป้าหมายและจะรายงานผลลัพธ์ แต่ตอนนี้เรามั่นใจว่าเราทำสิ่งที่ถูกต้องเมื่อเราตัดสินใจที่จะลดความซับซ้อนของทุกสิ่งและนำมันเข้าใกล้นิสัยของนักพัฒนามากขึ้น

ที่มา: will.com

เพิ่มความคิดเห็น