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

DevOps ইন্টারভিউ — Linux, Docker, Kubernetes, Terraform, CI/CD আর troubleshooting

DevOps Interview — Linux, Docker, Kubernetes, Terraform, CI/CD and Troubleshooting

Taught in Bangla, this page practises reasoned answers on Linux, Docker, Kubernetes, Terraform, CI/CD, GitOps and SRE, with a six-step troubleshooting method and honest ways to say you do not know. Four live drills read real or marked sample output for site down, full disk, slow deploy and stuck rollout. It adds Dockerfile and YAML review, take-home tasks, behavioural answers and a seven-day revision plan.

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

  • Linux, Docker, Kubernetes, Terraform, CI/CD আর SRE-র প্রচলিত প্রশ্নের সংক্ষিপ্ত, যুক্তিসহ উত্তর দেওয়া
  • “Site পড়ে গেছে”, “disk ভরা”, “deploy-এর পরে ধীর”, “deployment আটকে” পরিস্থিতিতে ক্রম মেনে এগোনো
  • Dockerfile আর Kubernetes YAML পড়ে ভুল ধরা, আর গুরুত্ব অনুযায়ী সাজানো
  • ক্যাপস্টোনের ওপর দাঁড়িয়ে take-home কাজের মান মাপা
  • “জানি না” সৎভাবে বলা, আর নিজের সত্যি ঘটনা দিয়ে আচরণগত উত্তর গোছানো

এই পাতার আউটপুট সম্পর্কে: এখানে নতুন করে docker, kubectl বা terraform চালানো হয়নি। আউটপুটগুলো কোর্সের পর্ব থেকে হুবহু বা ছেঁটে নেওয়া, আর প্রতিটির সাথে পর্বের নম্বর আছে। পর্বগুলোর পরিবেশ ছিল Docker Engine ২৯, এক node-এর local cluster (Kubernetes ১.৩৪) আর Terraform ১.১৭. আপনার version-এ লেখা কিছুটা আলাদা হতে পারে। “নমুনা” লেখা আউটপুট শেখার জন্য বানানো, আসল server থেকে নেওয়া নয়। চলার যোগ্য ব্লকগুলোর আউটপুট আসলেই চালিয়ে নেওয়া, যদিও তাদের ভেতরের ডেটা নমুনা।

ঈদের আগে একটি বড় রেস্তোরাঁয় নতুন বাবুর্চি নেওয়ার সময় মালিক শুধু রেসিপি জিজ্ঞেস করেন না। রান্নাঘরে নিয়ে গিয়ে বলেন, “ডাল পুড়ে গেছে, ৫০ জন অতিথি বসে আছেন, এখন কী করবেন?” DevOps ইন্টারভিউও অনেকটা এমন। সংজ্ঞা জানা দরকার, কিন্তু কথাবার্তা দ্রুত গড়ায় পরিস্থিতিতে: আউটপুট দেখে আপনি কী বুঝলেন, পরের ধাপে কী করবেন, আর কেন।

প্রশ্নগুলো মডিউল ধরে সাজানো। কঠিনতার চিহ্ন: (সহজ), (মাঝারি), (কঠিন). প্রশ্নগুলো কোনো নির্দিষ্ট কোম্পানি বা পরীক্ষা থেকে নেওয়া নয়। এ ধরনের প্রশ্ন প্রায়ই আসে, তবে আপনার ইন্টারভিউ ভিন্ন হতে পারে। Cloud-এর নকশার প্রশ্ন আছে পর্ব ৮০ · Cloud ইন্টারভিউ-তে, আর এখানে থাকছে চালানো আর সমস্যা খোঁজার দিক।

১ · উত্তর দেওয়ার পদ্ধতি — troubleshooting-এর ছয় ধাপ আর “জানি না”

রিভিশন: পর্ব ০৯ · Ops-এর shell, পর্ব ১৩ · Network হাতিয়ার, পর্ব ৬৭ · Incident management

সাধারণত এই ধরনের ইন্টারভিউতে তিনটি জিনিস দেখা হয়: আপনার ধারণা পরিষ্কার কি না, আপনি প্রমাণ দেখে এগোন কি না, আর production-এ আপনার হাত নিরাপদ কি না। “আমি pod delete করে দেব” শুনলে পরের প্রশ্ন আসবে, “কেন? তাতে কী প্রমাণ হারাবেন?” তাই কমান্ডের সাথে সবসময় কারণ বলুন।

Troubleshooting-এর ছয় ধাপ

Confirm, narrow, find the change, mitigate, find the cause, prevent

Troubleshooting-এর ছয় ধাপ আর শেখার ফিরতি পথ ১ · লক্ষণ নিশ্চিতকী ভাঙছে? নিজে মেপে দেখা ২ · সীমা টানাকখন থেকে, কোথায়, কাদের? ৩ · কী বদলেছেDeploy, config, traffic, certificate ৪ · ক্ষতি থামানোRollback, traffic সরানো, flag বন্ধ ৫ · মূল কারণঠিক করার পরে সমস্যা থামলে প্রমাণ ৬ · প্রতিরোধTest, alert, runbook, postmortem
ছবি ৮১.১ — ধাপ ৪ ইচ্ছা করেই ধাপ ৫-এর আগে। ব্যবহারকারীর কষ্ট আগে থামে, কারণ খোঁজা চলে তারপর। শেষের শিক্ষা আবার ধাপ ১-কে শক্ত করে।
প্র ১“আপনি কীভাবে সমস্যা খোঁজেন?” — এই খোলা প্রশ্নের ভালো উত্তর কেমন? (সহজ)

উত্তর: এলোমেলো কমান্ডের তালিকা না বলে ক্রম বলুন। আগে লক্ষণ নিজে মেপে নিশ্চিত করি, কারণ রিপোর্ট অনুমান হতে পারে। তারপর সীমা টানি: কখন থেকে, কোন path, কতজন। তারপর জিজ্ঞেস করি, ঠিক আগে কী বদলেছিল। প্রভাব বড় হলে আগে ক্ষতি থামাই, সাধারণত rollback দিয়ে। এরপর মূল কারণ খুঁজি, আর শেষে একটি test বা alert যোগ করি।

একটি ছোট উদাহরণ যোগ করলে উত্তর জীবন্ত হয়। পর্ব ০৯-এর নমুনা log-এ “checkout-এ 500” রিপোর্ট আসলে ৭টি 5xx ছিল, ৬টি 500 আর ১টি 504, সবই POST /api/orders-এ।

ফলো-আপ: “সবচেয়ে দামি একটি প্রশ্ন কোনটি?” — “ঠিক আগে কী বদলেছিল?”

প্র ২যে প্রশ্নের উত্তর জানেন না, সেখানে কী বলবেন? (সহজ)

উত্তর: অনুমানকে তথ্য বলে চালাবেন না। তিনটি অংশে বলুন: যা জানি, যা জানি না, আর কীভাবে জানব। যেমন: “Gateway API নিজে production-এ চালাইনি। জানি এটি Ingress-এর পরের ধাপ, আর এতে দায়িত্ব ভাগ করা যায়। নির্দিষ্ট field নিশ্চিত নই, তাই official docs দেখে --dry-run=server দিয়ে যাচাই করব।”

অচেনা বিষয়ে কাছের জানা ধারণা থেকে যুক্তি করতেও পারেন, তবে আগে বলে নিন, “এটি আমার অনুমান।”

ফলো-আপ: “Google করতে পারবেন না, তাহলে?” — যুক্তি দিয়ে পরীক্ষার পথ বলুন: কোন আউটপুট দেখলে কোন ধারণা বাদ পড়বে।

প্র ৩Production ভাঙছে। আগে মূল কারণ খুঁজবেন, না আগে ক্ষতি থামাবেন? (মাঝারি)

উত্তর: সাধারণত আগে ক্ষতি থামানো, যাকে mitigation বলে। Rollback, traffic সরানো বা feature বন্ধ করা কারণ পুরো না জেনেও করা যায়। ক্যাপস্টোনে ২৫% request ভাঙছিল: আগের SHA-তে ফিরতেই ২৬ সেকেন্ডে ক্ষতি থামল, কারণ পরে ধীরে-সুস্থে খোঁজা হলো।

দুটি ব্যতিক্রম মনে রাখুন। নিরাপত্তার ঘটনায় server মুছে ফেললে প্রমাণ হারায়, তাই আগে আলাদা করা হয়। আর schema বদলের পরে কোড rollback করলে ডেটা নষ্ট হতে পারে, তাই আগে দেখে নিতে হয় পুরোনো কোড নতুন schema-য় চলবে কি না।

ফলো-আপ: “Mitigation আর resolution কি এক?” — না। Mitigation ক্ষতি থামায়, resolution সেবা স্থির করে ঘটনা বন্ধ করে।

২ · Linux আর shell — permission, signal, load, log আর network

রিভিশন: পর্ব ০৮, পর্ব ০৯, পর্ব ১০, পর্ব ১১, পর্ব ১২, পর্ব ১৩, পর্ব ১৪

প্র ৪chmod 755 মানে কী? umask 027 থাকলে নতুন ফাইল আর directory কী অনুমতি পাবে? (সহজ)

উত্তর: 755 মানে owner rwx, group আর other r-x. প্রতিটি সংখ্যা r=4, w=2, x=1-এর যোগফল। umask 027 বলে কোন bit কেড়ে নেওয়া হবে। ফাইলের শুরু 666 থেকে হয় 640, directory-র 777 থেকে হয় 750.

ফলো-আপ: “Directory-তে x মানে কী?” — ভেতরে ঢোকা আর নাম ধরে ফাইলে পৌঁছানোর অনুমতি।

প্র ৫Exit code 137 আর 143 মানে কী? 137 মানেই কি memory শেষ? (সহজ)

উত্তর: Signal-এ মরলে exit code হয় ১২৮ + signal নম্বর। 137 = 128 + 9, মানে SIGKILL. 143 = 128 + 15, মানে SIGTERM. 137 মানেই OOM নয়। পর্ব ৪৩-এর আসল run-এ Reason: OOMKilled আর Exit Code: 137 একসাথে এসেছিল, কিন্তু আরেকটি Pod-এ Reason: Error আর 137: সেখানে grace period ফুরানোয় kubelet নিজে SIGKILL পাঠিয়েছিল।

ফলো-আপ: “তাহলে কীভাবে আলাদা করবেন?” — Kubernetes-এ Reason, Docker-এ .State.OOMKilled, আর VM-এ journalctl -k.

প্র ৬৪ core-এর server-এ load average 8. ভালো না খারাপ? (মাঝারি)

উত্তর: প্রতি core-এ ২, অর্থাৎ কাজ সারিতে জমছে। কিন্তু Linux-এর load-এ শুধু CPU-র অপেক্ষা নয়, D state-এর task-ও গোনা হয়, মানে যারা disk-এর অপেক্ষায় আটকে। তাই top-এর wa দেখুন। পর্ব ১১-এর নমুনায় ২ core-এ load 6.42, কিন্তু wa ৪১%: CPU আসল সমস্যা ছিল না, memory শেষ হয়ে swap চলছিল। তাই core বাড়ালে তেমন লাভ হতো না।

ফলো-আপ: “কোন ক্রমে দেখবেন?” — USE method: প্রতিটি resource-এর utilization, saturation আর errors.

প্র ৭free-তে free memory প্রায় শূন্য। এটি কি সমস্যা? (সহজ)

উত্তর: একা দেখলে নয়। Linux ফাঁকা RAM ফেলে রাখে না, disk-এর ডেটা page cache-এ রাখে, আর দরকার হলে ছেড়ে দেয়। তাই available ঘর দেখুন, আর vmstat-এর si, so দিয়ে দেখুন swap এখনই চলছে কি না।

ফলো-আপ: “drop_caches চালাবেন?” — না। কারণ ঠিক হয় না, উল্টো cache হারিয়ে disk আরও ব্যস্ত হয়।

প্র ৮Access log থেকে সবচেয়ে বেশি request করা ১০টি IP বের করুন। uniq-এর আগে sort কেন? (সহজ)

উত্তর: awk '{print $1}' access.log | sort | uniq -c | sort -rn | head. uniq শুধু পাশাপাশি একই লাইন মেলায়, তাই আগে sort লাগে। দ্বিতীয় sort -rn সংখ্যা ধরে বড় থেকে ছোট সাজায়।

ফলো-আপ: “grep 500 দিয়ে 500 গুনলে?” — পর্ব ০৯-এর আসল run-এ grep -c 500 দিল 13, কারণ byte-এর ঘরেও 500 ছিল। কড়া নকশা '" 500 ' দিল 6.

প্র ৯set -euo pipefail কী করে? এর কোন ফাঁদ জানেন? (মাঝারি)

উত্তর: -e ব্যর্থ কমান্ডে থামায়, -u অজানা variable-এ থামায়, আর pipefail pipeline-এর মাঝের ব্যর্থতা ধরে। ফাঁদ আছে দুটি। grep কিছু না পেলে exit 1 দেয়, তাই সাধারণ “মিল নেই” ফলেও script থামে। আর if deploy; then বা deploy || echo no লিখলে deploy function-এর ভেতরে -e কাজই করে না।

