Projekta agordo ene kaj ekster Kubernetes

Mi ĵus skribis respondu pri projektovivo en Docker kaj sencimiga kodo ekster ĝi, kie li mallonge menciis, ke vi povas fari vian propran agordan sistemon por ke la servo funkciu bone en Kuber, elprenas sekretojn kaj funkcias oportune loke, eĉ ekster Docker entute. Nenio komplika, sed la priskribita "recepto" povas esti utila al iu :) La kodo estas en Python, sed la logiko ne estas ligita al la lingvo.

Projekta agordo ene kaj ekster Kubernetes

La fono de la demando estas jena: iam estis unu projekto, unue ĝi estis malgranda monolito kun utilecoj kaj skriptoj, sed kun la tempo ĝi kreskis, dividita en servojn, kiuj siavice komencis esti dividitaj en mikroservojn, kaj tiam skaliĝis. Komence, ĉio ĉi estis farita sur nuda VPS, la procezoj de agordo kaj deplojado de kodo sur kiuj estis aŭtomatigitaj uzante Ansible, kaj ĉiu servo estis kompilita kun YAML-agordo kun la necesaj agordoj kaj ŝlosiloj, kaj simila agorda dosiero estis uzata por lokaj lanĉoj, kio estis tre oportuna, ĉar .k ĉi tiu agordo estas ŝarĝita en tutmondan objekton, alirebla de ie ajn en la projekto.

Tamen, la kresko de la nombro da mikroservoj, iliaj ligoj, kaj bezono de centralizita arbohakado kaj monitorado, antaŭsignis movon al Kuber, kiu daŭre estas en progreso. Kune kun helpo por solvi la menciitajn problemojn, Kubernetes ofertas siajn alirojn al infrastruktura administrado, inkluzive de tiel nomataj Sekretoj и manieroj labori kun ili. La mekanismo estas norma kaj fidinda, do estas laŭvorte peko ne uzi ĝin! Sed samtempe, mi ŝatus konservi mian nunan formaton por labori kun la agordo: unue, uzi ĝin unuforme en malsamaj mikroservoj de la projekto, kaj due, povi ruli la kodon sur la loka maŝino uzante unu simplan. agorda dosiero.

Ĉi-rilate, la mekanismo por konstrui agordan objekton estis modifita por povi funkcii kaj kun nia klasika agorda dosiero kaj kun sekretoj de Kuber. Pli rigida agorda strukturo ankaŭ estis precizigita, en la lingvo de la tria Python, jene:

Dict[str, Dict[str, Unio[str, int, flosilo]]]

Tio estas, la fina cogfig estas vortaro kun nomitaj sekcioj, ĉiu el kiuj estas vortaro kun valoroj de simplaj tipoj. Kaj sekcioj priskribas la agordon kaj aliron al rimedoj de certa tipo. Ekzemplo de peco de nia agordo:

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"

Samtempe, la kampo engine datumbazoj povas esti instalitaj sur SQLite, kaj redis starigis al mock, specifante ankaŭ la nomon de la konservenda dosiero - ĉi tiuj parametroj estas ĝuste rekonitaj kaj prilaboritaj, kio faciligas ruli la kodon loke por elpurigado, unutestado kaj ajnaj aliaj bezonoj. Ĉi tio estas precipe grava por ni, ĉar ekzistas multaj aliaj bezonoj - parto de nia kodo estas destinita por diversaj analizaj kalkuloj, ĝi funkcias ne nur sur serviloj kun orkestrado, sed ankaŭ per diversaj skriptoj, kaj sur la komputiloj de analizistoj, kiuj bezonas labori. kaj sencimigi kompleksajn datumtraktadduktojn sen zorgi pri malantaŭaj problemoj. Cetere, ne malutilus konigi, ke niaj ĉefaj iloj, inkluzive de la agorda aranĝokodo, estas instalitaj per setup.py – kune ĉi tio kunigas nian kodon en ununuran ekosistemon, sendependa de platformo kaj metodo de uzo.

La priskribo de Kubernetes-podo aspektas jene:

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

Tio estas, ĉiu sekreto priskribas unu sekcion. La sekretoj mem estas kreitaj jene:

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

Kune ĉi tio rezultigas la kreadon de YAML-dosieroj laŭ la vojo /etc/secrets/db-main/section_name.yaml

Kaj por lokaj lanĉoj, la agordo estas uzata, situanta en la radika dosierujo de la projekto aŭ laŭ la vojo specifita en la mediovariablo. La kodo respondeca pri ĉi tiuj komfortoj videblas en la spoiler.

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

La logiko ĉi tie estas sufiĉe simpla: ni kombinas grandajn agordojn de la projekta dosierujo kaj vojojn per mediovariablo, kaj malgrandajn agordajn sekciojn de Kuber-sekretoj, kaj poste antaŭprocezas ilin iomete. Krome iuj variabloj. Mi rimarkas, ke serĉante dosierojn el sekretoj, oni uzas profundlimon, ĉar K8s kreas kaŝitan dosierujon en ĉiu sekreto, kie la sekretoj mem estas konservitaj, kaj nur ligilo troviĝas sur pli alta nivelo.

Mi esperas, ke tio, kio estas priskribita, estos utila al iu :) Ajna komentoj kaj rekomendoj rilate sekurecon aŭ aliajn areojn por plibonigo estas akceptitaj. Ankaŭ la opinio de la komunumo estas interesa, ĉu eble indas aldoni subtenon por ConfigMaps (nia projekto ankoraŭ ne uzas ilin) ​​kaj publikigi la kodon en GitHub / PyPI? Persone, mi pensas, ke tiaj aferoj estas tro individuaj por ke projektoj estu universalaj, kaj iomete kaŝrigardu aliulajn efektivigojn, kiel tiu ĉi tie donita, kaj diskuton pri nuancoj, konsiloj kaj plej bonaj praktikoj, kiujn mi esperas vidi en la komentoj. , sufiĉas 😉

Nur registritaj uzantoj povas partopreni la enketon. Ensaluti, bonvolu.

Ĉu mi publikigu kiel projekto/biblioteko?

  • 0,0%Jes, mi uzus /kontribuon0

  • 33,3%Jes, tio sonas bonege4

  • 41,7%Ne, kiu bezonas fari ĝin mem en sia propra formato kaj laŭ siaj bezonoj5

  • 25,0%Mi detenos respondi3

Voĉdonis 12 uzantoj. 3 uzantoj sindetenis.

fonto: www.habr.com

Aldoni komenton