OOAAOWOOAAOW
LinuxNetworkingGitPythonDockerKubernetesHelmAWS
YouTube
কোর্সসমূহ
আমার লাইব্রেরি
LinuxNetworkingGitPythonDockerKubernetesHelmAWS
YouTube
OOAAOW YouTube Channel
Sponsor OOAAOW

DevOps Lab — Bangladeshi learner-দের জন্য তৈরি

সাবস্ক্রিপশনসাবস্ক্রিপশন নীতি

হোম/aws/মডিউল ৭
০৭

User data আর cloud-init — সার্ভার নিজেই নিজেকে সাজায়

Launch-এর সময় একটা স্ক্রিপ্ট দিয়ে দিলে সার্ভার প্রথম boot-এই নিজেকে সাজিয়ে নেয়। স্ক্রিপ্টের অংশগুলো, root হিসেবে একবারই চলার মানে, cloud-init-এর লগ কীভাবে পড়বে, apt-dnf গোলমাল, আর একটা পুরো ব্যর্থতা ধাপে ধাপে খুঁজে বের করা।

user datacloud-initbootstrapautomationlogsdebuggingidempotency⏱ ~৩৬ মিনিট
💡 ধারণা

হাতে সাজানোর তিনটে দাম

পর্ব ৫-৬-এ যা করেছি, সেটা একবার করলে ঠিকই আছে: সার্ভার চালু করো, SSH করো, apt-get install nginx, systemctl enable --now nginx, একটা index.html লেখো। সাত-আট মিনিটের কাজ।

এখন ধরো তিনটে সার্ভার লাগবে। তারপর ধরো একটা মুছে নতুন বানাতে হলো। তারপর ধরো ট্র্যাফিক বেড়ে গেল আর দশটা লাগবে — রাত দুটোয়।

হাতে সাজানোর দাম তিনটে, আর সময়টা তার মধ্যে সবচেয়ে কম গুরুত্বপূর্ণ:

১. সময়। আট মিনিট × দশটা সার্ভার = আশি মিনিট। খারাপ, কিন্তু সহনীয়।

২. Drift — আর এটাই আসল সমস্যা। দশটা সার্ভার হাতে সাজালে ওগুলো হুবহু এক হবে না। একটায় তুমি একটা প্যাকেজ বেশি বসিয়েছিলে কারণ কিছু কাজ করছিল না। আরেকটায় config ফাইলে একটা লাইন বদলেছিলে আর ভুলে গেছ। তিন নম্বরটা দু-সপ্তাহ আগে বানানো, তাই ওটায় nginx-এর একটা পুরোনো সংস্করণ।

এর ফল হলো সেই বাক্যটা, যেটা DevOps-এর সব দুঃখের উৎস: "ওই একটা সার্ভারেই সমস্যাটা হয়।" আর তুমি কখনো জানবে না কেন, কারণ পার্থক্যটা কোথায় তার কোনো লিখিত রেকর্ড নেই।

৩. এটা পুনরুৎপাদনযোগ্য নয়। ছ-মাস পরে কেউ জিজ্ঞেস করলে "এই সার্ভারটা কীভাবে বানানো হয়েছিল?" — উত্তর হবে "মনে নেই"। আর সেটা মানে দুর্যোগ থেকে ফেরার কোনো পরিকল্পনা নেই।

সমাধান একটা সরল ধারণা: সার্ভার সাজানোর ধাপগুলো একটা স্ক্রিপ্টে লিখে রাখো, আর launch-এর সময় AWS-কে ওটা দিয়ে দাও। সার্ভার চালু হওয়ার সময়েই নিজেকে সাজিয়ে নেবে।

তিনটে দাম একসাথে মিটে যায়:

দামস্ক্রিপ্টে লেখার পরে
সময়দশটা সার্ভারে একই আশি সেকেন্ড, মানুষের হাত ছাড়া
Driftঅসম্ভব — সবগুলো একই স্ক্রিপ্ট থেকে, তাই হুবহু এক
রেকর্ডস্ক্রিপ্টটাই রেকর্ড — git-এ রাখা যায়, পড়া যায়, পুনরায় চালানো যায়

আর এটা পরের দুটো পর্বের ভিত: পর্ব ৮-এ এই স্ক্রিপ্টটা একটা টেমপ্লেটের ভেতরে ঢুকবে, আর পর্ব ২১-এ auto scaling group ওই টেমপ্লেট থেকে নিজে নিজে সার্ভার বানাবে — যেগুলোর কোনোটায় তুমি কখনো SSH করবে না। ওই গোটা শৃঙ্খলটা এই এক স্ক্রিপ্টের উপরে দাঁড়িয়ে।

💡 ধারণা

User data — জিনিসটা আসলে কী

User data হলো একটা লেখা, যেটা তুমি launch-এর সময় instance-এর সাথে দিয়ে দাও। কনসোলে: Advanced details → User data, ঠিক ফর্মের শেষে। CLI-তে: --user-data।

ওই লেখাটা নিয়ে কাজ করে cloud-init — প্রায় সব আধুনিক Linux image-এর ভেতরে আগে থেকে বসানো একটা প্রোগ্রাম, যার কাজ প্রথম boot-এ মেশিনটাকে প্রস্তুত করা। হোস্টনেম বসানো, SSH-এর চাবি বসানো, নেটওয়ার্ক সাজানো — সব cloud-init করে। আর শেষে, তোমার স্ক্রিপ্টটা চালায়।