ফলো-আপ: “কেন দরকার?” — একটি বানান ভুলের cd ব্যর্থ হওয়ার পরেও rm -rf ./* চলে গেলে ভুল ফোল্ডার মুছে যায়।

প্র ১০Connection refused আর timeout, 502 আর 504: প্রতিটি দেখে কোন স্তরে তাকাবেন? (মাঝারি)

উত্তর: Refused মানে packet পৌঁছেছে, কিন্তু ওই port-এ কেউ শুনছে না, RST ফিরেছে, আর তা আসে খুব দ্রুত। দেখুন ss -tlnp আর process. Timeout মানে উত্তরই আসেনি, কেউ চুপচাপ ফেলে দিচ্ছে বা পথ নেই। দেখুন firewall, security group, route.

502 মানে proxy আছে, কিন্তু পেছনের app সংযোগ নেয়নি বা অচল উত্তর দিয়েছে। 504 মানে app সময়মতো উত্তর দেয়নি, তাই তার log আর ডেটাবেস দেখুন।

ফলো-আপ: “Site-এ ঢুকতে না পারলে প্রথমে?” — লক্ষণ নিশ্চিত করে স্তর ধরে: DNS, পথ, port, TLS, HTTP.

এবার shell-এর হাত ঝালাই। পর্ব ০৯-এর ২০ লাইনের নমুনা log-এ পাঁচটি প্রশ্নের উত্তর এক ব্লকে। চালানোর আগে অনুমান করুন: ধীর হওয়ার আগে আর পরে গড় সময় কত গুণ বদলাল?

export LC_ALL=C
cd "$(mktemp -d)"
cat > access.log <<'EOF'
203.0.113.7 - - [30/Oct/2026:14:01:05 +0600] "GET /api/products HTTP/1.1" 200 1500 0.041
203.0.113.7 - - [30/Oct/2026:14:01:12 +0600] "GET /api/products HTTP/1.1" 200 1500 0.038
203.0.113.25 - - [30/Oct/2026:14:01:33 +0600] "POST /api/login HTTP/1.1" 401 96 0.033
203.0.113.60 - - [30/Oct/2026:14:01:48 +0600] "POST /api/orders HTTP/1.1" 200 240 0.210
203.0.113.7 - - [30/Oct/2026:14:01:55 +0600] "GET /api/products HTTP/1.1" 200 1500 0.044
203.0.113.41 - - [30/Oct/2026:14:02:03 +0600] "GET /api/cart HTTP/1.1" 200 812 0.120
203.0.113.7 - - [30/Oct/2026:14:02:17 +0600] "GET /api/products HTTP/1.1" 200 1500 0.040
203.0.113.60 - - [30/Oct/2026:14:02:26 +0600] "POST /api/orders HTTP/1.1" 200 240 0.230
203.0.113.7 - - [30/Oct/2026:14:02:38 +0600] "GET /api/products HTTP/1.1" 200 1500 0.036
203.0.113.18 - - [30/Oct/2026:14:02:51 +0600] "GET /api/cart HTTP/1.1" 200 812 0.115
203.0.113.33 - - [30/Oct/2026:14:03:04 +0600] "POST /api/orders HTTP/1.1" 500 182 2.104
203.0.113.7 - - [30/Oct/2026:14:03:11 +0600] "GET /api/products HTTP/1.1" 200 1500 0.042
203.0.113.60 - - [30/Oct/2026:14:03:22 +0600] "POST /api/orders HTTP/1.1" 500 182 2.087
203.0.113.18 - - [30/Oct/2026:14:03:37 +0600] "GET /api/cart HTTP/1.1" 200 812 0.119
203.0.113.41 - - [30/Oct/2026:14:03:49 +0600] "POST /api/orders HTTP/1.1" 500 182 2.131
203.0.113.33 - - [30/Oct/2026:14:04:02 +0600] "POST /api/orders HTTP/1.1" 500 182 2.095
203.0.113.7 - - [30/Oct/2026:14:04:10 +0600] "GET /api/products HTTP/1.1" 200 1500 0.039
203.0.113.52 - - [30/Oct/2026:14:04:21 +0600] "POST /api/orders HTTP/1.1" 504 157 5.003
203.0.113.18 - - [30/Oct/2026:14:04:35 +0600] "POST /api/orders HTTP/1.1" 500 182 2.118
203.0.113.60 - - [30/Oct/2026:14:04:52 +0600] "POST /api/orders HTTP/1.1" 500 182 2.092
EOF
echo "== status =="; awk '{print $9}' access.log | sort | uniq -c | sort -rn
echo "== 5xx per minute =="; awk '$9 ~ /^5/ {print substr($4, 14, 5)}' access.log | sort | uniq -c
echo "== 5xx by path =="; awk '$9 ~ /^5/ {print $6, $7}' access.log | sort | uniq -c
echo "== slowest 3 =="; sort -k11,11nr access.log | head -3 | awk '{print $11, $9, $7}'
echo "== /api/orders mean seconds, before and from 14:03 =="
awk '$7 == "/api/orders" { k = (substr($4, 14, 5) < "14:03") ? "before" : "after"; s[k] += $11; n[k]++ } END { printf "before %.3f (n=%d)\nafter  %.3f (n=%d)\n", s["before"]/n["before"], n["before"], s["after"]/n["after"], n["after"] }' access.log
== status ==
     12 200
      6 500
      1 504
      1 401
== 5xx per minute ==
      3 14:03
      4 14:04
== 5xx by path ==
      7 "POST /api/orders
== slowest 3 ==
5.003 504 /api/orders
2.131 500 /api/orders
2.118 500 /api/orders
== /api/orders mean seconds, before and from 14:03 ==
before 0.220 (n=2)
after  2.519 (n=7)

৭টি 5xx-ই এক path-এ, আর ১৪:০৩-এর আগে একটিও নয়। সেখানে গড় সময় ০.২২০ থেকে ২.৫১৯ সেকেন্ড, প্রায় ১১.৫ গুণ। গড়ে ৫.০০৩ সেকেন্ডের 504-টিও ঢুকেছে। শেষ awk-এ s[k] যোগফল আর n[k] গণনা রাখে। অংশ ৮-এর তৃতীয় drill এই log নিয়েই।

৩ · Docker — image, layer, cache আর Dockerfile review

রিভিশন: পর্ব ৩৬, পর্ব ৩৭, পর্ব ৩৮, পর্ব ৩৯, পর্ব ৪০, পর্ব ৪১

প্র ১১Image আর container-এর পার্থক্য কী? Container কি ছোট VM? (সহজ)

উত্তর: Image হলো read-only layer-এর সারি। Container হলো তার ওপর একটি writable layer আর একটি চলমান process. VM-এর নিজের kernel থাকে, container host-এর kernel ভাগ করে, তাই হালকা, কিন্তু আলাদা থাকার সীমাও ভিন্ন।

ফলো-আপ: “Container মুছলে ভেতরের লেখা ফাইল?” — writable layer-এর সাথে যায়। তাই ডেটা রাখুন volume-এ।

প্র ১২RUN আর CMD, আবার CMD আর ENTRYPOINT-এর পার্থক্য কী? (সহজ)

উত্তর: RUN build-এর সময় চলে আর layer বানায়। CMD container চালুর সময় চলে আর শুধু config-এ থাকে। ENTRYPOINT মূল প্রোগ্রাম, CMD তার ডিফল্ট argument. docker run-এর শেষের লেখা শুধু CMD-কে বদলায়।

ফলো-আপ: “শুধু CMD থাকা image-এ docker run img hello দিলে?” — hello পুরো CMD-র জায়গা নেয়। পর্ব ৩৭-এর আসল run-এ executable file not found in $PATH, exit 127.

প্র ১৩Docker build cache কীভাবে কাজ করে? Build ধীর হলে কী বদলাবেন? (মাঝারি)

উত্তর: নিয়ম সরল: একটি ধাপ বাতিল হলে নিচের সব ধাপ বাতিল। পর্ব ৩৭-এর আসল run-এ COPY . . আগে আর pip পরে ছিল, তাই app.py-র একটি শব্দ বদলাতেই pip আবার চলল, যদিও dependency একই। সমাধান ক্রমে: আগে COPY requirements.txt ., তারপর install, শেষে source.

.dockerignore দিয়ে context ছোট রাখুন, আর CI-তে remote cache নিন।

ফলো-আপ: “.dockerignore শুধু গতির জন্য?” — না। ওই পর্বের run-এ এটি ছাড়া .env.sample image-এ ঢুকে গিয়েছিল, মানে secret-ও ঢুকতে পারে।

প্র ১৪পরের RUN-এ ফাইল মুছলে image ছোট হয় না কেন? Secret-এর ক্ষেত্রে এর মানে কী? (মাঝারি)

উত্তর: আগের layer read-only. নতুন layer-এ শুধু একটি whiteout চিহ্ন বসে, আসল বাইট আগের layer-এই থাকে। তাই মুছতে হবে একই RUN-এ। Secret হলে এটি ফাঁস: যে image টানবে, সে layer খুলে ফাইলটি পেতে পারে।

ফলো-আপ: “Build-এ secret লাগলে?” — BuildKit-এর secret mount, যা layer-এ থাকে না (পর্ব ৩৮)। ফাঁস হলে আগে key বাতিল করুন।

প্র ১৫Multi-stage build কেন? সংখ্যা দিয়ে বলুন। (সহজ)

উত্তর: Build-এর টুল ship না করে image ছোট আর নিরাপদ রাখতে। পর্ব ৩৮-এর আসল run-এ একই ছোট C প্রোগ্রাম: compiler-সহ এক stage ২২৯MB, multi-stage আর alpine ১২.১MB, multi-stage আর scratch ৪৭kB. ক্যাপস্টোনে এর আরেকটি ব্যবহার আছে: চূড়ান্ত image ফাইল নেয় test stage থেকে, তাই test ব্যর্থ হলে image-ই হয় না।

ফলো-আপ: “Scratch-এর দাম কী?” — ভেতরে shell নেই, তাই debug কঠিন।

প্র ১৬Dockerfile-এ CMD python app.py আর CMD ["python", "app.py"]-এর পার্থক্য production-এ কীভাবে ধরা পড়ে? (কঠিন)

উত্তর: প্রথমটি shell form: Docker চালায় /bin/sh -c, তাই sh হতে পারে PID 1, আর SIGTERM সবসময় app পর্যন্ত পৌঁছায় না। দ্বিতীয়টি exec form: app নিজেই PID 1. পর্ব ৩৮-এর আসল run-এ docker stop -t 10-এ shell form-এর একটি রূপ ১০.৩২ সেকেন্ড নিয়ে exit 137 দিল, আর exec form ০.২৯ সেকেন্ডে exit 0.

৫০টি container-এর rolling update-এ এই পার্থক্য deploy-কে অনেক ধীর করে, আর চলমান request ভাঙতে পারে।

ফলো-আপ: “App নিজেই PID 1 হলেই কি হলো?” — না। পর্ব ৩৯-এর run-এ handler ছাড়া Python PID 1 হিসেবে SIGTERM উপেক্ষা করে 137 দিল। Handler লিখুন, অথবা --init দিন: তখন exit 143.

প্র ১৭Dockerfile-এ EXPOSE 8000 দিলাম, তবু host থেকে পৌঁছাতে পারছি না। কেন? (সহজ)

উত্তর: EXPOSE মূলত নথি, সে port খোলে না। পর্ব ৩৭-এর আসল run-এ শুধু EXPOSE-এ curl exit 7 দিল, মানে সংযোগই হয়নি। -p দিয়ে publish করতে হয়, যেমন -p 127.0.0.1:8080:8000. শুধু 127.0.0.1-এ বাঁধলে বাইরের কেউ পৌঁছাতে পারেন না।

প্র ১৮latest tag কেন এড়াবেন? Tag আর digest-এর পার্থক্য কী? (মাঝারি)

উত্তর: latest শুধু default tag, সবচেয়ে নতুন image-এর নিশ্চয়তা নয়। Tag সরানো যায়, digest হলো manifest-এর SHA-256, তাই বদলায় না। latest-এ কোন code চলছে বলা যায় না, rollback-ও অনিশ্চিত। ক্যাপস্টোনে image tag ছিল commit SHA, আর উৎপাদনে digest-এ বাঁধা আরও শক্ত।

ফলো-আপ: “Signature কী প্রমাণ করে?” — কে সই করেছে আর digest অক্ষত আছে। কোড নিরাপদ, তা নয়।

৪ · Kubernetes — Pod-এর অবস্থা, debug, probe, rollout আর RBAC

রিভিশন: পর্ব ৪২, পর্ব ৪৩, পর্ব ৪৪, পর্ব ৪৫, পর্ব ৪৬, পর্ব ৪৭, পর্ব ৪৮, পর্ব ৪৯

Pod-এর সব ব্যর্থতা একটি মইয়ের ধাপ। আগে বুঝুন Pod কোন ধাপে আটকেছে, তাহলে কোথায় তাকাবেন তা নিজে থেকেই ঠিক হয়।

Pod কোন ধাপে আটকেছে

Each step of a Pod's start, and the STATUS you see when it fails there

Pod-এর শুরুর ধাপ আর প্রতিটি ধাপের ব্যর্থতার চিহ্ন Node পাওয়া Image নামা Config পাওয়া Process চলা Readiness Traffic পাওয়া PendingEvent: FailedScheduling ImagePullBackOffContainer চলেনি, log নেই CreateContainerConfigErrorSecret বা ConfigMap নেই CrashLoopBackOff · OOMKilledexit code, logs --previous Running, কিন্তু 0/1Probe ব্যর্থ, restart নয় Service-এ কেউ নেইSelector, port, EndpointSlice
ছবি ৮১.২ — ওপরের তিন ধাপে container একবারও চলেনি, তাই kubectl logs-এ কিছু পাবেন না। সেখানে describe-এর Events-ই ভরসা।
প্র ১৯kubectl get pods-এর STATUS কলাম আর Pod-এর phase কি এক জিনিস? (মাঝারি)

উত্তর: না। STATUS হলো kubectl-এর নিজের হিসাব করা লেখা। পর্ব ৪৩-এর আসল run-এ ImagePullBackOff Pod-এর phase ছিল Pending, আর CrashLoopBackOff Pod-এর phase ছিল Running.

তাই শুধু phase == Running দেখে alert বসালে ভাঙা Pod-ও সুস্থ মনে হবে। Alert বসান restart count আর Ready condition-এ।

Pod crash · আউটপুট ছাঁটা
কমান্ড
যা খুঁজছি
  1. দেখা। ৯ বার restart, ২১ মিনিট ধরে। শেষ restart ১৬ সেকেন্ড আগে। Crash সত্যি, ক্ষণিকের নয়।
  2. Describe. State Waiting, কারণ এখন বিরতিতে আছে। Last State-এ আসল ঘটনা: exit 1, Reason Error. App নিজে হার মেনেছে, OOM নয়, kubelet-ও মারেনি।
  3. আগের log. --previous মরে যাওয়া container-এর log দেখায়। নতুন container চালু হয়ে গেলে সাধারণ logs-এ কারণটি নাও থাকতে পারে।
  4. সিদ্ধান্ত। সমস্যা Pod-এ নয়, তার নির্ভরতায়। Pod মুছলে একই crash ফিরবে, আর প্রমাণ হারাবে।
প্র ২০CrashLoopBackOff-এর বিরতি কেমন বাড়ে? “Crash করছে” আর “BackOff”-এর পার্থক্য কী? (মাঝারি)

উত্তর: CrashLoopBackOff মানে “এখন বিরতিতে আছি”, চিরকাল crash নয়। পর্ব ৪৩-এর run-এ প্রথম restart প্রায় সঙ্গে সঙ্গে, তারপর kubelet-এর বার্তায় বিরতি 10s, 20s, 40s, 1m20s, 2m40s, আর 5m0s-এ থেমে গেল। মাপা ফাঁক বার্তার চেয়ে ০ থেকে ৯ সেকেন্ড বেশি ছিল।

নথি অনুযায়ী container ১০ মিনিট টানা ভালো চললে backoff আবার শুরু থেকে গোনা হয়। এটি ওই run-এ মাপা হয়নি, আর নতুন version-এ সংখ্যা বদলাতে পারে।

প্র ২১কোনো ভুল নেই, exit 0, তবু Pod CrashLoopBackOff-এ। কীভাবে সম্ভব? (মাঝারি)

উত্তর: restartPolicy Always মানে সত্যিই সবসময়, সফল exit-এও restart. পর্ব ৪৩-এ always-exit0 Pod ২৫ সেকেন্ডে ২ বার restart হয়েছিল। একবারের কাজ তাই Deployment-এ নয়, Job-এ চালান। আরেকটি কারণ: ভুল liveness path. ওই পর্বে সুস্থ nginx ভুল পথের জন্য kill হলো, Reason: Completed, Exit Code: 0, আর মিনিটখানেকে CrashLoopBackOff. কারণটি ছিল Events-এ।

প্র ২২Pod Pending. কীভাবে খুঁজবেন? “Node প্রায় খালি, তবু Pending” কেন হয়? (মাঝারি)

উত্তর: kubectl describe pod-এর Events পড়ুন। পর্ব ৪৮-এর আসল run:

Warning FailedScheduling 0/1 nodes are available: 1 Insufficient cpu,
1 Insufficient memory. … preemption: 0/1 nodes are available:
1 Preemption is not helpful for scheduling.

Scheduler আসল ব্যবহার নয়, বুক করা request দেখে। অন্য Pod বেশি request করে রাখলে node ব্যবহারে ফাঁকা থেকেও হিসাবে ভরা। অন্য কারণ: label না মেলা, taint আছে কিন্তু toleration নেই, PVC bound হয়নি।

ফলো-আপ: “PVC Pending কেন?” — মানানসই class নেই, provisioner-এর সমস্যা, অথবা WaitForFirstConsumer-এ Pod-এর অপেক্ষা।

প্র ২৩ImagePullBackOff এলে কী দেখবেন? logs কেন ফাঁকা? (সহজ)

উত্তর: Container একবারও চলেনি, তাই log নেই, RESTARTS ০, phase Pending. describe-এর Events পড়ুন। Message-এর শেষ শব্দই কারণ বলে: পর্ব ৪৩-এর run-এ ছিল not found, মানে tag বা নাম ভুল। unauthorized বা denied সাধারণত private registry-র অনুমতির সমস্যা। প্রথমে ErrImagePull, তারপর বিরতি দিয়ে চেষ্টা, তাই ImagePullBackOff.

প্র ২৪OOMKilled Pod পেলে আপনি কী করবেন? সোজা limit বাড়াবেন? (মাঝারি)

উত্তর: না। আগে memory-র গ্রাফ দেখুন। না নামা সিঁড়ি মানে leak, তাই কোড ঠিক করুন। ট্রাফিকের সাথে ওঠানামা মানে সীমা ছোট, তাই মেপে বাড়ান। পর্ব ৪৩-এর run-এ ৬৪ MiB সীমায় শেষ লাইন ছিল allocated 56 MiB, কারণ Python-এর নিজেরও memory লাগে। App error লেখার সুযোগই পায় না, তাই প্রমাণ থাকে status-এ।

ফলো-আপ: “CPU limit পার হলে?” — মরে না, throttle হয়। পর্ব ৪৮-এ ০.১ CPU-র Pod ৫ সেকেন্ডে মাত্র ০.৫৩ সেকেন্ড CPU পেল। Latency বাড়ে, log-এ কিছু থাকে না।

প্র ২৫CreateContainerConfigError মানে কী? Pod মুছতে হবে? (সহজ)

উত্তর: Image আছে, node আছে, কিন্তু container বানানোর তথ্য অসম্পূর্ণ, যেমন Secret নেই। পর্ব ৪৩-এর run-এ Event ছিল secret "db-secret" not found. Pod মোছার দরকার হয়নি: Secret তৈরি হতেই kubelet-এর পরের চেষ্টায় Pod 1/1 Running হলো।

// Read "kubectl get pods" rows and name the first thing to check.
// These rows are copied from real runs in the Kubernetes lessons.
const rows = `crash 0/1 CrashLoopBackOff 9 (16s ago) 21m
badimage 0/1 ImagePullBackOff 0 2m9s
oom 0/1 OOMKilled 0 12s
nosecret 0/1 CreateContainerConfigError 0 6s
too-big 0/1 Pending 0 4s
shop-a 0/1 Running 0 14s
live-bad 1/1 Running 1 (8s ago) 23s
shop-b 1/1 Running 0 14s`;
const next = {
  CrashLoopBackOff: "describe: exit code, then logs --previous",
  ImagePullBackOff: "describe Events: not found or unauthorized?",
  ErrImagePull: "describe Events: not found or unauthorized?",
  OOMKilled: "memory limit against real usage, leak or small limit?",
  CreateContainerConfigError: "describe Events: which Secret or ConfigMap is missing?",
  Pending: "describe Events: FailedScheduling message",
};
for (const row of rows.split("\n")) {
  const [name, ready, status, restarts] = row.split(" ");
  const [up, all] = ready.split("/").map(Number);
  let say = next[status];
  if (!say && status === "Running" && up < all) say = "not ready: read the readiness probe, no restart yet";
  if (!say && Number(restarts) > 0) say = "restarted: describe Last State and liveness Events";
  console.log(name.padEnd(9), status.padEnd(27), say || "looks healthy");
}
crash     CrashLoopBackOff            describe: exit code, then logs --previous
badimage  ImagePullBackOff            describe Events: not found or unauthorized?
oom       OOMKilled                   memory limit against real usage, leak or small limit?
nosecret  CreateContainerConfigError  describe Events: which Secret or ConfigMap is missing?
too-big   Pending                     describe Events: FailedScheduling message
shop-a    Running                     not ready: read the readiness probe, no restart yet
live-bad  Running                     restarted: describe Last State and liveness Events
shop-b    Running                     looks healthy

শেষ তিনটি সারি দেখুন। shop-a আর live-bad দুজনেই Running, কিন্তু একজন not ready, আরেকজন restart হয়েছে। STATUS একা গল্পটি বলে না। সব ঘর পড়ুন: READY, RESTARTS, তারপর Events.

প্র ২৬Service আছে, Pod আছে, DNS কাজ করে, তবু সংযোগ হচ্ছে না। কীভাবে এগোবেন? (কঠিন)

উত্তর: পর্ব ৪৫-এর আসল run-এ চারটি আলাদা ভুল ঘটানো হয়েছিল: selector টাইপো, targetPort: 9090 (app শোনে 8080), targetPort: web (নামটি নেই), আর সব Pod unready. চারটিতেই curl exit 7. তাই error দেখে কারণ বলা যায় না, কারণ ধরা পড়ে EndpointSlice আর Pod পড়ে।

ক্রম: kubectl get svc, Pod-এর ভেতর থেকে getent hosts, kubectl get pods --show-labels, slice-এর PORTS আর ready, তারপর Pod IP-তে সরাসরি curl.

ফলো-আপ: “সঙ্গে সঙ্গে ব্যর্থ আর timeout কি এক?” — না। ফাঁকা Service-এ ০ ms-এ বাতিল, মৃত Pod IP-তে ৩ সেকেন্ড অপেক্ষার পরে timeout.

// "Service not reachable" decision tree. Set what you observed.
const OBSERVED = {
  serviceExists: true,      // kubectl get svc api
  dnsResolves: true,        // getent hosts api (from a Pod)
  podsMatchSelector: false, // kubectl get pods -l <selector>
  somePodReady: true,       // READY column, or slice conditions
  slicePortSet: true,       // PORTS is not <unset>
  podIpWorks: true,         // curl PodIP:targetPort (from a Pod)
  clusterIpWorks: true,     // curl ClusterIP:port (from a Pod)
  outsideWorks: true,       // from outside the cluster
};
const TREE = [
  ["serviceExists", "Service exists?", "Wrong name or namespace. Check: kubectl get svc -A"],
  ["dnsResolves", "Name resolves?", "Use the full name; check namespace and CoreDNS Pods."],
  ["podsMatchSelector", "Pods match selector?", "Selector or label typo. Compare with --show-labels."],
  ["somePodReady", "Any Pod Ready?", "Read kubectl describe pod: probe, crash or image."],
  ["slicePortSet", "Slice port set?", "targetPort name not on the Pod. Fix the port name."],
  ["podIpWorks", "Pod answers directly?", "App not listening there, wrong targetPort, or NetworkPolicy."],
  ["clusterIpWorks", "ClusterIP answers?", "Service path broken: check port, kube-proxy, CNI, policy."],
  ["outsideWorks", "Reachable from outside?", "Check type, NodePort, firewall, LB health check."],
];
let step = 0, stopped = false;
for (const [key, question, fix] of TREE) {
  step++;
  if (OBSERVED[key]) { console.log(step + ". " + question + " yes"); continue; }
  console.log(step + ". " + question + " NO\nSTOP -> " + fix);
  stopped = true;
  break;
}
if (!stopped) console.log("All checks pass: test from the failing client itself.");
1. Service exists? yes
2. Name resolves? yes
3. Pods match selector? NO
STOP -> Selector or label typo. Compare with --show-labels.

podsMatchSelector এখানে false, তাই গাছ তৃতীয় ধাপে থামল। অন্য ঘরগুলো বদলে দেখুন প্রতিটি ফলাফল। এই গাছ পর্ব ৪৫-এর, আর অংশ ৮-এর প্রথম drill-এ এই শাখাটিই আসল আউটপুটে দেখবেন।

প্র ২৭kubectl get endpointslices-এর ENDPOINTS কলামে Pod-এর IP আছে। তার মানে কি সে traffic পাচ্ছে? (মাঝারি)

উত্তর: না। এই কলাম শুধু ঠিকানা দেখায়, অবস্থা নয়। পর্ব ৪৩-এর run-এ shop-a unready হওয়ার পরেও কলামে দুটি IP ছিল, কিন্তু ভেতরে ready=false, আর ৮টি অনুরোধের ৮টিই গেল shop-b-তে। তাই conditions.ready পড়ুন। পুরোনো Endpoints object পর্ব ৪৫-এর run-এ deprecated সতর্কতা দিয়েছিল (v1.33+).

প্র ২৮Liveness, readiness আর startup probe-এর পার্থক্য কী? Liveness-এ ডেটাবেস ছোঁয়া কেন ভুল? (মাঝারি)

উত্তর: Liveness ব্যর্থ হলে container restart. Readiness ব্যর্থ হলে শুধু traffic বন্ধ, restart নয়। Startup ধীরে চালু হওয়া app-কে সময় দেয়, আর সফল হওয়ার আগে বাকি দুটি শুরু হয় না।

Liveness ডেটাবেস ছুঁলে ডেটাবেস ধীর হলেই সব Pod-এর probe একসাথে ব্যর্থ, Kubernetes সব container মারে, নতুনগুলো খালি cache নিয়ে ধীর ডেটাবেসে আরও চাপ দেয়। একটি সমস্যা হয়ে যায় পুরো outage.

ফলো-আপ: “দুই probe-এ একই endpoint?” — ক্যাপস্টোনে তাই ছিল, ফলে readiness-এর সমস্যায় অকারণে RESTARTS 1. বড় service-এ আলাদা রাখুন।

প্র ২৯replicas: 10, maxSurge: 3, maxUnavailable: 2: rollout-এ সর্বোচ্চ Pod আর সর্বনিম্ন available কত? maxUnavailable: 0 কেন দেবেন? (মাঝারি)

উত্তর: সর্বোচ্চ ১০ + ৩ = ১৩, সর্বনিম্ন available ১০ − ২ = ৮. maxUnavailable ০ মানে নতুন Pod ready না হলে পুরোনোটি নামে না। ক্যাপস্টোনের প্রথম খারাপ release-এ ঠিক এটিই বাঁচিয়েছিল: নতুন Pod কখনো ready হয়নি, পুরোনো তিনটি চলল, ট্রাফিকে একটিও ভুল নেই।

ফলো-আপ: “PDB কি rolling update থামায়?” — না, PDB শুধু eviction-এর জন্য।

প্র ৩০Rollout আটকে গেলে Kubernetes কি নিজে rollback করে? (মাঝারি)

উত্তর: না। progressDeadlineSeconds পার হলে শুধু একটি condition বদলায়: Progressing=False, reason ProgressDeadlineExceeded. এটি মোট সময়ের সীমা নয়, শেষ অগ্রগতির পরের সময়। Default ৬০০ সেকেন্ড। সিদ্ধান্ত আপনার বা pipeline-এর।

পুরো ঘটনাটি অংশ ৮-এর চতুর্থ drill-এ আছে।

প্র ৩১Pod মোছার সময় কী ঘটে? ক্রমটি বলুন। (সহজ)

উত্তর: Pod Terminating হয়, পাশাপাশি Service থেকে সরে, preStop চলে, তারপর SIGTERM, আর সীমা ফুরালে SIGKILL. ডিফল্ট grace period ৩০ সেকেন্ড। App যদি SIGTERM সামলায় না, তাহলে চলমান request ভাঙে। ক্যাপস্টোনের app SIGTERM পেয়ে /healthz-এ 503 দেয় আর ৩ সেকেন্ড কাজ শেষ করে: এটিই graceful shutdown.

ফলো-আপ: “--grace-period=0 --force?” — শেষ উপায়। API থেকে Pod মুছলেও node-এ process চলতে পারে, kubectl নিজেই সতর্ক করে।

প্র ৩২Image-এ shell নেই, kubectl exec ব্যর্থ। কীভাবে ভেতরে দেখবেন? (মাঝারি)

উত্তর: kubectl debug দিয়ে ephemeral container জুড়ে দিন। পর্ব ৪৩-এর run-এ exec দিল executable file not found in $PATH, exit 127. kubectl debug nosh --image=alpine:3.20 --target=app চলন্ত Pod-এ নতুন container জুড়ল, Pod restart হয়নি, RESTARTS ০.

ফলো-আপ: “সবাইকে এই অধিকার দেবেন?” — না, RBAC দিয়ে সীমিত রাখুন।

প্র ৩৩RBAC-এ Role আর ClusterRole-এর পার্থক্য কী? কারও অনুমতি কীভাবে যাচাই করবেন? (মাঝারি)

উত্তর: Role এক namespace-এর। ClusterRole namespace-হীন, আর RoleBinding দিয়ে এক namespace-এও ব্যবহার করা যায়। RBAC শুধু অনুমতি যোগ করে: deny নিয়ম নেই, যা দেওয়া হয়নি তা বন্ধ।

যাচাই করুন kubectl auth can-i list pods -n abcl-kx --as=$SA দিয়ে। পর্ব ৪৯-এর আসল run-এ list pods yes, কিন্তু delete pods আর get secrets no. আর RoleBinding নিজের namespace-এর বাইরে খাটেনি।

ফলো-আপ: “৪০১ আর ৪০৩?” — ৪০১: পরিচয় গৃহীত হয়নি। ৪০৩: পরিচয় মিলেছে, অনুমতি নেই।

প্র ৩৪Forbidden error সারাতে কেউ Role-এ resources: ["*"], verbs: ["*"] দিতে চাইছেন। আপনি কী বলবেন? (কঠিন)

উত্তর: না বলব, আর সংখ্যা দেখাব। পর্ব ৪৯-এর run-এ এমন wildcard Role-এ app get secrets, create rolebindings আর create pods/exec সবই পেল। অর্থাৎ app দখল হলে namespace-এর সব Secret পড়া যায়, নিজেকে আরও অনুমতিও দেওয়া যায়। Error-এ লেখা resource আর verb দেখে শুধু সেটুকুই দিন, আর auth can-i দিয়ে যাচাই করুন। এটিই least privilege.

৫ · Terraform — state, plan, drift, for_each আর lock

রিভিশন: পর্ব ৫১, পর্ব ৫২, পর্ব ৫৩, পর্ব ৫৪, পর্ব ৫৫, পর্ব ৫৬

প্র ৩৫Terraform-এর state কেন লাগে? Secret কি এতে থাকে? (সহজ)

উত্তর: State config-কে বাস্তবের id-র সাথে মেলায়, metadata রাখে, আর plan দ্রুত করে। ভূমি অফিসের খতিয়ানের মতো: কোন দলিলের জমি কোনটি। Secret-ও এতে খোলা লেখায় থাকতে পারে। তাই backend-এ encryption আর ছোট অনুমতি লাগে, আর state ফাইল Git-এ রাখবেন না।

ফলো-আপ: “terraform plan “No changes” মানে সব ঠিক?” — মানে Terraform যা জানে তা ঠিক। হাতে বানানো জিনিস সে দেখে না।

প্র ৩৬plan পড়ার সময় আগে কী খোঁজেন? Saved plan কেন apply করবেন? (মাঝারি)

উত্তর: আগে শেষ লাইন: Plan: … to add, … to change, … to destroy, আর সেটি আপনার edit-এর সাথে মানায় কি না। তারপর must be replaced, will be destroyed, আর # forces replacement. Replace গোনা হয় ১ add আর ১ destroy হিসেবে।

terraform plan -out=v1.plan আর terraform apply v1.plan দিলে যা review হয়েছে ঠিক তাই চলে। State বদলে গেলে Terraform plan-টিকে stale বলে থামে।

ফলো-আপ: “~> 3.4 মানে?” — 3.4 বা ওপরে, তবে 4.0-এর নিচে।

প্র ৩৭Drift কী? কীভাবে ধরবেন, আর পাওয়ার পরে কী করবেন? (মাঝারি)

উত্তর: বাস্তব আর config-এর অমিল, সাধারণত হাতের বদলে। Terraform নিজে সারাক্ষণ দেখে না, চালালে তবেই দেখে। পর্ব ৫৩-এর আসল run-এ kubectl patch-এর পরে terraform plan -refresh-only দেখাল:

Note: Objects have changed outside of Terraform
  ~ "LOG_LEVEL" = "info" -> "debug"

plan -detailed-exitcode দেয় ০ (বদল নেই), ১ (error), ২ (বদল আছে)। রাতের pipeline-এ এটি চালালে drift-এর alert পাওয়া যায়।

হাতের বদল ভুল হলে apply দিয়ে ফেরান। ঠিক হলে code বদলান। শুধু apply -refresh-only দিলে state বদলায়, কিন্তু পরের plan আবার বদল দেখায়: ওই run-এ তাই 1 to change.

প্র ৩৮count না for_each? কেন? (মাঝারি)

উত্তর: স্থির পরিচয় দরকার হলে for_each. count-এ পরিচয় হলো অবস্থান, তাই তালিকার মাঝখান মুছলে পরের সব সরে যায়। পর্ব ৫২-এর আসল run-এ khulna মুছতে count ২টি জিনিস মুছে ১টি নতুন বানাল, আর for_each মুছল শুধু ১টি। Database হলে ডেটা যেত।

ফলো-আপ: “count কখন ঠিক?” — একই রকম কপি, অথবা শর্তে থাকা-না-থাকা, যেমন count = var.enabled ? 1 : 0.

// count vs for_each: which instances does a list edit touch?
const before = ["dhaka", "khulna", "sylhet"];
const after  = ["dhaka", "sylhet"];   // edit and run again
function countPlan(a, b) {
  const out = [];
  for (let i = 0; i < Math.max(a.length, b.length); i++) {
    const addr = "by_count[" + i + "]";
    if (i >= b.length) out.push(["-", addr, a[i] + " (index out of range)"]);
    else if (i >= a.length) out.push(["+", addr, b[i]]);
    else if (a[i] !== b[i]) out.push(["-/+", addr, a[i] + " -> " + b[i]]);
  }
  return out;
}
function eachPlan(a, b) {
  const out = [];
  for (const k of a) if (!b.includes(k)) out.push(["-", 'by_each["' + k + '"]', k]);
  for (const k of b) if (!a.includes(k)) out.push(["+", 'by_each["' + k + '"]', k]);
  return out;
}
function show(title, rows) {
  let add = 0, del = 0; console.log(title);
  for (const [sym, addr, note] of rows) {
    console.log("  " + sym.padEnd(4) + addr.padEnd(20) + note);
    if (sym !== "-") add++;
    if (sym !== "+") del++;
  }
  console.log("  Plan: " + add + " to add, 0 to change, " + del + " to destroy.");
}
show("count (identity = position)", countPlan(before, after));
show("for_each (identity = key)", eachPlan(before, after));
count (identity = position)
  -/+ by_count[1]         khulna -> sylhet
  -   by_count[2]         sylhet (index out of range)
  Plan: 1 to add, 0 to change, 2 to destroy.
for_each (identity = key)
  -   by_each["khulna"]   khulna
  Plan: 0 to add, 0 to change, 1 to destroy.

Sylhet-এর কিছুই বদলায়নি, তবু count-এ তার object নতুন হলো, কারণ সে [2] থেকে [1]-এ সরল। after-এ শেষের item মুছে চালান: তখন count-এও ক্ষতি নেই। প্রথম item মুছলে ক্ষতি সবচেয়ে বেশি।

প্র ৩৯Error acquiring the state lock পেলেন। কী করবেন? -lock=false দেবেন? (মাঝারি)

উত্তর: না। আগে Lock Info পড়ুন: কে ধরে আছেন, কখন থেকে। Lock-এর কাজই দুজনের একসাথে লেখা আটকানো। এটি ত্রুটি নয়, সুরক্ষা। CI-তে -lock-timeout=60s দিলে Terraform অপেক্ষা করে।

-lock=false সুরক্ষাটিই খুলে ফেলে। force-unlock শুধু তখন, যখন নিশ্চিত যে holder সত্যিই মৃত, আর ID নিজের চোখে দেখেছেন। পর্ব ৫৩-এর run-এ ভুল ID দিলে সে কিছু করেনি: lock id … does not match existing lock.

প্র ৪০Apply চলার সময় CI runner মরে গেল। Lock আটকে, resource অর্ধেক তৈরি। পুনরুদ্ধারের ক্রম কী? (কঠিন)

উত্তর: পর্ব ৫৩-এ এটি ইচ্ছা করে ঘটানো হয়েছিল। Holder রয়ে গেল, Job চলছিল। force-unlock-এর পরে plan বলল 1 to add, কারণ state-এ Job লেখা হয়নি। apply দিল jobs.batch "boighor-reindex" already exists. সমাধান terraform import.

অর্থাৎ ক্রম: (১) runner সত্যিই মৃত, নিশ্চিত করা; (২) সঠিক ID-তে force-unlock; (৩) plan পড়া; (৪) বাস্তবে যা তৈরি হয়েছে তা import; (৫) আবার plan-এ শূন্য দেখা।

প্র ৪১Lock কাজ করল, তবু সহকর্মীর পরের plan-এ 1 to destroy. কেন? (কঠিন)

উত্তর: Lock state-কে বাঁচায়, পুরোনো code থেকে বাঁচায় না। পর্ব ৫৩-এর উদাহরণে রাফি Job যোগ করে apply করলেন। মিতুর code-এ Job নেই, অথচ state-এ আছে, তাই তাঁর plan সেটি মুছতে চাইল। তাই apply হোক CI থেকে, main branch-এর সর্বশেষ code নিয়ে, আর plan পড়া বাধ্যতামূলক।

প্র ৪২Resource-এর নাম বদলালে destroy এড়াবেন কীভাবে? state rm আর destroy-এর পার্থক্য? (মাঝারি)

উত্তর: moved ব্লক দিয়ে: এটি infrastructure না ছুঁয়ে state-এর ঠিকানা বদলায়, plan-এ শূন্য দেখুন। state rm শুধু Terraform-কে ভুলিয়ে দেয়, জিনিসটি বাস্তবে থাকে। destroy বাস্তবের জিনিস মোছে। পর্ব ৫৩-এ state rm-এর পরে apply দিল configmaps "boighor-config" already exists.

প্র ৪৩Terraform-এ চলা Deployment-এ কেউ জরুরি মুহূর্তে kubectl rollout undo চালালেন। এরপর কী হবে? (মাঝারি)

উত্তর: ক্যাপস্টোনে এটি চালিয়ে দেখা হয়েছে: image বদলে গেল, কিন্তু Terraform তা জানে না। পরের plan-এ drift ধরা পড়ল, আর ~ image লাইন আবার নতুন SHA-তে ফেরাতে চাইল। পরের apply ভাঙা version ফিরিয়ে আনত।

নিয়ম: জরুরি মুহূর্তে undo চলতে পারে, তবে পরে অবশ্যই variable বা Git-এ একই সিদ্ধান্ত লিখতে হবে। GitOps-এও একই কথা।

৬ · CI/CD আর GitOps — pipeline, artifact, release কৌশল

রিভিশন: পর্ব ৫৭, পর্ব ৫৮, পর্ব ৫৯, পর্ব ৬০, পর্ব ৬১, পর্ব ৬২

প্র ৪৪একটি ছোট API-র জন্য CI/CD pipeline নকশা করুন। মুখে পাঁচ মিনিটে বলুন। (কঠিন)

উত্তর: আগে প্রশ্ন: কতবার deploy, দলের আকার, downtime চলবে কি না। তারপর ক্রম: দ্রুত check আগে (lint, unit), ব্যর্থ হলে থামা। Multi-stage build, image-এর tag commit SHA. Smoke test, scan আর SBOM. Registry-তে push. Dev থেকে prod-এ একই digest promote. Prod-এ canary বা rolling, SLO দেখে এগোনো। Rollback মানে আগের digest.

নিরাপত্তা: দীর্ঘস্থায়ী key নয়, OIDC. Action পূর্ণ commit SHA-তে pin. ক্যাপস্টোনের pipeline.sh এই ধাপগুলোর ছোট রূপ।

ফলো-আপ: “Runner বাড়িয়েও সময় কমছে না কেন?” — সময় critical path-এ আটকে আছে, runner-এর লাইনে নয়।

প্র ৪৫“Build once, deploy many” কেন? Environment-ভেদে যা আলাদা, তা কোথায় থাকবে? (মাঝারি)

উত্তর: পরীক্ষার ফল নির্দিষ্ট বাইটের। Prod-এর জন্য আবার build করলে বাইট বদলাতে পারে, তাই যা পরীক্ষিত তা আর চলে না। Config থাকে image-এর বাইরে, deploy-এর সময় আসে। Promotion-এ tag বা নথি বদলায়, digest নয়।

ফলো-আপ: “Rollback-এর শর্ত?” — পুরোনো digest registry-তে আছে, আর schema বা ডেটা পুরোনো কোডের সাথে মানানসই।

প্র ৪৬Blue-green আর canary-র পার্থক্য কী? Replica ratio দিয়ে ১% canary করবেন? (মাঝারি)

উত্তর: Blue-green দ্রুত ফেরে, কিন্তু blast radius ১০০%. Canary blast radius ছোট রাখে, কিন্তু দুই version দীর্ঘ সময় একসাথে চলে। Replica দিয়ে ১%-এ ১০০টি Pod লাগে, তাই L7 ওজন দিয়ে করুন।

ফলো-আপ: “Deploy আর release?” — Deploy কোড চালায়, release আচরণ খোলে। Flag দুটিকে আলাদা করে।

প্র ৪৭Zero downtime-এ database-এর কলামের নাম বদলাবেন কীভাবে? (কঠিন)

উত্তর: এক ধাপে নয়, কারণ rolling update-এ দুই version একসাথে চলে। Expand and contract: নতুন কলাম যোগ, দুই কলামেই লেখা, পুরোনো ডেটা backfill, পড়া নতুন কলামে, লেখা শুধু নতুনে, শেষে পুরোনো কলাম বাদ। প্রতিটি ধাপ আলাদা release, যাতে rollback সম্ভব থাকে।

প্র ৪৮Push-ভিত্তিক deploy আর GitOps-এর পার্থক্য কী? GitOps-এ rollback কীভাবে? (মাঝারি)

উত্তর: Pull-এ cluster-এর ভেতরের agent Git থেকে পড়ে, তাই CI-এর হাতে cluster credential লাগে না। Rollback হলো git revert, আর controller সেটি মিলিয়ে নেয়। kubectl rollout undo চালালে সেটি নিজেই drift, Git আবার উল্টে দেয়।

Pull সব ঝুঁকি সরায় না: config repository-তে merge মানেই deploy, আর agent-এর হাতে cluster-এ বড় অনুমতি থাকে।

ফলো-আপ: “Sync আর health?” — Sync মানে Git-এর সাথে মিল, health মানে সত্যিই কাজ করছে। পর্ব ৬০-এর ভুল tag-এর commit-এ YAML ঠিক ছিল, ধরা পড়ল শুধু চালাতে গিয়ে।

৭ · SRE — SLO, burn rate, alert আর incident

রিভিশন: পর্ব ৬৩, পর্ব ৬৪, পর্ব ৬৫, পর্ব ৬৬, পর্ব ৬৭, পর্ব ৬৮

প্র ৪৯SLI, SLO আর SLA-র পার্থক্য কী? কেন CPU ভালো SLI নয়? (সহজ)

উত্তর: SLI মাপ, SLO অভ্যন্তরীণ লক্ষ্য, SLA ফলাফলসহ চুক্তি। SLO সাধারণত SLA-র চেয়ে কড়া। ব্যবহারকারী CPU দেখেন না, তাই CPU ভালো SLI নয়। গড় latency-ও নয়, কারণ কিছু মানুষের কষ্ট গড়ে লুকিয়ে যায়। Page হবে ব্যবহারকারীর কষ্টে, ভেতরের কারণ থাকবে dashboard-এ।

ফলো-আপ: “RED আর USE?” — RED service-এর চোখে, USE resource-এর চোখে।

প্র ৫০৯৯.৯% SLO, ৩০ দিন। Error ০.৩% হলে burn rate কত? Budget কতদিনে শেষ? ১৪.৪ সংখ্যাটি কোথা থেকে এলো? (মাঝারি)

উত্তর: Burn = ০.০০৩ ÷ ০.০০১ = ৩. ৩০ ÷ ৩ = ১০ দিনে error budget শেষ। ১৪.৪ জাদু নয়: এই গতিতে ১ ঘণ্টায় ৩০ দিনের budget-এর ২% যায় (১৪.৪ × ১ ÷ ৭২০ = ০.০২). Google-এর SRE Workbook এই মানটি সূচনা হিসেবে দেখিয়েছে। আপনার service-এ অন্য মান ঠিক হতে পারে।

প্র ৫১Alert-এ দুটি জানালা কেন? ক্যাপস্টোনের আসল সংখ্যা দিয়ে বলুন। (মাঝারি)

উত্তর: লম্বা জানালা বলে ক্ষতিটি অর্থবহ, ছোট জানালা বলে সমস্যা এখনো চলছে। ক্যাপস্টোনে ৫ মিনিটের burn ১৫.৭ হলেও ১ ঘণ্টার burn ছিল ৯.৯, তাই alert চুপ রইল। দুটিই সীমা পেরোলে for: 1m শেষে alert বাজল, apply-র ১ মিনিট ৪৬ সেকেন্ড পরে। ক্ষতি থামার পরে ৫ মিনিটের burn ১২.৪-এ নামতেই থামল, যদিও ১ ঘণ্টার burn তখনো ৪৭.৩.

// Burn rate, and the two-window page rule. Change the numbers and run.
const SLO = 0.999, DAYS = 30, LIMIT = 14.4;
const budget = 1 - SLO;
const hours = DAYS * 24;
for (const e of [0.002, 0.003, 0.0144, 0.25, 1]) {
  const burn = e / budget;
  console.log(`error ${(e * 100).toFixed(2).padStart(6)}%  burn ${burn.toFixed(1).padStart(6)}x` +
    `  budget gone in ${(hours / burn).toFixed(1).padStart(6)} h`);
}
// [time label, 5-minute burn, 1-hour burn], measured in the capstone run.
const samples = [
  ["start", 0, 0],
  ["rollout done", 6.4, 3.9],
  ["one window over", 15.7, 9.9],
  ["both windows over", 28.1, 17.5],
  ["firing", 82.4, 43.9],
  ["rollback starts", 121.3, 63.6],
  ["alert ends", 12.4, 47.3],
];
console.log(`page rule: 5m > ${LIMIT} AND 1h > ${LIMIT}`);
for (const [when, short, long] of samples) {
  const on = short > LIMIT && long > LIMIT;
  console.log(when.padEnd(18), String(short).padStart(6), String(long).padStart(6), on ? "CONDITION TRUE" : "quiet");
}
error   0.20%  burn    2.0x  budget gone in  360.0 h
error   0.30%  burn    3.0x  budget gone in  240.0 h
error   1.44%  burn   14.4x  budget gone in   50.0 h
error  25.00%  burn  250.0x  budget gone in    2.9 h
error 100.00%  burn 1000.0x  budget gone in    0.7 h
page rule: 5m > 14.4 AND 1h > 14.4
start                   0      0 quiet
rollout done          6.4    3.9 quiet
one window over      15.7    9.9 quiet
both windows over    28.1   17.5 CONDITION TRUE
firing               82.4   43.9 CONDITION TRUE
rollback starts     121.3   63.6 CONDITION TRUE
alert ends           12.4   47.3 quiet

ওপরের অংশ হিসাব, নিচের সংখ্যাগুলো ক্যাপস্টোনের আসল run-এর। CONDITION TRUE মানে শর্ত পূরণ, তবে আসল alert for: 1m পরে firing হয়েছিল, তাই “both windows over” সারিতে সে তখনো pending. শেষ সারিতে ১ ঘণ্টার burn ৪৭.৩, তবু quiet: সমস্যা থেমে গেছে, এটিই ছোট জানালার কাজ।

প্র ৫২সব Pod ready, rollout “সফল”, অথচ ২৫% request-এ 500. কীভাবে সম্ভব? কী ধরল? (কঠিন)

উত্তর: Probe শুধু তার নিজের পথটুকু দেখে। ক্যাপস্টোনে নতুন বইয়ের rating ফাঁকা ছিল, তাই শূন্য দিয়ে ভাগ, কিন্তু /healthz সেই code ছোঁয়ই না, আর test দেখত শুধু প্রথম বই। বইগুলো পালা করে আসে, তাই প্রতি চারটিতে একটি ভাঙে। Burn হলো ০.২৫ ÷ ০.০০১ = ২৫০.

ধরল burn-rate alert. মোট ৮১১টি ব্যর্থ request, মাসিক budget-এর ১.৫৬%. Alert না থাকলে রাতের ৮ ঘণ্টায় ১,৪৪,০০০টি ভাঙত, budget-এর ২৭৮%.

ফলো-আপ: “কী বদলাবেন?” — প্রতিটি 5xx-এর কারণ log-এ লেখা, canary, আর সব বই ঘোরা test. ওই run-এ docker logs-এ কারণই ছিল না।

প্র ৫৩Incident-এ ভূমিকাগুলো কী কী? Commander কেন নিজে command চালান না? (সহজ)

উত্তর: Incident commander পুরো ঘটনার মালিক, ops lead আসল পরিবর্তন করেন, comms lead সবাইকে জানান, scribe সময়সহ লেখেন। Commander terminal-এ ডুবে গেলে পুরো ছবি হারিয়ে যায়। ছোট দলে একজন দুই ভূমিকা নিতে পারেন, তবে commander আর ops এক হলে সমস্যা বাড়ে।

ফলো-আপ: “Severity-র কি সর্বজনীন মান আছে?” — না, দলভেদে আলাদা।

প্র ৫৪Postmortem কেন blameless? MTTA আর MTTR-এর পার্থক্য কী? (মাঝারি)

উত্তর: ভয় থাকলে তথ্য লুকায়, আর ব্যবস্থা না বদলালে একই ভুল ফেরে। প্রশ্নটি “কে ভুল করল” নয়, “সিস্টেম কেন ভুলটিকে এতদূর আসতে দিল”। ক্যাপস্টোনের ঘটনার পরে নতুন test আগে commit করে দেখা হলো, সে ভুলটি ধরে কি না। ধরল, pipeline_exit=1.

MTTA মানুষের স্বীকার পর্যন্ত, MTTR সেবা ফেরা পর্যন্ত। সংজ্ঞা দলভেদে বদলায়, তাই উল্লেখ করে বলুন। ওই ঘটনায় MTTD ১ মিনিট ৪৬ সেকেন্ড।

প্র ৫৫Metric, log আর trace: deploy-এর পরে p99 বেড়েছে। কোনটি কখন? (কঠিন)

উত্তর: Metric বলে কিছু ভুল, আর কখন থেকে। Trace বলে অনুরোধটি কোন span-এ সময় নিল। Log বলে সেই জায়গায় ঠিক কী ঘটল। Exemplar থাকলে metric-এর মান থেকে সরাসরি একটি trace-এ যাওয়া যায়। Percentile মেলাতে histogram লাগে, কারণ bucket যোগ করা যায়।

ফলো-আপ: “Tail sampling কেন?” — শেষে ফল দেখে সিদ্ধান্ত নেয়, তাই ধীর আর ভুল trace রাখা যায়।

৮ · Live troubleshooting drill — চারটি পরিস্থিতি

রিভিশন: পর্ব ৪৫, পর্ব ০৮, পর্ব ১১, পর্ব ০৯, পর্ব ৪৪

এই অংশে ইন্টারভিউয়ার একটি লক্ষণ বলেন, আর আপনি ধাপে ধাপে কমান্ড চান। প্রতি ধাপে আউটপুট দেখে জোরে বলুন আপনি কী বুঝলেন, আর পরের কমান্ড কেন। নিচের stepper-এ পরের ধাপে যাওয়ার আগে নিজে অনুমান করুন।

দুর্বল অভ্যাসভালো অভ্যাস
সোজা restart বা delete podআগে প্রমাণ দেখা, তারপর কাজ
একসাথে তিনটি জিনিস বদলানোএকবারে একটি বদল, তারপর মাপা
Error দেখেই কারণ ঘোষণা“এটি আমার ধারণা, যাচাই করব এভাবে”
“ঠিক হয়ে গেছে” বলে থেমে যাওয়ামেপে দেখা, আর প্রতিরোধের কথা বলা

Drill ১ · “Site পড়ে গেছে”

আউটপুট আসল run থেকে নেওয়া, পর্ব ৪৫. একটি নতুন Service orders সাড়া দিচ্ছে না।

Service orders · পর্ব ৪৫-এর আসল আউটপুট
প্রশ্ন
কমান্ড
  1. লক্ষণ। ০ ms-এ ব্যর্থ, timeout নয়। কেউ সংযোগ নিচ্ছে না। একটি client Pod-এর ভেতর থেকে চালিয়ে লক্ষণ নিশ্চিত হলো।
  2. DNS বাদ। নাম ClusterIP-তে মিলছে। সমস্যা DNS নয়। এক ধাপে একটি বড় অংশ বাদ গেল।
  3. Slice ফাঁকা। PORTS আর ENDPOINTS দুটোই <unset>. Service-এর পেছনে কেউ নেই।
  4. Selector দেখা। app=apii, একটি বাড়তি i. Events ফাঁকা: কোথাও কোনো error আসেনি, এটিই এই ভুলের বিপদ।
  5. Pod সুস্থ। তিনটি Pod app=api label নিয়ে চলছে। Pod-এ নয়, ভুল Service-এ। Pod restart করে লাভ হতো না।
  6. একটি বদল। শুধু selector ঠিক করা হলো। Production-এ এটি Git-এও করুন, নইলে পরের deploy ভুলটি ফেরাবে।
  7. যাচাই। একটি Pod-এর নাম ফিরল। শিক্ষা: apply সফল হলেও সেবা ভাঙা থাকতে পারে, তাই deploy-এর পরে একটি আসল অনুরোধ পাঠিয়ে দেখুন।
প্র ৫৬Drill ১-এর বদলে curl বলল Could not resolve host. পরের ধাপ কী? আর 502 এলে? (মাঝারি)

উত্তর: নামই মেলেনি, packet রওনাই হয়নি। dig বা getent, namespace-সহ পূর্ণ নাম, আর Kubernetes-এ CoreDNS Pod দেখুন। 502 মানে proxy বেঁচে আছে, পেছনের app সংযোগ নেয়নি বা অচল উত্তর দিয়েছে: proxy-র error log আর ss -tlnp দেখুন। Ingress controller থেকে 503 এলে সেই Service-এর ready Pod আর EndpointSlice দেখুন।

Drill ২ · “Disk ভরা”

পর্ব ০৮-এর আউটপুট নমুনা, আসল server-এর নয়। পদ্ধতিটিই এখানে মূল কথা।

নমুনা আউটপুট · version-ভেদে আলাদা হতে পারে
প্রশ্ন
কমান্ড
  1. লক্ষণ। App থেমেছে, log-এ এই লাইন। আগে দেখুন কোন filesystem ভরেছে, কারণ সবগুলো একসাথে ভরে না।
  2. কতটুকু। / ৯৬% ভরা, /data ৬৫%. Size থেকে Used বাদ দিলে Avail মেলে না, কারণ ext4 সাধারণত root-এর জন্য জায়গা রাখে।
  3. কে। -x এক filesystem-এ রাখে। ২১ GB-র মধ্যে ১৯ GB log. কারণ প্রায়ই এমনই।
  4. কাজ। rm -rf /var/log/* নয়: প্রমাণ যায়, আর খোলা ফাইলে জায়গা ফেরেও না। আগে দেখুন কোন ফাইল, সম্ভব হলে snapshot, তারপর ঘূর্ণন।
  5. প্রথম ফাঁদ। মুছে ফেলা ফাইল কোনো process এখনো ধরে থাকলে জায়গা ফেরে না। lsof +L1 দিয়ে খুঁজে সেই service restart করলে ফেরে।
  6. দ্বিতীয় ফাঁদ। লাখ লাখ ছোট ফাইল inode শেষ করে দিতে পারে। তখন জায়গা থাকলেও একই error.
  7. প্রতিরোধ। logrotate, log কেন্দ্রীয় জায়গায় পাঠানো (পর্ব ৬৪), আর ৯০%-এর আগেই সতর্কতা।

বাস্তবে সমস্যা একা আসে না। পর্ব ১১-এর snapshot-এ ধীর server, ৯৭% disk আর প্রায় শেষ memory একসাথে। নিচের script সত্যিকারের সিস্টেমের কিছু পড়ে না, শুধু নিজের ভেতরের নমুনা লেখা পড়ে। আগে অনুমান করুন: কয়টি সতর্কতা আসল সমস্যা?

cd "$(mktemp -d)"
cat > snapshot.txt <<'EOF'
top - 14:32:07 up 12 days, 3:11, 1 user, load average: 6.42, 5.10, 3.87
%Cpu(s): 38.2 us, 7.1 sy, 0.0 ni, 12.4 id, 41.0 wa, 0.0 hi, 1.3 si, 0.0 st
              total  used  free  shared  buff/cache  available
Mem:           7820  7050   180      64         590        420
Swap:          2047  1460   587
Filesystem Size Used Avail Use% Mounted on
/dev/vda1    40G  37G  1.1G  97% /
/dev/vdb1   100G  61G   34G  65% /data
EOF
cores=2; warns=0
alert() { echo "WARN $1"; warns=$((warns + 1)); }
over() { awk -v a="$1" -v b="$2" 'BEGIN { exit !(a > b) }'; }
load1=$(sed -n 's/.*load average: \([0-9.]*\),.*/\1/p' snapshot.txt)
per=$(awk -v l="$load1" -v c="$cores" 'BEGIN { printf "%.2f", l / c }')
echo "load1=$load1 cores=$cores per-core=$per"
over "$per" 1 && alert "tasks are queueing"
wa=$(awk -F'[ ,]+' '/^%Cpu/ { print $10 }' snapshot.txt)
echo "iowait=$wa%"
over "$wa" 20 && alert "much time lost waiting for disk"
read -r avail pct < <(awk '/^Mem:/ { printf "%d %.1f\n", $7, 100 * $7 / $2 }' snapshot.txt)
echo "available=$avail MiB ($pct%)"
over 10 "$pct" && alert "less than 10% memory available"
read -r used swp < <(awk '/^Swap:/ { print $3, int(100 * $3 / $2) }' snapshot.txt)
echo "swap used=$used MiB ($swp%)"
over "$swp" 50 && alert "more than half of swap used"
while read -r mnt use; do alert "disk $mnt at $use%"; done < <(
  awk '$5 ~ /^[0-9]+%$/ && $5 + 0 >= 90 { print $6, $5 + 0 }' snapshot.txt)
