Projekti konfiguratsioon Kubernetes'is ja selle väliselt

Hiljuti kirjutasin vastuse projekti elust Dockers'is ja koodi silumisest väljaspool seda, kus mainisin, et võite luua oma konfiguratsioonisüsteemi, et teenus töötaks hästi ka Kubernetes'is, tõmbaks salasõnu ja tööle hakkaks mugavalt ka väljaspool Dockersit. Midagi keerulist ei ole, kuid kirjeldatud "retsept" võib kedagi huvitada 🙂 Kood on Pythonis, kuid loogika ei ole seotud keelekindlusega.

Projekti konfiguratsioon Kubernetes'is ja selle väliselt

Küsimuse eellugu on selline: elas-olles oli üks projekt, alguses oli see väike monoliit koos utiliidid ja skriptidega, kuid aja jooksul kasvas see, jagunes teenusteks, mis omakorda hakkasid jagunema mikroteenusteks, ning seejärel ka skaleeruma. Alguses toimus see kõik tühjadel VPS-idel, mille seadistus- ja juurutamisprotsessid automatiseeriti Ansible'i abil, ning igale teenusele koostati YAML-konfiguratsioon vajalike seadete ja võtmetega, ning sarnast konfiguratsioonifaili kasutati ka kohalikeks käivitusteks, mis oli väga mugav, kuna see konfiguratsioon laaditakse globaalsete objektide sisse, mis on projekti igast kohast ligipääsetavad.

Kuid mikroteenuste arvu, nende seoste ja samuti vajadus tsentraliseeritud logimise ja jälgimise järele, mis ennustas üleminekut Kubernetesesse, mis on endiselt käimas. Lisaks abile nende ülesannete lahendamisel pakub Kubernetes ka oma lähenemisviise infrastruktuuri haldamiseks, sealhulgas nn Saladused ja viisid nende käsitlemiseks. Mehhanism on standardne ja usaldusväärne, seega on sõna otseses mõttes patt seda mitte kasutada! Samas sooviksin säilitada oma praeguse tööformaat konfiguratsiooniga: esiteks, kasutada seda ühtlaselt erinevates mikroteenustes projektis ja teiseks, omada võimalust käivitada kood kohalikul masinal, kasutades ühte lihtsat konfiguratsioonifaili.

Selle tõttu on objekti konfiguratsiooni loomise mehhanismi täiustatud, et see saaks töötada nii meie klassikalise konfiguratsioonifaili kui ka Kubernetesest pärit saladustega. Samuti on seatud rangem konfiguratsiooni struktuur, nagu kolmandas Pythoni keeles, järgmine:

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

See, the final config is a dictionary with named sections, each of which is a dictionary with values of simple types. The sections describe the configuration and access to resources of a certain type. Here’s an example snippet of our config:

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"

At the same time, the field engine of the databases can be set to SQLite, while redis can be configured to mock, märkides ära ka faili nime salvestamiseks, – need parameetrid tuvastatakse ja töödeldakse korrektselt, võimaldades koodi kohalikku käivitamist silumiseks, üksuse testimiseks ja muude vajaduste jaoks. See on meie jaoks eriti oluline, kuna neid muid vajadusi on palju – osa meie koodist on mõeldud erinevate analüütiliste arvutuste tegemiseks, seda käitatakse mitte ainult orkestreeritud serverites, vaid ka erinevate skriptide ja analüütikute arvutites, kellel on vaja töötada välja ja siluda keerulisi andmetöötluse voosid ilma tagaplaneerimise küsimustest muretsemata. Ühtlasi pole üleliigne jagada, et meie peamised tööriistad, sealhulgas konfiguratsioonifaili koostamise kood, installitakse läbi setup.py – koos see ühendab meie koodi üheks ökosüsteemiks, sõltumatuks platvormist ja kasutamisviisist.

Pod'i kirjeldus Kuberneteses näeb välja 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 igas salajastes on üks jaotus. Salajased ise luuakse nii:

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

Koos see viib YAML-failide loomise juurde asukohas /etc/secrets/db-main/section_name.yaml

Kohalikeks käivitusteks kasutatakse konfiguratsiooni, mis asub projekti juurdirektoris või asukohas, mis on märgitud keskkonnamuutujas. Kood, mis vastutab nende mugavuste eest, 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):
    '''
    Parsee YAML konfiguratsioon mitme sektsiooniga
    '''
    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):
    '''
    Parsee YAML konfiguratsioon ühe sektsiooniga
    '''
    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 = {
        # Debugige konfiguratsiooni laadimise koodi
        KEY_LOG: [],
        # Debugige teisi koode
        KEY_DBG: is_yes(os.environ.get('DEBUG')),
    }
    # Lihtsate kohalike käituste jaoks
    CONFIG_SIMPLE = os.path.join(PROJECT_DIR, 'config.yaml')
    parse_big_config(config, CONFIG_SIMPLE)
    # Konteinerite testide jaoks
    CONFIG_ENVVAR = os.environ.get('CONFIG')
    if CONFIG_ENVVAR is not None:
        if not parse_big_config(config, CONFIG_ENVVAR):
            raise ValueError(
                f'Konfiguratsioonifaili ei leitud EnvVar: n'
                f'{CONFIG_ENVVAR}'
            )
    # K8s saladuste jaoks
    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()
    # Eeltöötlus
    for key, data in config.items():
        if key.startswith('db_'):
            if data['engine'] == 'sqlite':
                data['filename'] = os.path.join(PROJECT_DIR, data['filename'])
    # Õiguse verifitseerimiseks
    if config[KEY_DBG]:
        print(f'** Laaditud konfiguratsioon: n{yaml.dump(config)}')
    else:
        print(f'** Laaditud konfiguratsioon: {config[KEY_LOG]}')
    return config

config = build_config()

Siin on loogika tõeliselt lihtne: ühendame suurte konfigureerimiste failid projektikaustast ja keskkonna muutujatest, samuti väikesed konfiguratsioonisektsioonid Kubernetes'i saladustest, ning seejärel töötame need veidi ette. Lisaks mõned muutujad. Tõmbenäiteks, kui otsida faile saladustest, rakendatakse sügavuse piiri, kuna K8s loob igas saladuses veel peidetud kausta, kus saladused endid hoiustada, ja ühel tasemel üleval on lihtsalt link.

Loodan, et see kirjeldus osutub kellelegi kasulikuks 🙂 Ootan kõiki kommentaare ja soovitusi, mis puudutavad turvalisust või muid parendusi. Ka huvitab mind kogukonna arvamus, kas oleks mõistlik lisada ConfigMap'i tugi (meie projektis neid veel ei kasutata) ja avaldada kood GitHubis / PyPI-s? Isiklikult arvan, et sellised asjad on projektide jaoks liiga individuaalsed, et need saaksid universaalsed, ja piisab väikesest piilumisest teiste rakendustesse, nagu siin välja toodud, ning aruteludest nüansside, soovituste ja parimate praktikate üle, mida loodan kommentaarides näha 😉

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

Kas on mõtet avaldada projektina/raamatukoguna?

  • 0,0%Jah, ma kasutaksin ja panustaksin.

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

  • 41,7%Ei, kellelgi on niikuinii vaja teha oma formaadis ja vajadustele vastavalt.

  • 25,0%Jätan vastamata.

Hääletas 12 kasutajat. Jätkuvalt 3 kasutajat.

Allikas: habr.com

Osta usaldusväärne veebihosting DDoS kaitsega, VPS VDS serverid 🔥 Osta usaldusväärne veebihosting DDoS kaitsega, VPS VDS serverid | ProHoster