Neseniai rašiau
Klausimo pagrindas yra toks: kažkada buvo vienas projektas, iš pradžių tai buvo nedidelis monolitas su komunalinėmis paslaugomis ir scenarijais, bet laikui bėgant jis išaugo, dalijo į paslaugas, kurios savo ruožtu pradėjo skirstyti į mikropaslaugas ir tada padidintas. Iš pradžių visa tai buvo daroma naudojant tuščią VPS, kurio kodo nustatymo ir diegimo procesai buvo automatizuoti naudojant Ansible, o kiekviena paslauga buvo sudaryta naudojant YAML konfigūraciją su reikalingais nustatymais ir raktais, o panašus konfigūracijos failas buvo naudojamas lokalūs paleidimai, o tai buvo labai patogu, nes .k ši konfigūracija įkeliama į globalų objektą, pasiekiamą iš bet kurios projekto vietos.
Tačiau mikropaslaugų, jų jungčių skaičiaus augimas ir
Šiuo atžvilgiu konfigūracijos objekto kūrimo mechanizmas buvo pakeistas, kad būtų galima dirbti tiek su mūsų klasikiniu konfigūracijos failu, tiek su Kuber paslaptimis. Taip pat buvo nurodyta griežtesnė konfigūracijos struktūra trečiojo Python kalba:
Dict[str, Dict[str, Union[str, int, float]]]
Tai reiškia, kad galutinis krumpliaratis yra žodynas su pavadintais skyriais, kurių kiekvienas yra žodynas su paprastų tipų reikšmėmis. O skyriuose aprašoma tam tikro tipo išteklių konfigūracija ir prieiga prie jų. Mūsų konfigūracijos dalies pavyzdys:
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"
Tuo pačiu ir laukas engine
duomenų bazes galima įdiegti SQLite ir redis
nustatytas į mock
, nurodant ir failo, kurį norite išsaugoti, pavadinimą – šie parametrai yra teisingai atpažįstami ir apdorojami, todėl kodą lengva paleisti vietoje, kad būtų galima derinti, išbandyti vienetus ir bet kokius kitus poreikius. Mums tai ypač svarbu, nes yra daug kitų poreikių – dalis mūsų kodo skirta įvairiems analitiniams skaičiavimams, veikia ne tik serveriuose su orkestravimu, bet ir su įvairiais scenarijais, ir analitikų kompiuteriuose, kuriems reikia dirbti. ir derinti sudėtingus duomenų apdorojimo vamzdynus, nesukeldami rūpesčių dėl foninių problemų. Beje, nepakenktų pasidalinti, kad pagrindiniai mūsų įrankiai, įskaitant konfigūracijos išdėstymo kodą, yra įdiegti per setup.py
– kartu tai sujungia mūsų kodą į vieną ekosistemą, nepriklausomą nuo platformos ir naudojimo būdo.
Kubernetes ankšties aprašymas atrodo taip:
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
Tai yra, kiekviena paslaptis apibūdina vieną skyrių. Pačios paslaptys sukuriamos taip:
apiVersion: v1
kind: Secret
metadata:
name: db-main-secret
type: Opaque
stringData:
db_main.yaml: |
engine: sqlite
filename: main.sqlite3
Kartu tai sukuria YAML failus kelyje /etc/secrets/db-main/section_name.yaml
O vietiniams paleidimams naudojama konfigūracija, esanti projekto šakniniame kataloge arba aplinkos kintamajame nurodytu keliu. Už šiuos patogumus atsakingą kodą galima pamatyti spoileryje.
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 čia gana paprasta: sujungiame dideles konfigūracijas iš projekto katalogo ir kelius pagal aplinkos kintamąjį, o mažas konfigūracijos sekcijas iš Kuber paslapčių, tada šiek tiek iš anksto apdorojame jas. Plius kai kurie kintamieji. Pastebiu, kad ieškant failų iš paslapčių, naudojamas gylio apribojimas, nes K8s kiekvienoje paslaptyje sukuria paslėptą aplanką, kuriame saugomos pačios paslaptys, o tik nuoroda yra aukštesniame lygyje.
Tikiuosi, kas aprašyta bus kam nors naudinga :) Priimamos bet kokios pastabos ir rekomendacijos dėl saugumo ar kitų tobulinimo sričių. Bendruomenės nuomonė taip pat įdomi, galbūt verta pridėti ConfigMaps palaikymą (mūsų projektas jų dar nenaudoja) ir paskelbti kodą GitHub / PyPI? Asmeniškai manau, kad tokie dalykai yra per daug individualūs, kad projektai būtų universalūs, ir šiek tiek žvilgtelėjimas į kitų žmonių įgyvendinimus, kaip čia pateiktas, ir niuansų, patarimų ir geriausios praktikos aptarimas, kurį tikiuosi pamatyti komentaruose , užtenka 😉
Apklausoje gali dalyvauti tik registruoti vartotojai.
Ar turėčiau skelbti kaip projektą / biblioteką?
-
0,0%Taip, naudočiau /contribution0
-
33,3%Taip, tai skamba puikiai 4
-
41,7%Ne, kas turi tai padaryti patiems savo formatu ir pagal savo poreikius5
-
25,0%Susilaikysiu nuo atsakymo3
Balsavo 12 vartotojų. 3 vartotojai susilaikė.
Šaltinis: www.habr.com