Saya baru-baru ini menulis
Latar belakang dari pertanyaan ini adalah: dahulu kala ada satu proyek, pada awalnya itu adalah sebuah monolit kecil dengan utilitas dan skrip, tetapi seiring waktu berkembang, dibagi menjadi layanan, yang kemudian mulai dibagi menjadi layanan mikro, dan kemudian ditingkatkan. Pada awalnya, semua ini dilakukan pada VPS kosong, proses pengaturan dan penerapan kode diotomatisasi menggunakan Ansible, dan setiap layanan dikompilasi dengan konfigurasi YAML dengan pengaturan dan kunci yang diperlukan, dan file konfigurasi serupa digunakan untuk peluncuran lokal, yang sangat nyaman, karena .k konfigurasi ini dimuat ke dalam objek global, dapat diakses dari mana saja dalam proyek.
Namun, pertumbuhan jumlah layanan mikro, koneksinya, dan
Dalam hal ini, mekanisme untuk membangun objek konfigurasi telah dimodifikasi agar dapat bekerja dengan file konfigurasi klasik kami dan dengan rahasia dari Kuber. Struktur konfigurasi yang lebih kaku juga ditentukan, dalam bahasa Python ketiga, sebagai berikut:
Dikte[str, Dikte[str, Persatuan[str, int, float]]]
Artinya, cogfig terakhir adalah kamus dengan bagian bernama, yang masing-masing merupakan kamus dengan nilai dari tipe sederhana. Dan bagian menjelaskan konfigurasi dan akses ke sumber daya jenis tertentu. Contoh bagian dari 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 saat yang sama, lapangan engine
database dapat diinstal di SQLite, dan redis
mulai mock
, tentukan juga nama file yang akan disimpan - parameter ini dikenali dan diproses dengan benar, sehingga memudahkan menjalankan kode secara lokal untuk debugging, pengujian unit, dan kebutuhan lainnya. Hal ini sangat penting bagi kami karena masih banyak kebutuhan lainnya - sebagian dari kode kami ditujukan untuk berbagai perhitungan analitis, tidak hanya berjalan di server dengan orkestrasi, tetapi juga dengan berbagai skrip, dan di komputer analis yang perlu mengerjakannya. dan men-debug alur pemrosesan data yang kompleks tanpa mengkhawatirkan masalah backend. Omong-omong, tidak ada salahnya untuk berbagi bahwa alat utama kami, termasuk kode tata letak konfigurasi, diinstal melalui setup.py
β secara bersama-sama hal ini menyatukan kode kita ke dalam satu ekosistem, tidak bergantung pada platform dan metode penggunaan.
Deskripsi pod Kubernetes terlihat 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
Artinya, setiap rahasia menjelaskan satu bagian. Rahasianya sendiri dibuat seperti ini:
apiVersion: v1
kind: Secret
metadata:
name: db-main-secret
type: Opaque
stringData:
db_main.yaml: |
engine: sqlite
filename: main.sqlite3
Bersama-sama, hal ini menghasilkan pembuatan file YAML di sepanjang jalur /etc/secrets/db-main/section_name.yaml
Dan untuk peluncuran lokal, konfigurasi digunakan, terletak di direktori root proyek atau di sepanjang jalur yang ditentukan dalam variabel lingkungan. Kode yang bertanggung jawab atas kemudahan ini dapat dilihat di 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()
Logikanya di sini cukup sederhana: kami menggabungkan konfigurasi besar dari direktori proyek dan jalur berdasarkan variabel lingkungan, dan bagian konfigurasi kecil dari rahasia Kuber, lalu memprosesnya sedikit terlebih dahulu. Ditambah beberapa variabel. Saya perhatikan bahwa ketika mencari file dari rahasia, batasan kedalaman digunakan, karena K8s membuat folder tersembunyi di setiap rahasia tempat rahasia itu sendiri disimpan, dan hanya tautan yang terletak di tingkat yang lebih tinggi.
Saya harap apa yang dijelaskan akan bermanfaat bagi seseorang :) Setiap komentar dan rekomendasi mengenai keamanan atau area perbaikan lainnya diterima. Pendapat komunitas juga menarik, mungkin ada baiknya menambahkan dukungan untuk ConfigMaps (proyek kami belum menggunakannya) dan memublikasikan kodenya di GitHub / PyPI? Secara pribadi, menurut saya hal-hal seperti itu terlalu individual untuk proyek menjadi universal, dan sedikit mengintip implementasi orang lain, seperti yang diberikan di sini, dan diskusi tentang nuansa, tip, dan praktik terbaik, yang saya harap dapat dilihat di komentar , sudah cukup π
Hanya pengguna terdaftar yang dapat berpartisipasi dalam survei.
Haruskah saya menerbitkannya sebagai proyek/perpustakaan?
-
0,0%Ya, saya akan menggunakan /contribution0
-
33,3%Ya, kedengarannya bagus4
-
41,7%Tidak, siapa yang perlu melakukannya sendiri dalam formatnya sendiri dan sesuai dengan kebutuhannya5
-
25,0%Saya akan menahan diri untuk tidak menjawab3
12 pengguna memilih. 3 pengguna abstain.
Sumber: www.habr.com