echo "summary: $warns warnings"
load1=6.42 cores=2 per-core=3.21
WARN tasks are queueing
iowait=41.0%
WARN much time lost waiting for disk
available=420 MiB (5.4%)
WARN less than 10% memory available
swap used=1460 MiB (71%)
WARN more than half of swap used
WARN disk / at 97%
summary: 5 warnings

পাঁচটি সতর্কতা, কিন্তু পাঁচটি আলাদা সমস্যা নয়। Memory প্রায় শেষ, তাই swap চলছে। Swap হলো disk-এ যাওয়া, তাই wa ৪১%, আর আটকে থাকা task-গুলো load তুলেছে ৩.২১ প্রতি core-এ। অর্থাৎ চারটি সতর্কতার মূল এক। Disk ৯৭% আলাদা, স্বাধীন আগুন। সীমাগুলো উদাহরণ, প্রতিটি service-এর স্বাভাবিক মান নিজের মতো মেপে নিতে হয়। Script শুধু সতর্ক করে, সিদ্ধান্ত মানুষের।

Drill ৩ · “Deploy-এর পরে site ধীর”

পর্ব ০৯-এর ঘটনা। Log আর config কাল্পনিক অনলাইন বাজার অ্যাপের নমুনা, আর কমান্ডের ফল আসলেই চালিয়ে পাওয়া।

