Projet Configuratioun bannen a baussen Kubernetes

Ech geschriwwen kuerzem Äntwert iwwer Projet Liewen am Docker an Debugging Code dobaussen, wou hien kuerz erwähnt huet datt Dir Ären eegene Konfiguratiounssystem maache kënnt, sou datt de Service gutt am Kuber funktionnéiert, Geheimnisser ophëlt a praktesch lokal leeft, och ausserhalb vum Docker ganz. Näischt komplizéiert, awer dat beschriwwen "Rezept" ka fir een nëtzlech sinn :) De Code ass am Python, awer d'Logik ass net un d'Sprooch gebonnen.

Projet Configuratioun bannen a baussen Kubernetes

Den Hannergrond vun der Fro ass dëst: eemol gouf et e Projet, am Ufank war et e klenge Monolith mat Utilities a Scripten, awer mat der Zäit ass et gewuess, a Servicer opgedeelt, déi am Tour ugefaang hunn a Mikroservicer opgedeelt ze ginn, an dann opgeschalt. Am Ufank gouf dëst alles op bloe VPS gemaach, d'Prozesser fir de Code opzestellen an z'installéieren op deem automatiséiert goufen mat Ansible, an all Service gouf mat enger YAML Config mat den néidegen Astellungen a Schlësselen zesummegesat, an eng ähnlech Configuratiounsdatei gouf benotzt fir lokal lancéiert, déi ganz bequem war, well .k dëser config an engem globale Objet gelueden ass, zougänglech vun iwwerall am Projet.

Wéi och ëmmer, de Wuesstum vun der Zuel vu Mikroservicer, hir Verbindungen, an Bedierfnes fir zentraliséiert Logbicher an Iwwerwaachung, huet e Beweegung op Kuber virgeschloen, deen nach ëmmer amgaang ass. Zesumme mat Hëllef fir déi genannte Problemer ze léisen, bitt Kubernetes seng Approche fir d'Infrastrukturmanagement, inklusiv sougenannte Geheimnisser и Weeër mat hinnen ze schaffen. De Mechanismus ass Standard an zouverlässeg, also et ass wuertwiertlech eng Sënn et net ze benotzen! Awer gläichzäiteg wéilt ech mäi aktuellt Format fir d'Aarbecht mat der Configuratioun erhalen: éischtens, fir et eenheetlech a verschiddene Mikroservicer vum Projet ze benotzen, an zweetens, fir de Code op der lokaler Maschinn mat enger einfacher Maschinn auszeféieren. config Datei.

An dëser Hisiicht gouf de Mechanismus fir e Konfiguratiounsobjekt ze konstruéieren geännert fir souwuel mat eiser klassescher Configuratiounsdatei wéi och mat Kuber Geheimnisser ze schaffen. Eng méi steif Konfiguratiounsstruktur gouf och spezifizéiert, an der Sprooch vum drëtte Python, wéi follegt:

Dict[str, Dict[str, Union[str, int, float]]]

Dat ass, de leschte Zännstaang ass e Wierderbuch mat benannten Sektiounen, jidderee vun deem ass e Wierderbuch mat Wäerter vun einfachen Typen. A Sektiounen beschreiwen d'Konfiguratioun an den Zougang zu Ressourcen vun engem bestëmmten Typ. E Beispill vun engem Stéck vun eiser Configuratioun:

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"

Gläichzäiteg, den Terrain engine Datenbanken kënnen op SQLite installéiert ginn, an redis setzen op mock, spezifizéieren och den Numm vun der Datei fir ze späicheren - dës Parameter ginn korrekt unerkannt a veraarbecht, wat et einfach mécht de Code lokal fir Debugging, Eenheetstest an all aner Bedierfnesser ze lafen. Dëst ass besonnesch wichteg fir eis, well et vill aner Bedierfnesser gëtt - en Deel vun eisem Code ass fir verschidden analytesch Berechnungen geduecht, et leeft net nëmmen op Serveren mat Orchester, awer och mat verschiddene Scripten, an op Computeren vun Analysten, déi musse schaffen. an debug komplex Datenveraarbechtungspipelines ouni Suergen fir Backend Themen. Iwwregens, et géif net schueden ze deelen datt eis Haaptinstrumenter, dorënner de Configuratiouns Layoutcode, iwwer installéiert sinn setup.py - zesummen vereenegt dëst eise Code an een eenzegen Ökosystem, onofhängeg vun der Plattform an der Benotzungsmethod.

D'Beschreiwung vun engem Kubernetes Pod gesäit esou aus:

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

Dat ass, all Geheimnis beschreift eng Sektioun. D'Geheimnisser selwer ginn esou erstallt:

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

Zesummen resultéiert dëst an der Schafung vun YAML Dateien laanscht de Wee /etc/secrets/db-main/section_name.yaml

A fir lokal Starten gëtt d'Konfiguratioun benotzt, am Root-Verzeichnis vum Projet oder laanscht de Wee, deen an der Ëmfeldvariabel uginn ass. De Code verantwortlech fir dës Komfort kann am Spoiler gesi ginn.

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()

D'Logik hei ass zimmlech einfach: mir kombinéieren grouss Konfiguratiounen aus dem Projetsverzeechnes a Weeër no Ëmfeldvariabel, a kleng Konfiguratiounssektioune vu Kuber Geheimnisser, a preparéieren se dann e bëssen. Plus e puer Variabelen. Ech bemierken datt wann Dir no Dateien aus Geheimnisser sicht, eng Déiftbegrenzung benotzt gëtt, well K8s e verstoppte Dossier an all Geheimnis erstellt, wou d'Geheimnisser selwer gespäichert sinn, a just e Link ass op engem méi héijen Niveau.

Ech hoffen dat wat beschriwwe gëtt fir een nëtzlech wäert sinn :) All Kommentaren an Empfehlungen betreffend Sécherheet oder aner Beräicher fir Verbesserung ginn ugeholl. D'Meenung vun der Gemeinschaft ass och interessant, vläicht ass et derwäert Ënnerstëtzung fir ConfigMaps ze addéieren (eise Projet benotzt se nach net) an de Code op GitHub / PyPI ze publizéieren? Ech perséinlech mengen, datt esou Saachen ze individuell sinn fir Projeten universell ze sinn, an e bëssen op d'Ëmsetzung vun anere Leit kucken, wéi déi hei uginn, an eng Diskussioun iwwer Nuancen, Tipps a Best Practices, déi ech hoffen an de Kommentarer ze gesinn. , geet duer 😉

Nëmme registréiert Benotzer kënnen un der Ëmfro deelhuelen. Umellen, wann ech glift.

Soll ech als Projet/Bibliothéik publizéieren?

  • 0,0%Jo, ech géif /contribution0 benotzen

  • 33,3%Jo, dat kléngt super4

  • 41,7%Neen, wien muss et selwer an hirem eegene Format maachen an hir Besoinen passen5

  • 25,0%Ech äntweren net 3

12 Benotzer hunn gestëmmt. 3 Benotzer hu sech enthalen.

Source: will.com

Setzt e Commentaire