یک اصل ثابت در استقرار برنامهها این است که تنظیمات از ایمیج جدا بماند: یک ایمیج واحد باید در توسعه، آزمایش و تولید اجرا شود و فقط پیکربندی آن عوض شود. در Kubernetes این جداسازی با دو منبع انجام میشود: ConfigMap برای تنظیمات عادی و Secret برای دادهی حساس. این راهنما روشهای ساخت و تزریق آنها به Pod، رفتار بهروزرسانی و محدودیتهای امنیتی Secret را توضیح میدهد.
K8SKubernetes YAML GeneratorConfigMap و Secret را با فرم بسازید و به Deployment متصل کنید.ساخت ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
LOG_LEVEL: info
FEATURE_X: "true"
app.yaml: |
server:
port: 8080
cache:
ttl: 60s
مقدارهای ConfigMap رشتهاند؛ مقدارهایی مثل true و عددها را داخل کوتیشن بنویسید تا YAML آنها را به نوع دیگری تفسیر نکند. هر کلید میتواند یک مقدار کوتاه یا محتوای کامل یک فایل (با |) باشد. از خط فرمان هم میتوان ساخت:
kubectl create configmap app-config --from-literal=LOG_LEVEL=info --from-file=app.yaml
سه روش تزریق به Pod
۱. متغیر محیطی تکی (env)
env:
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: app-config
key: LOG_LEVEL
۲. همهی کلیدها (envFrom)
envFrom:
- configMapRef:
name: app-config
- secretRef:
name: app-secret
۳. فایل (volume)
containers:
- name: app
volumeMounts:
- name: config
mountPath: /etc/app
readOnly: true
volumes:
- name: config
configMap:
name: app-config
items:
- key: app.yaml
path: app.yaml
کدام روش؟
| روش | بهروزرسانی خودکار | مناسب برای |
|---|---|---|
| env / envFrom | خیر؛ نیاز به ساخت دوبارهی Pod | تنظیمات ساده و کلید-مقدار |
| volume | بله، پس از تأخیر کوتاه (بهجز subPath) | فایلهای پیکربندی کامل |
kubectl rollout restart deployment/app است؛ یا هش محتوای ConfigMap را بهعنوان annotation در Pod template قرار دهید (کاری که Helm معمولاً با یک checksum انجام میدهد) تا هر تغییر، rollout جدید بسازد.Secret
Secret ساختاری شبیه ConfigMap دارد، با دو تفاوت: مقدارها در فیلد data بهصورت Base64 نوشته میشوند (یا در stringData بهصورت متن ساده که API خودش کدگذاری میکند)، و رفتار آن در لاگ و دسترسیها حساستر است.
apiVersion: v1
kind: Secret
metadata:
name: app-secret
type: Opaque
stringData:
DB_PASSWORD: s3cr3t-change-me
API_TOKEN: replace-with-real-token
B64Base64 Encoder/Decoderمقدار Secret را به Base64 تبدیل کنید یا یک مقدار موجود را رمزگشایی و بررسی کنید.چند نوع داخلی Secret وجود دارد که ابزارها آنها را میشناسند: kubernetes.io/tls (گواهی و کلید برای Ingress)، kubernetes.io/dockerconfigjson (ورود به رجیستری خصوصی برای imagePullSecrets) و kubernetes.io/basic-auth.
kubectl create secret tls example-com-tls --cert=fullchain.pem --key=privkey.pem
kubectl create secret docker-registry regcred \
--docker-server=registry.example.com --docker-username=ci --docker-password="$TOKEN"
Secret چقدر امن است؟
پاسخ کوتاه: بهتنهایی زیاد نه. چند واقعیت مهم:
- Base64 رمزنگاری نیست. هر کسی که بتواند Secret را بخواند، با یک دستور آن را رمزگشایی میکند.
- etcd: مقدارها بهطور پیشفرض بدون رمزنگاری ذخیره میشوند. برای رمزنگاری در حالت سکون،
EncryptionConfigurationرا برای API server فعال کنید (یا از KMS ابری استفاده کنید). - RBAC: دسترسی
get/listروی Secretها را فقط به حسابهایی بدهید که لازم دارند؛listهمهی مقدارها را در یک درخواست برمیگرداند. - متغیر محیطی: مقدار envها بهراحتی در لاگ برنامه، crash dump و ابزارهای عیبیابی نشت میکند. mount بهصورت فایل معمولاً ایمنتر است.
- هر کسی که بتواند Pod بسازد در یک namespace، میتواند Secretهای آن را در Pod خودش mount کند.
Secret در Git: چطور؟
در رویکرد GitOps همهچیز در Git است، ولی Secret را نباید بهصورت متن ساده commit کرد. گزینههای رایج:
| ابزار | ایده |
|---|---|
| Sealed Secrets | Secret با کلید عمومی کلاستر رمزنگاری و در Git ذخیره میشود؛ فقط کنترلر داخل کلاستر آن را میگشاید |
| SOPS | فایلهای YAML با کلید (age، KMS، PGP) رمزنگاری میشوند و فقط مقدارها پوشیده میمانند |
| External Secrets Operator | Secret از یک مخزن خارجی (Vault، AWS Secrets Manager و …) به کلاستر همگام میشود |
ConfigMapهای تغییرناپذیر
با immutable: true، ConfigMap یا Secret بعد از ساخت قابلویرایش نیست؛ هم خطای ناخواسته را کم میکند و هم بار روی API server را (kubelet دیگر آن را پایش نمیکند). برای تغییر، یک نسخهی جدید با نام تازه میسازید (مثل app-config-v2) و Deployment را به آن ارجاع میدهید؛ و rollout هم بهطور طبیعی رخ میدهد.
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config-v2
immutable: true
data:
LOG_LEVEL: debug
عیبیابی
CreateContainerConfigError: ConfigMap یا Secret (یا کلید داخل آن) وجود ندارد. باkubectl describe podنام دقیق را ببینید.- برنامه مقدار قدیمی را میخواند: env است و Pod ریاستارت نشده، یا فایل با
subPathmount شده است. - مقدار با کاراکتر اضافه میآید: هنگام Base64کردن از
echoبدون-nاستفاده شده و خط جدید انتهای رشته هم رمز شده است.
kubectl get secret app-secret -o jsonpath='{.data.DB_PASSWORD}' | base64 -d
echo -n 'value' | base64 # -n مهم است
جمعبندی و مطالعهی بعدی
تنظیمات عادی را در ConfigMap، دادهی حساس را در Secret بگذارید؛ برای فایلهای پیکربندی از volume و برای مقدارهای ساده از env استفاده کنید؛ و Secret را همیشه با RBAC، رمزنگاری etcd و ابزار مدیریت رمز (Sealed Secrets، SOPS یا External Secrets) همراه کنید. مانیفستهای Deployment که این منابع به آنها متصل میشوند در راهنمای مانیفستهای Kubernetes آمده است و اگر Pod با خطای پیکربندی بالا نمیآید، راهنمای عیبیابی را ببینید.
پرسشهای متداول
آیا Secret در Kubernetes رمزنگاری میشود؟
تغییر ConfigMap چرا روی Pod اعمال نشد؟
kubectl rollout restart). فایلهای mountشده از ConfigMap پس از مدتی خودکار بهروز میشوند، مگر با subPath mount شده باشند.فرق env و envFrom چیست؟
env متغیرها را یکییکی (با نام و ارجاع به کلید) تعریف میکند؛ envFrom همهی کلیدهای یک ConfigMap یا Secret را یکجا به متغیر محیطی تبدیل میکند. envFrom کوتاهتر است ولی کنترل کمتری روی نامها میدهد.