Gần đây tôi đã viết
Nền tảng của câu hỏi là: ngày xưa có một dự án, ban đầu nó là một khối nhỏ với các tiện ích và tập lệnh, nhưng theo thời gian, nó phát triển, chia thành các dịch vụ, sau đó bắt đầu được chia thành microservice và sau đó mở rộng quy mô. Lúc đầu, tất cả điều này được thực hiện trên VPS trần, các quy trình thiết lập và triển khai mã được tự động hóa bằng Ansible và mỗi dịch vụ được biên dịch bằng cấu hình YAML với các cài đặt và khóa cần thiết, đồng thời sử dụng một tệp cấu hình tương tự cho khởi chạy cục bộ, rất thuận tiện vì .k cấu hình này được tải vào một đối tượng chung, có thể truy cập được từ mọi nơi trong dự án.
Tuy nhiên, sự tăng trưởng về số lượng vi dịch vụ, kết nối của chúng và
Về vấn đề này, cơ chế xây dựng đối tượng cấu hình đã được sửa đổi để có thể hoạt động với cả tệp cấu hình cổ điển của chúng tôi và với các bí mật từ Kuber. Cấu trúc cấu hình cứng nhắc hơn cũng được chỉ định, bằng ngôn ngữ của Python thứ ba, như sau:
Dict[str, Dict[str, Union[str, int, float]]]
Nghĩa là, cogfig cuối cùng là một từ điển có các phần được đặt tên, mỗi phần là một từ điển có các giá trị từ các kiểu đơn giản. Và các phần mô tả cấu hình và quyền truy cập vào các tài nguyên thuộc một loại nhất định. Một ví dụ về một phần cấu hình của chúng tôi:
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"
Đồng thời, lĩnh vực engine
cơ sở dữ liệu có thể được cài đặt trên SQLite và redis
đặt thành mock
, cũng chỉ định tên của tệp cần lưu - các tham số này được nhận dạng và xử lý chính xác, giúp dễ dàng chạy mã cục bộ để gỡ lỗi, kiểm tra đơn vị và bất kỳ nhu cầu nào khác. Điều này đặc biệt quan trọng đối với chúng tôi vì có nhiều nhu cầu khác - một phần mã của chúng tôi dành cho các phép tính phân tích khác nhau, nó không chỉ chạy trên các máy chủ có sự điều phối mà còn với nhiều tập lệnh khác nhau và trên máy tính của các nhà phân tích cần xử lý. và gỡ lỗi các quy trình xử lý dữ liệu phức tạp mà không phải lo lắng về các vấn đề phụ trợ. Nhân tiện, sẽ không có gì đáng tiếc khi chia sẻ rằng các công cụ chính của chúng tôi, bao gồm mã bố cục cấu hình, được cài đặt qua setup.py
– điều này cùng nhau hợp nhất mã của chúng tôi thành một hệ sinh thái duy nhất, độc lập với nền tảng và phương pháp sử dụng.
Mô tả của nhóm Kubernetes trông như thế này:
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
Nghĩa là, mỗi bí mật mô tả một phần. Bản thân những bí mật được tạo ra như thế này:
apiVersion: v1
kind: Secret
metadata:
name: db-main-secret
type: Opaque
stringData:
db_main.yaml: |
engine: sqlite
filename: main.sqlite3
Điều này cùng nhau dẫn đến việc tạo các tệp YAML dọc theo đường dẫn /etc/secrets/db-main/section_name.yaml
Và đối với các lần khởi chạy cục bộ, cấu hình được sử dụng, nằm trong thư mục gốc của dự án hoặc dọc theo đường dẫn được chỉ định trong biến môi trường. Mã chịu trách nhiệm về những tiện ích này có thể được nhìn thấy trong phần giới thiệu.
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()
Logic ở đây khá đơn giản: chúng tôi kết hợp các cấu hình lớn từ thư mục dự án và các đường dẫn theo biến môi trường cũng như các phần cấu hình nhỏ từ các bí mật Kuber, sau đó xử lý trước chúng một chút. Cộng với một số biến. Tôi lưu ý rằng khi tìm kiếm tệp từ bí mật, giới hạn độ sâu sẽ được sử dụng, vì K8s tạo một thư mục ẩn trong mỗi bí mật nơi lưu trữ bí mật và chỉ một liên kết được đặt ở cấp cao hơn.
Tôi hy vọng những gì được mô tả sẽ hữu ích cho ai đó :) Mọi nhận xét và đề xuất liên quan đến bảo mật hoặc các lĩnh vực khác cần cải thiện đều được chấp nhận. Ý kiến của cộng đồng cũng rất thú vị, có lẽ đáng để bổ sung hỗ trợ cho ConfigMaps (dự án của chúng tôi chưa sử dụng chúng) và xuất bản mã trên GitHub/PyPI? Cá nhân, tôi nghĩ rằng những thứ như vậy quá riêng biệt để các dự án có thể mang tính phổ quát và xem qua một chút cách triển khai của người khác, như cách được đưa ra ở đây và thảo luận về các sắc thái, mẹo và phương pháp hay nhất mà tôi hy vọng sẽ thấy trong phần nhận xét , thế là đủ 😉
Chỉ những người dùng đã đăng ký mới có thể tham gia khảo sát.
Tôi có nên xuất bản dưới dạng dự án/thư viện không?
-
0,0%Có, tôi sẽ sử dụng /contribution0
-
33,3%Vâng, điều đó nghe tuyệt vời4
-
41,7%Không, ai cần tự làm việc đó theo hình thức riêng và phù hợp với nhu cầu của họ5
-
25,0%Tôi sẽ không trả lời3
12 người dùng bình chọn. 3 người dùng bỏ phiếu trắng.
Nguồn: www.habr.com