Projekti konfigureerimine Kuberneteses ja väljaspool seda

Hiljuti kirjutasin vastuse projekti elust Dockeri ja koodi silumise kohta selle väliselt, kus mainisin korra, et on võimalik luua oma konfiguratsioonisüsteem, et teenus töötaks hästi ka Kubernetesis, tõmbaks saladusi ja käivitataks mugavalt ka lokaalselt, sealhulgas täiesti väljaspool Dockeri. Midagi keerulist ei ole, aga kirjeldatud "retsept" võib kellelegi abiks olla 🙂 Kood on Pythonis, kuid loogika ei ole keelele omane.

Projekti konfigureerimine Kuberneteses ja väljaspool seda

Küsimuse taust on järgmine: elas-oli üks projekt, alguses oli see väike monoliit utiliitide ja skriptidega, kuid aja jooksul kasvas, jagunes teenusteks, mis omakorda hakkasid jagunema mikroteenusteks ja seejärel veel ka skaleeruma. Alguses tehti see kõik tühjades VPS-des, nende seadistamise ja koodi juurutamise protsessid olid automatiseeritud Ansible'i abil ning igale teenusele koostati YAML-konfiguratsioon vajalike seadistuste ja võtmetega, ja sarnast konfigureerimisfaili kasutati lokaalseteks käivitamisteks, mis oli väga mugav, kuna see konfigureerimisfail laaditi globaalsetesse objektidesse, mis on saadaval igas projekti kohas.

Kuid mikroteenuste arvu, nende omavaheliste seoste ja samuti keskse logimise ja monitooringu vajadus, eeldasid kolimist Kubernetesse, mis on endiselt protsessis. Kui abistatakse nende ülesannete lahendamisel, pakub Kubernetes ka oma lähenemisviise infrastruktuuri haldamiseks, sealhulgas nn saladused ja nende käitlemise meetodid. Mehhanism on standardselt usaldusväärne, seega on tõeliselt patt seda mitte kasutada! Kuid samas tahaks säilitada oma praeguse töövormi konfiguratsiooni osas: esiteks, ühtlaselt kasutada seda erinevates projekti mikroteenustes, ja teiseks, saada käivitada koodi kohaliku masina peal, kasutades ühte lihtsat konfigureerimisfaili.

Seetõttu oli objekti konfiguratsiooni mehhanismi kohandatud nii, et see suudaks töötada nii meie klassikalise konfigureerimisfailiga kui ka Kubernetist saadud saladustega. Samuti kehtestati rangem konfiguratsiooni struktuur, rääkides kolmandast Pythonist, selline:

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

See tähendab, et lõplik konfiguratsioon on sõnastik nimetatud sektsioonidega, millest igaüks on sõnastik lihtsate tüüpide väärtustega. Ja sektsioonid kirjeldavad konfiguratsiooni ja juurdepääsu teatud tüüpi ressurssidele. Näide meie konfiguratsiooni osast:

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: info@test.com
  pw: "SuperHardPassword"

Sel juhul väli engine andmebaasi saab seadistada SQLite'le, kuid redis konfigureerida mock, määrates ka salvestamiseks faili nime – need parameetrid tuvastatakse ja töödeldakse õigesti, mis võimaldab koodi lihtsalt kohapeal käivitada, et debugida, teha üksusteste ja muid vajadusi. See on meile eriti oluline, kuna neid muid vajadusi on palju – osa meie koodist on mõeldud mitmesuguste analüütiliste arvutuste tegemiseks, seda käivitatakse mitte ainult orkestreerimisega serverites, vaid ka erinevate skriptide ja analüütikute arvutites, kes peavad tegelema ja debugima keerulisi andmete töötlemise torujuhtmeid, mitte muretsema backend-küsimustele. Üks huvitav asi, mida jagada, on see, et meie peamised tööriistad, sealhulgas konfi-kodeerimise kood, paigaldatakse läbi setup.py – need ühtlustavad meie koodi üheks ökosüsteemiks, mis ei sõltu platvormist ja kasutusviisist.

Kuberneteses on poda kirjeldus järgmine:

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

See tähendab, et iga saladuse sees on kirjas üks sektsioon. Saladusi luuakse nii:

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

See kõik viib XML-failide loomisele teel /etc/secrets/db-main/section_name.yaml

Ja kohalike käivituste jaoks kasutatakse konfi, mis asub projekti juurkataloogis või teel, mis on määratud keskkonnamuutuja kaudu. Kood, mis sellele mugavusele vastab, on nähtav spoileris.

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

Loogika on siin üsna lihtne: koondame suurte konfiguratsioonifailide sealt, kus on projekti direktor, ja teelt keskkonnamuutuja kaudu, ning väikeste sektsioonide konfiguratsioonid Kuberneteisest, seejärel töötleme neid natuke ette. Lisaks mõned muutujad. Tahan märkida, et salajaste failide otsimisel kasutatakse sügavuse piirangut, kuna K8s loob igas salas veel ühe peidetud kausta, kus saladused ise asuvad, ja ühe taseme võrra ülespoole asub lihtsalt link.

Loodan, et antud teave on kellelegi kasulik 🙂 Ootame igasuguseid kommentaare ja soovitusi turvalisuse või muude parenduste osas. Samuti huvitab, mida arvab kogukond, kas võiks lisada ConfigMapide toe (meie projektis need hetkel ei ole kasutuses) ja kas koodi tuleks vormistada GitHubis / PyPI-s? Isiklikult arvan, et sellised asjad on projektide jaoks liiga individuaalsed, et olla universaalsed, ja piisab, kui heita pilk teiste elluviimisele, nagu siin toodud, ning arutada nüansse, soovitusi ja parimaid praktikaid, mida loodan näha kommentaarides 😉

Ainult registreeritud kasutajad saavad küsitluses osaleda. Logige sisse, palun.

Kas tasub avaldada projektina / teegina?

  • 0,0%Jah, ma kasutaksin / panustaksin

  • 33,3%Jah, see kõlab hästi

  • 41,7%Ei, kellel on vajadus, teeb ise oma formaadis ja endale sobivalt

  • 25,0%Pean vastamata jääma

Hääletas 12 kasutajat. 3 kasutajat hoidusid.

Allikas: habr.com

Osta usaldusväärne veebimajutus DDoS-kaitsega veebisaitidele, VPS VDS serverid 🔥 Osta usaldusväärne veebimajutus DDoS-kaitsega veebisaitidele, VPS VDS serverid - ProHoster