การกำหนดค่าโครงการภายในและภายนอก Kubernetes

ฉันเพิ่งเขียน ตอบเกี่ยวกับอายุการใช้งานของโปรเจ็กต์ใน Docker และการดีบักโค้ดภายนอกซึ่งเขากล่าวสั้นๆ ว่าคุณสามารถสร้างระบบการกำหนดค่าของคุณเองได้ เพื่อให้บริการทำงานได้ดีใน Kuber ดึงความลับ และทำงานในพื้นที่ได้อย่างสะดวก แม้ว่าจะอยู่นอก Docker ก็ตาม ไม่มีอะไรซับซ้อน แต่ "สูตรอาหาร" ที่อธิบายไว้อาจมีประโยชน์สำหรับบางคน :) รหัสอยู่ใน Python แต่ตรรกะไม่ได้เชื่อมโยงกับภาษา

การกำหนดค่าโครงการภายในและภายนอก Kubernetes

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

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

ในเรื่องนี้ กลไกในการสร้างออบเจ็กต์การกำหนดค่าได้รับการแก้ไขเพื่อให้สามารถทำงานได้ทั้งกับไฟล์กำหนดค่าแบบคลาสสิกของเราและกับความลับจาก Kuber โครงสร้างการกำหนดค่าที่เข้มงวดยิ่งขึ้นได้รับการระบุในภาษาของ Python ตัวที่สามดังนี้:

Dict[str, Dict[str, ยูเนี่ยน[str, int, float]]]

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

adminka:
  django_secret: "ExtraLongAndHardCode"

db_main:
  engine: mysql
  host: 256.128.64.32
  user: cool_user
  password: "SuperHardPassword"

redis:
  host: 256.128.64.32
  pw: "SuperHardPassword"
  port: 26379

smtp:
  server: smtp.gmail.com
  port: 465
  email: [email protected]
  pw: "SuperHardPassword"

ขณะเดียวกันที่สนาม engine สามารถติดตั้งฐานข้อมูลบน SQLite และ redis ตั้งค่าให้ mockโดยระบุชื่อของไฟล์ที่จะบันทึกด้วย - พารามิเตอร์เหล่านี้ได้รับการยอมรับและประมวลผลอย่างถูกต้อง ซึ่งทำให้ง่ายต่อการเรียกใช้โค้ดในเครื่องสำหรับการดีบัก การทดสอบหน่วย และความต้องการอื่น ๆ นี่เป็นสิ่งสำคัญอย่างยิ่งสำหรับเราเนื่องจากมีความต้องการอื่นๆ มากมาย - ส่วนหนึ่งของโค้ดของเรามีไว้สำหรับการคำนวณเชิงวิเคราะห์ที่หลากหลาย ซึ่งไม่เพียงทำงานบนเซิร์ฟเวอร์ที่มีการเรียบเรียงเท่านั้น แต่ยังทำงานบนสคริปต์ต่างๆ ด้วย และบนคอมพิวเตอร์ของนักวิเคราะห์ที่ต้องทำงานผ่าน และดีบักไปป์ไลน์การประมวลผลข้อมูลที่ซับซ้อนโดยไม่ต้องกังวลกับปัญหาแบ็กเอนด์ อย่างไรก็ตาม การแชร์ว่าเครื่องมือหลักของเรา รวมถึงโค้ดเค้าโครงการกำหนดค่าได้รับการติดตั้งผ่านทางนั้นไม่ใช่เรื่องเสียหาย setup.py – เมื่อรวมเข้าด้วยกัน สิ่งนี้จะรวมโค้ดของเราไว้ในระบบนิเวศเดียว โดยไม่ขึ้นกับแพลตฟอร์มและวิธีการใช้งาน

คำอธิบายของพ็อด Kubernetes มีลักษณะดังนี้:

containers:
  - name : enter-api
    image: enter-api:latest
    ports:
      - containerPort: 80
    volumeMounts:
      - name: db-main-secret-volume
        mountPath: /etc/secrets/db-main

volumes:
  - name: db-main-secret-volume
    secret:
      secretName: db-main-secret

นั่นคือแต่ละความลับจะอธิบายหนึ่งส่วน ความลับนั้นถูกสร้างขึ้นดังนี้:

apiVersion: v1
kind: Secret
metadata:
  name: db-main-secret
type: Opaque
stringData:
  db_main.yaml: |
    engine: sqlite
    filename: main.sqlite3

เมื่อรวมกันแล้วจะส่งผลให้เกิดการสร้างไฟล์ YAML ตามเส้นทาง /etc/secrets/db-main/section_name.yaml

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

config.py

__author__ = 'AivanF'
__copyright__ = 'Copyright 2020, AivanF'