নমুনা log · কমান্ডের ফল আসল
প্রশ্ন
জানা গেল
  1. নিশ্চিত। ৬টি 500 আর ১টি 504. grep ' 500 ' দিলে 504 বাদ পড়ত। “ধীর” রিপোর্ট আসলে ত্রুটিও।
  2. সময়। ১৪:০১ আর ১৪:০২-তে একটিও নয়। খোঁজার জায়গা ছোট হলো।
  3. জায়গা। ৭টিই এক path-এ। পুরো server পড়ে যায়নি, /api/cart ঠিক আছে।
  4. কে ভুগছে। ৫টি IP, তাই এক client-এর ভুল নয়। সবচেয়ে বেশি request করা .7-এর ৭টিই 200, তাকে block করা লোভনীয় কিন্তু ভুল পথ।
  5. ধরন। এত সমান ২.১ সেকেন্ড সাধারণত timeout-এর ইঙ্গিত। ৫.০০৩ সেকেন্ডের 504: এই নমুনায় nginx নিজেই হাল ছেড়েছে।
  6. পেছনের সেবা। ২ সেকেন্ডের timeout আর কিছু কাজ মিলে ২.১ সেকেন্ড। সংখ্যা মিলে গেল।
  7. কী বদলেছে। ১৪:০২:৩৩-এ deploy, প্রথম error ১৪:০৩:০৪-এ, ৩১ সেকেন্ড পরে। এটি সবচেয়ে সম্ভাব্য কারণ, প্রমাণ হবে ঠিক করার পরে error থামলে।
  8. কাজ। Config আগের মানে ফেরানো, tail -F দিয়ে error থামা দেখা, তারপর কেন ৫ করা হয়েছিল তা খোঁজা।
