সরাসরি পর্বে যান
পর্ব ৪২ · ৮১-এর মধ্যে · মডিউল ৮

Kubernetes কেন — control plane, node আর reconciliation loop

Why Kubernetes — Control Plane, Nodes and the Reconciliation Loop

Taught in Bangla, this lesson shows where Compose stops and what an orchestrator adds, the control plane and node components, declarative desired state, the reconciliation loop, the path of kubectl apply through the scheduler, a real Pod-deletion test on a local cluster, reading a cluster with kubectl, etcd quorum, managed Kubernetes, and when to skip Kubernetes.

এই পর্বে যা শিখবেন

  • Compose কোন তিনটি কাজ পারে না, আর সেখান থেকে Kubernetes-এর দরকার কেন আসে
  • Control plane আর node-এর প্রতিটি অংশের কাজ, এবং কে কার সাথে কথা বলে
  • Declarative আর imperative-এর পার্থক্য, spec আর status-এর অর্থ
  • kubectl apply থেকে চলন্ত container পর্যন্ত পুরো পথ, watch আর scheduler-সহ
  • get, describe, explain, event, namespace, label আর selector ব্যবহার করে cluster পড়া
  • etcd quorum-এর হিসাব, managed Kubernetes-এ কে কী চালান, আর কখন Kubernetes না নেওয়াই ভালো

১ · Compose যেখানে থেমে যায়

মডিউল ৭-এ আপনি image বানিয়েছেন, container চালিয়েছেন, আর পর্ব ৪০-এ একটি file দিয়ে পুরো stack তুলেছেন। একটি VM-এ একটি কাল্পনিক অনলাইন বাজার অ্যাপ এভাবে ভালোই চলে। তারপর ঈদের আগে ভিড় বাড়ল, আর VM-টি রাত ২টায় বন্ধ হয়ে গেল। Compose এখানে কী করবে? কিছুই না, কারণ Compose নিজেই সেই VM-এর ওপর নির্ভর করে।

দরকারDocker ComposeKubernetes-এর মতো orchestrator
অনেক machineএকটি Docker Engine-এর ভেতরেই কাজ করেঅনেক machine মিলে একটি cluster; কোন container কোথায় বসবে, সে নিজে ঠিক করে
নিজে থেকে সেরে ওঠাrestart: always একই machine-এ container আবার চালায়; machine গেলে সব গেলSelf-healing: Pod হারালে অন্য node-এ নতুন Pod বসে
ধাপে ধাপে আপডেটup -d container বদলায়, মাঝে সাধারণত অল্প ফাঁক থাকেকয়েকটি করে Pod বদলায়, সমস্যা হলে থামে আর ফিরিয়ে আনা যায় (পর্ব ৪৪)
নজরদারিdocker compose up চললে কাজ শেষ; পরে কেউ মিলিয়ে দেখে নাController সারাক্ষণ মিলিয়ে দেখে

একটি বাস কোম্পানির ডিপো ভাবুন। দেয়ালের চার্টে লেখা: “সকাল ৮টায় এই রুটে ৩০টি বাস থাকবে।” একটি বাস নষ্ট হলে ম্যানেজার কোনো মালিককে ফোন করে অনুমতি চান না। তিনি চার্ট দেখেন, গুনে দেখেন ২৯টি আছে, আর অন্য একটি বাস পাঠান। চার্ট হলো desired state, ম্যানেজার হলো control plane, আর প্রতিটি বাসের চালক হলেন node-এ থাকা kubelet. Compose সেখানে একজন মালিক, যাঁর একটিই গাড়ি: গাড়ি নষ্ট হলে তিনি নিজেই সারান, অন্য গাড়ি পাঠানোর উপায় তাঁর নেই।

Google বহু বছর ধরে নিজের সব কাজ Borg নামের একটি অভ্যন্তরীণ cluster manager-এ চালাত। ২০১৪ সালে Google Kubernetes open source হিসেবে প্রকাশ করে; নামটি গ্রিক, অর্থ জাহাজের চালক বা মাঝি। ছোট করে লেখা হয় k8s, কারণ k আর s-এর মাঝে ৮টি অক্ষর। Borg-এর বিস্তারিত নিবন্ধ আসে পরে: Verma ও সহকর্মীদের “Large-scale cluster management at Google with Borg” (EuroSys, ২০১৫). একই বছর Kubernetes ১.০ প্রকাশিত হয়, আর Linux Foundation-এর অধীনে গঠিত CNCF (Cloud Native Computing Foundation) প্রকল্পটির দায়িত্ব নেয়। Burns ও সহকর্মীদের “Borg, Omega, and Kubernetes” (২০১৬) লেখায় এই তিন প্রজন্মের শিক্ষা পাবেন।

একই সময়ে Docker Swarm আর Apache Mesos-ও এই কাজ করত, আর আজও HashiCorp Nomad-এর মতো বিকল্প আছে। Kubernetes শুধু বেশি ব্যবহৃত, একমাত্র নয়। তবে cloud provider-গুলোর managed সেবা আর tool-এর বড় বাস্তুতন্ত্র একে আজকের চাকরির বাজারে প্রায় আবশ্যিক দক্ষতা করে তুলেছে।

২ · Cluster-এর মানচিত্র: control plane আর node

একটি Kubernetes cluster-এর দুই ভাগ। Control plane হলো ডিপোর অফিস: সিদ্ধান্ত নেয়, হিসাব রাখে। Node হলো সেই VM বা physical machine, যেখানে আপনার container সত্যিই চলে। পর্ব ৬-এ আপনি control plane আর data plane শব্দ দুটি cloud-এর প্রসঙ্গে দেখেছেন; এখানেও একই ভাগ: node-গুলো মিলে data plane.

Kubernetes cluster-এর অংশগুলো

সব তির API server-এ এসে মেলে। etcd-র সাথে কথা বলে শুধু API server.

Control plane আর node: সব সংযোগ API server-এ মেলে Control plane Node ১ Node ২ kubectl, CI API serverএকমাত্র দরজা etcdহিসাবের খাতা SchedulerPod → node Controllermanager: লুপ kubelet kubelet kube-proxy kube-proxy runtime (CRI) runtime (CRI) Pod Pod Pod Pod watch আর status
ছবি ৪২.১ — প্রতিটি অংশ শুধু API server-কে চেনে। কেউ কাউকে সরাসরি আদেশ দেয় না; সবাই API server-এর object পড়ে আর লেখে।
অংশকোথায়কাজডিপোর ভাষায়
API serverControl planeএকমাত্র দরজা: পরিচয় যাচাই, অনুমতি, নিয়ম যাচাই, তারপর সংরক্ষণঅফিসের কাউন্টার
etcdControl planeসব object রাখার key-value database; Raft দিয়ে কয়েকটি কপি মেলায়হিসাবের মূল খাতা
SchedulerControl planeযে Pod-এর node ঠিক হয়নি, তার জন্য node বেছে দেয়কোন বাস কোন রুটে, যিনি ঠিক করেন
Controller managerControl planeঅনেকগুলো controller একসাথে চালায়: Deployment, ReplicaSet, Node, Job প্রভৃতিচার্ট মিলিয়ে দেখা ম্যানেজার
kubeletপ্রতিটি nodeএই node-এর জন্য ঠিক হওয়া Pod চালায়, অবস্থা জানায়বাসের চালক
kube-proxyপ্রতিটি nodeService-এর ঠিকানা থেকে Pod-এ traffic পাঠানোর নিয়ম বসায় (পর্ব ৪৫); কিছু network plugin এই কাজ নিজেই করেস্টেশনের দিকনির্দেশক
Container runtimeপ্রতিটি nodeআসলে container চালায়; kubelet তার সাথে CRI দিয়ে কথা বলে। যেমন containerd, CRI-Oবাসের ইঞ্জিন

CRI (Container Runtime Interface) হলো kubelet আর runtime-এর মাঝের একটি gRPC চুক্তি। এর ফলে Kubernetes কোনো একটি runtime-এ বাঁধা নয়। ১.২৪ version (২০২২) থেকে Kubernetes-এর ভেতরের Docker সংযোগ (dockershim) সরানো হয়েছে, তবে Docker দিয়ে বানানো OCI image আগের মতোই চলে। পর্ব ৩৬-এর image এখানেও একই image.

এই পর্বের আউটপুট কোথা থেকে: নিচের সব kubectl আউটপুট একটি local single-node cluster-এ (Kubernetes ১.৩৪) আসল run থেকে নেওয়া। নাম, age, IP আর সময় আপনার cluster-এ আলাদা হবে। অপ্রাসঙ্গিক লাইন … দিয়ে ছাঁটা হয়েছে। Production থেকে এর বড় পার্থক্য: এখানে একটি machine-ই control plane আর node, আর etcd-র সদস্য মাত্র একজন। একাধিক node লাগে এমন অংশ আমরা model হিসেবে চিহ্নিত করেছি।

এই cluster-এ control plane-এর অংশগুলোও Pod হিসেবে চলে। তাই সেগুলো চোখে দেখা যায়:

$ kubectl get pods -n kube-system --no-headers
etcd-docker-desktop                      1/1   Running   0     4m52s
kube-apiserver-docker-desktop            1/1   Running   0     4m52s
kube-controller-manager-docker-desktop   1/1   Running   0     4m16s
kube-proxy-j6w94                         1/1   Running   0     4m16s
kube-scheduler-docker-desktop            1/1   Running   0     4m52s
…

৩ · আদেশ নয়, ফল বলুন: declarative desired state

