Hiljuti kirjutasin , kus mainisin korra, et on vĂ”imalik luua oma konfiguratsioonisĂŒsteem, et teenus töötaks hĂ€sti ka Kubernetesis, tĂ”mbaks saladusi ja kĂ€ivitataks mugavalt ka lokaalselt, sealhulgas tĂ€iesti vĂ€ljaspool Dockeri. Midagi keerulist ei ole, aga kirjeldatud "retsept" vĂ”ib kellelegi abiks olla đ Kood on Pythonis, kuid loogika ei ole keelele omane.

KĂŒsimuse taust on jĂ€rgmine: elas-oli ĂŒks projekt, alguses oli see vĂ€ike monoliit utiliitide ja skriptidega, kuid aja jooksul kasvas, jagunes teenusteks, mis omakorda hakkasid jagunema mikroteenusteks ja seejĂ€rel veel ka skaleeruma. Alguses tehti see kĂ”ik tĂŒhjades VPS-des, nende seadistamise ja koodi juurutamise protsessid olid automatiseeritud Ansible'i abil ning igale teenusele koostati YAML-konfiguratsioon vajalike seadistuste ja vĂ”tmetega, ja sarnast konfigureerimisfaili kasutati lokaalseteks kĂ€ivitamisteks, mis oli vĂ€ga mugav, kuna see konfigureerimisfail laaditi globaalsetesse objektidesse, mis on saadaval igas projekti kohas.
Kuid mikroteenuste arvu, nende omavaheliste seoste ja samuti , eeldasid kolimist Kubernetesse, mis on endiselt protsessis. Kui abistatakse nende ĂŒlesannete lahendamisel, pakub Kubernetes ka oma lĂ€henemisviise infrastruktuuri haldamiseks, sealhulgas ja . Mehhanism on standardselt usaldusvÀÀrne, seega on tĂ”eliselt patt seda mitte kasutada! Kuid samas tahaks sĂ€ilitada oma praeguse töövormi konfiguratsiooni osas: esiteks, ĂŒhtlaselt kasutada seda erinevates projekti mikroteenustes, ja teiseks, saada kĂ€ivitada koodi kohaliku masina peal, kasutades ĂŒhte lihtsat konfigureerimisfaili.
SeetÔttu oli objekti konfiguratsiooni mehhanismi kohandatud nii, et see suudaks töötada nii meie klassikalise konfigureerimisfailiga kui ka Kubernetist saadud saladustega. Samuti kehtestati rangem konfiguratsiooni struktuur, rÀÀkides kolmandast Pythonist, selline:
Dict[str, Dict[str, Union[str, int, float]]]
See tĂ€hendab, et lĂ”plik konfiguratsioon on sĂ”nastik nimetatud sektsioonidega, millest igaĂŒks on sĂ”nastik lihtsate tĂŒĂŒpide vÀÀrtustega. Ja sektsioonid kirjeldavad konfiguratsiooni ja juurdepÀÀsu teatud tĂŒĂŒpi ressurssidele. NĂ€ide meie konfiguratsiooni osast:
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"Sel juhul vĂ€li engine andmebaasi saab seadistada SQLite'le, kuid redis konfigureerida mock, mÀÀrates ka salvestamiseks faili nime â need parameetrid tuvastatakse ja töödeldakse Ă”igesti, mis vĂ”imaldab koodi lihtsalt kohapeal kĂ€ivitada, et debugida, teha ĂŒksusteste ja muid vajadusi. See on meile eriti oluline, kuna neid muid vajadusi on palju â osa meie koodist on mĂ”eldud mitmesuguste analĂŒĂŒtiliste arvutuste tegemiseks, seda kĂ€ivitatakse mitte ainult orkestreerimisega serverites, vaid ka erinevate skriptide ja analĂŒĂŒtikute arvutites, kes peavad tegelema ja debugima keerulisi andmete töötlemise torujuhtmeid, mitte muretsema backend-kĂŒsimustele. Ăks huvitav asi, mida jagada, on see, et meie peamised tööriistad, sealhulgas konfi-kodeerimise kood, paigaldatakse lĂ€bi setup.py â need ĂŒhtlustavad meie koodi ĂŒheks ökosĂŒsteemiks, mis ei sĂ”ltu platvormist ja kasutusviisist.
Kuberneteses on poda kirjeldus 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 iga saladuse sees on kirjas ĂŒks sektsioon. Saladusi luuakse nii:
apiVersion: v1
kind: Secret
metadata:
name: db-main-secret
type: Opaque
stringData:
db_main.yaml: |
engine: sqlite
filename: main.sqlite3See kÔik viib XML-failide loomisele teel /etc/secrets/db-main/section_name.yaml
Ja kohalike kÀivituste jaoks kasutatakse konfi, mis asub projekti juurkataloogis vÔi teel, mis on mÀÀratud keskkonnamuutuja kaudu. Kood, mis sellele mugavusele vastab, 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):
'''
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()Loogika on siin ĂŒsna lihtne: koondame suurte konfiguratsioonifailide sealt, kus on projekti direktor, ja teelt keskkonnamuutuja kaudu, ning vĂ€ikeste sektsioonide konfiguratsioonid Kuberneteisest, seejĂ€rel töötleme neid natuke ette. Lisaks mĂ”ned muutujad. Tahan mĂ€rkida, et salajaste failide otsimisel kasutatakse sĂŒgavuse piirangut, kuna K8s loob igas salas veel ĂŒhe peidetud kausta, kus saladused ise asuvad, ja ĂŒhe taseme vĂ”rra ĂŒlespoole asub lihtsalt link.
Loodan, et antud teave on kellelegi kasulik đ Ootame igasuguseid kommentaare ja soovitusi turvalisuse vĂ”i muude parenduste osas. Samuti huvitab, mida arvab kogukond, kas vĂ”iks lisada ConfigMapide toe (meie projektis need hetkel ei ole kasutuses) ja kas koodi tuleks vormistada GitHubis / PyPI-s? Isiklikult arvan, et sellised asjad on projektide jaoks liiga individuaalsed, et olla universaalsed, ja piisab, kui heita pilk teiste elluviimisele, nagu siin toodud, ning arutada nĂŒansse, soovitusi ja parimaid praktikaid, mida loodan nĂ€ha kommentaarides đ
Ainult registreeritud kasutajad saavad kĂŒsitluses osaleda. , palun.
Kas tasub avaldada projektina / teegina?
0,0%Jah, ma kasutaksin / panustaksin
33,3%Jah, see kÔlab hÀsti
41,7%Ei, kellel on vajadus, teeb ise oma formaadis ja endale sobivalt
25,0%Pean vastamata jÀÀma
HÀÀletas 12 kasutajat. 3 kasutajat hoidusid.
Allikas: habr.com
