ΠΠ΅Π΄Π°Π²Π½ΠΎ Ρ Π½Π°ΠΏΠΈΡΠ°Π»
ΠΡΠ΅Π΄ΡΡΡΠΎΡΠΈΡ Π²ΠΎΠΏΡΠΎΡΠ° ΡΠ°ΠΊΠΎΠ²Π°: ΠΆΠΈΠ»-Π±ΡΠ» ΠΎΠ΄ΠΈΠ½ ΠΏΡΠΎΠ΅ΠΊΡ, ΡΠ½Π°ΡΠ°Π»Π° ΠΎΠ½ Π±ΡΠ» ΠΌΠ°Π»Π΅Π½ΡΠΊΠΈΠΌ ΠΌΠΎΠ½ΠΎΠ»ΠΈΡΠΎΠΌ Ρ ΡΡΠΈΠ»ΠΈΡΠ°ΠΌΠΈ ΠΈ ΡΠΊΡΠΈΠΏΡΠ°ΠΌΠΈ, Π½ΠΎ ΡΠΎ Π²ΡΠ΅ΠΌΠ΅Π½Π΅ΠΌ ΡΠΎΡ, Π΄Π΅Π»ΠΈΠ»ΡΡ Π½Π° ΡΠ΅ΡΠ²ΠΈΡΡ, ΠΊΠΎΡΠΎΡΡΠ΅ Π² ΡΠ²ΠΎΡ ΠΎΡΠ΅ΡΠ΅Π΄Ρ ΡΡΠ°Π»ΠΈ Π΄Π΅Π»ΠΈΡΡΡΡ Π½Π° ΠΌΠΈΠΊΡΠΎΡΠ΅ΡΠ²ΠΈΡΡ, Π° ΠΏΠΎΡΠΎΠΌ Π΅ΡΡ ΠΈ ΡΠΊΠ΅ΠΉΠ»ΠΈΡΡΡΡ. ΠΠΎΠ½Π°ΡΠ°Π»Ρ ΡΡΠΎ Π²ΡΡ Π²ΡΠΏΠΎΠ»Π½ΡΠ»ΠΎΡΡ Π½Π° Π³ΠΎΠ»ΡΡ VPS, ΠΏΡΠΎΡΠ΅ΡΡΡ Π½Π°ΡΡΡΠΎΠΉΠΊΠΈ ΠΈ ΡΠ°Π·Π²ΠΎΡΠ°ΡΠΈΠ²Π°Π½ΠΈΡ ΠΊΠΎΠ΄Π° Π½Π° ΠΊΠΎΡΠΎΡΡΡ Π±ΡΠ»ΠΈ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΠ·ΠΈΡΠΎΠ²Π°Π½Π½Ρ Ρ ΠΏΠΎΠΌΠΎΡΡΡ Ansible, ΠΈ ΠΊΠ°ΠΆΠ΄ΠΎΠΌΡ ΡΠ΅ΡΠ²ΠΈΡΡ ΡΠΎΡΡΠ°Π²Π»ΡΠ»ΡΡ YAML-ΠΊΠΎΠ½ΡΠΈΠ³ Ρ Π½ΡΠΆΠ½ΡΠΌΠΈ Π½Π°ΡΡΡΠΎΠΉΠΊΠ°ΠΌΠΈ ΠΈ ΠΊΠ»ΡΡΠ°ΠΌΠΈ, ΠΈ Π°Π½Π°Π»ΠΎΠ³ΠΈΡΠ½ΡΠΉ ΠΊΠΎΠ½ΡΠΈΠ³-ΡΠ°ΠΉΠ» ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π»ΡΡ Π΄Π»Ρ Π»ΠΎΠΊΠ°Π»ΡΠ½ΡΡ Π·Π°ΠΏΡΡΠΊΠΎΠ², ΡΡΠΎ Π±ΡΠ»ΠΎ ΠΎΡΠ΅Π½Ρ ΡΠ΄ΠΎΠ±Π½ΠΎ, Ρ.ΠΊ ΡΡΠΎΡ ΠΊΠΎΠ½ΡΠΈΠ³ Π³ΡΡΠ·ΠΈΡΡΡ Π² Π³Π»ΠΎΠ±Π°Π»ΡΠ½ΡΠΉ ΠΎΠ±ΡΠ΅ΠΊΡ, Π΄ΠΎΡΡΡΠΏΠ½ΡΠΉ ΠΈΠ· Π»ΡΠ±ΠΎΠ³ΠΎ ΠΌΠ΅ΡΡΠ° Π² ΠΏΡΠΎΠ΅ΠΊΡΠ΅.
ΠΠ΄Π½Π°ΠΊΠΎ ΡΠΎΡΡ ΡΠΈΡΠ»Π° ΠΌΠΈΠΊΡΠΎΡΠ΅ΡΠ²ΠΈΡΠΎΠ², ΠΈΡ
ΡΠ²ΡΠ·Π΅ΠΉ, Π° ΡΠ°ΠΊΠΆΠ΅
Π ΡΠ²ΡΠ·ΠΈ Ρ ΡΡΠΈΠΌ, ΠΌΠ΅Ρ Π°Π½ΠΈΠ·ΠΌ ΠΏΠΎΡΡΡΠΎΠ΅Π½ΠΈΡ ΠΎΠ±ΡΠ΅ΠΊΡΠ°-ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΠΈ Π±ΡΠ» Π΄ΠΎΡΠ°Π±ΠΎΡΠ°Π½ ΡΠ°ΠΊ, ΡΡΠΎΠ±Ρ ΡΠΌΠ΅ΡΡ ΡΠ°Π±ΠΎΡΠ°ΡΡ ΠΊΠ°ΠΊ Ρ Π½Π°ΡΠΈΠΌ ΠΊΠ»Π°ΡΡΠΈΡΠ΅ΡΠΊΠΈΠΌ ΠΊΠΎΠ½ΡΠΈΠ³-ΡΠ°ΠΉΠ»ΠΎΠΌ, ΡΠ°ΠΊ ΠΈ Ρ ΡΠ΅ΠΊΡΠ΅ΡΠ°ΠΌΠΈ ΠΈΠ· ΠΡΠ±Π΅ΡΠ°. Π’Π°ΠΊΠΆΠ΅ Π±ΡΠ»Π° Π·Π°Π΄Π°Π½Π° Π±ΠΎΠ»Π΅Π΅ ΠΆΡΡΡΠΊΠ°Ρ ΡΡΡΡΠΊΡΡΡΠ° ΠΊΠΎΠ½ΡΠΈΠ³Π°, Π³ΠΎΠ²ΠΎΡΡ ΡΠ·ΡΠΊΠΎΠΌ ΡΡΠ΅ΡΡΠ΅Π³ΠΎ ΠΠΈΡΠΎΠ½Π°, ΡΠ°ΠΊΠ°Ρ:
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 Π²ΡΠ³Π»ΡΠ΄ΠΈΡ ΡΠ°ΠΊ:
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()
ΠΠΎΠ³ΠΈΠΊΠ° Π·Π΄Π΅ΡΡ Π΄ΠΎΠ²ΠΎΠ»ΡΠ½ΠΎ ΠΏΡΠΎΡΡΠ°Ρ: ΠΎΠ±ΡΠ΅Π΄ΠΈΠ½ΡΠ΅ΠΌ ΠΊΡΡΠΏΠ½ΡΠ΅ ΠΊΠΎΠ½ΡΠΈΠ³ΠΈ ΠΈΠ· Π΄ΠΈΡΠ΅ΠΊΡΠΎΡΠΈΠΈ ΠΏΡΠΎΠ΅ΠΊΡΠ° ΠΈ ΠΏΡΡΠΈ ΠΏΠΎ ΠΏΠ΅ΡΠ΅ΠΌΠ΅Π½Π½ΠΎΠΉ ΠΎΠΊΡΡΠΆΠ΅Π½ΠΈΡ, ΠΈ Π½Π΅Π±ΠΎΠ»ΡΡΠΈΠ΅ ΠΊΠΎΠ½ΡΠΈΠ³ΠΈ-ΡΠ΅ΠΊΡΠΈΠΈ ΠΈΠ· ΡΠ΅ΠΊΡΠ΅ΡΠΎΠ² ΠΡΠ±Π΅ΡΠ°, Π° Π·Π°ΡΠ΅ΠΌ Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ ΠΈΡ ΠΏΡΠ΅Π΄ΠΎΠ±ΡΠ°Π±Π°ΡΡΠ²Π°Π΅ΠΌ. ΠΠ»ΡΡ Π½Π΅ΠΊΠΎΡΠΎΡΡΠ΅ ΠΏΠ΅ΡΠ΅ΠΌΠ΅Π½Π½ΡΠ΅. ΠΠ°ΠΌΠ΅ΡΡ, ΡΡΠΎ ΠΏΡΠΈ ΠΏΠΎΠΈΡΠΊΠ΅ ΡΠ°ΠΉΠ»ΠΎΠ² ΠΈΠ· ΡΠ΅ΠΊΡΠ΅ΡΠΎΠ² ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΡΡΡ ΠΎΠ³ΡΠ°Π½ΠΈΡΠ΅Π½ΠΈΠ΅ Π³Π»ΡΠ±ΠΈΠ½Ρ, Ρ.ΠΊ K8s Π² ΠΊΠ°ΠΆΠ΄ΠΎΠΌ ΡΠ΅ΠΊΡΠ΅ΡΠ΅ ΡΠΎΠ·Π΄Π°ΡΡ Π΅ΡΡ ΡΠΊΡΡΡΡΡ ΠΏΠ°ΠΏΠΊΡ, Π³Π΄Π΅ ΡΠ°ΠΌΠΈ ΡΠ΅ΠΊΡΠ΅ΡΡ ΠΈ Ρ ΡΠ°Π½ΠΈΡΡΡ, Π° ΡΡΠΎΠ²Π½Π΅ΠΌ Π²ΡΡΠ΅ Π½Π°Ρ ΠΎΠ΄ΠΈΡΡΡ ΠΏΡΠΎΡΡΠΎ ΡΡΡΠ»ΠΊΠ°.
ΠΠ°Π΄Π΅ΡΡΡ, ΠΎΠΏΠΈΡΠ°Π½Π½ΠΎΠ΅ ΠΎΠΊΠ°ΠΆΠ΅ΡΡΡ ΠΊΠΎΠΌΡ-Π½ΠΈΠ±ΡΠ΄Ρ ΠΏΠΎΠ»Π΅Π·Π½ΡΠΌ π ΠΡΠΈΠ½ΠΈΠΌΠ°ΡΡΡΡ Π»ΡΠ±ΡΠ΅ ΠΊΠΎΠΌΠΌΠ΅Π½ΡΠ°ΡΠΈΠΈ ΠΈ ΡΠ΅ΠΊΠΎΠΌΠ΅Π½Π΄Π°ΡΠΈΠΈ ΠΊΠ°ΡΠ°ΡΠ΅Π»ΡΠ½ΠΎ Π±Π΅Π·ΠΎΠΏΠ°ΡΠ½ΠΎΡΡΠΈ ΠΈΠ»ΠΈ Π΄ΡΡΠ³ΠΈΡ ΠΌΠΎΠΌΠ΅Π½ΡΠΎΠ² Π½Π° ΡΠ»ΡΡΡΠ΅Π½ΠΈΠ΅. Π’Π°ΠΊΠΆΠ΅ ΠΈΠ½ΡΠ΅ΡΠ΅ΡΠ½ΠΎ ΠΌΠ½Π΅Π½ΠΈΠ΅ ΡΠΎΠΎΠ±ΡΠ΅ΡΡΠ²Π°, Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ ΡΡΠΎΠΈΡ Π΄ΠΎΠ±Π°Π²ΠΈΡΡ ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΊΡ ConfigMaps (Π² Π½Π°ΡΠ΅ΠΌ ΠΏΡΠΎΠ΅ΠΊΡΠ΅ ΠΎΠ½ΠΈ ΠΏΠΎΠΊΠ° Π½Π΅ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΡΡΡ) ΠΈ ΠΎΡΠΎΡΠΌΠΈΡΡ ΠΊΠΎΠ΄ Π½Π° ΠΠΈΡΠ₯Π°Π±Π΅ / PyPI? ΠΠΈΡΠ½ΠΎ Ρ Π΄ΡΠΌΠ°Ρ, ΡΡΠΎ ΡΠ°ΠΊΠΈΠ΅ Π²Π΅ΡΠΈ ΡΠ»ΠΈΡΠΊΠΎΠΌ ΠΈΠ½Π΄ΠΈΠ²ΠΈΠ΄ΡΠ°Π»ΡΠ½ΡΠ΅ Π΄Π»Ρ ΠΏΡΠΎΠ΅ΠΊΡΠΎΠ², ΡΡΠΎΠ±Ρ Π±ΡΡΡ ΡΠ½ΠΈΠ²Π΅ΡΡΠ°Π»ΡΠ½ΡΠΌΠΈ, ΠΈ Π΄ΠΎΡΡΠ°ΡΠΎΡΠ½ΠΎ Π½Π΅Π±ΠΎΠ»ΡΡΠΎΠ³ΠΎ ΠΏΠΎΠ΄Π³Π»ΡΠ΄ΡΠ²Π°Π½ΠΈΡ Π½Π° ΡΡΠΆΠΈΠ΅ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠΈ, Π²ΡΠΎΠ΄Π΅ ΠΏΡΠΈΠ²Π΅Π΄ΡΠ½Π½ΠΎΠΉ Π·Π΄Π΅ΡΡ, Π΄Π° ΠΎΠ±ΡΡΠΆΠ΄Π΅Π½ΠΈΡ Π½ΡΠ°Π½ΡΠΎΠ², ΡΠΎΠ²Π΅ΡΠΎΠ² ΠΈ best practices, ΠΊΠΎΡΠΎΡΠΎΠ΅ Ρ Π½Π°Π΄Π΅ΡΡΡ ΡΠ²ΠΈΠ΄Π΅ΡΡ Π² ΠΊΠΎΠΌΠΌΠ΅Π½ΡΠ°ΡΠΈΡΡ π
Π’ΠΎΠ»ΡΠΊΠΎ Π·Π°ΡΠ΅Π³ΠΈΡΡΡΠΈΡΠΎΠ²Π°Π½Π½ΡΠ΅ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»ΠΈ ΠΌΠΎΠ³ΡΡ ΡΡΠ°ΡΡΠ²ΠΎΠ²Π°ΡΡ Π² ΠΎΠΏΡΠΎΡΠ΅.
Π‘ΡΠΎΠΈΡ Π»ΠΈ ΠΏΡΠ±Π»ΠΈΠΊΠΎΠ²Π°ΡΡ ΠΊΠ°ΠΊ ΠΏΡΠΎΠ΅ΠΊΡ/Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΡ?
-
0,0%ΠΠ°, Ρ Π±Ρ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π» / ΠΊΠΎΠ½ΡΡΠΈΠ±ΡΡΠΈΠ»0
-
33,3%ΠΠ°, Π·Π²ΡΡΠΈΡ Π·Π΄ΠΎΡΠΎΠ²ΠΎ4
-
41,7%ΠΠ΅Ρ, ΠΊΠΎΠΌΡ Π½Π°Π΄ΠΎ ΡΠ΄Π΅Π»Π°ΡΡ ΡΠ°ΠΌΠΈ Π² ΡΠ²ΠΎΡΠΌ ΡΠΎΡΠΌΠ°ΡΠ΅ ΠΈ ΠΏΠΎΠ΄ ΡΠ²ΠΎΠΈ Π½ΡΠΆΠ΄Ρ5
-
25,0%ΠΠΎΠ·Π΄Π΅ΡΠΆΡΡΡ ΠΎΡ ΠΎΡΠ²Π΅ΡΠ°3
ΠΡΠΎΠ³ΠΎΠ»ΠΎΡΠΎΠ²Π°Π»ΠΈ 12 ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Π΅ΠΉ. ΠΠΎΠ·Π΄Π΅ΡΠΆΠ°Π»ΠΈΡΡ 3 ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ.
ΠΡΡΠΎΡΠ½ΠΈΠΊ: habr.com