Docker শেখার সময় আপনি ধাপগুলো বলে দিতেন: “এই container চালান, তারপর ওইটি মুছুন।” একে বলে imperative ধরন। Kubernetes-এর মূল ধরন declarative: আপনি শেষ ফলটি লিখে জমা দেন, আর পথ খোঁজে সিস্টেম। পার্থক্যটি রিকশাচালককে “ডানে যান, তারপর বামে” বলা আর রাইড-শেয়ারিং অ্যাপে শুধু গন্তব্য বসিয়ে দেওয়ার মতো।

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
  namespace: abcl-ka
  labels:
    app: web
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: nginx
          image: nginx:1.27-alpine
          imagePullPolicy: IfNotPresent
          resources:
            requests:
              cpu: 10m
              memory: 16Mi
            limits:
              cpu: 100m
              memory: 32Mi

এই file-কে বলে manifest. প্রতিটি API object-এর একই গড়ন:

ক্ষেত্রঅর্থকে লেখে
apiVersionAPI-র কোন দল আর version. apps/v1 মানে apps দল, v1আপনি
kindObject-এর ধরন: Pod, Deployment, Service…আপনি
metadataনাম, namespace, label, আর সিস্টেমের লেখা uid, resourceVersionদুজনেই
specযা চান: desired stateআপনি
statusযা আছে: দেখা অবস্থাController, kubelet

এই একটি ভাগ, spec বনাম status, পুরো Kubernetes-কে ব্যাখ্যা করে। Server-এ জমা থাকা object পড়লে দুটিই পাশাপাশি দেখা যায়:

$ kubectl get deploy web -n abcl-ka -o yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  …
  generation: 3
  name: web
  namespace: abcl-ka
  resourceVersion: "1303"
  uid: 152895a9-4ff0-43cd-88c8-9e8e2228b19c
spec:
  progressDeadlineSeconds: 600
  replicas: 3
  …
status:
  availableReplicas: 3
  …
  observedGeneration: 3
  readyReplicas: 3
  replicas: 3
  updatedReplicas: 3

spec-এ আপনার না লেখা progressDeadlineSeconds-ও আছে: API server ডিফল্ট মান বসিয়েছে। generation বাড়ে যখন spec বদলায়। observedGeneration জানায় controller কোন generation পর্যন্ত দেখেছে। দুটি সমান, অর্থাৎ controller সর্বশেষ চাওয়াটি দেখেছে।

একই file বারবার জমা দিলে কী হয়

create একটি আদেশ, তাই দ্বিতীয়বার ব্যর্থ। apply বলে “এটাই হোক”, তাই সে idempotent. নিচের run-এ আরেকটি পরীক্ষাও আছে: হাতে scale করে file থেকে সরে যাওয়া, যাকে drift বলে, তারপর apply-এ ফিরে আসা।

$ kubectl create -f web.yaml
Error from server (AlreadyExists): error when creating "web.yaml":
deployments.apps "web" already exists
$ kubectl apply -f web.yaml
deployment.apps/web unchanged

$ kubectl scale deploy/web --replicas=5 -n abcl-ka
deployment.apps/web scaled
$ kubectl get deploy web -n abcl-ka
NAME   READY   UP-TO-DATE   AVAILABLE   AGE
web    5/5     5            5           109s
$ kubectl apply -f web.yaml
deployment.apps/web configured
$ kubectl get deploy web -n abcl-ka
NAME   READY   UP-TO-DATE   AVAILABLE   AGE
web    3/3     3            3           111s

প্রথম error লম্বা বলে দুই লাইনে ভাঙা হয়েছে। scale-এর পরে cluster আর file মিলছিল না। Kubernetes এই drift নিজে থেকে ফেরায় না, কারণ scale-ও একটি বৈধ নতুন চাওয়া: সে spec-ই বদলেছে। apply আবার file-এর চাওয়াটি বসাল। তাই নিয়ম হলো, মূল সত্য একটি জায়গায় রাখুন, সাধারণত Git-এ। পর্ব ৬০-এর GitOps এই ধারণার ওপরেই দাঁড়ানো।

৪ · Reconciliation loop: পাম্প-অপারেটরের নিয়ম

একটি ফ্ল্যাটবাড়ির পাম্প-অপারেটর ভাবুন। তাঁর একটিই নিয়ম: ছাদের ট্যাংক তিন-চতুর্থাংশ ভরা থাকবে। তিনি কিছুক্ষণ পরপর ট্যাংক দেখেন। কম থাকলে পাম্প চালান, বেশি থাকলে বন্ধ করেন, ঠিক থাকলে কিছুই করেন না। কে কতটা পানি খরচ করল, তা তাঁর মনে রাখার দরকার নেই। এক ঘণ্টা ঘুমিয়ে উঠলেও তিনি শুধু এখনকার পানির উচ্চতা দেখে কাজ করেন। AC-র thermostat-ও একই নিয়মে চলে।

Kubernetes-এর প্রতিটি controller ঠিক এই পাম্প-অপারেটর। তার কাজ তিনটি ধাপের একটি অশেষ লুপ:

Observe → Diff → Act → আবার Observe
status দেখা → spec-এর সাথে পার্থক্য → পার্থক্যটুকু ঠিক করা

লক্ষ করুন, কোনো controller পুরো কাজ একবারে শেষ করে না। ReplicaSet controller Pod গোনে আর কম-বেশি মেটায়। Pod কোথায় বসবে, সেটি scheduler-এর কাজ। Container চালানো kubelet-এর কাজ। প্রত্যেকে নিজের ছোট লুপ চালায়, আর ফলটি API server-এ লিখে রাখে। একজনের লেখা অন্যজনের কাজের সূত্র হয়।

নিচের simulator-এ ১ tick মানে এক দফা লুপ। EVENTS বদলে দেখুন: Pod মরুক, আপনি চাওয়া বদলান, node হারান। Controller প্রতিবার শুধু পার্থক্যটুকু ঠিক করে।

const START_TICKS = 2;        // a new Pod needs 2 ticks to become Running
const EVENTS = {
  4:  { kill: 1, note: "1 Pod crashed" },
  7:  { desired: 5, note: "user: replicas=5" },
  11: { kill: 2, note: "2 Pods lost with a node" },
  15: { desired: 2, note: "user: replicas=2" },
};
let desired = 3, pods = [], nextId = 1;

console.log("tick desired running starting  action");
for (let t = 0; t <= 17; t++) {
  const ev = EVENTS[t];
  if (ev && ev.desired) desired = ev.desired;     // spec changed
  if (ev && ev.kill) pods.splice(0, ev.kill);     // world changed

  // OBSERVE: count what really exists now
  const running = pods.filter(p => p.readyAt <= t).length;
  const starting = pods.length - running;

  // DIFF and ACT: only the difference, then stop
  const diff = desired - pods.length;
  let action = "nothing to do";
  if (diff > 0) {
    for (let i = 0; i < diff; i++)
      pods.push({ name: "pod-" + nextId++, readyAt: t + START_TICKS });
    action = "create " + diff;
  } else if (diff < 0) {
    pods.splice(0, -diff);
    action = "delete " + (-diff);
  }
  const line = String(t).padStart(4) + String(desired).padStart(8) +
    String(running).padStart(8) + String(starting).padStart(9) + "  " + action;
  console.log(line + (ev ? "   <- " + ev.note : ""));
}
console.log("final pods:", pods.map(p => p.name).join(" "));

আউটপুটের অংশ:

tick desired running starting  action
   0       3       0        0  create 3
   1       3       0        3  nothing to do
   2       3       3        0  nothing to do
   3       3       3        0  nothing to do
   4       3       2        0  create 1   <- 1 Pod crashed
   …
  11       5       3        0  create 2   <- 2 Pods lost with a node
   …
  15       2       5        0  delete 3   <- user: replicas=2
   …
final pods: pod-7 pod-8

Tick ১-এ running ০, তবু controller নতুন Pod বানায়নি। কারণ starting-এর ৩টি সে গুনেছে। না গুনলে প্রতি tick-এ ৩টি করে Pod বাড়ত: এটি নিয়ন্ত্রণ-লুপের ক্লাসিক ভুল। Tick ৪ আর ১১-তে ঘটনার কারণ তার জানার দরকার নেই, সে শুধু সংখ্যা মেলায়। আসল ReplicaSet controller কোন Pod আগে মুছবে, তার নিয়ম এখানকার চেয়ে জটিল; এই simulator শুধু লুপটি দেখায়।

Level-triggered: ঘটনা নয়, অবস্থা

এই ধরনটিকে বলে level-triggered. Edge-triggered ব্যবস্থা ঘটনার ওপর চলে: “একটি Pod মরেছে” বার্তা হারালে সমস্যা চিরকাল থেকে যায়। Level-triggered ব্যবস্থা চলে এখনকার অবস্থার ওপর: controller crash করে ফিরলেও সে আবার গুনবে, আর ঠিক করে ফেলবে। তাই controller-কে যেকোনো মুহূর্তে বন্ধ করে আবার চালানো নিরাপদ। পর্ব ১৭-এর autoscaling-ও একই ধরনের লুপ।

৫ · kubectl apply-এর যাত্রা আর scheduler

এবার সব অংশকে একসাথে কাজ করতে দেখি। আসল run-এর web.yaml জমা দেওয়ার পর কী কী ঘটে, তা “পরে” চেপে দেখুন। লক্ষ করুন, kubectl কোনো node-এর সাথে কথাই বলে না।

  1. kubectlঅনুরোধ
  2. API serverযাচাই
  3. etcdসংরক্ষণ
  4. ControllerPod object
  5. Schedulernode বাছাই
  6. kubeletcontainer
  7. status৩/৩ Ready
