yakın zamanda yazdım
Sorunun arka planı şu: Bir zamanlar bir proje vardı, ilk başta yardımcı programlar ve komut dosyaları içeren küçük bir monolitti, ancak zamanla büyüdü, hizmetlere bölündü ve bunlar da mikro hizmetlere bölünmeye başladı ve sonra büyütüldü. İlk başta tüm bunlar, Ansible kullanılarak otomatikleştirilen kod kurma ve dağıtma işlemleri olan çıplak VPS üzerinde yapıldı ve her hizmet, gerekli ayarlar ve anahtarlar içeren bir YAML yapılandırmasıyla derlendi ve benzer bir yapılandırma dosyası kullanıldı. yerel başlatmalar, bu çok kullanışlıydı çünkü .k bu yapılandırma, projenin herhangi bir yerinden erişilebilen global bir nesneye yüklendi.
Ancak mikro hizmetlerin sayısındaki, bağlantılarındaki ve
Bu bağlamda, bir konfigürasyon nesnesi oluşturma mekanizması, hem klasik konfigürasyon dosyamızla hem de Kuber'in sırlarıyla çalışabilecek şekilde değiştirildi. Üçüncü Python dilinde daha katı bir yapılandırma yapısı da şu şekilde belirtildi:
Dict[str, Dict[str, Union[str, int, float]]]
Yani, son cogfig, her biri basit türlerden değerler içeren bir sözlük olan, adlandırılmış bölümlere sahip bir sözlüktür. Bölümler ise belirli bir türdeki kaynakların yapılandırmasını ve erişimini açıklar. Yapılandırmamızın bir parçasına bir örnek:
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"
Aynı zamanda saha engine
veritabanları SQLite'a kurulabilir ve redis
ayarlanır mock
, kaydedilecek dosyanın adını da belirterek - bu parametreler doğru bir şekilde tanınır ve işlenir; bu, hata ayıklama, birim testi ve diğer ihtiyaçlar için kodun yerel olarak çalıştırılmasını kolaylaştırır. Bu bizim için özellikle önemli çünkü başka birçok ihtiyaç var - kodumuzun bir kısmı çeşitli analitik hesaplamalar için tasarlandı, yalnızca düzenlemeli sunucularda değil, aynı zamanda çeşitli komut dosyalarıyla ve üzerinde çalışması gereken analistlerin bilgisayarlarında da çalışıyor. ve arka uç sorunlarından endişe etmeden karmaşık veri işleme hatlarında hata ayıklayın. Bu arada, config düzen kodu da dahil olmak üzere ana araçlarımızın, aracılığıyla kurulduğunu paylaşmaktan zarar gelmez. setup.py
– bu, kodumuzu platformdan ve kullanım yönteminden bağımsız olarak tek bir ekosistemde birleştirir.
Kubernetes bölmesinin açıklaması şuna benzer:
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
Yani her sır bir bölümü anlatır. Sırların kendisi şu şekilde yaratılmıştır:
apiVersion: v1
kind: Secret
metadata:
name: db-main-secret
type: Opaque
stringData:
db_main.yaml: |
engine: sqlite
filename: main.sqlite3
Bu, yol boyunca YAML dosyalarının oluşturulmasıyla sonuçlanır. /etc/secrets/db-main/section_name.yaml
Yerel başlatmalar için, projenin kök dizininde veya ortam değişkeninde belirtilen yol boyunca bulunan yapılandırma kullanılır. Bu kolaylıklardan sorumlu olan kod spoilerde görülebilir.
yapılandırma.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()
Buradaki mantık oldukça basittir: proje dizinindeki büyük yapılandırmaları ve ortam değişkenine göre yolları ve Kuber sırlarından küçük yapılandırma bölümlerini birleştirip ardından bunları biraz önceden işliyoruz. Ayrıca bazı değişkenler. Sırlardan dosya ararken derinlik sınırlamasının kullanıldığını unutmayın, çünkü K8'ler her sırda sırların depolandığı gizli bir klasör oluşturur ve yalnızca bir bağlantı daha yüksek bir seviyede bulunur.
Umarım anlatılanlar birilerine faydalı olur :) Güvenlik veya diğer iyileştirme alanlarıyla ilgili her türlü yorum ve öneri kabul edilir. Topluluğun görüşü de ilginç, belki ConfigMaps için destek eklemeye (projemiz henüz bunları kullanmıyor) ve kodu GitHub / PyPI'de yayınlamaya değer mi? Şahsen, bu tür şeylerin projelerin evrensel olamayacak kadar bireysel olduğunu ve burada verilen gibi diğer insanların uygulamalarına biraz göz atmayı ve yorumlarda görmeyi umduğum nüanslar, ipuçları ve en iyi uygulamalara dair bir tartışma olduğunu düşünüyorum. , yeter 😉
Ankete sadece kayıtlı kullanıcılar katılabilir.
Proje/kütüphane olarak yayınlamalı mıyım?
-
%0,0Evet, /contribution0'ı kullanırdım
-
%33,3Evet, kulağa harika geliyor4
-
%41,7Hayır, kimin kendi formatında ve ihtiyaçlarına göre bunu yapması gerekiyor5
-
%25,0Cevap vermekten kaçınacağım3
12 kullanıcı oy kullandı. 3 kullanıcı çekimser kaldı.
Kaynak: habr.com