Projektin konfigurointi Kubernetesin sisällä ja ulkopuolella

kirjoitin hiljattain vastaus projektin elämästä Dockerissa ja virheenkorjauskoodin sen ulkopuolella, jossa hän mainitsi lyhyesti, että voit tehdä oman konfigurointijärjestelmän niin, että palvelu toimii hyvin Kuberissa, kerää salaisuuksia ja toimii kätevästi paikallisesti, jopa kokonaan Dockerin ulkopuolella. Ei mitään monimutkaista, mutta kuvailtu "resepti" voi olla jollekin hyödyllinen :) Koodi on Pythonissa, mutta logiikka ei ole sidottu kieleen.

Projektin konfigurointi Kubernetesin sisällä ja ulkopuolella

Kysymyksen tausta on tämä: kerran oli yksi projekti, se oli aluksi pieni monoliitti apuohjelmien ja skriptien kanssa, mutta ajan myötä se kasvoi, jakautui palveluiksi, jotka puolestaan ​​alkoivat jakaa mikropalveluiksi, ja sitten skaalata. Aluksi kaikki tämä tehtiin paljaalla VPS:llä, jossa koodin asennus- ja käyttöönottoprosessit automatisoitiin Ansiblen avulla, ja jokainen palvelu koottiin YAML-konfiguraatiolla tarvittavilla asetuksilla ja avaimilla, ja vastaavaa konfigurointitiedostoa käytettiin paikalliset käynnistykset, mikä oli erittäin kätevää, koska .k tämä konfiguraatio ladataan globaaliin objektiin, joka on käytettävissä mistä tahansa projektin kohdasta.

Kuitenkin mikropalveluiden määrän kasvu, niiden yhteydet ja tarve keskitettyyn kirjaamiseen ja seurantaan, ennusti muuttoa Kuberiin, joka on edelleen kesken. Yhdessä mainittujen ongelmien ratkaisuun liittyvän avun kanssa Kubernetes tarjoaa lähestymistapojaan infrastruktuurin hallintaan, mm niin sanottuja salaisuuksia и tapoja työskennellä heidän kanssaan. Mekanismi on vakio ja luotettava, joten on kirjaimellisesti synti olla käyttämättä sitä! Mutta samalla haluaisin säilyttää nykyisen konfigurointimuotoni: ensinnäkin käyttää sitä yhtenäisesti projektin eri mikropalveluissa, ja toiseksi, että voin suorittaa koodin paikallisella koneella yhdellä yksinkertaisella konfigurointitiedosto.

Tässä suhteessa määritysobjektin rakennusmekanismia muokattiin, jotta se voisi toimia sekä klassisen konfigurointitiedoston että Kuberin salaisuuksien kanssa. Myös jäykempi konfigurointirakenne määriteltiin kolmannen Pythonin kielellä seuraavasti:

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

Toisin sanoen viimeinen hammasfig on sanakirja, jossa on nimetyt osiot, joista jokainen on sanakirja, jossa on arvoja yksinkertaisista tyypeistä. Ja osiot kuvaavat tietyntyyppisten resurssien määritystä ja pääsyä niihin. Esimerkki kokoonpanostamme:

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"

Samaan aikaan kenttä engine tietokannat voidaan asentaa SQLiteen ja redis asetettu mock, joka määrittää myös tallennettavan tiedoston nimen - nämä parametrit tunnistetaan ja käsitellään oikein, mikä tekee koodin suorittamisesta paikallisesti helppoa virheenkorjausta, yksikkötestausta ja muita tarpeita varten. Tämä on meille erityisen tärkeää, koska on monia muita tarpeita - osa koodistamme on tarkoitettu erilaisiin analyyttisiin laskelmiin, se toimii paitsi orkestroiduilla palvelimilla, myös erilaisilla skripteillä ja analyytikoiden tietokoneilla, jotka tarvitsevat läpi. ja korjaa monimutkaisia ​​tietojenkäsittelyputkia ilman huolestuttavia tausta-ongelmia. Muuten, ei haittaisi kertoa, että tärkeimmät työkalumme, mukaan lukien asetusten asettelukoodi, asennetaan setup.py – tämä yhdistää koodimme yhdeksi ekosysteemiksi alustasta ja käyttötavasta riippumatta.

Kuvaus Kubernetes podista näyttää tältä:

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

Eli jokainen salaisuus kuvaa yhtä osaa. Itse salaisuudet luodaan seuraavasti:

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

Yhdessä tämä johtaa YAML-tiedostojen luomiseen polun varrella /etc/secrets/db-main/section_name.yaml

Ja paikallisissa käynnistyksissä käytetään konfiguraatiota, joka sijaitsee projektin juurihakemistossa tai ympäristömuuttujassa määritettyä polkua pitkin. Näistä mukavuuksista vastaava koodi näkyy spoilerissa.

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

Logiikka tässä on melko yksinkertainen: yhdistämme suuret konfiguraatiot projektihakemistosta ja polut ympäristömuuttujien mukaan sekä pienet konfiguraatioosiot Kuber-salaisuuksista ja esikäsittelemme niitä sitten hieman. Lisäksi muutama muuttuja. Huomaan, että haettaessa tiedostoja salaisuuksista käytetään syvyysrajoitusta, koska K8s luo jokaiseen salaisuuteen piilotetun kansion, johon itse salaisuudet tallennetaan, ja vain linkki sijaitsee korkeammalla tasolla.

Toivottavasti kuvatusta on jollekin hyötyä :) Kaikki kommentit ja suositukset koskien turvallisuutta tai muita parannuskohteita otetaan vastaan. Yhteisön mielipide on myös mielenkiintoinen, ehkä kannattaa lisätä tuki ConfigMapsille (projektimme ei vielä käytä niitä) ja julkaista koodi GitHubissa / PyPI:ssä? Henkilökohtaisesti olen sitä mieltä, että tällaiset asiat ovat liian yksilöllisiä, jotta hankkeet olisivat yleismaailmallisia, ja pientä kurkistamista muiden toteutuksiin, kuten tässä annettu, ja keskustelua vivahteista, vinkeistä ja parhaista käytännöistä, joita toivon näkeväni kommenteissa , riittää 😉

Vain rekisteröityneet käyttäjät voivat osallistua kyselyyn. Kirjaudu sisään, ole kiltti.

Pitäisikö minun julkaista projektina/kirjastona?

  • 0,0%Kyllä, käyttäisin /contribution0

  • 33,3%Kyllä, kuulostaa hyvältä 4

  • 41,7%Ei, kenen pitää tehdä se itse omassa muodossaan ja tarpeidensa mukaan5

  • 25,0%Jätän vastaamatta 3

12 käyttäjää äänesti. 3 käyttäjää pidättyi äänestämästä.

Lähde: will.com

Lisää kommentti