Saya baru-baru ini menulis
Latar belakang kepada soalan ini ialah: pada suatu masa dahulu terdapat satu projek, pada mulanya ia adalah monolit kecil dengan utiliti dan skrip, tetapi dari masa ke masa ia berkembang, dibahagikan kepada perkhidmatan, yang seterusnya mula dibahagikan kepada perkhidmatan mikro, dan kemudian diperbesarkan. Pada mulanya, semua ini dilakukan pada VPS kosong, proses penyediaan dan penggunaan kod yang diautomatikkan menggunakan Ansible, dan setiap perkhidmatan telah disusun dengan konfigurasi YAML dengan tetapan dan kunci yang diperlukan, dan fail konfigurasi yang serupa digunakan untuk pelancaran tempatan, yang sangat mudah, kerana .k konfigurasi ini dimuatkan ke dalam objek global, boleh diakses dari mana-mana sahaja dalam projek.
Walau bagaimanapun, pertumbuhan dalam bilangan perkhidmatan mikro, sambungannya dan
Dalam hal ini, mekanisme untuk membina objek konfigurasi telah diubah suai untuk dapat berfungsi dengan fail konfigurasi klasik kami dan dengan rahsia daripada Kuber. Struktur konfigurasi yang lebih tegar juga ditentukan, dalam bahasa Python ketiga, seperti berikut:
Dict[str, Dict[str, Union[str, int, float]]]
Iaitu, cogfig terakhir ialah kamus dengan bahagian bernama, setiap satunya adalah kamus dengan nilai daripada jenis mudah. Dan bahagian menerangkan konfigurasi dan akses kepada sumber jenis tertentu. Contoh sekeping konfigurasi kami:
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"
Pada masa yang sama, padang engine
pangkalan data boleh dipasang pada SQLite, dan redis
ditetapkan untuk mock
, menyatakan juga nama fail untuk disimpan - parameter ini diiktiraf dan diproses dengan betul, yang memudahkan untuk menjalankan kod secara setempat untuk penyahpepijatan, ujian unit dan sebarang keperluan lain. Ini amat penting bagi kami kerana terdapat banyak keperluan lain - sebahagian daripada kod kami bertujuan untuk pelbagai pengiraan analitikal, ia berjalan bukan sahaja pada pelayan dengan orkestrasi, tetapi juga dengan pelbagai skrip, dan pada komputer penganalisis yang perlu bekerja melalui dan nyahpepijat saluran pemprosesan data yang kompleks tanpa membimbangkan isu bahagian belakang. Dengan cara ini, tidak salah untuk berkongsi bahawa alat utama kami, termasuk kod susun atur konfigurasi, dipasang melalui setup.py
β bersama-sama ini menyatukan kod kami menjadi satu ekosistem, bebas daripada platform dan kaedah penggunaan.
Perihalan pod Kubernetes kelihatan seperti ini:
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
Iaitu, setiap rahsia menerangkan satu bahagian. Rahsia itu sendiri dicipta seperti ini:
apiVersion: v1
kind: Secret
metadata:
name: db-main-secret
type: Opaque
stringData:
db_main.yaml: |
engine: sqlite
filename: main.sqlite3
Bersama-sama ini menghasilkan penciptaan fail YAML di sepanjang laluan /etc/secrets/db-main/section_name.yaml
Dan untuk pelancaran tempatan, konfigurasi digunakan, terletak dalam direktori akar projek atau sepanjang laluan yang ditentukan dalam pembolehubah persekitaran. Kod yang bertanggungjawab untuk kemudahan ini boleh dilihat dalam spoiler.
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()
Logiknya di sini agak mudah: kami menggabungkan konfigurasi besar daripada direktori projek dan laluan mengikut pembolehubah persekitaran, dan bahagian konfigurasi kecil daripada rahsia Kuber, dan kemudian memprosesnya sedikit. Ditambah beberapa pembolehubah. Saya perhatikan bahawa apabila mencari fail dari rahsia, had kedalaman digunakan, kerana K8s mencipta folder tersembunyi dalam setiap rahsia di mana rahsia itu sendiri disimpan, dan hanya pautan terletak pada tahap yang lebih tinggi.
Saya harap apa yang diterangkan akan berguna kepada seseorang :) Sebarang komen dan cadangan mengenai keselamatan atau bidang lain untuk penambahbaikan diterima. Pendapat komuniti juga menarik, mungkin ia patut menambah sokongan untuk ConfigMaps (projek kami belum menggunakannya lagi) dan menerbitkan kod di GitHub / PyPI? Secara peribadi, saya berpendapat bahawa perkara sedemikian terlalu individu untuk projek menjadi universal, dan sedikit mengintip pelaksanaan orang lain, seperti yang diberikan di sini, dan perbincangan tentang nuansa, petua dan amalan terbaik, yang saya harap dapat dilihat dalam ulasan , cukuplah π
Hanya pengguna berdaftar boleh mengambil bahagian dalam tinjauan.
Perlukah saya menerbitkan sebagai projek/perpustakaan?
-
0,0% Ya, saya akan menggunakan /contribution0
-
33,3% Ya, bunyinya bagus4
-
41,7% Tidak, siapa yang perlu melakukannya sendiri dalam format mereka sendiri dan untuk memenuhi keperluan mereka5
-
25,0% Saya akan menahan diri daripada menjawab3
12 pengguna mengundi. 3 pengguna berpantang.
Sumber: www.habr.com