🌐 Detecting your location…

كيفية إعداد Kubernetes محليًا باستخدام kind وk3d في عام 2026: الدليل الكامل

⏱️3 min read  ·  524 words

يُستخدم تشغيل Kubernetes محليًا ليعني جهازًا افتراضيًا ثقيلًا وانتظارًا طويلًا. kind وk3d غيرت ذلك عن طريق تشغيل المجموعات كحاويات، والتي تبدأ في ثوانٍ ولا تكلف شيئًا تقريبًا عندما تكون في وضع الخمول. يقوم هذا الدليل بإعداد مجموعة محلية عاملة مع الدخول وتحميل الصور المحلية وحلقة تطوير لا تتضمن الدفع إلى السجل عند كل تغيير.

النوع أو k3d: أيهما تختار

كلاهما يقوم بتشغيل Kubernetes داخل Docker. إنهم يختلفون في ما يقومون بتشغيله وما يقومون بتحسينه.

نوع ك 3د
كوبرنيتس المنبع، غير معدل k3s – خفيف الوزن، مع تبديل بعض المكونات
وقت البدء سريع أسرع
استخدام الذاكرة العالي أقل
الأفضل لـ اختبار مقابل السلوك المنبع الحقيقي، CI تكرار سريع، أجهزة كمبيوتر محمولة مقيدة

اخترنوع إذا كنت بحاجة إلى سلوك مماثل للإنتاج الأولي لـ Kubernetes، خاصة لمشغلي الاختبار أو وحدات التحكم في القبول. اخترك 3د إذا كنت تريد أسرع وأخف حلقة لتطوير التطبيقات. كلاهما ممتاز. يغطي هذا الدليل كل منها.

المتطلبات

# Docker must be running
docker version

# kubectl
brew install kubectl        # macOS
# or: curl -LO "https://dl.k8s.io/release/$(curl -Ls https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"

# kind
brew install kind

# k3d
brew install k3d

الخيار أ: النوع

تعتبر المجموعة أحادية العقدة أمرًا واحدًا، ولكن ملف التكوين يستحق الكتابة على الفور لأن الدخول يتطلب تعيينات المنافذ التي لا يمكن إضافتها لاحقًا دون إعادة إنشاء المجموعة.

# kind-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
  - role: control-plane
    kubeadmConfigPatches:
      - |
        kind: InitConfiguration
        nodeRegistration:
          kubeletExtraArgs:
            node-labels: "ingress-ready=true"
    extraPortMappings:
      - containerPort: 80
        hostPort: 80
        protocol: TCP
      - containerPort: 443
        hostPort: 443
        protocol: TCP
  - role: worker
  - role: worker
kind create cluster --name dev --config kind-config.yaml

# kubectl context is switched automatically
kubectl cluster-info --context kind-dev
kubectl get nodes

منع إعادة توجيه المنفذين المضيفين 80 و443 إلى عقدة نظام المجموعة، وهو ما يجعلextraPortMappings الوصول إلى وحدة تحكم الدخول الخاصة بك. أضفه مقدمًا — التعديل التحديثي يعني حذف المجموعة وإعادة إنشائها.http://localhostالدخول على النوع

الخيار ب: k3d

kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml

kubectl wait --namespace ingress-nginx \
  --for=condition=ready pod \
  --selector=app.kubernetes.io/component=controller \
  --timeout=90s

يعالج k3d تعيين المنافذ والدخول باستخدام العلامات، لذا يكون الإعداد أقصر. يتضمن k3s Traefik كوحدة تحكم في الدخول بشكل افتراضي.

لاستخدام ingress-nginx بدلاً من Traefik، قم بتعطيل الحزمة المجمعة في وقت الإنشاء.

k3d cluster create dev \
  --agents 2 \
  --port "80:80@loadbalancer" \
  --port "443:443@loadbalancer"

kubectl get nodes

نشر التطبيق

k3d cluster create dev \
  --agents 2 \
  --port "80:80@loadbalancer" \
  --k3s-arg "--disable=traefik@server:0"

أمر ضروري للتنمية المحلية. الافتراضي

# app.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: web
          image: my-app:dev
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 3000
          readinessProbe:
            httpGet:
              path: /healthz
              port: 3000
            initialDelaySeconds: 2
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
            limits:
              memory: 512Mi
---
apiVersion: v1
kind: Service
metadata:
  name: web
spec:
  selector:
    app: web
  ports:
    - port: 80
      targetPort: 3000
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web
spec:
  ingressClassName: nginx
  rules:
    - host: app.localhost
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web
                port:
                  number: 80

imagePullPolicy: IfNotPresent يجعل Kubernetes يحاول السحبAlways من سجل غير موجود، وفشلت الكبسولة معmy-app:devتحميل الصور المحلية — الخطوة التي يفوتها الجميعErrImagePull.

تعمل مجموعتك في حاوياتها الخاصة مع مخزن الصور الخاص بها. الصورة المبنية على مضيفك تكون غير مرئية لها حتى تقوم بتحميلها بشكل صريح.

ثم قم بالتقديم والتحقق.

# Build normally
docker build -t my-app:dev .

# kind
kind load docker-image my-app:dev --name dev

# k3d
k3d image import my-app:dev -c dev

إذا جلست القرون في

kubectl apply -f app.yaml
kubectl get pods -w
curl -H "Host: app.localhost" http://localhost/