প্র ৫৭Deploy-এর পরে latency বেড়েছে, কিন্তু কোনো error নেই, log-ও শান্ত। আর কী কী সন্দেহ করবেন? (মাঝারি)

উত্তর: প্রথমে CPU throttling: লক্ষণ হলো latency বাড়ে, log-এ কিছু থাকে না (পর্ব ৪৮). nr_throttled বা container CPU throttle metric দেখুন। তারপর সারি: M/M/1 মডেলে ব্যবহার ০.৮ থেকে ০.৯ হলে গড় সময় দ্বিগুণ হয়। তাই নতুন version একটু বেশি CPU খেলেই latency অনেক বাড়তে পারে। তারপর নির্ভরতা: trace দেখুন কোন span বড় হয়েছে। সাথে নতুন কোডে N+1 query, ঠান্ডা cache আর কম connection.

সব ক্ষেত্রে আগের version-এ ফেরার পথ খোলা রাখুন, আর canary-তে old-new তুলনা করুন।

ফলো-আপ: “CPU limit তুলে দিলেই হবে?” — আগে মেপে দেখুন। অন্ধভাবে তুললে অন্যদের ক্ষতি হতে পারে।

Drill ৪ · “Deployment আটকে গেছে”

আউটপুট আসল run থেকে নেওয়া, পর্ব ৪৪. চারটি replica, maxSurge ১, maxUnavailable ১, deadline ৪০ সেকেন্ড।

