لقد كتبت مؤخرا
خلفية السؤال هي كما يلي: ذات مرة كان هناك مشروع واحد، في البداية كان عبارة عن كتلة صغيرة بها أدوات مساعدة ونصوص، ولكن مع مرور الوقت نمت، مقسمة إلى خدمات، والتي بدورها بدأت تنقسم إلى خدمات صغيرة، و ثم تم تحجيمها. في البداية، تم كل هذا على VPS، حيث تمت عمليات إعداد ونشر التعليمات البرمجية تلقائيًا باستخدام Ansible، وتم تجميع كل خدمة بتكوين YAML مع الإعدادات والمفاتيح اللازمة، وتم استخدام ملف تكوين مماثل لـ عمليات الإطلاق المحلية، والتي كانت مريحة للغاية، لأنه يتم تحميل هذا التكوين في كائن عام، ويمكن الوصول إليه من أي مكان في المشروع.
ومع ذلك، فإن النمو في عدد الخدمات الصغيرة واتصالاتها و
في هذا الصدد، تم تعديل آلية إنشاء كائن التكوين لتتمكن من العمل مع ملف التكوين الكلاسيكي الخاص بنا ومع الأسرار من Kuber. تم أيضًا تحديد بنية تكوين أكثر صرامة، بلغة بايثون الثالثة، على النحو التالي:
Dict[str، Dict[str، Union[str، int، float]]]
أي أن التكوين النهائي عبارة عن قاموس يحتوي على أقسام مسماة، كل منها عبارة عن قاموس يحتوي على قيم من أنواع بسيطة. وتصف الأقسام التكوين والوصول إلى الموارد من نوع معين. مثال على جزء من التكوين لدينا:
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"
وفي نفس الوقت الميدان engine
يمكن تثبيت قواعد البيانات على SQLite، و redis
ضبط ل mock
، مع تحديد أيضًا اسم الملف المراد حفظه - يتم التعرف على هذه المعلمات ومعالجتها بشكل صحيح، مما يجعل من السهل تشغيل التعليمات البرمجية محليًا لتصحيح الأخطاء واختبار الوحدة وأي احتياجات أخرى. هذا مهم بشكل خاص بالنسبة لنا نظرًا لوجود العديد من الاحتياجات الأخرى - جزء من الكود الخاص بنا مخصص لإجراء حسابات تحليلية مختلفة، فهو لا يعمل فقط على الخوادم المنسقة، ولكن أيضًا مع البرامج النصية المختلفة، وعلى أجهزة الكمبيوتر الخاصة بالمحللين الذين يحتاجون إلى العمل من خلال وتصحيح مسارات معالجة البيانات المعقدة دون القلق بشأن مشكلات الواجهة الخلفية. بالمناسبة، لن يضرنا أن نشارك أن أدواتنا الرئيسية، بما في ذلك رمز تخطيط التكوين، يتم تثبيتها عبر setup.py
- يعمل هذا معًا على توحيد الكود الخاص بنا في نظام بيئي واحد، مستقل عن النظام الأساسي وطريقة الاستخدام.
يبدو وصف جراب Kubernetes كما يلي:
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
أي أن كل سر يصف قسمًا واحدًا. يتم إنشاء الأسرار نفسها على النحو التالي:
apiVersion: v1
kind: Secret
metadata:
name: db-main-secret
type: Opaque
stringData:
db_main.yaml: |
engine: sqlite
filename: main.sqlite3
يؤدي هذا معًا إلى إنشاء ملفات YAML على طول المسار /etc/secrets/db-main/section_name.yaml
وبالنسبة لعمليات الإطلاق المحلية، يتم استخدام التكوين الموجود في الدليل الجذر للمشروع أو على طول المسار المحدد في متغير البيئة. يمكن رؤية الكود المسؤول عن وسائل الراحة هذه في المفسد.
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()
المنطق هنا بسيط للغاية: نقوم بدمج التكوينات الكبيرة من دليل المشروع والمسارات حسب متغير البيئة، وأقسام التكوين الصغيرة من أسرار Kuber، ثم نقوم بمعالجتها مسبقًا قليلاً. بالإضافة إلى بعض المتغيرات. ألاحظ أنه عند البحث عن الملفات من الأسرار، يتم استخدام قيود العمق، لأن K8s يقوم بإنشاء مجلد مخفي في كل سر، حيث يتم تخزين الأسرار نفسها، ويوجد رابط فقط على مستوى أعلى.
آمل أن يكون ما تم وصفه مفيدًا لشخص ما :) يتم قبول أي تعليقات وتوصيات بخصوص الأمان أو مجالات التحسين الأخرى. رأي المجتمع مثير للاهتمام أيضًا، ربما يستحق إضافة دعم لـ ConfigMaps (مشروعنا لا يستخدمها بعد) ونشر الكود على GitHub / PyPI؟ أنا شخصياً أعتقد أن مثل هذه الأشياء فردية جدًا بحيث لا يمكن أن تكون المشاريع عالمية، وإلقاء نظرة خاطفة قليلاً على تطبيقات الآخرين، مثل تلك المذكورة هنا، ومناقشة الفروق الدقيقة والنصائح وأفضل الممارسات، والتي آمل أن أراها في التعليقات يكفي😉
يمكن للمستخدمين المسجلين فقط المشاركة في الاستطلاع.
هل يجب أن أنشر كمشروع/مكتبة؟
-
0,0%نعم، سأستخدم /contribution0
-
33,3%نعم، هذا يبدو عظيما4
-
41,7%لا، من يحتاج إلى القيام بذلك بنفسه بالشكل الذي يناسبه وبما يتناسب مع احتياجاته5
-
25,0%سأمتنع عن الرد 3
صوت 12 مستخدمًا. امتنع 3 مستخدما عن التصويت.
المصدر: www.habr.com