TerminalClient-এর দিকে
$ kubectl apply -f web.yaml
# YAML থেকে JSON, তারপর HTTPS-এ API server-এ
API serverক্রম, চলার আউটপুট নয়
Authentication   # আপনি কে?
Authorization    # RBAC: এই কাজের অনুমতি আছে?
Admission        # নীতি, ডিফল্ট মান
Validation       # schema ঠিক আছে?
Terminalএখনো কোনো Pod নেই
deployment.apps/web created
# etcd-তে Deployment object জমা হয়েছে
Eventsদুই controller
deployment/web             Scaled up replica set
                           web-69f4d599d6 from 0 to 3
replicaset/web-69f4d599d6  Created pod: web-69f4d599d6-jszbc
# Pod-এর spec.nodeName এখনো ফাঁকা
EventsScheduler
pod/web-69f4d599d6-jszbc  Scheduled
Successfully assigned abcl-ka/web-69f4d599d6-jszbc
to docker-desktop
Eventskubelet
Pulled   Container image "nginx:1.27-alpine"
         already present on machine
Created  Created container: nginx
Started  Started container nginx
Terminalএই run-এ প্রায় ২ সেকেন্ড
$ kubectl rollout status deploy/web -n abcl-ka
…
deployment "web" successfully rolled out
  1. জমা দেওয়া। kubectl manifest পড়ে আপনার পরিচয়সহ API server-এ অনুরোধ পাঠায়। kubectl কোনো machine-এ ঢুকে কিছু চালায় না।
  2. দরজার যাচাই। API server চারটি প্রশ্নের উত্তর খোঁজে: আপনি কে, অনুমতি আছে কি না, কোনো নীতি আটকাচ্ছে কি না, object-এর গড়ন ঠিক কি না। এখানে ব্যর্থ হলে কিছুই জমা হয় না।
  3. খাতায় লেখা। Object etcd-তে জমা হলো, আর আপনি পেলেন created. খেয়াল করুন: এই শব্দের অর্থ “চাওয়াটি লেখা হয়েছে”, Pod চলছে এমন নয়। এই মুহূর্তে একটি Pod-ও নেই।
  4. Controller-দের পালা। Deployment controller নতুন object দেখে একটি ReplicaSet বানাল। ReplicaSet controller গুনে পেল ০, চাই ৩, তাই ৩টি Pod object বানাল। এগুলো এখনো শুধু API-র লেখা, কোনো container নয়। পর্ব ৪৪-এ এই স্তর দুটি বিস্তারে দেখবেন।
  5. Scheduler-এর পালা। Scheduler নজর রাখে এমন Pod-এ, যার spec.nodeName ফাঁকা। সে node বেছে একটি binding লেখে। Scheduler নিজে কোনো container চালায় না; সে শুধু একটি ক্ষেত্র ভরে।
  6. kubelet-এর পালা। প্রতিটি kubelet নিজের node-এর Pod-এ নজর রাখে। সে নিজের নাম দেখে CRI দিয়ে runtime-কে ডাকল। Image আগেই ছিল, তাই pull লাগেনি।
  7. Status ফেরা। kubelet Pod-এর অবস্থা লেখে, ReplicaSet আর Deployment controller নিজের status মেলায়। তিনটি Pod Ready হওয়ায় rollout status শেষ হলো।
$ kubectl get deploy,rs,pods -n abcl-ka
NAME                  READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/web   3/3     3            3           2s

NAME                             DESIRED   CURRENT   READY   AGE
replicaset.apps/web-69f4d599d6   3         3         3       2s

NAME                       READY   STATUS    RESTARTS   AGE
pod/web-69f4d599d6-92562   1/1     Running   0          2s
pod/web-69f4d599d6-jszbc   1/1     Running   0          2s
pod/web-69f4d599d6-wbths   1/1     Running   0          2s

আসল আউটপুটে -o wide দেওয়া ছিল; এখানে সেই বাড়তি কলাম ছাঁটা। তিন স্তর একসাথে দেখা যাচ্ছে: Deployment, তার ReplicaSet, আর তার Pod. Pod-এর নামে ReplicaSet-এর নাম ঢুকে আছে। deployment.apps/web-এ ২ সেকেন্ডে ৩/৩ সম্ভব হয়েছে, কারণ image আগেই node-এ ছিল। নতুন image নামাতে হলে বেশি সময় লাগবে।

Scheduler: আগে বাদ, তারপর নম্বর

Scheduler দুই ধাপে কাজ করে। Filter: যে node-এ Pod বসতেই পারবে না, সেগুলো বাদ। Score: বাকিদের নম্বর দিয়ে সেরাটি বাছাই। নিচের simulator-এ POD আর NODES বদলে দেখুন। সব node একটি নমুনা। Capacity-র হিসাব হয় Pod-এর ঘোষিত request দিয়ে, node-এর এখনকার আসল ব্যবহার দিয়ে নয়। পুরো গল্প পর্ব ৪৮-এ।

const POD = { cpu: 500, mem: 512, nodeSelector: { disk: "ssd" }, image: "shop:1.4" };

const NODES = [ // cpu in millicores, mem in MiB, free = capacity - requested
  { name: "node-a", ready: true,  cap: [2000, 4096], used: [1800, 1024], disk: "ssd", images: [] },
  { name: "node-b", ready: true,  cap: [2000, 4096], used: [ 500, 1024], disk: "ssd", images: [] },
  { name: "node-c", ready: true,  cap: [4000, 8192], used: [2000, 6000], disk: "ssd", images: ["shop:1.4"] },
  { name: "node-d", ready: true,  cap: [4000, 8192], used: [ 200,  512], disk: "hdd", images: [] },
  { name: "node-e", ready: false, cap: [4000, 8192], used: [   0,    0], disk: "ssd", images: [] },
];

function why(n) {               // FILTER: any "no" removes the node
  if (!n.ready) return "node not Ready";
  if (POD.nodeSelector.disk !== n.disk) return "selector disk=ssd";
  if (n.cap[0] - n.used[0] < POD.cpu) return "not enough cpu";
  if (n.cap[1] - n.used[1] < POD.mem) return "not enough memory";
  return "";
}
function score(n) {             // SCORE: most free share after placing
  const cpu = (n.cap[0] - n.used[0] - POD.cpu) / n.cap[0];
  const mem = (n.cap[1] - n.used[1] - POD.mem) / n.cap[1];
  const free = Math.round(((cpu + mem) / 2) * 100);
  const bonus = n.images.includes(POD.image) ? 10 : 0;   // image is cached
  return { free, bonus, total: free + bonus };
}

const left = NODES.filter(n => {
  console.log("filter", n.name, why(n) ? "OUT: " + why(n) : "ok");
  return !why(n);
});
const ranked = left.map(n => ({ n: n.name, ...score(n) }))
  .sort((a, b) => b.total - a.total || a.n.localeCompare(b.n));
for (const r of ranked)
  console.log("score ", r.n, "free", r.free, "+ image", r.bonus, "=", r.total);
console.log(ranked.length ? "result: bind Pod to " + ranked[0].n
                          : "result: Pending (no node fits)");

আউটপুট:

filter node-a OUT: not enough cpu
filter node-b ok
filter node-c ok
filter node-d OUT: selector disk=ssd
filter node-e OUT: node not Ready
score  node-b free 56 + image 0 = 56
score  node-c free 29 + image 10 = 39
result: bind Pod to node-b

হাতে মিলিয়ে দেখুন। node-b-তে Pod বসানোর পরে CPU-র ৫০% আর memory-র (4096 − 1024 − 512) ÷ 4096 = ৬২.৫% ফাঁকা থাকবে, গড় ৫৬%. node-c-তে image থাকার বোনাস পেয়েও ৩৯. আসল scheduler-এ নম্বর আসে অনেকগুলো plugin থেকে, ওজনও আলাদা; এখানকার ১০ নম্বরের বোনাস বোঝানোর জন্য ধরে নেওয়া। সব node বাদ গেলে Pod ব্যর্থ হয় না, Pending থেকে অপেক্ষা করে।

এই Pending অবস্থা আমরা আসল cluster-এও তৈরি করেছি। একটি Pod-এ nodeSelector: {disktype: ssd} দিলাম, অথচ node-এ এমন label নেই:

$ kubectl get pod needs-ssd -n abcl-ka
NAME        READY   STATUS    RESTARTS   AGE
needs-ssd   0/1     Pending   0          4s

$ kubectl get events -n abcl-ka \
    --field-selector involvedObject.name=needs-ssd
LAST SEEN   TYPE      REASON             OBJECT          MESSAGE
4s          Warning   FailedScheduling   pod/needs-ssd   0/1 nodes are available:
1 node(s) didn't match Pod's node affinity/selector. no new claims to deallocate,
preemption: 0/1 nodes are available: 1 Preemption is not helpful for scheduling.

Event-এর একটি লম্বা বার্তা পড়ার সুবিধায় কয়েক লাইনে ভাঙা হয়েছে। 0/1 nodes are available মানে ১টি node-এর ০টি ফিল্টার পার হয়েছে। Pending দেখলে প্রথম কাজ এই event পড়া: scheduler নিজেই কারণ লিখে রাখে।

৬ · আসল পরীক্ষা: একটি Pod মুছে দেখি

এতক্ষণের দাবি কি সত্য? ৩টি Pod চলছে। আমরা একটি মুছে দিলাম, আর পাশে একটি watch চালিয়ে রাখলাম। বাঁয়ের সময়ের কলামটি kubectl-এর নয়: আমাদের ছোট একটি script প্রতিটি লাইনের সাথে যোগ করেছে, delete কমান্ড শুরুর কত সেকেন্ড পরে লাইনটি এলো।

$ kubectl get pods -l app=web -n abcl-ka --watch-only --output-watch-events &
$ kubectl delete pod web-69f4d599d6-92562 -n abcl-ka

 সময়    EVENT      NAME                   READY   STATUS
