آموزش کوبرنتیز؛ شب هشتم: ConfigMapها¶
امشب پیکربندی غیرمحرمانه را از Image جدا میکنیم، آن را هم بهشکل متغیر محیطی و هم فایل Mountشده مصرف میکنیم و تفاوت رفتار این دو روش هنگام بهروزرسانی را میبینیم.
مدل ذهنی ConfigMap¶
ConfigMap دادههای کلید/مقدار را در API کوبرنتیز نگه میدارد. Pod میتواند یک کلید مشخص را مصرف کند، کلیدها را به متغیر محیطی تبدیل کند یا آنها را بهشکل فایل نمایش دهد. ConfigMap فقط برای پیکربندی غیرمحرمانه مناسب است.
ConfigMap key ── valueFrom ──> environment variable (captured at process start)
ConfigMap key ── volume ─────> file (eventually refreshed by kubelet)
وقتی ConfigMap تغییر میکند، متغیرهای محیطی داخل Process موجود تغییر نمیکنند. فایلهای Projectشده معمولاً با کمی تأخیر بهروزرسانی میشوند، نه بلافاصله. Mount کردن با subPath نیز بهروزرسانی خودکار ConfigMap را دریافت نمیکند.
Manifest برنامه¶
فایل app.yaml یک ConfigMap را از دو مسیر در اختیار NGINX قرار میدهد:
apiVersion: v1
kind: ConfigMap
metadata:
name: web-config
namespace: course-night-8
data:
COURSE_NIGHT: "8"
index.html: |
<!doctype html>
<html><body><h1>Configuration version 1</h1></body></html>
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: course-night-8
spec:
replicas: 2
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:1.27-alpine
env:
- name: COURSE_NIGHT
valueFrom:
configMapKeyRef:
name: web-config
key: COURSE_NIGHT
ports:
- name: http
containerPort: 80
volumeMounts:
- name: content
mountPath: /usr/share/nginx/html
readOnly: true
volumes:
- name: content
configMap:
name: web-config
items:
- key: index.html
path: index.html
---
apiVersion: v1
kind: Service
metadata:
name: web
namespace: course-night-8
spec:
selector:
app: web
ports:
- name: http
port: 80
targetPort: http
استقرار و بررسی¶
kubectl create namespace course-night-8
kubectl apply -f app.yaml
kubectl rollout status deployment/web --namespace course-night-8
kubectl get configmap web-config --namespace course-night-8 -o yaml
kubectl exec --namespace course-night-8 deployment/web -- \
sh -c 'printf "COURSE_NIGHT=%s\n" "$COURSE_NIGHT"; cat /usr/share/nginx/html/index.html'
kubectl run client --namespace course-night-8 --rm -it \
--restart=Never --image=curlimages/curl -- curl --fail http://web
Volume مربوط به ConfigMap محتوای Image را در دایرکتوری Mountشده جایگزین میکند. اگر فایلهای اصلی دایرکتوری اهمیت دارند، یک فایل مشخص را Mount کنید یا تمام فایلهای لازم را در ConfigMap قرار دهید.
روشهای مختلف ساخت ConfigMap¶
فرمانهای زیر شیوههای ساخت را بدون Apply کردن Object اضافی نشان میدهند:
kubectl create configmap literal-demo --namespace course-night-8 \
--from-literal=color=blue --dry-run=client -o yaml
kubectl create configmap file-demo --namespace course-night-8 \
--from-file=index.html --dry-run=client -o yaml
برای پیکربندی ماندگار، Manifest اعلانی انتخاب بهتری است؛ زیرا بازبینیپذیر و قابل بازتولید است.
آزمایش رفتار بهروزرسانی¶
متن index.html در app.yaml را به Configuration version 2 تغییر دهید:
kubectl diff -f app.yaml
kubectl apply -f app.yaml
kubectl get configmap web-config --namespace course-night-8 \
-o jsonpath='{.data.index\.html}{"\n"}'
تا دو دقیقه فایل Mountشده را بررسی کنید:
kubectl exec --namespace course-night-8 deployment/web -- \
sh -c 'while ! grep -q "version 2" /usr/share/nginx/html/index.html; do date; sleep 5; done; cat /usr/share/nginx/html/index.html'
اکنون مقدار COURSE_NIGHT را در Manifest به "88" تغییر و Apply کنید. ConfigMap تغییر میکند، اما متغیر محیطی Podهای موجود همچنان 8 باقی میماند:
kubectl apply -f app.yaml
kubectl exec --namespace course-night-8 deployment/web -- \
printenv COURSE_NIGHT
kubectl rollout restart deployment/web --namespace course-night-8
kubectl rollout status deployment/web --namespace course-night-8
kubectl exec --namespace course-night-8 deployment/web -- \
printenv COURSE_NIGHT
Rollout، Processهای تازهای میسازد که مقدار جدید را میخوانند. در محیط تولید معمولاً از Checksum پیکربندی در Annotation مربوط به Pod Template استفاده میشود تا این Restart خودکار انجام شود.
تمرین خرابی: کلید گمشده¶
موقتاً مقدار configMapKeyRef.key را از COURSE_NIGHT به MISSING تغییر دهید، Apply کنید و Pod جدید را بررسی کنید:
kubectl apply -f app.yaml
kubectl get pods --namespace course-night-8
kubectl describe pod <new-pod-name> --namespace course-night-8
kubectl get events --namespace course-night-8 \
--sort-by=.metadata.creationTimestamp
Container بهدلیل نبودن یک کلید اجباری شروع نمیشود. نام کلید را تعمیر، دوباره Apply و تا پایان Rollout صبر کنید.
چکلیست پایان¶
- یک ConfigMap را هم از طریق متغیر محیطی و هم فایل مصرف کردهام.
- رفتار بهروزرسانی هر دو روش را توضیح میدهم.
- خرابی ناشی از کلید گمشده را تشخیص داده و تعمیر کردهام.
- توضیح میدهم چرا Password و Token نباید داخل ConfigMap باشند.