Ik koartlyn skreau
De eftergrûn fan 'e fraach is dizze: eartiids wie d'r ien projekt, earst wie it in lytse monolyt mei nutsbedriuwen en skripts, mar yn 'e rin fan' e tiid groeide it, ferdield yn tsjinsten, dy't op har beurt begon te wurde ferdield yn mikrotsjinsten, en dan opskaald. Earst waard dit alles dien op bleate VPS, de prosessen foar it ynstellen en ynsetten fan koade wêrop't automatisearre waarden mei Ansible, en elke tsjinst waard kompilearre mei in YAML-konfiguraasje mei de nedige ynstellings en kaaien, en in ferlykbere konfiguraasjetriem waard brûkt foar lokale lansearringen, dat wie tige handich, omdat .k dizze config wurdt laden yn in globale foarwerp, tagonklik fan oeral yn it projekt.
De groei fan it oantal mikrotsjinsten, har ferbiningen, en
Yn dit ferbân waard it meganisme foar it bouwen fan in konfiguraasjeobjekt oanpast om sawol mei ús klassike konfiguraasjetriem as mei geheimen fan Kuber te wurkjen. In mear rigide konfiguraasjestruktuer waard ek spesifisearre, yn 'e taal fan' e tredde Python, as folget:
Dict[str, Dict[str, Union[str, int, float]]]
Dat is, de lêste cogfig is in wurdboek mei neamde seksjes, elk fan dat is in wurdboek mei wearden fan ienfâldige typen. En seksjes beskriuwe de konfiguraasje en tagong ta boarnen fan in bepaald type. In foarbyld fan in stik fan ús konfiguraasje:
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"
Tagelyk, it fjild engine
databases kinne wurde ynstallearre op SQLite, en redis
Klear foar mock
, spesifisearje ek de namme fan it te bewarjen bestân - dizze parameters wurde korrekt erkend en ferwurke, wat it maklik makket om de koade lokaal út te fieren foar debuggen, ienheidstesten en alle oare behoeften. Dit is foaral wichtich foar ús, om't d'r in protte oare behoeften binne - in diel fan ús koade is bedoeld foar ferskate analytyske berekkeningen, it rint net allinich op servers mei orkestraasje, mar ek mei ferskate skripts, en op 'e kompjûters fan analysten dy't moatte wurkje troch en debug komplekse gegevensferwurkingspipelines sûnder soargen oer backend-problemen. Trouwens, it soe gjin sear dwaan om te dielen dat ús wichtichste ark, ynklusyf de konfiguraasje-yndielingskoade, binne ynstalleare fia setup.py
- tegearre dit ferieniget ús koade yn ien ekosysteem, ûnôfhinklik fan platfoarm en metoade fan gebrûk.
De beskriuwing fan in Kubernetes-pod sjocht der sa út:
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
Dat is, elk geheim beskriuwt ien seksje. De geheimen sels binne sa makke:
apiVersion: v1
kind: Secret
metadata:
name: db-main-secret
type: Opaque
stringData:
db_main.yaml: |
engine: sqlite
filename: main.sqlite3
Mei-elkoar resultearret dit yn it meitsjen fan YAML-bestannen lâns it paad /etc/secrets/db-main/section_name.yaml
En foar lokale lansearringen wurdt de konfiguraasje brûkt, lizzend yn 'e root-map fan it projekt of lâns it paad spesifisearre yn' e omjouwingsfariabele. De koade ferantwurdlik foar dizze gemak kin sjoen wurde yn 'e spoiler.
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()
De logika hjir is frij simpel: wy kombinearje grutte konfiguraasjes út 'e projektmap en paden troch omjouwingsfariabele, en lytse konfiguraasje-seksjes fan Kuber-geheimen, en ferwurkje se dan in bytsje. Plus guon fariabelen. Ik merk op dat by it sykjen nei triemmen út geheimen, wurdt in djipte beheining brûkt, omdat K8s makket in ferburgen map yn elk geheim dêr't de geheimen sels wurde opslein, en krekt in keppeling leit op in heger nivo.
Ik hoopje dat wat beskreaun wurdt nuttich wêze foar immen :) Alle opmerkings en oanbefellings oangeande feiligens of oare gebieten foar ferbettering wurde akseptearre. De miening fan 'e mienskip is ek nijsgjirrich, miskien is it wurdich stipe ta te foegjen foar ConfigMaps (ús projekt brûkt se noch net) en publisearje de koade op GitHub / PyPI? Persoanlik fyn ik dat sokke dingen te yndividueel binne foar projekten om universeel te wêzen, en in bytsje sjoch nei de ymplemintaasje fan oaren, lykas de hjir jûn, en in diskusje oer nuânses, tips en best practices, dy't ik hoopje te sjen yn 'e kommentaren , is genôch 😉
Allinnich registrearre brûkers kinne meidwaan oan 'e enkête.
Moat ik publisearje as projekt/bibleteek?
-
0,0%Ja, ik soe /contribution0 brûke
-
33,3%Ja, dat klinkt geweldich 4
-
41,7%Nee, wa moat it sels dwaan yn in eigen opmaak en by har behoeften5
-
25,0%Ik sil my ûnthâlde fan antwurd3
12 brûkers stimden. 3 brûkers ûntholden har.
Boarne: www.habr.com