Kubernetes daxilində və xaricində layihə konfiqurasiyası

Bu yaxınlarda yazdım Docker-də layihənin həyatı və ondan kənarda sazlama kodu haqqında cavab, burada qısaca qeyd etdi ki, öz konfiqurasiya sisteminizi yarada bilərsiniz ki, xidmət Kuber-də yaxşı işləyir, sirləri açır və yerli olaraq, hətta Docker-dən kənarda da rahat işləsin. Mürəkkəb bir şey yoxdur, amma təsvir edilən “resept” kiməsə faydalı ola bilər :) Kod Python-dadır, lakin məntiq dilə bağlı deyil.

Kubernetes daxilində və xaricində layihə konfiqurasiyası

Sualın arxa planı belədir: bir vaxtlar bir layihə var idi, əvvəlcə kommunal və skriptləri olan kiçik bir monolit idi, lakin zaman keçdikcə böyüdü, xidmətlərə bölündü, o da öz növbəsində mikroservislərə bölünməyə başladı və sonra böyüdü. Əvvəlcə bütün bunlar çılpaq VPS-də edildi, kodun qurulması və yerləşdirilməsi prosesləri Ansible vasitəsilə avtomatlaşdırıldı və hər bir xidmət lazımi parametrlər və açarlarla YAML konfiqurasiyası ilə tərtib edildi və oxşar konfiqurasiya faylı üçün istifadə edildi. yerli işə salındı, bu çox rahat idi, çünki .k bu konfiqurasiya qlobal obyektə yüklənir, layihənin istənilən yerindən əlçatandır.

Bununla belə, mikroservislərin sayının artması, onların əlaqəsi və mərkəzləşdirilmiş giriş və monitorinq ehtiyacı, hələ də davam edən Kuberə köçməyi qabaqcadan xəbər verdi. Qeyd olunan problemlərin həllində yardımla birlikdə Kubernetes infrastrukturun idarə edilməsinə öz yanaşmalarını, o cümlədən sözdə sirlər и onlarla işləməyin yolları. Mexanizm standart və etibarlıdır, ona görə də ondan istifadə etməmək günahdır! Ancaq eyni zamanda, konfiqurasiya ilə işləmək üçün hazırkı formatımı saxlamaq istərdim: birincisi, onu layihənin müxtəlif mikroservislərində vahid şəkildə istifadə etmək, ikincisi, bir sadə istifadə edərək kodu yerli maşında işlədə bilmək konfiqurasiya faylı.

Bununla əlaqədar olaraq, konfiqurasiya obyektinin qurulması mexanizmi həm klassik konfiqurasiya faylımızla, həm də Kuber-in sirləri ilə işləyə bilmək üçün dəyişdirildi. Üçüncü Python dilində daha sərt konfiqurasiya strukturu da aşağıdakı kimi göstərilmişdir:

Dict[küç, Dict[küç, Union[str, int, float]]]

Yəni, son dişli, hər biri sadə növlərdən dəyərləri olan bir lüğət olan adlandırılmış bölmələri olan bir lüğətdir. Və bölmələr konfiqurasiyanı və müəyyən bir növ resurslara çıxışı təsvir edir. Konfiqurasiyamızın bir parçasına bir nümunə:

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"

Eyni zamanda, sahə engine verilənlər bazası SQLite-də quraşdırıla bilər və redis təyin edin mock, saxlanacaq faylın adının da göstərilməsi - bu parametrlər düzgün şəkildə tanınır və işlənir, bu, sazlama, vahid testi və hər hansı digər ehtiyaclar üçün kodu yerli olaraq işə salmağı asanlaşdırır. Bu, bizim üçün xüsusilə vacibdir, çünki bir çox başqa ehtiyaclar da var - kodun bir hissəsi müxtəlif analitik hesablamalar üçün nəzərdə tutulub, o, təkcə orkestrasiya ilə serverlərdə deyil, həm də müxtəlif skriptlərlə və işləməli olan analitiklərin kompüterlərində işləyir. və arxa uç problemlərini narahat etmədən mürəkkəb məlumat emal boru kəmərlərini sazlayın. Yeri gəlmişkən, əsas alətlərimizin, o cümlədən konfiqurasiya layout kodunun vasitəsilə quraşdırıldığını bölüşmək zərər verməz. setup.py – birlikdə bu, kodumuzu platformadan və istifadə üsulundan asılı olmayaraq vahid ekosistemdə birləşdirir.

Kubernetes podunun təsviri belə görünür:

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

Yəni hər sirr bir bölməni təsvir edir. Sirlərin özləri belə yaradılmışdır:

apiVersion: v1
kind: Secret
metadata:
  name: db-main-secret
type: Opaque
stringData:
  db_main.yaml: |
    engine: sqlite
    filename: main.sqlite3

Birlikdə bu, yol boyunca YAML fayllarının yaradılması ilə nəticələnir /etc/secrets/db-main/section_name.yaml

Yerli işə salınmalar üçün layihənin kök qovluğunda və ya mühit dəyişənində göstərilən yolda yerləşən konfiqurasiya istifadə olunur. Bu rahatlıqlara cavabdeh olan kodu spoylerdə görmək olar.

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()

Buradakı məntiq olduqca sadədir: biz layihə kataloqundan və ətraf mühit dəyişəninə görə yollardan böyük konfiqurasiyaları və Kuber sirlərindən kiçik konfiqurasiya bölmələrini birləşdiririk və sonra onları bir az əvvəlcədən emal edirik. Üstəlik bəzi dəyişənlər. Qeyd edirəm ki, sirlərdən faylları axtararkən dərinlik məhdudiyyətindən istifadə olunur, çünki K8s hər bir sirrdə sirlərin özlərinin saxlandığı gizli qovluq yaradır və sadəcə bir keçid daha yüksək səviyyədə yerləşir.

Ümid edirəm ki, təsvir edilənlər kimsə üçün faydalı olacaq :) Təhlükəsizlik və ya təkmilləşdirmə üçün digər sahələrlə bağlı hər hansı şərh və tövsiyələr qəbul edilir. İcmanın rəyi də maraqlıdır, bəlkə ConfigMaps (bizim layihəmiz hələ onlardan istifadə etmir) üçün dəstək əlavə etməyə və kodu GitHub / PyPI-də dərc etməyə dəyər? Şəxsən mən hesab edirəm ki, bu cür şeylər layihələrin universal olması üçün çox fərdidir və burada verilən kimi digər insanların tətbiqlərinə bir az nəzər salmaq və şərhlərdə görəcəyimə ümid etdiyim nüansların, məsləhətlərin və ən yaxşı təcrübələrin müzakirəsi. , kifayətdir 😉

Sorğuda yalnız qeydiyyatdan keçmiş istifadəçilər iştirak edə bilər. Daxil olunxahiş edirəm.

Layihə/kitabxana kimi dərc etməliyəm?

  • 0,0%Bəli, /contribution0 istifadə edərdim

  • 33,3%Bəli, əla səslənir4

  • 41,7%Xeyr, bunu kimin öz formatında və ehtiyaclarına uyğun olaraq etməsi lazımdır5

  • 25,0%Cavab verməkdən çəkinəcəyəm3

12 istifadəçi səs verib. 3 istifadəçi bitərəf qalıb.

Mənbə: www.habr.com

Добавить комментарий