+0.07s  MODIFIED   web-69f4d599d6-92562   1/1     Terminating
+0.08s  ADDED      web-69f4d599d6-ns5z4   0/1     Pending
+0.09s  MODIFIED   web-69f4d599d6-ns5z4   0/1     Pending
+0.09s  MODIFIED   web-69f4d599d6-92562   1/1     Terminating
+0.11s  MODIFIED   web-69f4d599d6-ns5z4   0/1     ContainerCreating
+0.92s  MODIFIED   web-69f4d599d6-92562   0/1     Completed
+1.94s  MODIFIED   web-69f4d599d6-92562   0/1     Completed
+1.95s  MODIFIED   web-69f4d599d6-92562   0/1     Completed
+1.95s  DELETED    web-69f4d599d6-92562   0/1     Completed
+1.99s  MODIFIED   web-69f4d599d6-ns5z4   1/1     Running

$ kubectl get pods -n abcl-ka
NAME                   READY   STATUS    RESTARTS   AGE
web-69f4d599d6-jszbc   1/1     Running   0          36s
web-69f4d599d6-ns5z4   1/1     Running   0          10s
web-69f4d599d6-wbths   1/1     Running   0          36s

Watch-এর অংশ থেকে RESTARTS আর AGE কলাম ছাঁটা হয়েছে। লক্ষণীয় চারটি বিষয়:

  • ০.০১ সেকেন্ডের ব্যবধান: Watch-এ পুরোনো Pod Terminating দেখানোর ১০ মিলিসেকেন্ডের মধ্যে নতুন Pod ADDED. ReplicaSet controller মুছে যাওয়ার অপেক্ষা করেনি, কারণ Terminating Pod-কে সে আর গোনে না।
  • নতুন নাম, নতুন Pod: 92562 ফিরে আসেনি, এসেছে ns5z4. Pod বদলযোগ্য, পোষা প্রাণী নয়। তার IP-ও বদলাতে পারে, তাই Service লাগে (পর্ব ৪৫).
  • প্রায় ২ সেকেন্ড: Pending থেকে Running. এই গতি শুধু এখানকার: image আগেই ছিল, এবং app-টি ছোট।
  • এটি জাদু নয়: মাত্র একটি controller গুনে দেখেছে ২ আছে, ৩ চাই।

Watch: বারবার জিজ্ঞেস না করে খবর পাওয়া

Controller যদি প্রতি সেকেন্ডে পুরো তালিকা চাইত, ৫০০০ Pod-এর cluster-এ API server আর etcd ভেঙে পড়ত। সমাধান watch: client একটি HTTP সংযোগ খোলা রাখে, আর API server বদল হলেই একটি করে event ঠেলে পাঠায়। প্রতিটি event-এ থাকে পুরো object আর একটি resourceVersion. আসল stream দেখুন। এখানে Deployment-টি watch করে আমরা --replicas=4 দিলাম:

