Kubernetes içinde ve dışında proje yapılandırması

yakın zamanda yazdım Docker'daki proje ömrü ve bunun dışındaki kodda hata ayıklama hakkında yanıtHizmetin Kuber'de iyi çalışması, sırları ortaya çıkarması ve Docker'ın tamamen dışında bile yerel olarak rahatça çalışması için kendi yapılandırma sisteminizi oluşturabileceğinizden kısaca bahsetti. Karmaşık bir şey yok ama anlatılan "tarif" birisinin işine yarayabilir :) Kod Python'da ama mantık dile bağlı değil.

Kubernetes içinde ve dışında proje yapılandırması

Sorunun arka planı şu: Bir zamanlar bir proje vardı, ilk başta yardımcı programlar ve komut dosyaları içeren küçük bir monolitti, ancak zamanla büyüdü, hizmetlere bölündü ve bunlar da mikro hizmetlere bölünmeye başladı ve sonra büyütüldü. İlk başta tüm bunlar, Ansible kullanılarak otomatikleştirilen kod kurma ve dağıtma işlemleri olan çıplak VPS üzerinde yapıldı ve her hizmet, gerekli ayarlar ve anahtarlar içeren bir YAML yapılandırmasıyla derlendi ve benzer bir yapılandırma dosyası kullanıldı. yerel başlatmalar, bu çok kullanışlıydı çünkü .k bu yapılandırma, projenin herhangi bir yerinden erişilebilen global bir nesneye yüklendi.

Ancak mikro hizmetlerin sayısındaki, bağlantılarındaki ve merkezi kayıt tutma ve izleme ihtiyacı, halen devam eden Kuber'e geçişin habercisi oldu. Bahsedilen sorunların çözümüne yönelik yardımın yanı sıra Kubernetes, aşağıdakiler de dahil olmak üzere altyapı yönetimine yönelik yaklaşımlarını sunmaktadır: sözde Sırlar и onlarla çalışmanın yolları. Mekanizma standart ve güvenilirdir, bu yüzden onu kullanmamak tam anlamıyla günahtır! Ancak aynı zamanda, yapılandırmayla çalışmak için mevcut formatımı korumak istiyorum: birincisi, bunu projenin farklı mikro hizmetlerinde eşit şekilde kullanmak ve ikinci olarak, kodu yerel makinede basit bir komut kullanarak çalıştırabilmek. yapılandırma dosyası.

Bu bağlamda, bir konfigürasyon nesnesi oluşturma mekanizması, hem klasik konfigürasyon dosyamızla hem de Kuber'in sırlarıyla çalışabilecek şekilde değiştirildi. Üçüncü Python dilinde daha katı bir yapılandırma yapısı da şu şekilde belirtildi:

Dict[str, Dict[str, Union[str, int, float]]]

Yani, son cogfig, her biri basit türlerden değerler içeren bir sözlük olan, adlandırılmış bölümlere sahip bir sözlüktür. Bölümler ise belirli bir türdeki kaynakların yapılandırmasını ve erişimini açıklar. Yapılandırmamızın bir parçasına bir örnek:

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"

Aynı zamanda saha engine veritabanları SQLite'a kurulabilir ve redis ayarlanır mock, kaydedilecek dosyanın adını da belirterek - bu parametreler doğru bir şekilde tanınır ve işlenir; bu, hata ayıklama, birim testi ve diğer ihtiyaçlar için kodun yerel olarak çalıştırılmasını kolaylaştırır. Bu bizim için özellikle önemli çünkü başka birçok ihtiyaç var - kodumuzun bir kısmı çeşitli analitik hesaplamalar için tasarlandı, yalnızca düzenlemeli sunucularda değil, aynı zamanda çeşitli komut dosyalarıyla ve üzerinde çalışması gereken analistlerin bilgisayarlarında da çalışıyor. ve arka uç sorunlarından endişe etmeden karmaşık veri işleme hatlarında hata ayıklayın. Bu arada, config düzen kodu da dahil olmak üzere ana araçlarımızın, aracılığıyla kurulduğunu paylaşmaktan zarar gelmez. setup.py – bu, kodumuzu platformdan ve kullanım yönteminden bağımsız olarak tek bir ekosistemde birleştirir.

Kubernetes bölmesinin açıklaması şuna benzer:

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

Yani her sır bir bölümü anlatır. Sırların kendisi şu şekilde yaratılmıştır:

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

Bu, yol boyunca YAML dosyalarının oluşturulmasıyla sonuçlanır. /etc/secrets/db-main/section_name.yaml

Yerel başlatmalar için, projenin kök dizininde veya ortam değişkeninde belirtilen yol boyunca bulunan yapılandırma kullanılır. Bu kolaylıklardan sorumlu olan kod spoilerde görülebilir.

yapılandırma.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()

Buradaki mantık oldukça basittir: proje dizinindeki büyük yapılandırmaları ve ortam değişkenine göre yolları ve Kuber sırlarından küçük yapılandırma bölümlerini birleştirip ardından bunları biraz önceden işliyoruz. Ayrıca bazı değişkenler. Sırlardan dosya ararken derinlik sınırlamasının kullanıldığını unutmayın, çünkü K8'ler her sırda sırların depolandığı gizli bir klasör oluşturur ve yalnızca bir bağlantı daha yüksek bir seviyede bulunur.

Umarım anlatılanlar birilerine faydalı olur :) Güvenlik veya diğer iyileştirme alanlarıyla ilgili her türlü yorum ve öneri kabul edilir. Topluluğun görüşü de ilginç, belki ConfigMaps için destek eklemeye (projemiz henüz bunları kullanmıyor) ve kodu GitHub / PyPI'de yayınlamaya değer mi? Şahsen, bu tür şeylerin projelerin evrensel olamayacak kadar bireysel olduğunu ve burada verilen gibi diğer insanların uygulamalarına biraz göz atmayı ve yorumlarda görmeyi umduğum nüanslar, ipuçları ve en iyi uygulamalara dair bir tartışma olduğunu düşünüyorum. , yeter 😉

Ankete sadece kayıtlı kullanıcılar katılabilir. Giriş yapLütfen.

Proje/kütüphane olarak yayınlamalı mıyım?

  • %0,0Evet, /contribution0'ı kullanırdım

  • %33,3Evet, kulağa harika geliyor4

  • %41,7Hayır, kimin kendi formatında ve ihtiyaçlarına göre bunu yapması gerekiyor5

  • %25,0Cevap vermekten kaçınacağım3

12 kullanıcı oy kullandı. 3 kullanıcı çekimser kaldı.

Kaynak: habr.com

Yorum ekle