Hiljuti kirjutasin , kus mainisin, et võite luua oma konfiguratsioonisüsteemi, et teenus töötaks hästi ka Kubernetes'is, tõmbaks salasõnu ja tööle hakkaks mugavalt ka väljaspool Dockersit. Midagi keerulist ei ole, kuid kirjeldatud "retsept" võib kedagi huvitada 🙂 Kood on Pythonis, kuid loogika ei ole seotud keelekindlusega.

Küsimuse eellugu on selline: elas-olles oli üks projekt, alguses oli see väike monoliit koos utiliidid ja skriptidega, kuid aja jooksul kasvas see, jagunes teenusteks, mis omakorda hakkasid jagunema mikroteenusteks, ning seejärel ka skaleeruma. Alguses toimus see kõik tühjadel VPS-idel, mille seadistus- ja juurutamisprotsessid automatiseeriti Ansible'i abil, ning igale teenusele koostati YAML-konfiguratsioon vajalike seadete ja võtmetega, ning sarnast konfiguratsioonifaili kasutati ka kohalikeks käivitusteks, mis oli väga mugav, kuna see konfiguratsioon laaditakse globaalsete objektide sisse, mis on projekti igast kohast ligipääsetavad.
Kuid mikroteenuste arvu, nende seoste ja samuti , mis ennustas üleminekut Kubernetesesse, mis on endiselt käimas. Lisaks abile nende ülesannete lahendamisel pakub Kubernetes ka oma lähenemisviise infrastruktuuri haldamiseks, sealhulgas ja . Mehhanism on standardne ja usaldusväärne, seega on sõna otseses mõttes patt seda mitte kasutada! Samas sooviksin säilitada oma praeguse tööformaat konfiguratsiooniga: esiteks, kasutada seda ühtlaselt erinevates mikroteenustes projektis ja teiseks, omada võimalust käivitada kood kohalikul masinal, kasutades ühte lihtsat konfiguratsioonifaili.
Selle tõttu on objekti konfiguratsiooni loomise mehhanismi täiustatud, et see saaks töötada nii meie klassikalise konfiguratsioonifaili kui ka Kubernetesest pärit saladustega. Samuti on seatud rangem konfiguratsiooni struktuur, nagu kolmandas Pythoni keeles, järgmine:
Dict[str, Dict[str, Union[str, int, float]]]
See, the final config is a dictionary with named sections, each of which is a dictionary with values of simple types. The sections describe the configuration and access to resources of a certain type. Here’s an example snippet of our config:
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: info@test.com
pw: "SuperHardPassword"At the same time, the field engine of the databases can be set to SQLite, while redis can be configured to mock, märkides ära ka faili nime salvestamiseks, – need parameetrid tuvastatakse ja töödeldakse korrektselt, võimaldades koodi kohalikku käivitamist silumiseks, üksuse testimiseks ja muude vajaduste jaoks. See on meie jaoks eriti oluline, kuna neid muid vajadusi on palju – osa meie koodist on mõeldud erinevate analüütiliste arvutuste tegemiseks, seda käitatakse mitte ainult orkestreeritud serverites, vaid ka erinevate skriptide ja analüütikute arvutites, kellel on vaja töötada välja ja siluda keerulisi andmetöötluse voosid ilma tagaplaneerimise küsimustest muretsemata. Ühtlasi pole üleliigne jagada, et meie peamised tööriistad, sealhulgas konfiguratsioonifaili koostamise kood, installitakse läbi setup.py – koos see ühendab meie koodi üheks ökosüsteemiks, sõltumatuks platvormist ja kasutamisviisist.
Pod'i kirjeldus Kuberneteses näeb välja järgmine:
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-secretSee tähendab, et igas salajastes on üks jaotus. Salajased ise luuakse nii:
apiVersion: v1
kind: Secret
metadata:
name: db-main-secret
type: Opaque
stringData:
db_main.yaml: |
engine: sqlite
filename: main.sqlite3Koos see viib YAML-failide loomise juurde asukohas /etc/secrets/db-main/section_name.yaml
Kohalikeks käivitusteks kasutatakse konfiguratsiooni, mis asub projekti juurdirektoris või asukohas, mis on märgitud keskkonnamuutujas. Kood, mis vastutab nende mugavuste eest, on nähtav spoileris.
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):
'''
Parsee YAML konfiguratsioon mitme sektsiooniga
'''
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):
'''
Parsee YAML konfiguratsioon ühe sektsiooniga
'''
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 = {
# Debugige konfiguratsiooni laadimise koodi
KEY_LOG: [],
# Debugige teisi koode
KEY_DBG: is_yes(os.environ.get('DEBUG')),
}
# Lihtsate kohalike käituste jaoks
CONFIG_SIMPLE = os.path.join(PROJECT_DIR, 'config.yaml')
parse_big_config(config, CONFIG_SIMPLE)
# Konteinerite testide jaoks
CONFIG_ENVVAR = os.environ.get('CONFIG')
if CONFIG_ENVVAR is not None:
if not parse_big_config(config, CONFIG_ENVVAR):
raise ValueError(
f'Konfiguratsioonifaili ei leitud EnvVar: n'
f'{CONFIG_ENVVAR}'
)
# K8s saladuste jaoks
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()
# Eeltöötlus
for key, data in config.items():
if key.startswith('db_'):
if data['engine'] == 'sqlite':
data['filename'] = os.path.join(PROJECT_DIR, data['filename'])
# Õiguse verifitseerimiseks
if config[KEY_DBG]:
print(f'** Laaditud konfiguratsioon: n{yaml.dump(config)}')
else:
print(f'** Laaditud konfiguratsioon: {config[KEY_LOG]}')
return config
config = build_config()Siin on loogika tõeliselt lihtne: ühendame suurte konfigureerimiste failid projektikaustast ja keskkonna muutujatest, samuti väikesed konfiguratsioonisektsioonid Kubernetes'i saladustest, ning seejärel töötame need veidi ette. Lisaks mõned muutujad. Tõmbenäiteks, kui otsida faile saladustest, rakendatakse sügavuse piiri, kuna K8s loob igas saladuses veel peidetud kausta, kus saladused endid hoiustada, ja ühel tasemel üleval on lihtsalt link.
Loodan, et see kirjeldus osutub kellelegi kasulikuks 🙂 Ootan kõiki kommentaare ja soovitusi, mis puudutavad turvalisust või muid parendusi. Ka huvitab mind kogukonna arvamus, kas oleks mõistlik lisada ConfigMap'i tugi (meie projektis neid veel ei kasutata) ja avaldada kood GitHubis / PyPI-s? Isiklikult arvan, et sellised asjad on projektide jaoks liiga individuaalsed, et need saaksid universaalsed, ja piisab väikesest piilumisest teiste rakendustesse, nagu siin välja toodud, ning aruteludest nüansside, soovituste ja parimate praktikate üle, mida loodan kommentaarides näha 😉
Ainult registreeritud kasutajad saavad küsitluses osaleda. , palun.
Kas on mõtet avaldada projektina/raamatukoguna?
0,0%Jah, ma kasutaksin ja panustaksin.
33,3%Jah, see kõlab suurepäraselt.
41,7%Ei, kellelgi on niikuinii vaja teha oma formaadis ja vajadustele vastavalt.
25,0%Jätan vastamata.
Hääletas 12 kasutajat. Jätkuvalt 3 kasutajat.
Allikas: habr.com
