Mi ĵus skribis
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
Ĉ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.
Ĉ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