Nedavno sam napisao
Pozadina pitanja je sljedeća: jednom davno postojao je jedan projekt, u početku je to bio mali monolit s pomoćnim programima i skriptama, ali je s vremenom rastao, dijelio se na servise, koji su se opet počeli dijeliti na mikroservise, i zatim povećao. U početku se sve to radilo na golom VPS-u, procesi postavljanja i implementacije koda na kojem su bili automatizirani pomoću Ansiblea, a svaka usluga je kompajlirana s YAML konfiguracijom s potrebnim postavkama i ključevima, a slična konfiguracijska datoteka korištena je za lokalno pokreće, što je bilo vrlo zgodno, jer se .k ova konfiguracija učitava u globalni objekt, dostupan s bilo kojeg mjesta u projektu.
Međutim, rast broja mikroservisa, njihove povezanosti i
U tom smislu, mehanizam za konstrukciju konfiguracijskog objekta je modificiran kako bi mogao raditi i s našom klasičnom konfiguracijskom datotekom i s tajnama iz Kubera. Također je određena stroža konfiguracijska struktura, u jeziku trećeg Pythona, kako slijedi:
Dict[str, Dict[str, Union[str, int, float]]]
Odnosno, konačni cogfig je rječnik s imenovanim odjeljcima, od kojih je svaki rječnik s vrijednostima iz jednostavnih tipova. A odjeljci opisuju konfiguraciju i pristup resursima određene vrste. Primjer dijela naše konfiguracije:
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"
Istovremeno, polj engine
baze podataka mogu se instalirati na SQLite, i redis
postavljen mock
, navodeći i naziv datoteke za spremanje - ti se parametri ispravno prepoznaju i obrađuju, što olakšava lokalno pokretanje koda za otklanjanje pogrešaka, testiranje jedinica i sve druge potrebe. Ovo nam je posebno važno jer postoje mnoge druge potrebe - dio našeg koda namijenjen je raznim analitičkim izračunima, radi ne samo na poslužiteljima s orkestracijom, već i s raznim skriptama, te na računalima analitičara koji trebaju raditi kroz i otklanjanje pogrešaka u složenim cjevovodima za obradu podataka bez problema s pozadinom. Usput, ne bi škodilo podijeliti da su naši glavni alati, uključujući konfiguracijski kod za raspored, instalirani putem setup.py
– zajedno to ujedinjuje naš kod u jedinstveni ekosustav, neovisno o platformi i načinu korištenja.
Opis Kubernetes pod-a izgleda ovako:
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
Odnosno, svaka tajna opisuje jedan odjeljak. Same tajne nastaju ovako:
apiVersion: v1
kind: Secret
metadata:
name: db-main-secret
type: Opaque
stringData:
db_main.yaml: |
engine: sqlite
filename: main.sqlite3
Zajedno to rezultira stvaranjem YAML datoteka na putu /etc/secrets/db-main/section_name.yaml
A za lokalna pokretanja koristi se konfiguracija koja se nalazi u korijenskom direktoriju projekta ili duž staze navedene u varijabli okruženja. Kôd odgovoran za te pogodnosti može se vidjeti u spojleru.
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()
Logika je ovdje prilično jednostavna: kombiniramo velike konfiguracije iz direktorija projekta i staze prema varijabli okruženja i male konfiguracijske dijelove iz Kuberovih tajni, a zatim ih malo pretprocesiramo. Plus neke varijable. Napominjem da se kod traženja datoteka iz tajni koristi ograničenje dubine, jer K8s stvara skrivenu mapu u svakoj tajni gdje su pohranjene same tajne, a samo se poveznica nalazi na višoj razini.
Nadam se da će ovo što je opisano nekome biti od koristi :) Prihvaćamo sve komentare i preporuke vezane uz sigurnost ili druga područja za poboljšanje. Mišljenje zajednice je također zanimljivo, možda je vrijedno dodati podršku za ConfigMaps (naš projekt ih još ne koristi) i objaviti kod na GitHub / PyPI? Osobno mislim da su takve stvari previše individualne da bi projekti bili univerzalni, a malo zavirivanja u tuđe implementacije, poput ove dane ovdje, te rasprava o nijansama, savjetima i najboljim primjerima iz prakse, za koje se nadam da ću ih vidjeti u komentarima , dovoljno je 😉
U anketi mogu sudjelovati samo registrirani korisnici.
Trebam li objavljivati kao projekt/biblioteku?
-
0,0%Da, koristio bih /contribution0
-
33,3%Da, to zvuči sjajno4
-
41,7%Ne, tko to treba učiniti sam u svom formatu i prema svojim potrebama5
-
25,0%Suzdržat ću se od odgovora3
Glasovalo je 12 korisnika. Suzdržana su bila 3 korisnika.
Izvor: www.habr.com