Deployment web · পর্ব ৪৪-এর আসল আউটপুট
প্রশ্ন
কমান্ড
  1. শুরু। এই কমান্ড সফল, কারণ API শুধু object লিখেছে। Image আছে কি না সে আগে থেকে জানে না।
  2. Pod. নতুন ২টি ব্যর্থ, পুরোনো ৩টি চলছে। Controller ১টি পুরোনো সরিয়েছে আর ২টি নতুন এনেছে, যা surge আর unavailable-এর পুরো ভাগ।
  3. আসল প্রশ্ন। ব্যবহারকারী ভুগছেন? ২০টি অনুরোধের ২০টিই 200. সেবা ভাঙেনি, শুধু ক্ষমতা কমেছে: READY 3/4.
  4. Rollout status. প্রায় ৪২ সেকেন্ড পরে ব্যর্থ বলল, কারণ deadline ৪০ সেকেন্ড ছিল।
  5. Condition. Progressing=False, কিন্তু Available=True. কিছুই নিজে থেকে বদলায়নি। Kubernetes নিজে rollback করে না।
  6. কারণ। শেষ শব্দ not found: tag ভুল। অনুমতির সমস্যা হলে অন্য শব্দ আসত।
  7. Undo. পুরোনো template ফিরল, ভাঙা ReplicaSet ০-তে নামল, সেবা কোনো মুহূর্তে বন্ধ হয়নি। Terraform বা GitOps চালালে একই সিদ্ধান্ত সেখানেও লিখুন।
প্র ৫৮Deployment আটকে আছে, কিন্তু image ঠিক আছে। Pod 0/1 Running, RESTARTS 1. Pipeline সবুজ ছিল। কী ঘটেছে হতে পারে? (কঠিন)

উত্তর: Image নামছে, app চলছে, কিন্তু readiness পাস করছে না, তাই নতুন environment-এ পার্থক্য খুঁজুন। ক্যাপস্টোনের আসল run-এ ঠিক এটি হয়েছিল। Log বলল:

catalog cache failed: [Errno 30] Read-only file system: '/tmp/boighor-catalog.json'

ল্যাপটপের container-এ /tmp লেখা যায়, cluster-এ আমরাই read-only root filesystem দিয়েছিলাম। Terraform দিল Error: Deployment exceeded its progress deadline, আর max_unavailable = 0 পুরোনো Pod রেখে দিল, ট্রাফিকে ০টি ভুল। আগের SHA দিতেই ১ সেকেন্ডে rollback, কারণ পুরোনো Pod সরেইনি।

ফলো-আপ: “প্রতিরোধ?” — Smoke test-এ --read-only, আর Pod-এ emptyDir-এ লেখার জায়গা। RESTARTS 1 এসেছিল একই /healthz liveness-এও থাকায়।

৯ · Code review অনুশীলন আর take-home কাজ

রিভিশন: পর্ব ৩৮, পর্ব ৪৩, পর্ব ৪৯, পর্ব ৭৬ · ক্যাপস্টোন, Code review

Dockerfile review — ভুল পুঁতে রাখা

নিচের Dockerfile build হবে, চলবেও। পাঁচ মিনিটে নিজে কমপক্ষে ছয়টি সমস্যা লিখুন, গুরুত্ব অনুযায়ী সাজান, তারপর checker চালান। এতে ব্যবহৃত DB_PASSWORD-এর মান নকল।

