پیکربندی پروژه در داخل و خارج از Kubernetes

اخیرا نوشتم پاسخ در مورد عمر پروژه در داکر و اشکال زدایی کد خارج از آن، جایی که او به طور خلاصه اشاره کرد که می توانید سیستم پیکربندی خود را بسازید تا سرویس در Kuber به خوبی کار کند، اسرار را کشف کند و به راحتی به صورت محلی اجرا شود، حتی در کل خارج از Docker. هیچ چیز پیچیده ای نیست، اما "دستور العمل" توصیف شده ممکن است برای کسی مفید باشد :) کد در پایتون است، اما منطق به زبان گره خورده نیست.

پیکربندی پروژه در داخل و خارج از Kubernetes

پیشینه سوال این است: روزی روزگاری یک پروژه وجود داشت، در ابتدا یک تکپارچه کوچک با ابزارها و اسکریپت ها بود، اما با گذشت زمان رشد کرد، به خدمات تقسیم شد، که به نوبه خود به میکروسرویس ها تقسیم شد و سپس بزرگ شد. در ابتدا، همه این کارها بر روی VPS خالی انجام شد، فرآیندهای راه اندازی و استقرار کد روی آن با استفاده از Ansible به صورت خودکار انجام شد و هر سرویس با یک پیکربندی YAML با تنظیمات و کلیدهای لازم کامپایل شد و از یک فایل کانفیگ مشابه برای راه اندازی محلی، که بسیار راحت بود، زیرا .k این پیکربندی در یک شی سراسری بارگذاری می شود که از هر نقطه از پروژه قابل دسترسی است.

با این حال، رشد تعداد میکروسرویس ها، اتصالات آنها و نیاز به ثبت و نظارت متمرکز، انتقال به کوبر را پیش بینی کرد که هنوز در حال انجام است. Kubernetes همراه با کمک در حل مشکلات ذکر شده، رویکردهای خود را برای مدیریت زیرساخت از جمله ارائه می دهد به اصطلاح رازها и راه های کار با آنها. مکانیزم استاندارد و قابل اعتماد است، بنابراین استفاده نکردن از آن به معنای واقعی کلمه گناه است! اما در عین حال، من می خواهم فرمت فعلی خود را برای کار با پیکربندی حفظ کنم: اولاً از آن به طور یکنواخت در میکروسرویس های مختلف پروژه استفاده کنم و ثانیاً بتوانم کد را روی ماشین محلی با استفاده از یک ساده اجرا کنم. فایل پیکربندی

در این راستا، مکانیسم ساخت یک شیء پیکربندی اصلاح شد تا بتوان هم با فایل پیکربندی کلاسیک ما و هم با اسرار Kuber کار کرد. یک ساختار پیکربندی سفت و سخت تر نیز در زبان پایتون سوم به شرح زیر مشخص شد:

Dict[str، Dict[str، Union[str، int، float]]]

یعنی cogfig نهایی یک فرهنگ لغت با بخشهای نامگذاری شده است که هر کدام یک فرهنگ لغت با مقادیر از انواع ساده است. و بخش ها پیکربندی و دسترسی به منابع یک نوع خاص را توصیف می کنند. نمونه ای از قسمتی از پیکربندی ما:

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با مشخص کردن نام فایل برای ذخیره - این پارامترها به درستی شناسایی و پردازش می شوند، که اجرای کد به صورت محلی برای اشکال زدایی، تست واحد و هر نیاز دیگری را آسان می کند. این به ویژه برای ما مهم است زیرا نیازهای بسیار دیگری نیز وجود دارد - بخشی از کد ما برای محاسبات تحلیلی مختلف در نظر گرفته شده است، نه تنها بر روی سرورهای دارای هماهنگی، بلکه با اسکریپت های مختلف و روی رایانه های تحلیلگرانی که نیاز به کار دارند اجرا می شود. و خطوط لوله پردازش داده های پیچیده را بدون نگرانی مشکلات backend اشکال زدایی کنید. به هر حال، به اشتراک گذاشتن اینکه ابزارهای اصلی ما، از جمله کد طرح بندی پیکربندی، از طریق نصب شده اند، ضرری ندارد. 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()

منطق اینجا بسیار ساده است: پیکربندی‌های بزرگ را از دایرکتوری پروژه و مسیرها بر اساس متغیر محیطی و بخش‌های پیکربندی کوچک از Secrets Kuber را با هم ترکیب می‌کنیم و سپس آن‌ها را کمی پیش پردازش می‌کنیم. به علاوه برخی از متغیرها. توجه دارم که هنگام جستجوی فایل‌ها از اسرار، از محدودیت عمق استفاده می‌شود، زیرا K8s یک پوشه مخفی در هر مخفی ایجاد می‌کند که در آن اسرار خود ذخیره می‌شوند و فقط یک پیوند در سطح بالاتری قرار دارد.

امیدوارم آنچه شرح داده شده برای کسی مفید باشد :) هر گونه نظر و توصیه در مورد امنیت یا سایر زمینه های بهبود پذیرفته می شود. نظر جامعه نیز جالب است، شاید ارزش افزودن پشتیبانی از ConfigMaps را داشته باشد (پروژه ما هنوز از آنها استفاده نمی کند) و انتشار کد در GitHub / PyPI؟ شخصاً فکر می‌کنم که چنین چیزهایی برای پروژه‌ها بسیار فردی هستند که نمی‌توانند جهانی باشند، و کمی نگاه کردن به پیاده‌سازی‌های افراد دیگر، مانند آنچه در اینجا ارائه شد، و بحث در مورد تفاوت‌های ظریف، نکات و بهترین شیوه‌ها، که امیدوارم در نظرات ببینم. ، کافی است 😉

فقط کاربران ثبت نام شده می توانند در نظرسنجی شرکت کنند. ورود، لطفا.

آیا باید به عنوان پروژه/کتابخانه منتشر کنم؟

  • ٪۱۰۰بله، من از /contribution0 استفاده می کنم

  • ٪۱۰۰بله، عالی به نظر می رسد4

  • ٪۱۰۰نه، چه کسی باید این کار را خودش در قالب خودش و مطابق با نیازهایش انجام دهد

  • ٪۱۰۰از پاسخ دادن خودداری می کنم3

12 کاربر رای دادند. 3 کاربر رای ممتنع دادند.

منبع: www.habr.com

اضافه کردن نظر