Նախագծի կազմաձևումը Kubernetes-ի ներսում և դրսում

Վերջերս գրեցի պատասխանել Docker-ում նախագծի կյանքի և դրանից դուրս կոդի վրիպազերծման մասին, որտեղ նա հակիրճ նշեց, որ դուք կարող եք ստեղծել ձեր սեփական կազմաձևման համակարգը, որպեսզի ծառայությունը լավ աշխատի Kuber-ում, բացահայտի գաղտնիքները և աշխատի հարմար տեղում, նույնիսկ ընդհանրապես Docker-ից դուրս: Ոչինչ բարդ չէ, բայց նկարագրված «բաղադրատոմսը» կարող է օգտակար լինել ինչ-որ մեկին :) Կոդը Python-ում է, բայց տրամաբանությունը կապված չէ լեզվի հետ։

Նախագծի կազմաձևումը Kubernetes-ի ներսում և դրսում

Հարցի նախապատմությունը հետևյալն է. ժամանակին մի նախագիծ կար, սկզբում այն ​​փոքր մոնոլիտ էր կոմունալ ծառայություններով և սցենարներով, բայց ժամանակի ընթացքում այն ​​աճեց, բաժանվեց ծառայությունների, որոնք իրենց հերթին սկսեցին բաժանվել միկրոսերվիսների և հետո մեծացավ: Սկզբում այս ամենը արվում էր մերկ VPS-ի վրա, որի վրա կոդի տեղադրման և տեղակայման գործընթացները ավտոմատացված էին Ansible-ի միջոցով, և յուրաքանչյուր ծառայություն կազմվում էր YAML կոնֆիգուրով՝ անհրաժեշտ կարգավորումներով և ստեղներով, և նմանատիպ կոնֆիգուրային ֆայլ օգտագործվում էր դրա համար։ տեղական գործարկումներ, ինչը շատ հարմար էր, քանի որ .k այս կազմաձևը բեռնված է գլոբալ օբյեկտում, որը հասանելի է նախագծի ցանկացած կետից:

Այնուամենայնիվ, միկրոծառայությունների թվի աճը, դրանց միացումները և կենտրոնացված անտառահատումների և մոնիտորինգի անհրաժեշտություն, կանխագուշակեց տեղափոխվել Կուբեր, որը դեռ ընթացքի մեջ է։ Նշված խնդիրների լուծմանն աջակցելու հետ մեկտեղ Kubernetes-ն առաջարկում է ենթակառուցվածքների կառավարման իր մոտեցումները, այդ թվում այսպես կոչված Գաղտնիքներ и նրանց հետ աշխատելու ուղիներ. Մեխանիզմը ստանդարտ է և հուսալի, ուստի այն չօգտագործելը բառացիորեն մեղք է: Բայց միևնույն ժամանակ, ես կցանկանայի պահպանել կոնֆիգուրայի հետ աշխատելու իմ ներկայիս ձևաչափը. նախ՝ այն միատեսակ օգտագործել նախագծի տարբեր միկրոսերվիսներում, և երկրորդ՝ կարողանամ գործարկել կոդը տեղական մեքենայի վրա՝ օգտագործելով մեկ պարզ կազմաձևման ֆայլ:

Այս առումով, կոնֆիգուրացիայի օբյեկտի կառուցման մեխանիզմը փոփոխվել է, որպեսզի կարողանա աշխատել ինչպես մեր դասական կոնֆիգուրացիայի ֆայլի, այնպես էլ Kuber-ի գաղտնիքների հետ: Երրորդ Python-ի լեզվով նշվեց նաև ավելի կոշտ կազմաձևման կառուցվածքը հետևյալ կերպ.

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 pod-ի նկարագրությունը հետևյալն է.

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 օգտատեր ձեռնպահ է մնացել։

Source: www.habr.com

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