، فمن المؤكد أنك تخطيت خطوة التحميل أو غادرتImagePullBackOff في وضعها الافتراضي.imagePullPolicyحلقة داخلية سريعة

إن إعادة البناء والتحميل وإعادة النشر يدويًا لكل تغيير أمر بطيء جدًا بحيث لا يمكن استمراره. طريقتان لإصلاحه.

إمالة أو سقالة

شاهد المصدر الخاص بك، وأعد البناء، وتحميل الصورة، وقم بتحديث النشر تلقائيًا.إعادة توجيه المنفذ

# Tiltfile
docker_build('my-app', '.')
k8s_yaml('app.yaml')
k8s_resource('web', port_forwards='3000:3000')
tilt up

يكفي عندما تحتاج فقط إلى الوصول إلى الخدمة دون الدخول.وحدات التخزين المستمرة

kubectl port-forward svc/web 3000:80
# now http://localhost:3000

توفر كلتا الأداتين فئة تخزين افتراضية، لذلك يعمل PersistentVolumeClaim بدون تكوين.

للاحتفاظ بالبيانات على مضيفك حتى ينجو من حذف المجموعة، قم بتثبيت دليل مضيف في وقت الإنشاء.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: data
spec:
  accessModes: [ReadWriteOnce]
  resources:
    requests:
      storage: 1Gi

التصحيح

# kind-config.yaml
nodes:
  - role: control-plane
    extraMounts:
      - hostPath: /Users/me/k8s-data
        containerPath: /data

هو الأمر الأول الذي يتم تشغيله لأي مشكلة تقريبًا. يوضح قسم الأحداث في الأسفل ما إذا كانت الصورة قد فشلت في السحب، أو كانت العقدة تفتقر إلى الموارد، أو فشل المسبار.

# Why is a pod not starting? Events are at the bottom.
kubectl describe pod <pod-name>

# Logs, including from a crashed previous container
kubectl logs <pod-name>
kubectl logs <pod-name> --previous

# Shell into a running container
kubectl exec -it <pod-name> -- sh

# Debug a container with no shell using an ephemeral container
kubectl debug -it <pod-name> --image=busybox --target=web

# Cluster-wide recent events, newest last
kubectl get events --sort-by=.metadata.creationTimestamp

kubectl describe podتنظيف

أخطاء شائعة

# kind
kind delete cluster --name dev

# k3d
k3d cluster delete dev

# k3d can also stop and restart without losing state
k3d cluster stop dev
k3d cluster start dev

نسيان تحميل الصورة.

لا يمكن للمجموعة رؤية صور Docker الخاصة بمضيفك. تحميلها بشكل صريح.مغادرة

في الوضع الافتراضي.imagePullPolicy مع العلامة الافتراضية هي:latest، والذي يفشل في الصور المحلية فقط.Alwaysإضافة تعيينات المنفذ بعد الإنشاء.

يتم إصلاحها عند إنشاء المجموعة. خطط لمنافذ الدخول قبل الإنشاء.إغفال طلبات الموارد.

وبدونها، لا يستطيع المجدول التفكير في السعة، وتبالغ المجموعات المحلية في الالتزام حتى يتم إخلاء الكبسولات.بافتراض أن الإنتاج المحلي يساوي الإنتاج.

لا تحتوي المجموعات المحلية على موازن تحميل حقيقي، ولا فئات تخزين سحابية، ولا يوجد تطبيق لسياسة الشبكة بشكل افتراضي. تعامل معهم كأداة تطوير، وليس كمحاكاة للإنتاج.الخلاصة

يحتاج إعداد Kubernetes المحلي الإنتاجي إلى أربعة أشياء صحيحة:

أنشئ المجموعة بتعيينات المنافذ التي ستحتاجها للدخول، وقم بتحميل الصور المحلية بشكل صريح في المجموعة، وقم بتعيين لذلك لا يلاحق Kubernetes السجل، ويقوم بأتمتة حلقة إعادة البناء باستخدام Tilt أو Skaffold.imagePullPolicy: IfNotPresent استخدم النوع عندما تحتاج إلى سلوك متطابق مع المنبع وk3d عندما تريد الحلقة الأخف والأسرع. يتيح لك كلاهما حذف مجموعة وإعادة إنشائها في ثوانٍ، وهي الميزة الحقيقية – لا تعد المجموعة المحلية المعطلة مشكلة تستحق التصحيح. استخدم النوع عندما تحتاج إلى سلوك متطابق مع المنبع وk3d عندما تريد الحلقة الأخف والأسرع. يتيح لك كلاهما حذف مجموعة وإعادة إنشائها في ثوانٍ، وهي الميزة الحقيقية – لا تعد المجموعة المحلية المعطلة مشكلة تستحق التصحيح.

MD Rafikul Islam

Written by

MD Rafikul Islam is a software developer and the editor of TechPulse. He writes about developer tooling, hardware, and the practical decisions that come up in day-to-day engineering work — which laptop to buy, which framework to commit to, why a build broke at 2am. He tests the tools he writes about and says plainly when something is not worth the money. Corrections and corrections requests are welcome at rony.yf25@gmail.com.

✍️ Leave a Comment

Your email address will not be published. Required fields are marked *

🌐 Read in:🇬🇧 English🇩🇪 Deutsch🇧🇷 Português🇸🇦 العربية🇮🇳 हिन्दी🇧🇩 বাংলা