$ kubectl get --raw '/apis/apps/v1/namespaces/abcl-ka/deployments?watch=true&timeoutSeconds=12&fieldSelector=metadata.name%3Dweb'
{"type":"ADDED","object":{"kind":"Deployment","apiVersion":"apps/v1","metadata":{"name":"web","namespace":"abcl-ka",…,"resourceVersion":"1062","generation":1,…
…

# script-এ প্রতিটি লাইনের কয়েকটি ক্ষেত্র ছেঁকে নিলে (scale কমান্ড থেকে সময়):
  সময়   type      rv    gen spec  replicas ready observedGen
-1.44s  ADDED     1062  1   3     3        3     1
+0.08s  MODIFIED  1190  2   4     3        3     1
+0.09s  MODIFIED  1193  2   4     3        3     2
+0.10s  MODIFIED  1195  2   4     3        3     2
+0.12s  MODIFIED  1201  2   4     4        3     2
+2.38s  MODIFIED  1238  2   4     4        4     2

এই একই stream ধাপে ধাপে দেখা যাক। Table-এর মানগুলো আসল run-এর, শুধু শেষ ধাপটি পুনঃসংযোগের ধারণা দেখানো একটি model.

Client-এর হাতে থাকা Deployment/web
সময়
event type
resourceVersion
spec.replicas
status.replicas
status.readyReplicas
observedGeneration
  1. প্রথম ছবি। Watch শুরু হতেই API server বর্তমান অবস্থা ADDED হিসেবে পাঠাল। spec আর status মিলছে, ৩ আর ৩, করার কিছু নেই।
  2. চাওয়া বদল। scale spec.replicas-কে ৪ করল। ৮০ মিলিসেকেন্ডে event এলো। এখন spec ৪, status ৩: এই ফাঁকই controller-এর কাজের সংকেত। generation বেড়ে ২, কিন্তু observedGeneration এখনো ১।
  3. Controller দেখেছে। ১০ মিলিসেকেন্ড পরে observedGeneration ২. Deployment controller জানিয়ে দিল, নতুন চাওয়াটি সে পড়েছে। Replica সংখ্যা এখনো ৩।
  4. নতুন Pod object. status.replicas ৪, কিন্তু readyReplicas ৩: চতুর্থ Pod আছে, প্রস্তুত নয়। এর আগের 1195 event-টি জায়গা বাঁচাতে এখানে বাদ।
  5. মিলে গেছে। প্রায় ২.৩৮ সেকেন্ডে readyReplicas ৪. চাওয়া আর পাওয়া সমান, তাই controller আবার চুপ। rv ধারাবাহিক নয়, কারণ এই সংখ্যাটি পুরো etcd জুড়ে একটিই ক্রম, সব object-এর লেখা তা বাড়ায়।
  6. সংযোগ কাটলে (model). Watch চিরকাল চলে না। Client শেষ দেখা resourceVersion দিয়ে আবার watch শুরু করে, তাই মাঝের event হারায় না। অনেক পুরোনো নম্বর দিলে server 410 Gone বলে, তখন client পুরো তালিকা আবার পড়ে। Controller level-triggered বলে এতে কোনো ক্ষতি নেই।

৭ · Cluster পড়া: kubectl, event, namespace আর label

kubectl-এর শত কমান্ডের মধ্যে প্রথম দিনের জন্য এই পাঁচটিই যথেষ্ট। তিনটি শুধু পড়ে, তাই নিরাপদ।

কমান্ডপ্রশ্ন
kubectl get podsকী কী আছে, কী অবস্থায়?
kubectl describe pod Xএটির বিস্তারিত আর সাম্প্রতিক event কী?
kubectl explain deployment.spec.replicasএই ক্ষেত্রটির অর্থ কী? (cluster-এর নিজের schema থেকে)
kubectl get events --sort-by=.lastTimestampসম্প্রতি কী ঘটেছে?
kubectl logs XContainer নিজে কী বলছে? (পর্ব ৪৩)
$ kubectl explain deployment.spec.replicas
GROUP:      apps
KIND:       Deployment
VERSION:    v1

FIELD: replicas <integer>

DESCRIPTION:
    Number of desired pods. This is a pointer to distinguish between explicit
    zero and not specified. Defaults to 1.

$ kubectl describe pod web-69f4d599d6-jszbc -n abcl-ka
Name:             web-69f4d599d6-jszbc
Namespace:        abcl-ka
…
Labels:           app=web
                  pod-template-hash=69f4d599d6
Status:           Running
IP:               10.1.0.9
Controlled By:  ReplicaSet/web-69f4d599d6
Containers:
  nginx:
    Image:          nginx:1.27-alpine
    …
    Ready:          True
    Restart Count:  0
    Limits:
      cpu:     100m
      memory:  32Mi
    Requests:
      cpu:        10m
      memory:     16Mi
…
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  24s   default-scheduler  Successfully assigned abcl-ka/web-69f4d599d6-jszbc to docker-desktop
  Normal  Pulled     23s   kubelet            Container image "nginx:1.27-alpine" already present on machine
  Normal  Created    23s   kubelet            Created container: nginx
  Normal  Started    23s   kubelet            Started container nginx

Debug-এর সময় describe-এর সবচেয়ে নিচের Events অংশই প্রথম পড়ুন। From কলামে দেখুন কে কাজটি করেছে: scheduler, তারপর kubelet, ঠিক ধাপে ধাপে দেখা ক্রমে। Controlled By জানায় এই Pod-এর মালিক কে। AI-এর দেওয়া কোনো ক্ষেত্রের নামে সন্দেহ হলে explain চালান: সে আপনার cluster-এর সত্যিকারের API থেকে উত্তর দেয়। Event চিরকাল থাকে না, ডিফল্টে প্রায় এক ঘণ্টা পরে মুছে যায়, তাই ঘটনার পরপরই পড়ুন।

Namespace: একই cluster-এ আলাদা ঘর

Namespace হলো একই cluster-এর ভেতরে নামের আলাদা এলাকা, বহুতল ভবনের আলাদা ফ্ল্যাটের মতো। দুই namespace-এ একই নামের Deployment থাকতে পারে। -n না দিলে kubectl default namespace দেখে, আর তাই “আমার Pod গেল কোথায়” প্রশ্নের অর্ধেক উত্তর এটাই:

$ kubectl get pods -n default
No resources found in default namespace.

Pod চলছিল, শুধু অন্য namespace-এ। মনে রাখবেন, namespace নামের সীমানা আর অনুমতির একক, তবে নিজে থেকে কোনো network দেয়াল নয়; সেজন্য NetworkPolicy লাগে (পর্ব ৪৯). Node আর Namespace-এর মতো কিছু object কোনো namespace-এর ভেতরে থাকে না।

Label আর selector: Kubernetes-এর আঠা

Label হলো object-এ লাগানো ছোট key-value ট্যাগ, যেমন app=web. Selector হলো সেই ট্যাগ দিয়ে খোঁজা। ReplicaSet কোনো নামের তালিকা রাখে না। সে প্রতিবার জিজ্ঞেস করে: “app=web label-ওয়ালা কয়টি Pod আছে?” তাই label বদলালে কী হয়, সেটি আসল cluster-এ দেখা যাক:

$ kubectl get pods -n abcl-ka -L app
NAME                   READY   STATUS    RESTARTS   AGE    APP
web-69f4d599d6-jszbc   1/1     Running   0          107s   web
web-69f4d599d6-ns5z4   1/1     Running   0          81s    web
web-69f4d599d6-wbths   1/1     Running   0          107s   web

$ kubectl label pod web-69f4d599d6-wbths app=debug --overwrite -n abcl-ka
pod/web-69f4d599d6-wbths labeled

$ kubectl get pods -n abcl-ka -L app        # 4 সেকেন্ড পরে
NAME                   READY   STATUS    RESTARTS   AGE    APP
web-69f4d599d6-gk8vl   1/1     Running   0          4s     web
web-69f4d599d6-jszbc   1/1     Running   0          111s   web
web-69f4d599d6-ns5z4   1/1     Running   0          85s    web
web-69f4d599d6-wbths   1/1     Running   0          111s   debug

$ kubectl get pods -n abcl-ka -l app=web
NAME                   READY   STATUS    RESTARTS   AGE
web-69f4d599d6-gk8vl   1/1     Running   0          4s
web-69f4d599d6-jszbc   1/1     Running   0          111s
web-69f4d599d6-ns5z4   1/1     Running   0          85s
$ kubectl get pods -n abcl-ka -l 'app in (web,debug)' --no-headers | wc -l
4

কোনো Pod মারা যায়নি, অথচ এখন ৪টি Pod. ReplicaSet গুনে পেল app=web মাত্র ২টি, তাই নতুন gk8vl বানাল। wbths এখনো চলছে, কিন্তু তার মালিক নেই: আগে ownerReferences-এ ReplicaSet ছিল, label বদলের পরে তালিকাটি ফাঁকা। এই কৌশলে কোনো সমস্যাগ্রস্ত Pod-কে সরিয়ে রেখে তদন্ত করা যায়। কাজ শেষে এটি হাতে মুছতে হবে, কারণ কোনো controller আর এর দায়িত্বে নেই।

একটি Deployment-এর selector যেন অন্য কারও Pod ধরে না ফেলে। দুটি workload একই label ব্যবহার করলে একে অন্যের Pod-কে নিজের ভেবে গুনতে পারে, আর Service ভুল Pod-এ traffic পাঠাতে পারে। apps/v1-এ Deployment-এর selector তৈরির পরে বদলানো যায় না, তাই শুরুতেই ভেবে লিখুন।

৮ · কিছু নষ্ট হলে: etcd quorum আর node failure

etcd হলো cluster-এর একমাত্র স্মৃতি। তাই production-এ এর সাধারণত ৩ বা ৫টি সদস্য থাকে, আর প্রতিটি লেখা quorum, অর্থাৎ সদস্যদের সংখ্যাগরিষ্ঠ অংশ, নিশ্চিত করলে তবেই পাকা হয়। সদস্য সংখ্যা n হলে quorum = ⌊n/2⌋ + ১, আর সহ্য করা যায় n − quorum সদস্যের বিদায়। Raft কীভাবে এটি করে, তার পুরো গল্প System Design কোর্সের Consensus আর Raft পর্বে পাবেন। এখানে শুধু operations-এর হিসাব:

// etcd quorum math for 1 to 7 members. Change DOWN and P_DOWN.
const DOWN = 2;        // members that are down right now
const P_DOWN = 0.01;   // assumed: each member down 1% of the time, independently

function choose(n, k) {
  let c = 1;
  for (let i = 1; i <= k; i++) c = c * (n - i + 1) / i;
  return c;
}
function pNoQuorum(n, q) {     // lost if more than n - q members are down
  let sum = 0;
  for (let k = n - q + 1; k <= n; k++)
    sum += choose(n, k) * P_DOWN ** k * (1 - P_DOWN) ** (n - k);
  return sum;
}

console.log("members quorum tolerate  down=" + DOWN + "      P(no quorum)");
for (let n = 1; n <= 7; n++) {
  const q = Math.floor(n / 2) + 1;
  const alive = Math.max(n - DOWN, 0);
  const state = alive >= q ? "writes ok" : "BLOCKED";
  console.log(String(n).padStart(7) + String(q).padStart(7) +
    String(n - q).padStart(9) + "  " + state.padEnd(10) +
    pNoQuorum(n, q).toExponential(2).padStart(13));
}

আউটপুট:

members quorum tolerate  down=2      P(no quorum)
      1      1        0  BLOCKED         1.00e-2
      2      2        0  BLOCKED         1.99e-2
      3      2        1  BLOCKED         2.98e-4
      4      3        1  BLOCKED         5.92e-4
      5      3        2  writes ok       9.85e-6
      6      4        2  writes ok       1.96e-5
      7      4        3  writes ok       3.42e-7

৪ সদস্য ৩-এর চেয়ে বেশি সহ্য করে না, উল্টো ঝুঁকি প্রায় দ্বিগুণ (2.98e-4 বনাম 5.92e-4), কারণ নষ্ট হতে পারে এমন যন্ত্র বেড়েছে কিন্তু সহনশীলতা বাড়েনি। তাই etcd-র সদস্য সংখ্যা বিজোড় রাখা হয়। ১% আর স্বাধীন ব্যর্থতা এখানে ধরে নেওয়া সংখ্যা; এক rack-এ সব রাখলে স্বাধীনতার ধারণা ভেঙে যায়, তাই সদস্যরা আলাদা availability zone-এ থাকে। ৩-এর উদাহরণ হাতে: 3 × (0.01)² × 0.99 + (0.01)³ ≈ 2.98 × 10⁻⁴.

মূল ধারণা

Quorum গেলে চলমান app সঙ্গে সঙ্গে বন্ধ হয় না। লেখা থেমে যায়: নতুন deploy, scale বা সেরে ওঠা হবে না। কিন্তু node-এ চলা container চলতেই থাকে, কারণ kubelet আর runtime-এর প্রতিটি মুহূর্তে control plane লাগে না। অফিস বন্ধ হলেও রাস্তার বাস চলতে থাকে, শুধু নষ্ট বাসের জায়গায় নতুন বাস আসে না।

একটি node চলে গেলে

আমাদের cluster-এ node একটিই, তাই এই পরীক্ষা সেখানে করা সম্ভব নয়। নিচের stepper একটি model: তিন node, ৪ replica. সময়গুলো ডিফল্ট আচরণের মোটামুটি হিসাব, version আর provider-ভেদে আলাদা হতে পারে। তবে ৩০০ সেকেন্ডের সংখ্যাটি আমাদের আসল describe-এর Tolerations লাইনেই দেখেছেন।

Model · ৪ replica, ৩ node
সময়
node-1
node-1-এর Pod
node-2-এর Pod
node-3-এর Pod
API-র Ready হিসাব
  1. স্বাভাবিক অবস্থা। ৪টি Pod ৩টি node-এ ছড়ানো। প্রতিটি kubelet নিয়মিত হৃৎস্পন্দন পাঠায়, যা একটি Lease object নবায়ন করে।
  2. node-1-এর বিদ্যুৎ গেল। ঠিক এই মুহূর্তে API server এখনো ৪/৪ দেখাচ্ছে, অথচ ২টি Pod আসলে নেই। Control plane-এর জানা সবসময় একটু পুরোনো।
  3. Node controller টের পেল। কিছুক্ষণ হৃৎস্পন্দন না পেয়ে (ডিফল্টে প্রায় ৪০–৫০ সেকেন্ড, version-ভেদে) সে node-কে Unknown করল, একটি taint বসাল, আর Pod-গুলোকে NotReady করল। ফলে Service আর এগুলোতে traffic পাঠায় না।
  4. ৩০০ সেকেন্ডের সহনশীলতা শেষ। Pod-এর toleration ফুরোলে এগুলো মোছার জন্য চিহ্নিত হলো: Terminating. কেন অপেক্ষা? ছোট network সমস্যায় সব Pod সরিয়ে ফেললে ক্ষতিই বেশি।
  5. ReplicaSet লুপ চলল। Terminating Pod গোনা হয় না, তাই ২ আছে, ৪ চাই। ২টি নতুন Pod object তৈরি হলো। Scheduler taint-এর কারণে node-1-কে বাদ দিয়ে node-2 আর node-3 বেছে নিল।
  6. আবার ৪/৪. নতুন দুটি Pod চলছে। পুরোনো দুটি API-তে Terminating হয়ে আটকে আছে, কারণ তাদের kubelet সাড়া দিতে পারছে না। এতে নতুন Pod চলতে বাধা নেই।
  7. Node ফিরল। kubelet ফিরে দেখল a আর b মোছার চিহ্ন পেয়েছে, তাই সেগুলো পরিষ্কার করল। node-1 আবার খালি ও প্রস্তুত, তবে Pod নিজে থেকে এখানে ফেরে না।

এই মডেল একটি অপ্রিয় সত্য জানায়: ডিফল্টে node-এর মৃত্যুর পর Pod সরতে পাঁচ মিনিটের বেশি লাগতে পারে। তাই replica আগে থেকেই একাধিক node আর zone-এ ছড়িয়ে রাখা দরকার, যাতে বাকিরা ততক্ষণ traffic সামলাতে পারে।

আরও গভীরে: Controller সরাসরি API server-এ বারবার প্রশ্ন করে না। Client library-র informer একবার list করে, তারপর watch চালিয়ে একটি local cache তাজা রাখে, আর পরিবর্তিত object-এর key একটি work queue-তে তোলে। দুই লেখকের সংঘাত ঠেকায় resourceVersion-ভিত্তিক optimistic concurrency: পুরোনো নম্বর নিয়ে লিখতে গেলে 409 Conflict আসে। HA control plane-এ API server একসাথে অনেকগুলো চলে (load balancer-এর পেছনে), কিন্তু scheduler আর controller manager-এর একটিই সক্রিয় থাকে, Lease দিয়ে leader election করে।

৯ · Managed Kubernetes, আর কখন Kubernetes নয়

etcd-র backup, control plane-এর আপগ্রেড আর certificate নবায়ন নিজের হাতে করা ভারী কাজ। তাই বেশিরভাগ দল managed Kubernetes নেয়: provider control plane চালায়, আপনি সাধারণত node আর workload সামলান। পর্ব ২-এর shared responsibility এখানেও খাটে।

কাজনিজে চালানো (kubeadm)Managed (EKS, AKS, GKE)
API server, etcd, schedulerআপনিProvider; etcd আপনি সরাসরি দেখতেই পান না
Control plane আপগ্রেডআপনিProvider করে, তবে কখন হবে, সেই সিদ্ধান্ত অনেকটা আপনার
Node VM আর তার আপগ্রেডআপনিসাধারণত ভাগাভাগি; GKE Autopilot বা AWS Fargate-এর মতো ধরনে provider বেশি নেয়
Workload, YAML, RBAC, Secretআপনিসবসময় আপনি
খরচনিজের machine আর শ্রমNode-এর খরচ, আর অনেক ক্ষেত্রে cluster-প্রতি ফি; provider-এর pricing পাতা দেখুন

তিন provider-এর নাম: Amazon EKS, Azure Kubernetes Service (AKS) আর Google Kubernetes Engine (GKE). এদের কোনোটি সেরা বলা হচ্ছে না; আপনার দল যে cloud-এ আছে, সাধারণত সেটিই স্বাভাবিক পছন্দ। শেখার জন্য নিজের কম্পিউটারে kind, minikube বা Docker Desktop-এর Kubernetes যথেষ্ট, তাতে cloud-এর খরচ নেই।

কখন Kubernetes নয়

পরিস্থিতিভালো পথ
১–২টি service, একটি VM-ই যথেষ্টVM + Compose + systemd (পর্ব ১১, ৪০)
Stateless API, ops জানা মানুষ নেইManaged container সেবা বা PaaS (পর্ব ১৯)
মাঝে মাঝে আসা ছোট কাজFaaS (পর্ব ৬৯)
অনেক service, অনেক দল, ঘন ঘন deployKubernetes যুক্তিসঙ্গত
Cloud-এর বাইরেও একই platform দরকারKubernetes যুক্তিসঙ্গত

Kubernetes আপনার অ্যাপকে নিজে থেকে নির্ভরযোগ্য করে না। ভুল image, ভুল config আর ভুল probe সে নিখুঁত দক্ষতায় সব node-এ ছড়িয়ে দেবে। তার ওপর network, নিরাপত্তা, আপগ্রেড আর observability শেখার বড় খরচ আছে। প্রশ্নটি “Kubernetes কি ভালো?” নয়; প্রশ্নটি “আমাদের সমস্যা কি এই খরচের যোগ্য?”

পরীক্ষা ও ইন্টারভিউতে:

  • Control plane-এর চারটি অংশ কী? API server, etcd, scheduler, controller manager.
  • etcd-র সাথে সরাসরি কে কথা বলে? শুধু API server.
  • ৫ সদস্যের etcd কয়টি বিদায় সহ্য করে? Quorum ৩, তাই ২টি।
  • Reconciliation loop কী? Desired আর observed অবস্থা মিলিয়ে পার্থক্যটুকু ঠিক করার অশেষ লুপ।
  • Pod মুছলে আবার আসে কেন? কারণ Deployment-এর ReplicaSet সংখ্যা মেলায়; স্থায়ীভাবে কমাতে replicas বদলাতে হবে।

১০ · AI-এর যুগে Kubernetes

AI YAML খুব দ্রুত লেখে, আর YAML দেখতে নিখুঁত হলেও ভুল হতে পারে। বিশেষ করে পুরোনো টিউটোরিয়ালের API version তার স্মৃতিতে রয়ে গেছে। Cluster বদলানোর আগে যাচাই করা আপনার কাজ।

AI-এর ভুলঝুঁকিযাচাই
সরানো API version, যেমন extensions/v1beta1 Deployment (১.১৬-তে সরানো)Apply ব্যর্থkubectl api-resources
বানানো ক্ষেত্র বা flagError, বা ক্ষেত্র নিষ্ক্রিয়kubectl explain, --dry-run=server
image: nginx:latestকোন version চলছে জানা যায় নানির্দিষ্ট tag বা digest (পর্ব ৪১)
resources বাদScheduler অন্ধ, node-এ চাপRequest আর limit (পর্ব ৪৮)
cluster-admin অনুমতিএক ভুলে পুরো cluster ঝুঁকিতেLeast privilege (পর্ব ৪৯)
সতর্কতা ছাড়া kubectl delete বা --forceভুল namespace-এ কাজ মুছে যাওয়াআগে get, context আর namespace দেখা

AI-কে YAML লিখতে বলার সময় cluster-এর version আর যাচাইয়ের ধাপ জুড়ে দিন:

আমার Kubernetes cluster-এর version 1.34. নিচের অ্যাপের জন্য একটি Deployment manifest লেখো। [অ্যাপের বিবরণ, image-এর নির্দিষ্ট tag, port] শর্ত: ১. এই version-এ চালু আছে এমন apiVersion ব্যবহার করবে, আর কোনটি কেন নিলে বলবে। ২. latest tag নয়; resources.requests আর limits দেবে, মানগুলো কেন, তাও বলবে। ৩. প্রতিটি ক্ষেত্র কী করে, এক লাইনে বাংলায় ব্যাখ্যা করবে। ৪. কোনো ক্ষেত্র সম্পর্কে নিশ্চিত না হলে তা বলবে, বানিয়ে লিখবে না। ৫. apply করার আগে আমি কোন কোন যাচাই কমান্ড চালাব, তা দেবে। কোনো delete কমান্ড দিলে আলাদা করে সতর্ক করবে।

AI-এর দেওয়া YAML apply করার আগে

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন, তারপর “→ উত্তর” চাপুন।

প্র ০১Borg তো Google-এ চলছিলই। তাহলে Kubernetes আলাদা করে বানানো হলো কেন, আর Borg থেকে কী শেখা হলো?

২০১৫ সালের Borg নিবন্ধে দেখা যায়, Google তার প্রায় সব কাজ বড় বড় cluster-এ এই একটি ব্যবস্থায় চালাত। কিন্তু Borg ছিল Google-এর নিজের পরিবেশে বাঁধা, ভেতরের নানা সিস্টেমের সাথে জড়ানো। সেটি হুবহু বাইরে দেওয়ার মতো ছিল না। তাই নতুন করে লেখা হলো, আর শেখা বিষয়গুলো নকশায় ঢোকানো হলো। “Borg, Omega, and Kubernetes” (২০১৬) লেখায় লেখকেরা নিজেই কয়েকটি শিক্ষা তুলে ধরেছেন:

  • Label, নির্দিষ্ট দল নয়: Borg-এ কাজ দলবদ্ধ হতো “job”-এর ভেতরে সংখ্যা দিয়ে। Kubernetes-এ কোনো দল আগে থেকে বাঁধা নয়; label আর selector দিয়ে যেভাবে খুশি ভাগ করা যায়। একই Pod একসাথে Deployment আর Service-এর ভেতরে পড়ে।
  • প্রতি Pod-এ একটি IP: Borg-এ এক machine-এর সব কাজ একই IP ভাগ করত, তাই port বরাদ্দ একটি বড় ঝামেলা ছিল। Kubernetes প্রতিটি Pod-কে নিজের IP দিল।
  • একটি কেন্দ্রীয় API: সব অংশ API server-এর মাধ্যমে কথা বলে, তাই নতুন controller লেখা সহজ।

ব্যবসার দিকটিও ভাবার মতো। Open source করলে একটি মানদণ্ড তৈরি হয়, যা কোনো এক cloud-এ বাঁধা নয়; তখনকার প্রতিযোগিতায় এটি Google Cloud-এর পক্ষে সাহায্য করতে পারে, এমন ব্যাখ্যা প্রায়ই শোনা যায়। এটি বিশ্লেষকদের ব্যাখ্যা, কোনো ঘোষিত তথ্য নয়। CNCF-এর হাতে দেওয়ায় অন্য কোম্পানিগুলোও নিশ্চিন্তে যোগ দিতে পেরেছে।

মূল উপলব্ধি: একটি সিস্টেমের দ্বিতীয় প্রজন্ম প্রথমটির ভুল থেকে শেখে। Kubernetes কোনো হঠাৎ আবিষ্কার নয়; এটি এক দশকের বেশি সময়ের cluster চালানোর অভিজ্ঞতার পরিষ্কার একটি রূপ।

প্র ০২Controller কেন ঘটনার ওপর নির্ভর না করে বর্তমান অবস্থার ওপর চলে? ঘটনা-ভিত্তিক নকশা কি বেশি দক্ষ নয়?

ঘটনা-ভিত্তিক নকশায় নিয়ম হয় এমন: “Pod মরলে একটি নতুন বানান।” শুনতে সরল আর দক্ষ। সমস্যা শুরু হয় বিতরণ করা সিস্টেমের বাস্তবতায়: বার্তা হারায়, দুবার আসে, ভুল ক্রমে আসে, আর শোনার সময় প্রোগ্রাম নিজেই বন্ধ থাকতে পারে।

  • বার্তা হারালে: controller আপগ্রেডের সময় একটি Pod মরল। ঘটনা-ভিত্তিক ব্যবস্থায় Pod চিরকালের জন্য কম থাকল।
  • বার্তা দুবার এলে: ২টি নতুন Pod বানানো হলো, চাওয়ার চেয়ে বেশি।
  • বার্তা জমে গেলে: ১০০টি পুরোনো ঘটনা একে একে সামলাতে হয়, যদিও এখনকার অবস্থা দেখলে একটিই কাজ বাকি।

Level-triggered নকশায় controller প্রশ্ন করে: “এখন কী আছে, আর কী চাই?” বার্তা হারালে পরের দফায় ঠিক হয়ে যায়। দুবার চালালেও ক্ষতি নেই, কারণ দ্বিতীয়বার পার্থক্য শূন্য। অর্থাৎ কাজটি নিজে থেকেই idempotent. আপনি simulator-এ দেখেছেন, controller কারণ জানে না, শুধু সংখ্যা জানে।

দক্ষতার প্রশ্নের উত্তর হলো, Kubernetes দুটিকে মিলিয়েছে। Watch event দ্রুত খবর দেয়, তাই controller সাথে সাথে জাগে। কিন্তু event শুধু “দেখার সংকেত”, সিদ্ধান্তের ভিত্তি নয়। সিদ্ধান্ত নেওয়া হয় পুরো অবস্থা মিলিয়ে। Informer আবার নির্দিষ্ট সময় পরপর cache-এর সব object নতুন করে দেখতেও পারে, যাকে resync বলে। এটি নিরাপত্তার জাল।

দাম আছে: controller-কে অবস্থা মিলিয়ে দেখার মতো করে লিখতে হয়, আর “এখনো চলছে” বুঝতে হয় (যেমন starting Pod গোনা)। না হলে simulator-এ দেখা অতিরিক্ত Pod তৈরির ভুল হবে। Terraform-এর plan (পর্ব ৫২) আর GitOps (পর্ব ৬০) একই ধারণার ভিন্ন রূপ।

মূল উপলব্ধি: নির্ভরযোগ্য সিস্টেম ধরে নেয়, বার্তা হারাবে আর প্রোগ্রাম মরবে। বর্তমান অবস্থা থেকে বারবার হিসাব করলে অতীতের ভুল নিজে থেকেই মুছে যায়।

প্র ০৩পুরো control plane বন্ধ হয়ে গেলে কি আপনার অ্যাপও বন্ধ হবে? তাহলে control plane-কে এত সুরক্ষিত রাখার দরকার কী?

সাধারণ উত্তর: সঙ্গে সঙ্গে নয়। kubelet যে Pod চালাচ্ছে, সেগুলো চলতে থাকে। Container crash করলে kubelet নিজেই সেই node-এ আবার চালাতে পারে, যদি Pod-টি তার জানা থাকে। kube-proxy-র বসানো নিয়মও থেকে যায়। ফলে ব্যবহারকারী হয়তো কিছুই টের পান না। এই ধর্মকে অনেকে static stability বলেন: পরিচালনার অংশ পড়ে গেলেও চলমান কাজ টিকে থাকে।

তবে সময়ের সাথে ক্ষতি জমে:

  • Self-healing বন্ধ: কোনো node মরলে Pod আর সরে না।
  • Deploy বন্ধ: জরুরি bug fix-ও পাঠানো যায় না।
  • Scale বন্ধ: ভিড় বাড়লে নতুন Pod আসে না।
  • Service-এর তালিকা জমে যায়: Pod বদলালে নতুন ঠিকানা ছড়ায় না।

আবার কিছু জিনিস control plane-এর ওপর গোপনে নির্ভর করে। ডিসেম্বর ২০২৪-এ OpenAI তাদের প্রকাশিত postmortem-এ জানায়, একটি নতুন telemetry সেবা বড় cluster-গুলোর API server-এ অতিরিক্ত চাপ দিয়েছিল; control plane ভেঙে পড়লে cluster-এর ভেতরের DNS-ও কিছু সময় পরে কাজ বন্ধ করে, আর data plane-এর সেবাগুলো আক্রান্ত হয়। প্রকাশিত বিবরণ অনুযায়ী DNS cache কিছুক্ষণ সমস্যাটি আড়াল করেছিল। আর, control plane-এ ঢোকার পথটিই বন্ধ থাকায় ঠিক করতেও বেশি সময় লাগে। এটি একটি জনসমক্ষে প্রকাশিত ঘটনা, বিস্তারিত তাদের লেখাতেই দেখা ভালো।

etcd-র ক্ষেত্রে আরও একটি কথা: হারানো মানে cluster-এর স্মৃতি হারানো। তাই নিজে চালালে নিয়মিত snapshot নেওয়া আর restore অনুশীলন করা বাধ্যতামূলক।

মূল উপলব্ধি: Control plane না থাকলে অ্যাপ চলে, কিন্তু সেরে ওঠা, বদল আর বৃদ্ধি থেমে যায়। আর যে control plane দিয়ে সমস্যা ঠিক করবেন, সেটিই অচল হলে উদ্ধারের পথও বন্ধ, তাই আগে থেকে ভাবুন।

প্র ০৪Managed Kubernetes নিলে কি অপারেশনের কাজ শেষ? Provider কী নেয়, আর কী আপনার ওপরই থেকে যায়?

Managed সেবা শুধু সবচেয়ে কঠিন কিন্তু সবচেয়ে একঘেয়ে অংশটি নেয়। etcd-র quorum, API server-এর স্কেল, control plane-এর certificate আর আপগ্রেডের ভারী কাজ provider-এর। সাধারণত control plane একাধিক availability zone-এ চলে, আর provider একটি SLA দেয়, যার শর্ত provider-ভেদে আলাদা। শুধু এই অংশ নিজে চালানোর চেয়ে কম মানুষে কাজ হয়, এটি বড় লাভ। রাত ২টায় etcd-র disk ভরে গেলে আপনাকে ঘুম থেকে উঠতে হয় না, সেই দায়িত্ব provider-এর দলের।

তবু আপনার ওপরে অনেক কিছু থাকে:

  • আপগ্রেডের দায়: Kubernetes-এ প্রতি বছর কয়েকটি minor version আসে, পুরোনোগুলোর সহায়তা শেষ হয়। Provider-ভেদে নীতি আলাদা, তবে সরানো API আপনার YAML-এ থাকলে ঠিক করবেন আপনিই।
  • Add-on: ingress, DNS-এর স্কেল, CNI, monitoring আর certificate-এর অনেকটা আপনার পছন্দ ও দায়।
  • নিরাপত্তা: RBAC, cloud IAM-এর সাথে পরিচয় জোড়া, Secret, Pod-এর অনুমতি।
  • খরচ: ভুলে যাওয়া load balancer, বড় আকারের node আর ফাঁকা request-এর বিল আসবে আপনার নামে (পর্ব ৭৩).

আরও একটি ভুল ধারণা হলো, Kubernetes মানে lock-in থেকে মুক্তি। YAML অনেকটাই বহনযোগ্য, কিন্তু load balancer-এর annotation, storage class, IAM-এর সংযোগ আর network প্রতিটি cloud-এ আলাদা। একই সাথে, সবকিছু provider-এর ভরসায় ছেড়ে দিলে provider-এর নিজের outage-এ আপনার করার কিছু থাকে না; multi-zone নকশা তাই আপনার দায়। পর্ব ২-এর বাড়ির মালিক আর ভাড়াটের উদাহরণ এখানেও খাটে: দালান provider-এর, ঘরের ভেতর আপনার।

মূল উপলব্ধি: Managed সেবা দায়িত্ব সরায়, শেষ করে না। চুক্তিতে কে কী করবে তা পড়ুন, আর যা আপনার ওপর আছে, তার জন্য মানুষ ও সময় রাখুন।

প্র ০৫“সবাই Kubernetes ব্যবহার করে” কি একটি ভালো যুক্তি? একটি ছোট দল এই সিদ্ধান্ত কীভাবে নেবে?

না। Kubernetes ডিজাইন করা হয়েছে অনেক machine, অনেক দল আর অনেক service-এর জটিলতা সামলাতে। এই জটিলতা আপনার না থাকলে আপনি সমস্যা কিনছেন, সমাধান নয়। একে অনেকে resume-driven development বলেন: সিদ্ধান্ত নেওয়া হয় চাকরির বাজার দেখে, প্রয়োজন দেখে নয়। শেখার জন্য Kubernetes চমৎকার, কিন্তু প্রতিটি অ্যাপের জন্য নয়।

একটি কাল্পনিক অনলাইন বাজার অ্যাপের ৩ জনের দল ভাবুন। একটি API, একটি worker, একটি managed database. দুটি VM আর একটি load balancer দিয়ে মাসে কয়েকবার deploy হয়। এখানে Kubernetes আনলে কী যোগ হবে?

  • নতুন ধারণা: Pod, Service, Ingress, RBAC, probe, CNI, Helm: প্রতিটি শেখার ও ভুলের ঝুঁকি।
  • নতুন কাজ: নিয়মিত cluster আপগ্রেড, add-on আপগ্রেড, node patching.
  • নতুন ব্যর্থতার ধরন: DNS, network plugin, control plane-এর সীমা। আগে যে সমস্যা একটি VM-এর log দেখে বোঝা যেত, এখন তা কয়েকটি স্তর ঘুরে খুঁজতে হবে।

সিদ্ধান্তের জন্য কয়েকটি প্রশ্ন কাজে লাগে:

  • কয়টি service আছে, আর কয়টি দল একসাথে deploy করে?
  • Traffic-এর ওঠানামা কতটা? সত্যিই কি স্বয়ংক্রিয় scaling দরকার?
  • দলে কে রাত ২টায় cluster ঠিক করবেন?
  • আজকের সবচেয়ে বড় কষ্টটি কি সত্যিই orchestration, নাকি পরীক্ষা, অবজারভেবিলিটি বা deploy প্রক্রিয়া?

পথটি একমুখী নয়। Image আর Twelve-Factor অভ্যাস ঠিক থাকলে পরে স্থানান্তর সহজ। আজ managed container সেবায় থেকে, দল বড় হলে Kubernetes-এ যাওয়া একটি স্বাভাবিক পথ। উল্টো, একটি বড় দলের জন্য Kubernetes-ই প্রায়ই সবচেয়ে সরল পথ, কারণ সবাই একই ভাষায় কথা বলে, আর পর্ব ৬২-এর platform engineering সেটি আরও সহজ করে।

মূল উপলব্ধি: প্রযুক্তি বাছাই হোক আপনার সমস্যা দেখে। সবচেয়ে ছোট যে ব্যবস্থায় কাজ নিরাপদে চলে, সেটিই ভালো প্রকৌশল।

অনুশীলন

হিসাব, অনুমান আর নকশার সমালোচনা। শেষটি ঐচ্ছিক, নিজের কম্পিউটারে করার মতো।

  1. Quorum-এর হিসাব: ৫ সদস্যের একটি etcd cluster-এ ২ সদস্য নষ্ট। (ক) এখনো লেখা যাবে কি? (খ) আরও একজন গেলে কী হবে? (গ) খরচ বাঁচাতে কেউ ৫ থেকে ৪-এ নামাতে চাইছেন: সহনশীলতা কত হবে?

    (ক) Quorum = ⌊5/2⌋ + 1 = ৩. বাকি ৩ জন, তাই লেখা যাবে, তবে আর একটিও সহ্য করার ক্ষমতা নেই।

    (খ) বাকি ২ জন, যা quorum-এর কম। লেখা থেমে যাবে, তাই API server-এ নতুন বদল হবে না। চলমান Pod চলতে থাকবে।

    (গ) ৪-এর quorum ৩, সহনশীলতা ১: ৫-এর ২ থেকে কমে গেল। ৩ সদস্যেও সহনশীলতা ১, তাই ৪ রাখার কোনো লাভ নেই, নামাতে হলে ৩-এ নামান।

  2. ফল অনুমান করুন: web.yaml-এ replicas: 3. এই ক্রমে কমান্ড চলল: kubectl apply -f web.yaml, তারপর kubectl scale deploy/web --replicas=5, তারপর একটি Pod-এর kubectl delete pod, শেষে আবার kubectl apply -f web.yaml. প্রতিটি কমান্ডের পরে কয়টি Pod থাকবে, আর শেষ কমান্ড কী ছাপবে? এবার একটি Pod-এর label বদলে app=debug করলে মোট কয়টি Pod হবে?

    প্রথমে ৩, scale-এর পরে ৫. delete pod-এর পরেও ৫, কারণ ReplicaSet নতুন একটি বানাবে; মোছা Pod শুধু বদলে যাবে। শেষ apply-এ চাওয়া আবার ৩ হবে, তাই ২টি Pod মুছবে, আর ছাপবে deployment.apps/web configured. আমাদের আসল run-এ এই শব্দটিই দেখেছেন।

    Label বদলালে মোট Pod হবে ৪: ReplicaSet-এর গোনা ৩টি আর মালিকহীন ১টি, যেমন আসল run-এ wbths.

  3. নকশার সমালোচনা: একজন সহকর্মী প্রস্তাব দিলেন, “একটি VM-এ kubeadm দিয়ে Kubernetes বসাই, etcd-ও সেখানে। Backup লাগবে না, কারণ Kubernetes self-healing. আমাদের দুটি service, আর ops জানেন শুধু একজন।” এই প্রস্তাবের সমস্যাগুলো ধরুন, আর একটি ভালো বিকল্প দিন।
    • একক ব্যর্থতার বিন্দু: VM গেলে control plane, etcd আর সব Pod একসাথে গেল। এক node-এ self-healing যাওয়ার কোনো জায়গা নেই।
    • etcd সদস্য ১: সহনশীলতা ০; disk নষ্ট হলে cluster-এর সব তথ্য হারাবে।
    • Self-healing মানে backup নয়: ভুল করে মোছা object “চাওয়া” হিসেবেই গৃহীত হয়, ফেরত আসে না।
    • মানুষের ঝুঁকি: একজনই জানেন, তিনি ছুটিতে থাকলে কী হবে?

    বিকল্প: দুটি service-এর জন্য Compose আর systemd সহ VM, নিয়মিত backup আর health check, বা managed container সেবা। Kubernetes সত্যিই দরকার হলে managed cluster নিন, আর node একাধিক zone-এ রাখুন।

  4. হাতে-কলমে (ঐচ্ছিক, কমান্ড): নিজের কম্পিউটারে kind বা minikube-এর মতো local cluster চালিয়ে পরীক্ষাটি করুন। এতে cloud-এর খরচ নেই, তবে কিছু disk আর memory লাগবে। একটি Deployment বানান, একটি Pod মুছুন, event পড়ুন। তিনটি কমান্ড লিখুন: নতুন namespace তৈরি, Deployment-এর সব Pod label দিয়ে দেখা, আর কাজ শেষে পরিষ্কার করা।
    kubectl config current-context        # local cluster তো?
    kubectl create namespace demo
    kubectl create deployment web --image=nginx:1.27-alpine \
      --replicas=3 -n demo
    kubectl get pods -n demo -l app=web -w   # আরেক terminal-এ
    kubectl delete pod <pod-name> -n demo
    kubectl get events -n demo --sort-by=.lastTimestamp
    kubectl delete namespace demo         # শুধু demo মুছবে

    kubectl create deployment ডিফল্টে app=web label দেয়। delete namespace ভেতরের সবকিছু মুছে দেয়, তাই নাম দুবার পড়ুন। আসল কোনো cluster-এ এই পরীক্ষা করবেন না।

নিজেকে যাচাই করুন

ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।

ক্রমkubectl apply থেকে চলন্ত container পর্যন্ত ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. API server পরিচয়, অনুমতি আর schema যাচাই করে
  2. Object etcd-তে জমা হয়
  3. Controller Pod object তৈরি করে
  4. Scheduler Pod-এর জন্য node বেছে দেয়
  5. kubelet CRI দিয়ে runtime-কে container চালাতে বলে

Kubernetes cluster-এ etcd-র সাথে সরাসরি কোন অংশ কথা বলে?

  • প্রতিটি node-এর kubelet
  • শুধু API server
  • Scheduler আর controller manager
  • kubectl

kubectl apply ছাপল deployment.apps/web created. এই মুহূর্তে নিশ্চিতভাবে কী সত্য?

  • সব Pod চলছে
  • Scheduler সব Pod-এর node ঠিক করেছে
  • Deployment object API server-এ জমা হয়েছে
  • Image pull শেষ হয়েছে

৩ replica-র Deployment-এর একটি Pod kubectl delete pod দিয়ে মোছা হলো। Pod-টি কেন আবার তৈরি হলো?

  • kubelet মোছা Pod ফিরিয়ে আনে
  • Scheduler নতুন Pod বানায়
  • API server মুছে যাওয়া রেকর্ড ফিরিয়ে আনে
  • ReplicaSet controller চাওয়া আর পাওয়ার পার্থক্য মেটায়

৪ সদস্যের etcd cluster-এ কয়টি সদস্য নষ্ট হলেও লেখা চলবে?

  • ১টি
  • ২টি
  • ৩টি
  • একটিও নয়

একটি Pod Pending অবস্থায় আছে, আর event-এ লেখা 0/3 nodes are available. প্রথমে কী করা উচিত?

  • Pod মুছে আবার চেষ্টা করা
  • kubectl describe pod দিয়ে পুরো event পড়া
  • kubectl logs দেখা
  • Cluster আবার চালু করা

Managed Kubernetes (যেমন EKS, AKS বা GKE) নিলেও সাধারণত কোন কাজটি ব্যবহারকারীর দায়িত্বে থাকে?

  • etcd-র quorum সামলানো
  • API server-এর availability
  • Workload-এর manifest আর RBAC অনুমতি
  • Control plane-এর certificate নবায়ন

শব্দকোষ

লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন, অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:

মনে রাখুন

  1. Compose এক machine-এ থামে; Kubernetes অনেক node জুড়ে বসানো, সেরে ওঠা আর ধাপে ধাপে আপডেট দেয়।
  2. Control plane: API server, etcd, scheduler, controller manager. Node: kubelet, kube-proxy, container runtime.
  3. spec হলো চাওয়া, status হলো পাওয়া; controller পার্থক্যটুকু লুপে ঠিক করে।
  4. Pending, event, label: describe-এর Events আগে পড়ুন; label আর selector দিয়েই object-গুলো একে অন্যকে চেনে।
  5. etcd quorum = ⌊n/2⌋ + ১, সদস্য বিজোড় রাখুন; quorum গেলে লেখা থামে, চলমান Pod চলে।

পরের পর্বে: আজ Pod-কে একটি ছোট বাক্স হিসেবে দেখলেন। পর্ব ৪৩-এ এর ভেতরে ঢুকব: একটি Pod-এ একাধিক container কেন, তার lifecycle, আর probe দিয়ে Kubernetes কীভাবে বোঝে অ্যাপটি সত্যিই সুস্থ।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

এই পর্বটি শেয়ার করুন:
এই পর্বে ভুল পেয়েছেন? জানান