Nemrég írtam
A kérdés háttere a következő: valamikor volt egy projekt, eleinte egy kis monolit volt közművekkel és szkriptekkel, de idővel egyre nőtt, szétvált szolgáltatásokra, amiket viszont elkezdtek mikroszolgáltatásokra osztani, ill. majd felnagyítva. Eleinte mindez csupasz VPS-en történt, amelyen a kód beállítási és telepítési folyamatait az Ansible segítségével automatizálták, és minden szolgáltatáshoz YAML konfigurációt fordítottak a szükséges beállításokkal és kulcsokkal, valamint egy hasonló konfigurációs fájlt használtak. lokális indítások, ami nagyon kényelmes volt, mert .k ez a konfiguráció egy globális objektumba van betöltve, a projektben bárhonnan elérhető.
Azonban a mikroszolgáltatások számának növekedése, azok kapcsolatai, ill
Ebben a tekintetben a konfigurációs objektum létrehozásának mechanizmusa módosult, hogy a klasszikus konfigurációs fájlunkkal és a Kuber titkaival is működjön. Egy merevebb konfigurációs szerkezetet is megadtak a harmadik Python nyelvén, az alábbiak szerint:
Dict[str, Dict[str, Union[str, int, float]]]
Vagyis a végső fogaskerék egy szótár névvel ellátott szakaszokkal, amelyek mindegyike egyszerű típusokból származó értékeket tartalmazó szótár. A szakaszok pedig egy bizonyos típusú erőforrások konfigurációját és hozzáférését írják le. Példa a konfigurációnk egy darabjára:
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"
Ugyanakkor a mező engine
adatbázisok telepíthetők SQLite-ra, ill redis
állítva mock
, megadva a mentendő fájl nevét is – ezeket a paramétereket a rendszer helyesen ismeri fel és dolgozza fel, ami megkönnyíti a kód helyi futtatását hibakereséshez, egységteszthez és egyéb igényekhez. Ez különösen fontos számunkra, mert sok más igény is felmerül - a kódunk egy része különféle analitikai számításokhoz készült, nem csak hangszerelésű szervereken fut, hanem különféle szkriptekkel, illetve elemzők számítógépein is, akiknek át kell dolgozniuk. és hibakeresés bonyolult adatfeldolgozási folyamatokban anélkül, hogy aggasztó háttérproblémák kellenek. Egyébként nem ártana megosztani, hogy a fő eszközeink, köztük a konfigurációs elrendezési kód is telepítve van setup.py
– együtt ez egyesíti a kódunkat egyetlen ökoszisztémává, platformtól és felhasználási módtól függetlenül.
A Kubernetes pod leírása így néz ki:
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
Vagyis minden titok egy szakaszt ír le. Maguk a titkok így jönnek létre:
apiVersion: v1
kind: Secret
metadata:
name: db-main-secret
type: Opaque
stringData:
db_main.yaml: |
engine: sqlite
filename: main.sqlite3
Ez együttesen YAML fájlok létrehozását eredményezi az útvonal mentén /etc/secrets/db-main/section_name.yaml
A helyi indításoknál pedig a konfigurációt használják, amely a projekt gyökérkönyvtárában vagy a környezeti változóban megadott útvonalon található. Az ezekért a kényelemért felelős kód a spoilerben látható.
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()
A logika itt meglehetősen egyszerű: a projektkönyvtárból és a környezeti változók szerinti elérési utakból kombináljuk a nagy konfigurációkat, a Kuber-titkok kis konfigurációs szakaszait pedig egy kicsit elődolgozzuk. Plusz néhány változó. Megjegyzem, amikor a titkokból keresünk fájlokat, mélységi korlátozást alkalmazunk, mivel a K8s minden titokban létrehoz egy rejtett mappát, ahol maguk a titkok vannak tárolva, és csak egy hivatkozás található magasabb szinten.
Remélem, a leírtak hasznosak lesznek valakinek :) Bármilyen észrevételt, javaslatot a biztonsággal vagy egyéb fejlesztendő területekkel kapcsolatban szívesen fogadunk. A közösség véleménye is érdekes, talán érdemes a ConfigMaps támogatását hozzáadni (projektünk még nem használja), és a kódot GitHubon / PyPI-n közzétenni? Személy szerint úgy gondolom, hogy ezek a dolgok túl egyéniek ahhoz, hogy a projektek univerzálisak legyenek, és egy kis bepillantás mások megvalósításaiba, mint amilyen az itt található, és árnyalatok, tippek és legjobb gyakorlatok megbeszélése, amit remélem látni fogok a megjegyzésekben , elég 😉
A felmérésben csak regisztrált felhasználók vehetnek részt.
Projektként/könyvtárként publikáljak?
-
0,0%Igen, a /contribution0-t használnám
-
33,3%Igen, ez jól hangzik 4
-
41,7%Nem, kinek kell saját formátumában és igényeinek megfelelően megtennie5
-
25,0%Eltekintek a válaszadástól3
12 felhasználó szavazott. 3 felhasználó tartózkodott.
Forrás: will.com