Projekti konfigureerimine Kubernetes sees ja väljaspool

Kirjutasin hiljuti vastus projekti elu kohta Dockeris ja koodi silumise kohta väljaspool seda, kus ta mainis lühidalt, et saate luua oma konfiguratsioonisüsteemi nii, et teenus Kuberis hästi töötaks, tõmbaks saladusi ja töötaks mugavalt kohapeal, isegi väljaspool Dockerit. Ei midagi keerulist, aga kirjeldatud “retseptist” võib kellelegi kasu olla :) Kood on Pythonis, aga loogika pole keelega seotud.

Projekti konfigureerimine Kubernetes sees ja väljaspool

Küsimuse taust on järgmine: kunagi oli üks projekt, algul oli see väike monoliit koos kommunaalteenuste ja skriptidega, kuid aja jooksul see kasvas, jagunes teenusteks, mis omakorda hakkasid jagunema mikroteenusteks ja siis suurendati. Alguses tehti seda kõike tühja VPS-iga, mille koodi seadistamise ja juurutamise protsessid automatiseeriti Ansible abil ning iga teenus kompileeriti vajalike sätete ja võtmetega YAML-i konfiguratsiooniga ning sarnast konfiguratsioonifaili kasutati kohalikud käivitamised, mis oli väga mugav, sest .k see konfiguratsioon laaditakse globaalsesse objekti, kuhu pääseb ligi kõikjalt projektis.

Kuid mikroteenuste arvu kasv, nende ühenduste ja vajadus tsentraliseeritud metsaraie ja seire järele, nägi ette kolimist Kuberisse, mis on veel pooleli. Koos abiga nimetatud probleemide lahendamisel pakub Kubernetes oma lähenemisviise infrastruktuuri haldamisele, sh niinimetatud saladused и viise nendega töötamiseks. Mehhanism on standardne ja töökindel, seega on sõna otseses mõttes patt seda mitte kasutada! Kuid samal ajal tahaksin säilitada oma senise vormingu konfiguratsiooniga töötamiseks: esiteks kasutada seda projekti erinevates mikroteenustes ühtlaselt ja teiseks, et saaksin koodi käivitada kohalikus masinas ühe lihtsa meetodi abil. konfiguratsioonifail.

Sellega seoses muudeti konfiguratsiooniobjekti koostamise mehhanismi, et see saaks töötada nii meie klassikalise konfiguratsioonifailiga kui ka Kuberi saladustega. Kolmanda Pythoni keeles täpsustati ka jäigem konfiguratsioonistruktuur järgmiselt:

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

See tähendab, et viimane hammasratas on nimeliste jaotistega sõnastik, millest igaüks on lihtsate tüüpide väärtustega sõnastik. Ja jaotistes kirjeldatakse konfiguratsiooni ja juurdepääsu teatud tüüpi ressurssidele. Näide meie konfiguratsioonist:

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"

Samas põld engine andmebaase saab installida SQLite'i ja redis seatud mock, täpsustades ka salvestatava faili nime – need parameetrid tuvastatakse ja töödeldakse õigesti, mis teeb koodi lokaalse käivitamise silumiseks, üksuse testimiseks ja muudeks vajadusteks lihtsaks. See on meie jaoks eriti oluline, kuna on palju muid vajadusi - osa meie koodist on mõeldud erinevateks analüütilisteks arvutusteks, see ei tööta ainult orkestratsiooniga serverites, vaid ka erinevate skriptidega ning analüütikute arvutites, kes peavad läbi töötama. ja siluda keerulisi andmetöötluskonveine ilma taustaprobleeme muretsemata. Muide, poleks paha jagada, et meie peamised tööriistad, sealhulgas konfiguratsiooni paigutuse kood, installitakse setup.py – koos ühendab see meie koodi üheks ökosüsteemiks, mis ei sõltu platvormist ja kasutusviisist.

Kubernetes podi kirjeldus näeb välja selline:

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 saladus kirjeldab ühte jaotist. Saladused ise luuakse järgmiselt:

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

Selle tulemuseks on YAML-failide loomine tee ääres /etc/secrets/db-main/section_name.yaml

Kohaliku käivitamise korral kasutatakse konfiguratsiooni, mis asub projekti juurkataloogis või keskkonnamuutujas määratud tee ääres. Nende mugavuste eest vastutav kood on näha 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: ühendame suured konfiguratsioonid projektikataloogist ja teed keskkonnamuutujate kaupa ning väikesed konfiguratsioonisektsioonid Kuberi saladustest ning seejärel eeltöötleme neid veidi. Lisaks mõned muutujad. Märgin, et saladustest failide otsimisel kasutatakse sügavuse piirangut, kuna K8s loob igasse saladusse peidetud kausta, kuhu saladused ise salvestatakse ja lihtsalt link asub kõrgemal tasemel.

Loodan, et kirjeldatu on kellelegi kasulik :) Kõik kommentaarid ja soovitused turvalisuse või muude parendusvaldkondade kohta on teretulnud. Huvitav on ka kogukonna arvamus, võib-olla tasub lisada ConfigMapsi tugi (meie projekt neid veel ei kasuta) ja kood GitHubis / PyPI-s avaldada? Isiklikult arvan, et sellised asjad on liiga individuaalsed, et projektid oleksid universaalsed, ja natukene piilumine teiste inimeste teostuste poole, nagu siin toodud, ja nüansside, näpunäidete ja parimate praktikate arutelu, mida loodan kommentaarides näha. , piisab 😉

Küsitluses saavad osaleda ainult registreerunud kasutajad. Logi sissepalun.

Kas ma peaksin avaldama projekti/raamatukoguna?

  • 0,0%Jah, ma kasutaksin /contribution0

  • 33,3%Jah, see kõlab suurepäraselt 4

  • 41,7%Ei, kes peab seda ise tegema oma formaadis ja vastavalt oma vajadustele5

  • 25,0%Ma hoidun vastamast3

12 kasutajat hääletas. 3 kasutajat jäi erapooletuks.

Allikas: www.habr.com

Lisa kommentaar