import os
import yaml

__all__ = ['config']
PROJECT_DIR = os.path.abspath(__file__ + 3 * '/..')
SECRETS_DIR = '/etc/secrets'
KEY_LOG = '_config_log'
KEY_DBG = 'debug'

def is_yes(value):
    if isinstance(value, str):
        value = value.lower()
        if value in ('1', 'on', 'yes', 'true'):
            return True
    else:
        if value in (1, True):
            return True
    return False

def update_config_part(config, key, data):
    if key not in config:
        config[key] = data
    else:
        config[key].update(data)

def parse_big_config(config, filename):
    '''
    Parse YAML config with multiple section
    '''
    if not os.path.isfile(filename):
        return False
    with open(filename) as f:
        config_new = yaml.safe_load(f.read())
        for key, data in config_new.items():
            update_config_part(config, key, data)
        config[KEY_LOG].append(filename)
        return True

def parse_tiny_config(config, key, filename):
    '''
    Parse YAML config with a single section
    '''
    with open(filename) as f:
        config_tiny = yaml.safe_load(f.read())
        update_config_part(config, key, config_tiny)
        config[KEY_LOG].append(filename)

def combine_config():
    config = {
        # To debug config load code
        KEY_LOG: [],
        # To debug other code
        KEY_DBG: is_yes(os.environ.get('DEBUG')),
    }
    # For simple local runs
    CONFIG_SIMPLE = os.path.join(PROJECT_DIR, 'config.yaml')
    parse_big_config(config, CONFIG_SIMPLE)
    # For container's tests
    CONFIG_ENVVAR = os.environ.get('CONFIG')
    if CONFIG_ENVVAR is not None:
        if not parse_big_config(config, CONFIG_ENVVAR):
            raise ValueError(
                f'No config file from EnvVar:n'
                f'{CONFIG_ENVVAR}'
            )
    # For K8s secrets
    for path, dirs, files in os.walk(SECRETS_DIR):
        depth = path[len(SECRETS_DIR):].count(os.sep)
        if depth > 1:
            continue
        for file in files:
            if file.endswith('.yaml'):
                filename = os.path.join(path, file)
                key = file.rsplit('.', 1)[0]
                parse_tiny_config(config, key, filename)
    return config

def build_config():
    config = combine_config()
    # Preprocess
    for key, data in config.items():
        if key.startswith('db_'):
            if data['engine'] == 'sqlite':
                data['filename'] = os.path.join(PROJECT_DIR, data['filename'])
    # To verify correctness
    if config[KEY_DBG]:
        print(f'** Loaded config:n{yaml.dump(config)}')
    else:
        print(f'** Loaded config from: {config[KEY_LOG]}')
    return config

config = build_config()

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

ฉันหวังว่าสิ่งที่อธิบายไว้จะเป็นประโยชน์กับใครบางคน :) ยอมรับความคิดเห็นและคำแนะนำเกี่ยวกับการรักษาความปลอดภัยหรือด้านอื่น ๆ ที่ต้องปรับปรุง ความคิดเห็นของชุมชนก็น่าสนใจเช่นกัน บางทีอาจคุ้มค่าที่จะเพิ่มการรองรับ ConfigMaps (โครงการของเรายังไม่ได้ใช้) และการเผยแพร่โค้ดบน GitHub / PyPI โดยส่วนตัวแล้ว ฉันคิดว่าสิ่งเหล่านี้เป็นเรื่องเฉพาะตัวเกินไปสำหรับโครงการที่เป็นสากล และแอบดูการใช้งานของผู้อื่น เช่นเดียวกับที่ให้ไว้ที่นี่ และการอภิปรายเกี่ยวกับความแตกต่าง เคล็ดลับ และแนวปฏิบัติที่ดีที่สุด ซึ่งฉันหวังว่าจะเห็นในความคิดเห็น , ก็พอแล้ว 😉

เฉพาะผู้ใช้ที่ลงทะเบียนเท่านั้นที่สามารถเข้าร่วมในการสำรวจได้ เข้าสู่ระบบ, โปรด.

ฉันควรเผยแพร่เป็นโครงการ/ห้องสมุดหรือไม่?

  • ลด 0,0%ใช่ ฉันจะใช้ /contribution0

  • ลด 33,3%ใช่ มันฟังดูดีมาก4

  • ลด 41,7%ไม่ ใครบ้างที่ต้องดำเนินการด้วยตนเองในรูปแบบของตนเองและเพื่อให้เหมาะกับความต้องการของตนเอง5

  • ลด 25,0%ฉันจะงดตอบ3

ผู้ใช้ 12 คนโหวต ผู้ใช้ 3 รายงดออกเสียง

ที่มา: will.com

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