// A small Dockerfile reviewer. Paste your own file and run again.
const dockerfile = `FROM python:latest
ADD . /app
WORKDIR /app
ENV DB_PASSWORD=not-a-real-password
RUN pip install -r requirements.txt
RUN apt-get update
RUN apt-get install -y curl
EXPOSE 8000
CMD python app.py`;
const lines = dockerfile.split("\n");
const has = re => lines.some(l => re.test(l));
const rules = [
  [/^FROM \S+:latest|^FROM [^:]+$/, "base image not pinned: use a version, better a digest"],
  [/^ADD /, "ADD used: COPY is plainer, ADD also unpacks archives and fetches URLs"],
  [/^(ENV|ARG) \S*(PASSWORD|SECRET|TOKEN|KEY)/i, "secret in the image: it stays in metadata and layers"],
  [/^RUN .*update\s*$/, "update alone: a cached layer goes stale, join it with install"],
  [/^CMD [^[]|^ENTRYPOINT [^[]/, "shell form: sh becomes PID 1, SIGTERM may not reach the app"],
];
let n = 0;
const say = (at, text) => console.log(`${++n}. line ${at}: ${text}`);
lines.forEach((l, i) => rules.forEach(([re, text]) => { if (re.test(l)) say(i + 1, text); }));
const copyAll = lines.findIndex(l => /^(COPY|ADD) \. /.test(l));
const install = lines.findIndex(l => /^RUN .*(pip|npm|apk|apt-get) .*install/.test(l));
if (copyAll >= 0 && copyAll < install)
  say(copyAll + 1, "everything copied before install: one source edit reruns install");
if (!has(/^USER /)) say("-", "no USER: the container runs as root");
if (!has(/ AS /i)) say("-", "single stage: check that build tools are not shipped");
console.log(n ? `${n} findings for a human to judge` : "no findings (a linter cannot prove it is good)");
1. line 1: base image not pinned: use a version, better a digest
2. line 2: ADD used: COPY is plainer, ADD also unpacks archives and fetches URLs
3. line 4: secret in the image: it stays in metadata and layers
4. line 6: update alone: a cached layer goes stale, join it with install
5. line 9: shell form: sh becomes PID 1, SIGTERM may not reach the app
6. line 2: everything copied before install: one source edit reruns install
7. line -: no USER: the container runs as root
8. line -: single stage: check that build tools are not shipped
8 findings for a human to judge

এই checker পর্বগুলোর নিয়ম থেকে বানানো ছোট একটি শিক্ষার script, কোনো আসল linter নয়। গুরুত্বের ক্রম নিজে ঠিক করুন: সবার আগে secret, কারণ সেটি ফাঁস হলে key বদলাতে হবে। তারপর root, shell form আর pin না করা base. শেষ লাইনটি আলোচনার: Python app-এ multi-stage সবসময় বড় লাভ দেয় না। ভুলে যাবেন না, linter বলে না কেন আপনার image-এ curl দরকার।

প্র ৫৯ওপরের Dockerfile সংশোধন করে লিখুন, আর বদলগুলো এক লাইনে ব্যাখ্যা করুন। (মাঝারি)

উত্তর: এই নকশায় চেকারটি কোনো finding দেয়নি (নিজে পেস্ট করে দেখুন), তবে এটি চালিয়ে build করা হয়নি। Package আর version আপনার app অনুযায়ী বদলাবে।

FROM python:3.12-alpine AS deps
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt

FROM python:3.12-alpine
WORKDIR /app
COPY --from=deps /install /usr/local
COPY app.py .
USER 10001:10001
EXPOSE 8000
CMD ["python", "app.py"]

Version pin করা। requirements.txt আগে, তাই source বদলালে install আবার চলে না। Secret বাদ: সেটি চালুর সময় secret manager থেকে আসবে। শুধু দরকারি ফাইল COPY, সাথে .dockerignore. Non-root USER. Exec form CMD. curl-এর RUN বাদ, কারণ app-এর দরকার নেই বলে ধরে নিয়েছি: সত্যিই লাগলে একই RUN-এ update আর install.

ফলো-আপ: “এর পরে আরও শক্ত করতে?” — Base image digest-এ বাঁধা, আর চালানোর সময় read-only filesystem.

Kubernetes YAML review — ভুল পুঁতে রাখা

একই ভাবে। প্রথম ভুলটি apply-এই ধরা পড়বে। বাকিগুলো পড়বে রাত দুটোয়।

apiVersion: apps/v1
kind: Deployment
metadata:
  name: orders
spec:
  replicas: 1
  selector:
    matchLabels:
      app: orders
  template:
    metadata:
      labels:
        app: order
    spec:
      containers:
        - name: orders
          image: registry.example.com/orders:latest
          env:
            - name: DB_PASSWORD
              value: not-a-real-password
          ports:
            - containerPort: 8080
          livenessProbe:
            httpGet:
              path: /db-check
              port: 8000
// Review a Deployment, written here as a plain object (the YAML above).
const d = {
  replicas: 1,
  selector: { app: "orders" },
  labels: { app: "order" },
  image: "registry.example.com/orders:latest",
  env: [{ name: "DB_PASSWORD", value: "not-a-real-password" }],
  containerPort: 8080,
  liveness: { path: "/db-check", port: 8000 },
  readiness: null,
  resources: null,
  securityContext: null,
};
const notes = [];
const flag = (bad, text) => { if (bad) notes.push(text); };
const same = (a, b) => Object.entries(a).every(([k, v]) => b[k] === v);
flag(!same(d.selector, d.labels), "BLOCK selector does not match template labels: the API refuses this");
flag(/:latest$|^[^:]*$/.test(d.image), "HIGH  tag latest: no rollback target, no link to a commit");
flag(d.env.some(e => /PASS|SECRET|TOKEN/i.test(e.name) && e.value), "HIGH  secret as plain text: use secretKeyRef");
flag(d.liveness && d.liveness.port !== d.containerPort, "HIGH  liveness port differs from containerPort: restart loop");
flag(d.liveness && /db/i.test(d.liveness.path), "HIGH  liveness touches the database: slow DB restarts every Pod");
flag(!d.readiness, "HIGH  no readiness probe: traffic can reach a Pod that is not ready");
flag(!d.resources, "MED   no requests or limits: BestEffort QoS, the scheduler books nothing");
flag(!d.securityContext, "MED   no securityContext: add runAsNonRoot, drop capabilities");
flag(d.replicas < 2, "MED   one replica: a node failure or eviction stops the service");
notes.forEach((n, i) => console.log(String(i + 1).padStart(2) + ". " + n));
console.log(notes.length + " findings");
 1. BLOCK selector does not match template labels: the API refuses this
 2. HIGH  tag latest: no rollback target, no link to a commit
 3. HIGH  secret as plain text: use secretKeyRef
 4. HIGH  liveness port differs from containerPort: restart loop
 5. HIGH  liveness touches the database: slow DB restarts every Pod
 6. HIGH  no readiness probe: traffic can reach a Pod that is not ready
 7. MED   no requests or limits: BestEffort QoS, the scheduler books nothing
 8. MED   no securityContext: add runAsNonRoot, drop capabilities
 9. MED   one replica: a node failure or eviction stops the service
9 findings

Checker YAML পড়ে না, ওপরের মানগুলো একটি object-এ লেখা। BLOCK মানে apply-ই হবে না: selector আর template label না মিললে API server Deployment নেয় না। বাকি HIGH আর MED ভাগ আমাদের নিজের বিচার, কোনো মান নয়। ইন্টারভিউতে এভাবে গুরুত্ব ভাগ করে বলাই শক্তি দেখায়, শুধু তালিকা নয়।

প্র ৬০ওপরের YAML সংশোধন করুন। প্রতিটি বদলের কারণ বলুন। (মাঝারি)

উত্তর: এই YAML parse করে যাচাই করা, cluster-এ চালানো হয়নি। সংখ্যাগুলো ক্যাপস্টোনের ধরনে, আপনার app মেপে ঠিক করবেন। /ready আর /healthz app-এ থাকতে হবে।

apiVersion: apps/v1
kind: Deployment
metadata:
  name: orders
spec:
  replicas: 3
  selector:
    matchLabels:
      app: orders
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  template:
    metadata:
      labels:
        app: orders
    spec:
      securityContext:
        runAsNonRoot: true
        seccompProfile:
          type: RuntimeDefault
      containers:
        - name: orders
          image: registry.example.com/orders:1a2b3c4d5e6f
          env:
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: orders-db
                  key: password
          ports:
            - name: http
              containerPort: 8080
          readinessProbe:
            httpGet:
              path: /ready
              port: http
          livenessProbe:
            httpGet:
              path: /healthz
              port: http
          resources:
            requests: {cpu: 20m, memory: 32Mi}
            limits: {cpu: 200m, memory: 64Mi}
          securityContext:
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            capabilities:
              drop: [ALL]

Label মেলানো। Tag হলো commit SHA. Secret আলাদা object থেকে। Liveness শুধু process-এর নিজের অবস্থা দেখে, ডেটাবেস নয়, আর port এখন নাম ধরে। Readiness আলাদা। Request দিলে scheduler হিসাব করতে পারে। Non-root আর read-only. তিনটি replica আর maxUnavailable: 0.

ফলো-আপ: “Read-only হলে app /tmp-এ লিখবে কোথায়?” — emptyDir volume mount করে দিন। ক্যাপস্টোনের প্রথম খারাপ release ঠিক এখানেই ভেঙেছিল।

Take-home কাজের তালিকা

অনেক সময় বাড়িতে করার একটি কাজ দেওয়া হয়, যেমন “একটি ছোট API container-এ তুলে Kubernetes-এ চালান”। ক্যাপস্টোন এরই বড় রূপ। জমা দেওয়ার আগে এই তালিকা দেখুন। দেওয়া সময় আর নিয়ম মানুন, cloud-এ কিছু চালালে খরচের সীমা রাখুন, আর শেষে সব মুছে ফেলুন।

সততাই শক্তি: ক্যাপস্টোনের নিজের readiness score ছিল ২৩/৩৯ = ৫৯%, আর তিনটি launch blocker বাকি: remote state, মানুষের কাছে পৌঁছানো alert আর TLS. এই লেখাটিই তার সেরা অংশ। সবকিছু “done” বলার চেয়ে যা বাকি তা সৎভাবে লেখা অনেক বেশি পেশাদার। ওজনগুলো আমাদের নিজের সিদ্ধান্ত, কোনো মান নয়।

প্র ৬১Take-home-এ সময় কম। কোনটি রাখবেন, কোনটি বাদ দেবেন? (মাঝারি)

উত্তর: যা চালিয়ে দেখানো যায় তা আগে: চলমান পথ, test, পরিষ্কার README. চকচকে জিনিস পরে। পাঁচ টুলের অর্ধেক কাজের চেয়ে দুই টুলের পূর্ণ কাজ ভালো। যা বাদ দিলেন তা লিখে রাখুন, সাথে “সময় পেলে কীভাবে করতাম”।

১০ · আচরণগত প্রশ্ন, ইন্টারভিউয়ারকে প্রশ্ন আর শেষ রিভিশন

রিভিশন: পর্ব ০৭ · DevOps আর SRE, পর্ব ৬৭, Software engineering ইন্টারভিউ

আচরণগত প্রশ্নে STAR কাঠামো কাজে দেয়: Situation (পরিস্থিতি), Task (আপনার দায়িত্ব), Action (আপনি নিজে কী করলেন), Result (ফল, সংখ্যায়)। সাথে একটি শেখা। নিচের গল্পগুলো কাল্পনিক, শুধু কাঠামো দেখানোর জন্য। ইন্টারভিউতে নিজের সত্যি ঘটনা বলুন। বানানো গল্প দুটি ফলো-আপেই ভেঙে পড়ে।

প্র ৬২“আপনার করা একটি ভুলে production ভেঙেছিল, এমন ঘটনা বলুন।” (কাল্পনিক উত্তর) (মাঝারি)

উত্তর: কাল্পনিক উদাহরণ। S: “একটি শিক্ষানবিশ পদে আমাদের ছোট অ্যাপের config আমি বদলেছিলাম।” T: “Connection সংখ্যা কমানোর দায়িত্ব ছিল আমার।” A: “আমি ৫০ থেকে ৫ করলাম, পরীক্ষা না করে। Error বাড়তেই নিজে জানালাম, আগের মানে ফেরালাম, তারপর log থেকে কারণ বের করলাম।” R: “মিনিট দশেকের মধ্যে সেবা ফিরল। আমি config-বদলের জন্য review আর একটি alert যোগ করলাম।”

লক্ষ করুন: দোষ অন্যের ঘাড়ে নেই, নিজের কাজ স্পষ্ট, শেষে ব্যবস্থার বদল।

প্র ৬৩“সহকর্মীর সাথে কারিগরি মতভেদ হলে কী করেন?” (কাল্পনিক উত্তর) (মাঝারি)

উত্তর: কাল্পনিক উদাহরণ। S: “একজন সহকর্মী সব deploy blue-green করতে চাইলেন, আমি চাইলাম canary.” T: “দলকে একটি সিদ্ধান্তে আসতে হবে।” A: “আমরা দুটিরই ঝুঁকি, খরচ আর দুই version-এর সামঞ্জস্য লিখলাম, আর ঠিক করলাম কোন মাপে সিদ্ধান্ত হবে।” R: “কম ট্রাফিকের service-এ canary-র নমুনা যথেষ্ট ছিল না, তাই সেখানে তাঁর পথই বেছে নিলাম।”

এখানে শক্তি হলো নিজের মত বদলানোর ক্ষমতা।

প্র ৬৪“রাতে page এলো, আপনি জানেন না কী করতে হবে। কী করবেন?” (সহজ)

উত্তর: Runbook খুলব, প্রভাব মাপব, আর দেরি না করে সাহায্য ডাকব। একা ঘণ্টাখানেক লড়াই করা বীরত্ব নয়। সময়সহ নোট রাখব, আর প্রভাব বড় হলে rollback-কে প্রথম বিকল্প ধরব। পরদিন runbook-এ ফাঁক থাকলে তা পূরণ করব।

ইন্টারভিউয়ারকে আপনার প্রশ্ন

  • On-call কীভাবে ভাগ হয়, আর গত মাসে রাতে কতবার page এসেছিল?
  • একটি commit production-এ পৌঁছাতে কত সময় লাগে, আর rollback কীভাবে হয়?
  • শেষ বড় incident থেকে কী বদলেছে?
  • এই ভূমিকায় infrastructure-এর কতটা কোডে, আর কতটা হাতে?

শেষ সাত দিনের রিভিশন পরিকল্পনা

দিনে ঘণ্টা দুয়েক ধরে সাজানো। আপনার সময় অনুযায়ী বদলে নিন। প্রতিদিন প্রশ্নগুলো জোরে বলুন, শুধু পড়বেন না।

দিনকাজপর্বশেষে যা পারবেন
১Linux, log আর network৯, ১১, ১৩অংশ ২ আর log block মুখে মুখে
২Docker৩৭, ৩৮Dockerfile review ৫ মিনিটে
৩Kubernetes-এর ব্যর্থতা৪৩, ৪৪, ৪৫ছবি ৮১.২ না দেখে আঁকা
৪Kubernetes-এর resource আর নিরাপত্তা, YAML review৪৮, ৪৯YAML-এর ৯টি সমস্যা
৫Terraform৫২, ৫৩Drift, lock, for_each মুখে
৬CI/CD আর SRE৫৭, ৫৯, ৬৬Pipeline নকশা, burn rate হিসাব
৭চার drill জোরে, নিজের দুটি গল্প, নকল ইন্টারভিউ৭৬৩০ মিনিটের কথোপকথন

আগের দিন সন্ধ্যায় নতুন কিছু শিখবেন না। Laptop, internet আর screen share পরীক্ষা করুন। আপনি যদি কোনো vendor certificate-এর পথে থাকেন, তার নিজের syllabus আলাদা, আর এই কোর্স একা তার পূর্ণ প্রস্তুতির দাবি করে না।

AI-এর যুগে ইন্টারভিউর প্রস্তুতি

AI একজন ধৈর্যশীল নকল ইন্টারভিউয়ার হতে পারে, উত্তর যাচাইয়ের সঙ্গীও। কিন্তু সে আপনার cluster দেখে না, আর প্রায়ই * অনুমতি দেয়, 0.0.0.0/0 খোলে, secret code-এ লেখে, latest tag আর সরানো API version বসায়, ভুয়া flag বানায়, খরচ ভুলে যায়, আর সাবধান না করে terraform destroy, kubectl delete বা rm -rf বলে দেয়। Live ইন্টারভিউতে AI ব্যবহারের নিয়ম আগে জেনে নিন, আর নিয়ম ভাঙবেন না।

AI-কে উত্তর লিখতে না বলে আপনাকে চেপে ধরতে বলুন। আসল কোম্পানির তথ্য, log বা key কখনো দেবেন না।

তুমি একজন কড়া DevOps ইন্টারভিউয়ার। আমার স্তর: [শুরু/মাঝারি/উন্নত]। ১. আমাকে একটি live troubleshooting drill দাও। শুধু লক্ষণ বলো, কারণ বলো না। ২. আমি কমান্ড চাইলে নমুনা আউটপুট দাও, আর পরিষ্কার লেখো যে এটি বানানো। ৩. আমি কারণ ছাড়া কিছু বদলাতে চাইলে থামিয়ে জিজ্ঞেস করো কেন। ৪. শেষে পাঁচটি ক্ষেত্রে নম্বর দাও: পদ্ধতি, প্রমাণ, নিরাপত্তা, যোগাযোগ, প্রতিরোধ। ৫. কোনো tool-এর আচরণ নিয়ে নিশ্চিত না হলে "নিশ্চিত নই" লেখো, আর কোন official docs দেখব বলো।

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

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

ক্রমProduction-এ সমস্যা এলে ভালো troubleshooting-এর ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. লক্ষণ নিজে মেপে নিশ্চিত করা
  2. কখন থেকে, কোথায়, কাদের: সীমা টানা
  3. ঠিক আগে কী বদলেছিল, তা দেখা
  4. Rollback বা অন্য পথে ক্ষতি থামানো
  5. মূল কারণ খুঁজে প্রমাণ করা
  6. Test বা alert যোগ করে প্রতিরোধ

(সহজ) Kubernetes-এ একটি Pod-এর STATUS ImagePullBackOff, RESTARTS ০. kubectl logs কেন কিছু দেখায় না?

  • Log rotation আগেই log মুছে দিয়েছে
  • Container একবারও চলেনি
  • --previous ছাড়া logs কাজ করে না
  • RBAC-এ logs পড়া নিষেধ

(মাঝারি) একটি Pod-এর describe-এ দেখা গেল Reason: Error, Exit Code: 137, আর Events-এ Liveness probe failed. সবচেয়ে যুক্তিসংগত ব্যাখ্যা কোনটি?

  • Memory limit পার হওয়ায় kernel-এর OOM kill
  • App নিজে code-এর ভেতর থেকে exit(137) ডেকেছে
  • Image pull ব্যর্থ হওয়ায় container চালুই হয়নি
  • Probe ব্যর্থ হওয়ায় kubelet থামাল, SIGTERM না সামলানোয় SIGKILL

(মাঝারি) একটি Service-এর kubectl get endpointslices-এ PORTS আর ENDPOINTS দুটোই <unset>, DNS কাজ করছে, Pod-গুলো Running. সবচেয়ে আগে কী মেলাবেন?

  • Service-এর selector আর Pod-এর label
  • CoreDNS-এর log আর Corefile
  • Node-এর kernel version আর uptime
  • Pod-এর memory limit আর request

(সহজ) ৩০ দিনের ৯৯.৯% SLO-তে error ০.৩% চলতে থাকলে budget কতদিনে শেষ হবে?

  • ৩ দিনে
  • ৫ দিনে
  • ১০ দিনে
  • ৩০ দিনে

(মাঝারি) replicas: 4, maxSurge: 1, maxUnavailable: 1. নতুন image-এর tag registry-তে নেই। ব্যবহারকারীর কী হবে?

  • সব Pod নেমে গিয়ে সেবা বন্ধ হবে
  • পুরোনো ৩টি Pod সেবা চালাবে, ক্ষমতা কমবে
  • Kubernetes নিজে আগের version-এ ফিরবে
  • kubectl set image কমান্ডটিই ব্যর্থ হবে

(সহজ) terraform plan -detailed-exitcode 2 ফেরত দিল। এর অর্থ কী?

  • Plan সফল, কিন্তু বদল আছে
  • Plan-এ error হয়েছে
  • কোনো বদল নেই
  • State lock আটকে আছে

(মাঝারি) resource "x" "b" { count = length(var.names) }, আর var.names = ["dhaka", "khulna", "sylhet"]. তালিকা থেকে "khulna" সরালে কী হবে, যখন নাম বদলানো যায় না?

  • শুধু khulna মুছবে, বাকিরা অক্ষত থাকবে
  • কিছুই হবে না, plan ফাঁকা আসবে
  • [1] replace হবে আর [2] মুছবে
  • তিনটিই replace হবে, [0]-সহ

(মাঝারি) Error acquiring the state lock পেয়ে একজন বললেন, “-lock=false দিয়ে চালিয়ে দিন।” সেরা উত্তর কোনটি?

  • হ্যাঁ, এতে সময় বাঁচবে, ঝুঁকি সামান্য
  • State ফাইল মুছে দিয়ে নতুন করে apply করি
  • সাথে সাথে force-unlock চালিয়ে এগোই
  • Lock Info দেখে holder-এর খোঁজ নিই, দরকারে অপেক্ষা করি

(সহজ) Dockerfile-এ COPY . . আছে RUN pip install -r requirements.txt-এর আগে। শুধু app.py বদলালে কী হবে?

  • শুধু COPY ধাপ আবার চলবে
  • COPY থেকে নিচের সব ধাপ আবার চলবে, pip-সহ
  • Build সম্পূর্ণ cache থেকে আসবে
  • FROM থেকে সব আবার চলবে

(সহজ) একটি Dockerfile-এ RUN cp /tmp/key.pem /app/ && ..., আর পরের লাইনে RUN rm /app/key.pem. Image থেকে key কি মুছে গেছে?

  • হ্যাঁ, পুরোপুরি মুছে গেছে
  • হ্যাঁ, তবে image-এর আকার বেড়েছে
  • না, আগের layer-এ থেকে গেছে
  • docker build-ই ব্যর্থ হবে

(কঠিন) একটি API-র /healthz liveness আর readiness দুটোতেই আছে, আর সেটি ডেটাবেসে query করে। ডেটাবেস ধীর হলে কী ঘটতে পারে?

  • শুধু readiness ব্যর্থ, কোনো restart নয়
  • কিছুই নয়, probe-এর timeout নেই
  • শুধু ডেটাবেসের Pod restart হবে
  • সব API Pod একসাথে restart হয়ে সমস্যা বেড়ে যায়

(মাঝারি) Node-এর CPU ব্যবহার ২০%, তবু নতুন Pod Pending, Event-এ Insufficient cpu. কেন?

  • Scheduler ব্যবহার নয়, বুক করা request গোনে
  • Metrics-server না থাকায় ব্যবহার মাপা যায় না
  • Pod-এর limit node-এর তুলনায় কম
  • Node-এর kernel CPU throttle করছে

(সহজ) একটি log-এ POST /api/orders-এর সময় হঠাৎ ০.২ থেকে সব অনুরোধে প্রায় ২.১ সেকেন্ড হলো। এত সমান সংখ্যা সাধারণত কিসের ইঙ্গিত?

  • Client-এর network খারাপ
  • DNS ভুল
  • পেছনের কোনো timeout
  • CDN cache miss

(সহজ) df -h-এ / ৯৮% ভরা, কিন্তু du-তে মোট অনেক কম। সবচেয়ে সম্ভাব্য কারণ কী?

  • Inode শেষ হয়ে গেছে, তাই জায়গা ভুল দেখায়
  • মুছে ফেলা ফাইল কোনো process এখনো ধরে আছে
  • du সবসময় ভুল হিসাব দেয়, df ঠিক
  • RAM ভরে গেছে, তাই disk-ও ভরা দেখায়

(মাঝারি) নিচের কোনটি GitOps-এ rollback-এর সবচেয়ে উপযুক্ত পথ?

  • kubectl rollout undo দিয়ে cluster-এ ফেরা
  • Controller মুছে হাতে kubectl apply চালানো
  • Registry থেকে নতুন image মুছে ফেলা
  • git revert করে নতুন commit, controller মিলিয়ে নেবে

(মাঝারি) ৯৯.৯% SLO-তে ৫ মিনিটের burn ১৫.৭, ১ ঘণ্টার burn ৯.৯, সীমা দুটিতেই ১৪.৪, শর্ত AND. Alert-এর কী হবে?

  • বাজবে না, ১ ঘণ্টার জানালা সীমার নিচে
  • সঙ্গে সঙ্গে page হিসেবে বাজবে
  • Budget পুরো শেষ হওয়ার পরে বাজবে
  • Page নয়, শুধু ticket হিসেবে যাবে

(সহজ) Exec form আর shell form-এর কোন দাবিটি ঠিক?

  • Exec form সবসময় ছোট image দেয়
  • Shell form-এ environment variable চলে না
  • Exec form-এ app নিজে PID 1 হয়ে signal পেতে পারে
  • দুটির মধ্যে চলার সময় কোনো পার্থক্য নেই

(মাঝারি) ইন্টারভিউতে একটি tool নিয়ে প্রশ্ন, যা আপনি ব্যবহার করেননি। সবচেয়ে ভালো উত্তর কোনটি?

  • আন্দাজে আত্মবিশ্বাসের সাথে উত্তর দেওয়া
  • “জানি না” বলে থেমে যাওয়া
  • প্রশ্ন এড়িয়ে অন্য বিষয়ে কথা বলা
  • ব্যবহার করিনি বলা, জানা অংশ বলা, আর শেখার পথ বলা

শব্দকোষ

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

মনে রাখুন

  1. কমান্ডের সাথে কারণ বলুন: কী দেখলেন, কী বুঝলেন, পরের ধাপ কেন।
  2. আগে ক্ষতি থামান, পরে কারণ খুঁজুন, আর “ঠিক আগে কী বদলেছিল” জিজ্ঞেস করুন।
  3. Kubernetes-এ আগে বুঝুন Pod কোন ধাপে আটকেছে, তারপর Events, Reason আর --previous.
  4. Plan-এর শেষ লাইন পড়ুন, lock সম্মান করুন, পরিচয় স্থির রাখতে for_each.
  5. “জানি না” দুর্বলতা নয়। যা জানেন, যা জানেন না, আর কীভাবে জানবেন, তিনটিই বলুন।

পথের শেষ: এটিই এই কোর্সের শেষ পর্ব। আপনি ৮১টি পর্ব পেরিয়ে এসেছেন। এবার নিজের একটি ছোট প্রজেক্ট চালান, মাপুন, ভাঙুন আর সারান। অভিনন্দন, আর ইন্টারভিউর জন্য শুভকামনা।

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

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