সার্ভারটা ওই লেখাটা কোথা থেকে পায়? এখানে একটা সুন্দর ব্যাপার আছে, আর এটা জানা দরকার কারণ পর্ব ২০-এ এই ঠিকানাটা আবার আসবে:

প্রতিটা EC2 instance-এর ভেতর থেকে একটা বিশেষ ঠিকানা পৌঁছানো যায় — 169.254.169.254। ওটা কোনো আসল সার্ভার নয়, ওটা instance metadata service, যেটা শুধু ওই instance-এর জন্য ওই instance-এর ভেতর থেকেই পাওয়া যায়। Cloud-init boot-এর সময় ওখান থেকে user data পড়ে নেয়:

ubuntu@ip-10-0-1-42:~$ curl http://169.254.169.254/latest/user-data
#!/bin/bash
apt-get update -y
apt-get install -y nginx

একই জায়গা থেকে instance নিজের সম্পর্কে অন্য সব কিছুও জানতে পারে — তার id, তার instance type, সে কোন zone-এ, তার public IP। স্ক্রিপ্টে এটা মাঝে মাঝে খুব কাজে লাগে:

INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)
AZ=$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone)
একটা নিরাপত্তার কথা এখানেই বলে রাখি, কারণ পর্ব ২০-এ এটা একটা নিয়ম হিসেবে ফিরে আসবে। এই ঠিকানাটা instance-এর ভেতরের যেকোনো প্রক্রিয়া থেকে পৌঁছানো যায় — তোমার অ্যাপ্লিকেশন থেকেও। আর পর্ব ১০-এ দেখব এই একই ঠিকানা থেকে instance-এর role-এর অস্থায়ী চাবিও পাওয়া যায়।

তার মানে তোমার অ্যাপ্লিকেশনে যদি একটা দুর্বলতা থাকে যেটা দিয়ে আক্রমণকারী যেকোনো URL আনিয়ে নিতে পারে, সে এই ঠিকানাটা আনিয়ে তোমার সার্ভারের AWS চাবি পড়ে নিতে পারে। এটা তত্ত্ব নয় — এভাবেই বড় বড় তথ্য ফাঁস হয়েছে। সমাধানের নাম IMDSv2, আর সেটা পর্ব ২০-এর টেমপ্লেটে আমরা স্পষ্ট করে চালু করব।
▶ ডেমো

একটা bootstrap স্ক্রিপ্ট, লাইন ধরে ধরে

নিচের স্ক্রিপ্টটা একটা ওয়েব সার্ভার তৈরি করে। ছয় লাইন, আর প্রতিটা লাইনের একটা কারণ আছে:

লাইন ১ — #!/bin/bash

এটা বাধ্যতামূলক, আর user data-র সবচেয়ে সাধারণ ভুল এটা বাদ দেওয়া। Cloud-init প্রথম দুটো অক্ষর দেখে সিদ্ধান্ত নেয় লেখাটা কী ধরনের — #! দেখলে বোঝে এটা একটা স্ক্রিপ্ট, চালাতে হবে। না থাকলে ও কিছুই করে না, আর কোনো ভুলও দেখায় না। লক্ষণটা হবে: সার্ভার চালু হলো, 2/2 এলো, আর স্ক্রিপ্টের কোনো চিহ্ন নেই কোথাও।

লাইন ২ — set -euxo pipefail

এটা আবশ্যক নয়, কিন্তু এটা দিলে পরে এক ঘণ্টা বাঁচে। চারটে অক্ষর, চারটে আলাদা কাজ:

অক্ষরকী করেকেন দরকার
-eকোনো কমান্ড ব্যর্থ হলে স্ক্রিপ্টটা ওখানেই থামেনইলে ব্যর্থতার পরেও বাকিটা চলে আর ফল হয় অর্ধেক-সাজানো সার্ভার
-uকোনো অসংজ্ঞায়িত ভ্যারিয়েবল ব্যবহার করলে থামেrm -rf $DIR/ যেখানে DIR খালি — ভাবো কী হয়
-xপ্রতিটা কমান্ড চালানোর আগে ছাপেলগে পড়ার মতো কিছু থাকে। এটাই সবচেয়ে কাজের
-o pipefailpipe-এর মাঝের কোনো কমান্ড ব্যর্থ হলে পুরোটা ব্যর্থ ধরেনইলে `cmd1 \cmd2`-তে cmd1 ব্যর্থ হলেও সফল মনে হয়

-x আলাদা করে বলার মতো। এটা ছাড়া লগে শুধু প্রোগ্রামগুলোর নিজের বকবক থাকে; এটা দিলে প্রতিটা লাইন + চিহ্ন দিয়ে ছাপা হয় — অর্থাৎ লগটা স্ক্রিপ্টের চলার হিসাব হয়ে যায়, আর কোন লাইনে থেমেছে সেটা সরাসরি দেখা যায়।

🔒

বাকি অংশটা সাবস্ক্রাইবারদের জন্য

১৪১টি অংশের ২৯টি দেখানো হয়েছে, ১১২টি বাকি

←

আগের module

নেটওয়ার্ক নিরাপত্তা — security group আর NACL

পরের module

Launch template — একবার লেখো, যতবার দরকার চালাও

→