Cunfigurazione di u prugettu in Kubernetes è fora

Recentemente aghju scrittu risponde à a vita di u prughjettu in Docker è u codice di debugging fora di questu, induve ellu hà dettu brevemente chì pudete fà u vostru propiu sistema di cunfigurazione in modu chì u serviziu funziona bè in Kuber, tira sicreti, è corre convenientemente in u locu, ancu fora di Docker in tuttu. Nunda complicata, ma a "ricetta" descritta pò esse utile à qualchissia :) U codice hè in Python, ma a logica ùn hè micca ligata à a lingua.

Cunfigurazione di u prugettu in Kubernetes è fora

U fondu di a quistione hè questu: una volta ci era un prughjettu, in prima era un picculu monolitu cù utilità è scripts, ma cù u tempu hè cresciutu, divisu in servizii, chì à u turnu cuminciò à esse divisu in microservizi, è poi scalata. À u principiu, tuttu questu hè statu fattu in VPS nudu, i prucessi di creazione è implementazione di codice nantu à quale sò stati automatizati cù Ansible, è ogni serviziu hè statu compilatu cù una cunfigurazione YAML cù i paràmetri è e chjavi necessarii, è un schedariu di cunfigurazione simili hè stata utilizata per lanciari lucali, chì era assai còmuda, perchè .k sta cunfigurazione hè caricata in un ughjettu glubale, accessibile da ogni locu in u prugettu.

In ogni casu, a crescita in u numeru di microservizi, e so cunnessione, è bisognu di logu è monitoraghju centralizzati, prefigurava un muvimentu in Kuber, chì hè sempre in prugressu. Inseme cù l'assistenza per risolve i prublemi citati, Kubernetes offre i so approcci à a gestione di l'infrastruttura, cumprese i cosiddetti Secrets и manere di travaglià cun elli. U mecanismu hè standard è affidabile, cusì hè literalmente un peccatu per ùn aduprà! Ma à u stessu tempu, mi piacerebbe mantene u mo formatu attuale per travaglià cù a cunfigurazione: prima, per usà uniformemente in diversi microservizii di u prugettu, è in segundu, per esse capace di eseguisce u codice nantu à a macchina lucale utilizendu una simplice. schedariu di cunfigurazione.

In questu sensu, u mecanismu per a custruzzione di un oggettu di cunfigurazione hè statu mudificatu per pudè travaglià sia cù u nostru schedariu di cunfigurazione classicu sia cù secreti da Kuber. Una struttura di cunfigurazione più rigida hè stata ancu specificata, in a lingua di u terzu Python, cusì:

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

Vale à dì, u cogfig finale hè un dizziunariu cù sezioni chjamate, ognuna di quale hè un dizziunariu cù valori da tipi simplici. E sezzioni descrizanu a cunfigurazione è l'accessu à e risorse di un certu tipu. Un esempiu di un pezzu di a nostra cunfigurazione:

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"

À u listessu tempu, u campu engine basa di dati pò esse installatu nantu à SQLite, è redis stabilitu à mock, specificendu ancu u nome di u schedariu per salvà - sti paràmetri sò ricunnisciuti currettamente è processati, chì facenu fàciule per eseguisce u codice in u locu per debugging, test di unità è qualsiasi altri bisogni. Questu hè soprattuttu impurtante per noi perchè ci sò assai altri bisogni - una parte di u nostru codice hè destinata à diversi calculi analitici, ùn viaghja micca solu in i servitori cù l'orchestrazione, ma ancu cù diversi script, è in l'urdinatori di l'analista chì anu bisognu di travaglià. è debug pipelines di trasfurmazioni di dati cumplessi senza preoccupari prublemi di backend. Per via, ùn saria micca male di sparte chì i nostri strumenti principali, cumpresu u codice di cunfigurazione, sò stallati via setup.py - Inseme, questu unisce u nostru codice in un solu ecosistema, indipendente da a piattaforma è u metudu d'usu.

A descrizzione di un pod Kubernetes hè cusì:

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

Questu hè, ogni sicretu descrive una sezione. I sicreti stessi sò creati cusì:

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

Inseme, questu risultatu in a creazione di schedari YAML longu u percorsu /etc/secrets/db-main/section_name.yaml

È per i lanciari lucali, a cunfigurazione hè aduprata, situata in u repertoriu radicali di u prugettu o longu u percorsu specificatu in a variabile di l'ambiente. U codice rispunsevuli di sti comodità pò esse vistu in u spoiler.

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

A logica quì hè abbastanza sèmplice: cumbinemu grandi cunfigurazioni da u repertoriu di u prughjettu è i percorsi per variabile di l'ambiente, è picculi sezioni di cunfigurazione da i secreti di Kuber, è poi preprocessà un pocu. Plus alcune variabili. Aghju nutatu chì quandu cercate i fugliali da i sicreti, una limitazione di prufundità hè utilizata, perchè K8s crea un cartulare oculatu in ogni sicretu induve i sicreti stessi sò almacenati, è solu un ligame hè situatu à un livellu più altu.

Spergu chì ciò chì hè descrittu serà utile à qualcunu :) Ogni cumenti è raccomandazioni in quantu à a sicurità o altre aree per migliurà sò accettati. L'opinione di a cumunità hè ancu interessante, forse vale a pena aghjunghje supportu per ConfigMaps (u nostru prughjettu ùn li usa ancu) è publicà u codice in GitHub / PyPI ? In modu persunale, pensu chì tali cose sò troppu individuali per i prughjetti per esse universali, è un pocu sguardu à l'implementazione di l'altri, cum'è quellu chì hè datu quì, è una discussione di sfumature, cunsiglii è pratiche megliu, chì speru di vede in i cumenti. , basta 😉

Solu l'utilizatori registrati ponu participà à l'indagine. Firmà lu, per piacè.

Deve publicà cum'è prughjettu / biblioteca ?

  • 0,0%Iè, aghju aduprà /contribution0

  • 33,3%Iè, chì sona bellu4

  • 41,7%Innò, chì hà bisognu à fà ellu stessu in u so propiu furmatu è per adattà à i so bisogni5

  • 25,0%Mi asterraghju da risponde 3

12 utilizatori anu vutatu. 3 utilizatori si sò astenuti.

Source: www.habr.com

Add a comment