متى يستحق تشغيل k3s على VPS واحد؟
يمنحك k3s واجهة Kubernetes API الحقيقية على VPS واحد، لكنه يستهلك الذاكرة وقد يفشل التثبيت بسبب تعارض المنفذ 80. اكتشف متى يظل Docker Compose أنسب.
ما هو k3s وما الذي توفره عقدة واحدة منه
k3s توزيعة كاملة من Kubernetes، ومجمّعة في ملف ثنائي واحد. يتيح لك تشغيلها على VPS واحد استخدام واجهة Kubernetes API الفعلية من دون مستوى تحكم مؤلف من ثلاث آلات. وهي توزيعة معتمدة من Kubernetes، لذلك يمكن تطبيق manifest يعمل هنا على عنقود مُدار لاحقاً. يستغرق التثبيت أمراً واحداً ونحو دقيقة. أما التكلفة فهي ذاكرة لا تعود متاحة لتطبيقاتك، إضافة إلى مجموعة من حالات الفشل التي لا تحدث عند استخدام Docker Compose.
تطوّر SUSE k3s لمواقع edge وعمليات التثبيت الصغيرة. وكل اختلاف عن Kubernetes upstream يهدف إلى تقليل الحجم. مخزن البيانات الافتراضي هو sqlite عبر طبقة shim تسمى kine، وليس etcd، لذلك لا توجد quorum لـetcd يجب الحفاظ عليها. ويمَثّل containerd داخل الملف الثنائي بدلاً من تثبيته بشكل منفصل. ويضم الملف الثنائي نفسه أيضاً CoreDNS لخدمة DNS داخل العنقود، وTraefik بوصفه وحدة تحكم ingress، وServiceLB، المعروف أيضاً باسم klipper-lb، لكي تعمل خدمات LoadBalancer من دون مزود سحابي خلفها، وlocal-path provisioner لوحدات التخزين الدائمة، وmetrics-server، وflannel لشبكات pods. تبدأ كل هذه المكونات افتراضياً. لذلك يُعد تعارض المنافذ الموضح أدناه المشكلة الأولى الأكثر شيوعاً على VPS كان يشغّل خدمات أخرى مسبقاً.
متى يكون تشغيل عقدة واحدة من k3s مناسباً
اتبع هذه القاعدة. شغّل k3s عندما تكون واجهة Kubernetes البرمجية هي ما تحتاج إليه: عندما تتعلم Kubernetes على جهاز تتحكم فيه، أو عندما يكون البرنامج الذي تريده ينشر مخطط Helm فقط. وتُعد قابلية نقل ملفات Manifest مهمة أيضاً، لأن Deployment الذي تكتبه هنا يمكن نقله إلى عنقود مُدار من دون تعديل. شغّل Docker Compose عندما تكون التطبيقات هي ما تحتاج إليه. يبدأ Compose الحاويات نفسها مع عدد أقل بكثير من المكونات المتحركة، كما أن ملف Compose على VPS أسهل في القراءة بعد عام من مجلد يحتوي على ملفات Manifest.
كن واضحاً بشأن ما لا توفره عقدة واحدة.
- لا توفر الإتاحة العالية. عند إعادة تشغيل VPS، تتوقف كل أعباء العمل. يعيد Kubernetes جدولة pod على عقدة أخرى، ولا توجد عقدة أخرى.
- لا توفر تحديثاً تدريجياً يحافظ على تشغيل الخدمة، إلا إذا كان التطبيق يتحمل تشغيل نسختين متماثلتين على جهاز واحد مع مشاركة volume واحد.
- توفر تخزيناً مرتبطاً بالجهاز، للسبب الموضح في قسم local-path أدناه.
- توفر control plane يستهلك نحو 1 غيغابايت من RAM سواء نشرت أي شيء أم لا.
لا يجعل أي من ذلك k3s خياراً سيئاً. لكنه يجعله خياراً سيئاً للسبب الذي يذكره الناس عادة، وهو الاعتمادية. إذا كان ما تحتاج إليه فعلاً هو عدة أجهزة حتى تتمكن من إنشاء عنقود حقيقي متعدد العقد، فهذه هي الخطوة الأولى: يحدد Proxmox على أجهزتك الخاصة مقابل VPS مستأجر مصدر العقد قبل أن يحدد k3s ما سيُشغَّل عليها.
تكلفة k3s من الذاكرة العشوائية ووحدة المعالجة المركزية قبل نشر أي شيء
ينشر مشروع k3s أرقاماً مقاسة بدلاً من التقديرات. اقرأها بعناية، لأن الرقم المتداول لا يمثّل k3s في وضع الخمول.
The data behind this chart
[
{
"label": "Server, sqlite datastore",
"ram_mb": "1,596",
"cpu_percent_of_one_core": 6
},
{
"label": "Server, embedded etcd",
"ram_mb": "1,606",
"cpu_percent_of_one_core": 6
},
{
"label": "Agent node only",
"ram_mb": "275",
"cpu_percent_of_one_core": 3
}
]استخدمت عقدة خادم في ذلك الاختبار 1,596 MB من الذاكرة عند المئين 95، وحوالي 6 بالمئة من نواة واحدة. هذه أرقام منشورة وليست قياسات من هذا الدليل. أُجري الاختبار باستخدام k3s v1.26.5 مع تفعيل جميع المكونات المضمّنة، إضافةً إلى مكدس مراقبة Prometheus وGrafana. لذلك يشمل الرقم عبء عمل فعلياً، وليس عنقوداً فارغاً. أدى استبدال sqlite بـ embedded etcd إلى رفع الاستخدام إلى 1,606 MB. استخدمت عقدة agent، التي تشغّل kubelet وcontainerd من دون مستوى تحكم، 275 MB. الحد الأدنى الموثّق للخادم هو نواتان و2 GB من الذاكرة العشوائية. ويشمل هذا الحد الأدنى k3s ومكوناته المضمّنة قبل تشغيل أعباء العمل الخاصة بك.
القراءة العملية هي أن مستوى التحكم والإضافات المضمّنة يتركان مساحة قليلة جداً على VPS بسعة 2 GB. وعند زيادة الضغط، يبدأ kubelet أولاً بإخلاء الـpods. وتُعد سعة 4 GB حداً أدنى مريحاً لعقدة واحدة تشغّل بضع خدمات صغيرة. قِس موارد جهازك بنفسك بدلاً من الاعتماد على أي رقم منشور، بما في ذلك هذا الرقم.
free -h
sudo k3s kubectl top node
sudo k3s kubectl get pods -Aشغّل free -h قبل التثبيت، ثم شغّله مرة أخرى بعد أن تقرأ كل pod في kube-system الحالة Running. يوضّح الفرق تكلفة مستوى التحكم على أجهزتك. يعرض k3s kubectl top node القيمة error: Metrics API not available خلال الدقيقة أو الدقيقتين الأوليين بعد التثبيت، لأن metrics-server لم يجمع أي بيانات بعد. هذا ليس عطلاً. إذا كنت تجهّز جهازاً واحداً لتشغيل k3s وأعمال أخرى في الوقت نفسه، فتنطبق الحسابات الواردة في تحديد سعة الذاكرة العشوائية ووحدة المعالجة المركزية لـVPS هنا من دون تغيير.
ثبّت k3s على إصدار محدد، وليس على latest
يستخدم سطر البدء السريع الذي ينسخه الجميع الإصدار الذي تشير إليه القناة المستقرة في يوم تشغيله. إذا كنت تنوي الإبقاء على الجهاز، فثبّت الإصدار. ينشر k3s قناة لكل إصدار فرعي من Kubernetes، لذلك يتابع INSTALL_K3S_CHANNEL=v1.36 إصدارات التصحيح ضمن v1.36 ولا ينتقل تلقائياً إلى إصدار فرعي آخر. اعتباراً من August 2026، تشير القناة المستقرة إلى v1.36.3+k3s1.
اكتب ملف الإعداد أولاً، ثم نفّذ التثبيت. يقرأ k3s الملف /etc/rancher/k3s/config.yaml عند بدء التشغيل، لذلك تُطبَّق كل إعداداته في أول إقلاع وفي كل إقلاع لاحق.
sudo mkdir -p /etc/rancher/k3s
sudo tee /etc/rancher/k3s/config.yaml >/dev/null <<'EOF'
tls-san:
- k3s.example.com
EOF
curl -sfL https://get.k3s.io | INSTALL_K3S_CHANNEL=v1.36 sh -لتثبيت إصدار محدد بدلاً من قناة، استخدم INSTALL_K3S_VERSION=v1.36.3+k3s1. علامة الجمع جزء من الوسم. ثم تحقّق من بدء التشغيل بنجاح.
k3s --version
sudo systemctl status k3s
sudo k3s kubectl get node
sudo k3s kubectl get pods -Aيجب أن يعرض kubectl get node عقدة واحدة بحالة STATUS تساوي Ready خلال نحو ثلاثين ثانية، ويجب أن تصل كل Pod في kube-system إلى الحالة Running أو Completed. إذا بقيت العقدة في حالة NotReady، فهذا يعني عادةً أن وقت تشغيل الحاويات لم يبدأ، لذلك اقرأ sudo journalctl -u k3s -n 100 --no-pager. في صورة VPS غير معتادة، نفّذ sudo k3s check-config قبل تصحيح أي مشكلة أخرى؛ فهو يعرض ميزات النواة المفقودة، وهذا يقدّم إجابة أسرع بكثير من قراءة السجلات.
سبب استخدام المنفذ 80 مسبقاً، وما الذي يجب التخلي عنه لإصلاحه
هذا هو العطل الذي يظهر عادةً على VPS كان يقدّم خدمة من قبل. ينجح التثبيت، لكن Traefik لا يحصل على عنوان أبداً. وتستمر الخدمة التي كانت تعمل لديك، لذلك لا يبدو شيء معطلاً إلى أن تحاول الوصول إلى ingress.
الآلية كالتالي: ينشئ مخطط Traefik المضمّن Service من النوع LoadBalancer على المنفذين 80 و443. يستجيب ServiceLB لهذا الطلب بإنشاء DaemonSet من pods صغيرة، تبدأ أسماؤها بالبادئة svclb-، وتحجز رقمي المنفذين باعتبارهما hostPort على كل عقدة. ينشر hostPort منفذ الحاوية مباشرةً في مساحة أسماء الشبكة الخاصة بالعقدة، تماماً كما يفعل docker run -p 80:80. إذا كان nginx أو Caddy أو Apache أو حاوية أخرى تستخدم المنفذ 80، فلن يسلّمه kernel إلى جهة ثانية، ولذلك لا يجد scheduler مكاناً لوضع الـpod.
sudo k3s kubectl -n kube-system get pods
sudo k3s kubectl -n kube-system get svc traefik
sudo ss -lntp '( sport = :80 or sport = :443 )'سترى pod الخاص بـsvclb في حالة Pending، وسترى الخدمة من دون عنوان خارجي:
svclb-traefik-8f2c1a-r6k9x 0/2 Pending 0 3m
traefik LoadBalancer 10.43.62.11 <pending> 80:31480/TCP,443:30219/TCPيعرض تشغيل kubectl -n kube-system describe pod svclb-traefik-... السبب مباشرةً:
0/1 nodes are available: 1 node(s) didn't have free ports for the requested pod ports.يخبرك ss -lntp بالعملية التي تستخدم المنفذ. توجد عدة طرق للحل، ولكل طريقة تكلفة.
امنح المنافذ إلى k3s. أوقف خادم الويب الحالي وعطّل تشغيله، ثم دع Traefik يملك المنفذين 80 و443. هذا هو الخيار الصحيح عندما سيصبح VPS خادم k3s فقط، وعندما ستُنقل كل الخدمات التي كنت تقدّمها إلى خلف Ingress.
عطّل ServiceLB واحتفظ بالـproxy الحالي. ثبّت باستخدام --disable=servicelb. ما زالت Service من النوع LoadBalancer تخصّص NodePort، لذلك يبقى Traefik قابلاً للوصول عبر منفذ مرتفع مثل 31480، ويوجّه nginx أو Caddy الطلبات إلى 127.0.0.1:31480. ما تتخلى عنه هو العنوان الخارجي: ستعرض الخدمة <pending> دائماً. وقد يبدو ذلك عطلاً، لكنه في الواقع نتيجة اختيارك.
عطّل Traefik ووجّه الطلبات باستخدام proxy الخاص بك. ثبّت باستخدام --disable=traefik. لن يكون لديك بعد ذلك ingress controller، ولذلك لن تنفّذ Ingress objects أي شيء: ستبقى في API من دون controller يراقبها. هذا مناسب عندما توجّه الطلبات من proxy على المضيف إلى NodePorts، وهو الخيار الصريح إذا كنت تعرف مسبقاً كيف تريد معالجة HTTP. إذا لم تحسم ما الذي يجب وضعه في الواجهة، فاحسم الاختيار بين nginx وCaddy وTraefik باعتبارها reverse proxy قبل تعطيل أي مكوّن.
يجب وضع كلا الخيارين في برنامج التثبيت أو في ملف الإعداد:
tls-san:
- k3s.example.com
disable:
- traefik
- servicelbيعمل تعديل ذلك الملف بعد التثبيت ثم تشغيل sudo systemctl restart k3s أيضاً، لأن --disable لا يكتفي بتخطي مكوّن أثناء التثبيت. بل يحذف أيضاً مكوّناً منشوراً مسبقاً، ولذلك يسري التغيير على cluster قيد التشغيل.
للاحتفاظ بـTraefik مع تغيير طريقة إعداد المخطط، لا تعدّل /var/lib/rancher/k3s/server/manifests/traefik.yaml. يعيد k3s كتابة ذلك الملف بالقيم الافتراضية عند كل بدء تشغيل. أضف ملفاً منفصلاً في الدليل نفسه، لأن أي شيء في /var/lib/rancher/k3s/server/manifests يُطبّق تلقائياً عند بدء التشغيل وكلما تغيّر الملف على القرص.
apiVersion: helm.cattle.io/v1
kind: HelmChartConfig
metadata:
name: traefik
namespace: kube-system
spec:
valuesContent: |-
ports:
web:
forwardedHeaders:
trustedIPs:
- 10.0.0.0/8يضبط هذا المثال قيمة واحدة في مخطط Traefik، وهي عناوين الـproxy الموثوقة. وتضبط الآلية نفسها أي قيمة أخرى يتيحها المخطط، بما في ذلك منافذه.
التخزين الدائم على عقدة واحدة
يأتي k3s مع StorageClass افتراضي باسم local-path، ويعتمد على local-path provisioner من Rancher. يحصل عليه PersistentVolumeClaim الذي لا يحتوي على storageClassName. توجد وحدات التخزين في /var/lib/rancher/k3s/storage، مع مجلد فرعي واحد لكل وحدة تخزين، على قرص العقدة نفسها.
sudo k3s kubectl get storageclass
sudo k3s kubectl get pvc -A
sudo ls -l /var/lib/rancher/k3s/storageتترتب على عبارة «على قرص العقدة نفسها» نتيجتان، ولن تظهر كلتاهما فوراً، بل لاحقاً.
يستخدم StorageClass القيمة volumeBindingMode: WaitForFirstConsumer، لذلك تبقى PVC جديدة في حالة Pending إلى أن يقوم pod بتركيبها فعلياً. يعرض kubectl describe pvc ما يلي:
waiting for first consumer to be created before bindingهذا سلوك طبيعي. لذلك لن يؤدي إنشاء PVC وحدها والانتظار إلى تغيير حالتها.
بعد ربط وحدة التخزين، تحمل node affinity للعقدة التي أنشأتها. ويؤدي ذلك إلى تثبيت كل pod يستخدم هذا الطلب على تلك العقدة طوال عمر وحدة التخزين. لن تلاحظ المشكلة على عقدة واحدة. لكن عند إضافة عقدة ثانية لاحقاً، سيبدو pod الذي يرفض الانتقال وكأن به خللاً في المجدول، إلى أن تشغّل kubectl get pv -o yaml وتجد اسم المضيف في nodeAffinity.
أنت مسؤول عن النسخ الاحتياطية. تؤدي إعادة إنشاء VPS إلى حذف ذلك المجلد، وكذلك يفعل سكربت إلغاء التثبيت أدناه. انسخ /var/lib/rancher/k3s/storage احتياطياً، إضافة إلى مخزن بيانات sqlite في /var/lib/rancher/k3s/server/db/state.db، على أن تنسخه بعد إيقاف الخدمة لأنه قاعدة بيانات قيد الاستخدام. البديل هو التعامل مع العنقود باعتباره قابلاً للحذف، والاحتفاظ بكل manifest في git.
Ingress وTLS
مع إبقاء Traefik مفعّلاً، يكفي استخدام كائن Ingress قياسي.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: hello
annotations:
cert-manager.io/cluster-issuer: letsencrypt
spec:
ingressClassName: traefik
tls:
- hosts:
- hello.example.com
secretName: hello-tls
rules:
- host: hello.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: hello
port:
number: 80لا تظهر الشهادات تلقائياً. الحل المعتاد هو cert-manager، الذي يُثبَّت من manifest المنشور الخاص به، مع كائن ClusterIssuer واحد. الإصدار v1.21.1 هو الإصدار الحالي اعتباراً من August 2026.
sudo k3s kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.21.1/cert-manager.yamlapiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt
spec:
acme:
email: you@example.com
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-account-key
solvers:
- http01:
ingress:
ingressClassName: traefikيعني تحدي HTTP-01 أن خادم ACME (بيئة إدارة الشهادات التلقائية) يتصل بـ http://hello.example.com/.well-known/acme-challenge/... من الإنترنت العام. لذلك يجب أن يشير سجل DNS من النوع A مسبقاً إلى VPS، ويجب أن يصل المنفذ 80 إلى Traefik. إذا عطّلت ServiceLB ووضعت proxy خاصاً بك أمام Traefik، فيجب أن يمرّر ذلك الـproxy مسار التحدي أيضاً، وإلا يتوقف cert-manager ويعرض الرسالة التالية على كائن Challenge:
Waiting for HTTP-01 challenge propagation: wrong status code '404', expected '200'راقب إصدار الشهادة باستخدام sudo k3s kubectl describe certificate hello-tls وsudo k3s kubectl get order,challenge -A.
ملف kubeconfig، ولماذا يبقى خادم API خاصاً
يكتب k3s بيانات اعتماد المسؤول في /etc/rancher/k3s/k3s.yaml. يملك root الملف، ويُنشئه افتراضياً بالوضع 600. يحتوي الملف على شهادة عميل بصلاحيات cluster-admin، لذلك فإن أي شخص يستطيع قراءته يسيطر على العنقود.
sudo k3s kubectl get node
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
kubectl get nodeيفشل kubectl المثبّت بشكل منفصل، عند عدم ضبط KUBECONFIG، مع The connection to the server localhost:8080 was refused - did you specify the right host or port? لأنّه يعود إلى قيمة افتراضية لا علاقة لها بـk3s. اضبط KUBECONFIG، أو استخدم sudo k3s kubectl، الذي يقرأ الملف الصحيح تلقائياً.
سترى التوصية باستخدام --write-kubeconfig-mode 644 حتى يتمكن مستخدم عادي من تشغيل kubectl. افهم أثر ذلك: فهو يجعل بيانات اعتماد cluster-admin قابلة للقراءة من كل حساب محلي على الجهاز. قد يكون ذلك مقبولاً على جهاز يديره مسؤول واحد. لكنه غير مناسب على جهاز مشترك. يتيح نسخ الملف لمستخدم واحد الوصول إليه من دون نشره:
mkdir -p ~/.kube
sudo install -o $USER -g $USER -m 600 /etc/rancher/k3s/k3s.yaml ~/.kube/configيقرأ السطر server: في ذلك الملف https://127.0.0.1:6443. لاستخدام kubectl من جهازك المحمول، لا تفتح المنفذ 6443 أمام الإنترنت. يشكل Kubernetes API عاماً هدفاً دائماً، وقد يؤدي كشفه إلى استخدام العناقيد الصغيرة لتعدين العملات المشفرة لصالح شخص آخر. أنشئ نفقاً عبر SSH واترك العنوان في الملف كما هو:
ssh -N -L 6443:127.0.0.1:6443 user@your-vps
KUBECONFIG=./k3s.yaml kubectl get nodeإذا كان يجب الوصول إلى API عبر عنوان شبكة خاصة، فثبّت باستخدام tls-san مع إدراج ذلك الاسم أو العنوان، ثم عدّل سطر server: في الملف المنسوخ ليطابقه. من دون إدخال SAN (subject alternative name)، يرفض kubectl الاتصال:
x509: certificate is valid for 127.0.0.1, 10.43.0.1, not 203.0.113.10المنافذ الواردة الموثقة للعنقود هي TCP 6443 لـAPI، وUDP 8472 لـflannel VXLAN بين العقد، وTCP 10250 لمقاييس kubelet. في العقدة الواحدة، لا يحتاج أي منها إلى أن يكون مفتوحاً أمام الإنترنت.
containerd ليس Docker
يشغّل k3s نسخة containerd مضمّنة خاصة به، ولا يشارك مخزن الصور مع Docker. تكون الصورة التي أنشأتها للتو باستخدام docker build غير مرئية لـk3s، لذلك تفشل الـpod مع ErrImagePull رغم أن docker images يعرضها. استوردها صراحةً:
docker save myapp:0.1 | sudo k3s ctr images import -
sudo k3s crictl imagesبعد ذلك، تجنّب استخدام الوسم :latest مع تلك الحاوية، لأن :latest يستخدم افتراضياً imagePullPolicy بقيمة Always، ولذلك يتصل kubelet بسجل الصور على أي حال. تستخدم أي وسم آخر افتراضياً IfNotPresent، الذي يعتمد على الصورة التي استوردتها. يمكن تشغيل كليهما على VPS واحد، ومن المفيد معرفة أن تثبيت Docker عادي على VPS وk3s يحتفظ كل منهما بمخزن الصور الخاص به وقواعد iptables الخاصة به على الجهاز نفسه.
كيفية إزالة k3s
ينشئ برنامج التثبيت نصاً لإلغاء التثبيت. لا توجد إزالة جزئية ولا طريقة للتراجع.
sudo /usr/local/bin/k3s-uninstall.shيوقف الخدمة ويزيلها، ويحذف مخزن البيانات، ويحذف بيانات وحدات التخزين المستمرة، ويزيل إعدادات العقدة، ويزيل الأدوات التي أضافها برنامج التثبيت. في عقدة الوكيل، يكون النص البرمجي هو k3s-agent-uninstall.sh بدلاً من ذلك. انسخ كل ما يوجد ضمن /var/lib/rancher/k3s/storage إلى خارج الخادم أولاً، لأن ذلك المجلد سيُحذف معه. بعد ذلك، تحقق من عدم بقاء أي عملية تستخدم المنافذ أو الواجهات، باستخدام ip link show وsudo ss -lntp. تُزال أي واجهة cni0 أو flannel.1 متبقية عند إعادة التشغيل التالية.
إن تبين أن عقدة واحدة من Kubernetes تتضمن مكونات أكثر مما تتطلبه المهمة، فهذه نتيجة طبيعية وليست فشلاً. وعادةً ما تستغرق إعادة أعباء العمل إلى Compose فترة بعد الظهر.
أنماط الفشل والعبارات التي ستظهر لك
Node NotReady، أو إعادة تشغيل k3s في حلقة متكررة. اقرأ sudo journalctl -u k3s -n 200 --no-pager أولاً. في VPS صغير، يكون السبب الشائع هو أن قاتل نفاد الذاكرة في النواة ينهي العملية، ويظهر ذلك في dmesg كسطر يذكر k3s-server. الحد الأدنى الموثق البالغ 2 GB هو حد فعلي.
بقاء Pod في حالة Pending. يحدد kubectl describe pod السبب في كل مرة. يشير Insufficient memory أو Insufficient cpu إلى أن العقدة لم تعد تملك مساحة كافية. أما didn't have free ports فهو تعارض hostPort المذكور أعلاه. وظهور waiting for first consumer في PVC يعني أن WaitForFirstConsumer يعمل كما ينبغي.
ImagePullBackOff. إما أن الوسم غير موجود في أي registry يمكن للعقدة الوصول إليه، أو أنك أنشأت image باستخدام Docker ولم تستوردها إلى containerd.
يستجيب Traefik، لكن التطبيق لا يستجيب. يأتي نص الاستجابة 404 page not found من Traefik نفسه، ويعني أن الطلب وصل، لكن لم يطابقه أي router. تحقق من أن host في Ingress يطابق الاسم الذي أدخلته، وأن ingressClassName هو traefik.
يفشل DNS داخل cluster بينما يحلّ المضيف الأسماء بشكل صحيح. تحقق من CoreDNS باستخدام sudo k3s kubectl -n kube-system logs -l k8s-app=kube-dns. تؤدي رسالة مثل plugin/loop: Loop ... detected for zone "." إلى منع CoreDNS من البدء. يحدث ذلك لأن CoreDNS يوجّه الطلبات إلى resolver يعيد توجيهها إليه، وهذا ما يسببه عنوان loopback في /etc/resolv.conf. وجّه k3s إلى ملف upstream الفعلي باستخدام --resolv-conf /run/systemd/resolve/resolv.conf.
FAQ
هل يستحق تشغيل k3s على VPS واحد؟
يستحق ذلك عندما تكون واجهة Kubernetes البرمجية هي ما تريده: لتعلّمها على جهاز تتحكم فيه، أو للحفاظ على قابلية نقل عمليات النشر بصيغة manifests، أو لتشغيل برمجيات لا تنشر إلا مخطط Helm، أو لبناء شيء ستنقله لاحقاً إلى عنقود مُدار. لا يستحق ذلك عندما تريد فقط تشغيل الحاويات، لأن Docker Compose يحقق ذلك مع قدر أقل بكثير من الصيانة، ويوفّر نحو غيغابايت إضافية من الذاكرة الحرة. لا توفر العقدة الواحدة إتاحة عالية، لذلك لا تكون الموثوقية سبباً لاختيارها.
لماذا تبقى خدمة LoadBalancer في k3s بحالة Pending؟
ينشئ ServiceLB وحدات svclb- تحجز منافذ الخدمة على العقدة باستخدام hostPort، ولذلك لا تُجدول إلا عندما تكون هذه المنافذ حرة. إذا كان nginx أو وكيل آخر يستخدم المنفذ 80 مسبقاً، تبقى الوحدة في حالة Pending ولا تحصل الخدمة على عنوان خارجي. يعرض kubectl -n kube-system describe pod svclb-... نتيجة 0/1 nodes are available: 1 node(s) didn't have free ports for the requested pod ports. حرّر المنفذ، أو أعد التثبيت باستخدام --disable=servicelb، ثم وجّه الطلبات إلى NodePort الذي تستمر الخدمة في تخصيصه.
ما مقدار الذاكرة التي يحتاج إليها k3s على VPS؟
الحد الأدنى الموثق لعقدة الخادم هو نواتان و2 GB، ويغطي ذلك k3s ومكوّناته المضمّنة قبل تشغيل أحمالك. قاس تحليل المشروع نفسه عقدة خادم باستخدام 1,596 MB مع تشغيل حزمة مراقبة عليها، لذلك اعتبر 2 GB الحد الأدنى و4 GB أول حجم مريح لعقدة واحدة. قِس جهازك باستخدام free -h قبل التثبيت، ثم أعد القياس بعد أن تقرأ كل وحدة في kube-system الحالة Running.
هل يمكنني تشغيل Docker وk3s على VPS نفسه؟
نعم، ويظل كل منهما منفصلاً عن الآخر. يستخدم k3s خدمة containerd مضمّنة خاصة به، لذلك لا تظهر له صورة أنشأتها باستخدام docker build حتى تشغّل docker save myapp:0.1 | sudo k3s ctr images import -. يكتب كل منهما أيضاً قواعد iptables الخاصة به وشبكات bridge الخاصة به. راقب إجمالي الذاكرة، لأن Docker وk3s وحاوياتك لن تتسع في جهاز بسعة 2 GB.
كيف أزيل k3s بالكامل؟
شغّل sudo /usr/local/bin/k3s-uninstall.sh على عقدة خادم، أو sudo /usr/local/bin/k3s-agent-uninstall.sh على عقدة agent. يوقف ذلك الخدمة، ويحذف مخزن البيانات، ويحذف بيانات وحدات التخزين الدائمة تحت /var/lib/rancher/k3s/storage، ويزيل الأدوات المضمّنة. انسخ أي بيانات تريد الاحتفاظ بها إلى خارج الجهاز أولاً، لأنه لا توجد طريقة للتراجع. تختفي واجهة الشبكة المتبقية cni0 أو flannel.1 عند إعادة التشغيل التالية.