Kohët e fundit kam shkruar
Sfondi i pyetjes është ky: një herë e një kohë kishte një projekt, në fillim ishte një monolit i vogël me shërbime dhe skripta, por me kalimin e kohës u rrit, u nda në shërbime, të cilat nga ana e tyre filluan të ndaheshin në mikroshërbime, dhe pastaj u përshkallëzua. Në fillim, e gjithë kjo u bë në VPS të zhveshur, proceset e konfigurimit dhe vendosjes së kodit në të cilin u automatizuan duke përdorur Ansible, dhe secili shërbim u përpilua me një konfigurim YAML me cilësimet dhe çelësat e nevojshëm, dhe një skedar i ngjashëm konfigurimi u përdor për niset lokale, gjë që ishte shumë e përshtatshme, sepse .k ky konfigurim ngarkohet në një objekt global, i aksesueshëm nga kudo në projekt.
Megjithatë, rritja e numrit të mikroshërbimeve, lidhjeve të tyre dhe
Në këtë drejtim, mekanizmi për ndërtimin e një objekti konfigurimi u modifikua për të qenë në gjendje të punojë si me skedarin tonë të konfigurimit klasik ashtu edhe me sekretet nga Kuber. Një strukturë më e ngurtë konfigurimi u specifikua gjithashtu, në gjuhën e Python-it të tretë, si më poshtë:
Dict[str, Dict[str, Union[str, int, float]]]
Kjo do të thotë, cogfig-u përfundimtar është një fjalor me seksione të emërtuara, secila prej të cilave është një fjalor me vlera nga lloje të thjeshta. Dhe seksionet përshkruajnë konfigurimin dhe aksesin në burimet e një lloji të caktuar. Një shembull i një pjese të konfigurimit tonë:
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"
Në të njëjtën kohë, fusha engine
bazat e të dhënave mund të instalohen në SQLite, dhe redis
vendosur në mock
, duke specifikuar edhe emrin e skedarit që do të ruhet - këto parametra njihen dhe përpunohen saktë, gjë që e bën të lehtë ekzekutimin e kodit në nivel lokal për korrigjimin e gabimeve, testimin e njësisë dhe çdo nevojë tjetër. Kjo është veçanërisht e rëndësishme për ne sepse ka shumë nevoja të tjera - një pjesë e kodit tonë është menduar për llogaritje të ndryshme analitike, ai funksionon jo vetëm në serverë me orkestrim, por edhe me skripta të ndryshëm, dhe në kompjuterët e analistëve që duhet të punojnë përmes dhe korrigjoni tubacionet komplekse të përpunimit të të dhënave pa shqetësuese problemet e backend. Nga rruga, nuk do të dëmtonte të ndajmë që mjetet tona kryesore, duke përfshirë kodin e paraqitjes së konfigurimit, janë instaluar nëpërmjet setup.py
– së bashku kjo bashkon kodin tonë në një ekosistem të vetëm, të pavarur nga platforma dhe mënyra e përdorimit.
Përshkrimi i një pod Kubernetes duket si ky:
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
Kjo do të thotë, çdo sekret përshkruan një pjesë. Vetë sekretet krijohen si kjo:
apiVersion: v1
kind: Secret
metadata:
name: db-main-secret
type: Opaque
stringData:
db_main.yaml: |
engine: sqlite
filename: main.sqlite3
Së bashku kjo rezulton në krijimin e skedarëve YAML përgjatë rrugës /etc/secrets/db-main/section_name.yaml
Dhe për nisjet lokale, përdoret konfigurimi, i vendosur në direktorinë rrënjë të projektit ose përgjatë shtegut të specifikuar në variablin e mjedisit. Kodi përgjegjës për këto lehtësi mund të shihet në 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()
Logjika këtu është mjaft e thjeshtë: ne kombinojmë konfigurime të mëdha nga direktoria e projektit dhe shtigjet sipas ndryshores së mjedisit, dhe seksione të vogla konfigurimi nga sekretet e Kuber, dhe më pas i përpunojmë ato pak. Plus disa variabla. Vërej se kur kërkoni skedarë nga sekretet, përdoret një kufizim i thellësisë, sepse K8s krijon një dosje të fshehur në secilën sekret ku ruhen vetë sekretet, dhe vetëm një lidhje ndodhet në një nivel më të lartë.
Shpresoj që ajo që përshkruhet do të jetë e dobishme për dikë :) Çdo koment dhe rekomandim në lidhje me sigurinë ose fusha të tjera për përmirësim pranohet. Mendimi i komunitetit është gjithashtu interesant, ndoshta ia vlen të shtohet mbështetje për ConfigMaps (projekti ynë nuk i përdor ende ato) dhe të publikojë kodin në GitHub / PyPI? Personalisht, mendoj se gjëra të tilla janë shumë individuale që projektet të jenë universale, dhe pak vështrim në zbatimet e njerëzve të tjerë, si ky i dhënë këtu, dhe një diskutim për nuancat, këshillat dhe praktikat më të mira, të cilat shpresoj t'i shoh në komente. , mjafton 😉
Vetëm përdoruesit e regjistruar mund të marrin pjesë në anketë.
A duhet të botoj si projekt/bibliotekë?
-
0,0%Po, do të përdorja /contribution0
-
33,3%Po, kjo tingëllon mirë4
-
41,7%Jo, kush duhet ta bëjë vetë në formatin e tij dhe për t'iu përshtatur nevojave të tij5
-
25,0%Do të përmbahem nga përgjigjja3
12 përdorues votuan. 3 përdorues abstenuan.
Burimi: www.habr.com