SSD Nodes Learn Hosting plans →
নির্দেশিকা Matt Connorদ্বারা Matt Connor · আপডেট করা হয়েছে 2026-08-21

Linux binary চলছে না: glibc বনাম musl কী করবেন

GLIBC_2.34 not found দেখালে build host-ই version floor ঠিক করেছে। Binary কী দাবি করে জানুন, তারপর portableভাবে ship করার 4টি উপায়ের সঠিকটি বেছে নিন।

কেন Linux binary পুরোনো সার্ভারে চলবে না

একটি portable Linux binary তৈরি করা কঠিন, কারণ glibc, অর্থাৎ GNU C library, কেবল একদিকে compatibility বজায় রাখে। পুরোনো binary নতুন glibc-তে চলতে থাকে। নতুন binary পুরোনো glibc-তে চলে না। যে মেশিনে আপনি compile করেন, সেটিই আপনার deploy করা প্রতিটি মেশিনের জন্য সর্বনিম্ন compatibility স্তর নির্ধারণ করে।

Error message-এ প্রয়োজনীয় সঠিক version উল্লেখ থাকে:

./mytool: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.38' not found (required by ./mytool)

কিছু corrupt নয় এবং কোনো configuration-ও ভুল নয়। Dynamic loader binary-র ভেতরে সংরক্ষিত একটি version tag পড়েছে, system libc-তে সেই tag খুঁজেছে, tag-টি পায়নি এবং program start করতে অস্বীকার করেছে। File-টি আবার download করে chmod +x চালালেও কিছু পরিবর্তন হবে না, কারণ প্রয়োজনীয়তাটি file-টির ভেতরেই লেখা আছে। আপনাকে হয় binary কীভাবে build করা হয় তা পরিবর্তন করতে হবে, অথবা কী ship করবেন তা পরিবর্তন করতে হবে।

glibc প্রতীক সংস্করণিং আসলে যা করে

glibc যে প্রতিটি function export করে, তার সঙ্গে একটি version tag থাকে। printf-এর ভেতরের libc.so.6 আসলে printf@@GLIBC_2.2.5। glibc কোনো function-এর আচরণ বা ABI (application binary interface) পরিবর্তন করলে পুরোনোটিকে প্রতিস্থাপন করে না। এটি পুরোনো code-কে পুরোনো tag-এর অধীনে রেখে নতুন code-কে নতুন tag-এর অধীনে যোগ করে। ফলে একটি libc.so.6-তে একই symbol-এর একাধিক version একসঙ্গে থাকতে পারে। 2009 সালের একটি binary তখনও 2009 সালের tag খুঁজে পায়। এ কারণেই forward compatibility এত ভালোভাবে কাজ করে।

Link ধাপে কোন version ব্যবহার করা হয়েছে, তা নথিভুক্ত হয়। আপনার binary-তে একটি .gnu.version_r section থাকে, যেখানে কার্যত লেখা থাকে, "আমার libc.so.6 থেকে GLIBC_2.38 প্রয়োজন।" পুরোনো libc-তে সেই tag কখনো ছিল না। তাই main চালানোর আগেই loader থেমে যায়। কোনো fallback নেই। কারণ fallback থাকলে program-কে যে function-এর বিরুদ্ধে compile করা হয়েছিল, তার বদলে নীরবে অন্য একটি function দেওয়া হতো।

2021 সালের পর সবচেয়ে সাধারণ trigger হলো glibc 2.34। এই release-এ libpthread এবং libdl-কে libc-এর সঙ্গে একীভূত করা হয় এবং __libc_start_main-কে, অর্থাৎ প্রতিটি C program চালু করা function-কে, GLIBC_2.34 tag-এ সরিয়ে নেওয়া হয়। তাই glibc 2.34 বা তার পরের version থাকা যেকোনো distribution-এ compile করা একটি hello-world program GLIBC_2.34 দাবি করে, যদিও source code-এ কোনো আধুনিক function call নেই। এ কারণেই বহু বছর নিজের code পরিবর্তন না করলেও মানুষের কাছে সমস্যাটি হঠাৎ দেখা দেয়।

আমার distro কোন glibc version release করে?

Chartglibc version in each distribution's own repositories
The data behind this chart
[
  {
    "distro": "CentOS 7",
    "glibc": 2.17
  },
  {
    "distro": "RHEL 8",
    "glibc": 2.28
  },
  {
    "distro": "Ubuntu 20.04",
    "glibc": 2.31
  },
  {
    "distro": "Debian 11",
    "glibc": 2.31
  },
  {
    "distro": "RHEL 9",
    "glibc": 2.34
  },
  {
    "distro": "Ubuntu 22.04",
    "glibc": 2.35
  },
  {
    "distro": "Debian 12",
    "glibc": 2.36
  },
  {
    "distro": "Ubuntu 24.04",
    "glibc": 2.39
  },
  {
    "distro": "Debian 13",
    "glibc": 2.41
  }
]

এগুলো হলো প্রতিটি distribution-এর নিজস্ব repository-তে থাকা version, যা distribution-গুলো প্রকাশ করেছে এবং August 2026-এ বর্তমান ছিল। CentOS 7-এর end of life অনেক আগেই হয়ে গেছে। তবু উত্তরাধিকারসূত্রে পাওয়া server-গুলো এখনও এটি চালায় বলে এটি তালিকায় রাখা হয়েছে। আপনার কাছে থাকা যেকোনো box-এ ldd --version চালান। এটি প্রথম লাইনে glibc release দেখায়। আপনি getconf GNU_LIBC_VERSION-ও চালাতে পারেন।

এই 9টি row-কে একটি ধাপভিত্তিক তালিকা হিসেবে দেখুন। glibc 2.41 সহ Debian 13-এ build করলে ফলাফল Debian 13-এর চেয়ে পুরোনো কোনো system-এ চলবে না। glibc 2.31 সহ Ubuntu 20.04-এ build করলে একই source ওই line-এর উপরের প্রতিটি row-তে চলবে, Debian 13-এর box-সহ। আপনাকে যে সবচেয়ে পুরোনো server support করতে হবে, সেটিই একমাত্র গুরুত্বপূর্ণ build host। তাই আপনি যে distribution standardise করেন, সেটিই তার জন্য compile করা সবকিছুর ABI floor নির্ধারণ করে। fleet তৈরি হওয়ার আগেই এই সিদ্ধান্ত নেওয়া উচিত। VPS-এ কোন OS চালাবেন তা বেছে নেওয়ার মতো অন্যান্য trade-off-এর পাশাপাশি এটি বিবেচনা করুন: আপনার VPS-এ কোন OS চালাবেন তা বেছে নেওয়া

একটি binary-এর জন্য প্রয়োজনীয় সর্বনিম্ন glibc সংস্করণ কীভাবে খুঁজে বের করব?

ফাইল থেকেই তথ্যটি পড়ুন। এটি যেকোনো কিছুর ক্ষেত্রে কাজ করে, এমনকি build note ছাড়া কোনো vendor-এর দেওয়া binary-এর ক্ষেত্রেও।

objdump -T ./mytool | grep -o 'GLIBC_[0-9.]*' | sort -Vu | tail -5

শেষ লাইনটিই সর্বনিম্ন প্রয়োজনীয় সংস্করণ। objdump না থাকলে binutils package install করুন। ওই সিস্টেমে কিছু install করতে না পারলে strings -a ./mytool | grep -o 'GLIBC_[0-9.]*' | sort -Vu | tail -5 ব্যবহার করলেও কাছাকাছি ফল পাবেন, কারণ tag-গুলো ফাইলের ভেতরে plain string হিসেবে সংরক্ষিত থাকে।

readelf -V ./mytool একই requirement কাঠামোবদ্ধভাবে দেখায়। Version needs section '.gnu.version_r' শিরোনামযুক্ত block খুঁজুন। সেখানে প্রতিটি tag-এর জন্য একটি করে Name: GLIBC_x.y line থাকে। এগুলো সেই library-এর অধীনে group করা থাকে, যেটি tag-গুলো সরবরাহ করবে।

কোন function set সর্বনিম্ন সংস্করণ নির্ধারণ করেছে তা জানতে tag-টি grep করুন: objdump -T ./mytool | grep GLIBC_2.38। এটি প্রায়ই একটি মাত্র symbol হয়, এবং কখনও এমন symbol-ও হতে পারে যা এড়িয়ে চলা সম্ভব। objdump -T একেবারেই কিছু print না করলে binary-টি statically linked। তাই এতে dynamic symbol table নেই এবং print করার মতো কোনো version requirement-ও নেই।

একটি binary সম্পর্কে file এবং readelf -d আপনাকে কী জানায়

file এক লাইনে architecture এবং link type জানায়।

file ./mytool

একটি সাধারণ glibc build এভাবে দেখা যায়:

ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=..., for GNU/Linux 3.2.0, not stripped

একটি static build-এ statically linked লেখা থাকে এবং কোনো interpreter-এর নাম থাকে না। একটি musl build-এ অন্য interpreter-এর নাম থাকে:

ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-musl-x86_64.so.1, ...

গুরুত্বপূর্ণ field হলো interpreter। এটি সেই dynamic loader, যেটি আপনার program চালানোর আগে kernel চালায়। এই নির্দিষ্ট path-টি target machine-এ অবশ্যই থাকতে হবে। কেউ সেখানে musl install না করলে Debian বা Ubuntu server-এ /lib/ld-musl-x86_64.so.1 থাকে না।

readelf -d ./mytool binary-টির প্রয়োজনীয় shared library-গুলো নাম অনুযায়ী তালিকাভুক্ত করে:

Dynamic section at offset 0x2d58 contains 27 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)   Shared library: [libssl.so.3]
 0x0000000000000001 (NEEDED)   Shared library: [libc.so.6]
 0x000000000000001d (RUNPATH)  Library runpath: [$ORIGIN/../lib]

প্রতিটি NEEDED entry একটি বাধ্যতামূলক dependency, যা soname অনুযায়ী মেলানো হয়। libssl.so.3 হলো OpenSSL 3। তাই শুধু libssl.so.1.1 থাকা server-এ ওই binary load হবে না। এর কারণ soname: ভিন্ন soname ইচ্ছাকৃতভাবে incompatible ABI নির্দেশ করে। RUNPATH loader-কে প্রথমে কোথায় search করতে হবে তা জানায়। $ORIGIN binary-টি থাকা directory-তে প্রসারিত হয়। এভাবেই একটি self-contained bundle নিজের library খুঁজে পায়।

আপনি বিশ্বাস করেন না এমন binary-তে ldd চালাবেন না। glibc-তে ldd loader-এর অধীনে program চালিয়ে dependency resolve করতে পারে। ফলে hostile file code execute করার সুযোগ পায়। readelf এবং objdump শুধু bytes পড়ে। এর আগে নিশ্চিত করুন যে download করা file-টি project আসলেই publish করেছে। কারণ published checksum-এর সঙ্গে download যাচাই করা-ই একমাত্র ধাপ, যা আপনাকে জানায় আপনি কার bytes হাতে রেখেছেন।

আপনি যে ত্রুটিগুলো বাস্তবে দেখবেন এবং প্রতিটির অর্থ

Loader এমন একটি GLIBC version উল্লেখ করে যা এটি খুঁজে পায় না। Binary-টি target system-এ থাকা glibc-এর চেয়ে নতুন glibc-এর বিরুদ্ধে compile করা হয়েছিল। Target system-এ কিছু install করলেই এটি নিরাপদে ঠিক হবে না। নিচের চারটি option-এর একটি বেছে নিন।

আপনি স্পষ্টভাবে দেখতে পাচ্ছেন এমন একটি file-এর ক্ষেত্রে shell No such file or directory দেখায়। অনুপস্থিত জিনিসটি binary নয়, interpreter। ELF header-এ loader path না থাকলে execve, ENOENT ফেরত দেয় এবং shell তার কাছে থাকা একমাত্র message-টি দেখায়। file চালিয়ে interpreter path দেখুন। glibc-only server-এ musl-linked binary চালালে ঠিক এই symptom দেখা যায়।

cannot execute binary file: Exec format error-এর অর্থ architecture ভুল: arm64 server-এ x86-64 binary, অথবা এর বিপরীত। file output-এর প্রথম line-এ আপনি কোন architecture-এর binary ব্যবহার করছেন তা দেখা যায়।

error while loading shared libraries: libssl.so.3: cannot open shared object file-এর অর্থ একটি NEEDED library অনুপস্থিত, অথবা অন্য soname-এ উপস্থিত। সংশ্লিষ্ট distribution package install করুন। Distribution family অনুযায়ী package name আলাদা হয়। তাই README থেকে কোনো apt line copy করার আগে সেটি রূপান্তর করুন। dnf এবং apt command-এর সমতুল্য রূপ সেই mapping দেখায়।

glibc-এর অধীনে ঠিকমতো চলা musl build থেকে শুধু Segmentation fault দেখা যায়। সাধারণত কারণটি thread stack size। এটি option 2-এ ব্যাখ্যা করা হয়েছে।

একটি বহনযোগ্য Linux binary বিতরণের চারটি উপায়

প্রতিটি পদ্ধতির জন্য আপনাকে বাস্তব কোনো মূল্য দিতে হবে। আপনার program run time-এ কী করে, তার ভিত্তিতে পদ্ধতি বেছে নিন; কোনটি সবচেয়ে পরিষ্কার শোনায়, তার ভিত্তিতে নয়।

Option 1: আপনি যে পুরোনোতম distro সমর্থন করেন, সেটির ওপর build করুন

সবচেয়ে নিরস উত্তর, এবং সাধারণত সঠিকটিও এটিই। আপনি যে পুরোনোতম distribution সমর্থনের প্রতিশ্রুতি দেন, সেই distribution-এর container image-এর ভেতরে compile করুন। Linker কেবল সেই tag-গুলোই record করতে পারে, যেগুলো পুরোনো glibc-তে বাস্তবে আছে। তাই binary-তে ওই release-ই সর্বনিম্ন compatibility floor হিসেবে থাকে, অথচ binary স্বাভাবিক dynamic binary হিসেবেই থাকে এবং glibc-এর সম্পূর্ণ আচরণ অক্ষুণ্ণ থাকে।

docker run --rm -v "$PWD:/src" -w /src ubuntu:20.04 sh -c 'apt-get update && apt-get install -y build-essential && make'

Output-টি glibc 2.31 এবং তার পরের সব version-এ চলে। অনুমান না করে যাচাই করুন: আগে দেওয়া objdump -T one-liner-টি result-এর বিরুদ্ধে চালান এবং দেখুন সর্বোচ্চ tag-টি আপনার প্রত্যাশিত tag কি না।

এর বিনিময়ে toolchain পুরোনো হয়ে যায়। পুরোনো base image-এর সঙ্গে পুরোনো compiler-ও থাকে। আপনার code-এর সাম্প্রতিক C++ standard প্রয়োজন হলে এটি সমস্যা তৈরি করে। Go এবং Rust সাধারণত এই সমস্যা এড়ায়, কারণ তাদের toolchain distribution package-এর বাইরে আলাদাভাবে container-এ install হয়। C এবং C++-এর জন্য distribution-এর নিজস্ব toolchain channel থেকে নতুন compiler যোগ করতে পারেন। অথবা manylinux image ব্যবহার করতে পারেন। এগুলো এমনভাবে তৈরি যে পুরোনো glibc-এর সঙ্গে বর্তমান GCC একত্রে ব্যবহার করা যায়। Zig-এর bundled C compiler-ও সরাসরি নির্দিষ্ট glibc target করতে পারে, যেমন zig cc -target x86_64-linux-gnu.2.28-এ দেখানো হয়েছে। এতে পুরোনো image সংরক্ষণ না করেও একই compatibility floor পাওয়া যায়।

বিকল্প 2: musl-এর বিরুদ্ধে static linking করুন

musl হলো ছোট একটি C library, যা static linking বিবেচনায় রেখে লেখা হয়েছে। একটি static musl binary-তে নিজস্ব libc থাকে, কোনো interpreter-এর নাম থাকে না, এবং সঠিক architecture-এর যেকোনো Linux kernel-এ এটি চলে। অধিকাংশ single-file tool download এভাবেই তৈরি করা হয়।

sudo apt install -y musl-tools
musl-gcc -static -O2 hello.c -o hello
file ./hello

file-এ এখন statically linked লেখা থাকা উচিত এবং কোনো interpreter field থাকা উচিত নয়। Rust-এর জন্য target যোগ করে তার বিরুদ্ধে build করুন:

rustup target add x86_64-unknown-linux-musl
cargo build --release --target x86_64-unknown-linux-musl

Go-এর ক্ষেত্রে এগুলোর কোনোটি প্রয়োজন হয় না। CGO_ENABLED=0 go build ব্যবহার করলে ফলাফল আগে থেকেই static থাকে এবং কোনো libc-ই link করে না।

NSS lookup পরিবর্তিত হয়। glibc NSS (name service switch)-এর মাধ্যমে user এবং host name resolve করে। Program চলার সময় এটি libnss_* module-কে dlopen দিয়ে load করে। Staticভাবে linked glibc এটি করতে পারে না, এবং linker নিচের ভাষায় warning দেয়:

warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking

musl কোনো NSS implementation না থাকায় এই warning এড়ায়। এর নিজস্ব resolver আছে এবং এটি সরাসরি /etc/resolv.conf/etc/hosts পড়ে। সাধারণ VPS-এ এটি যথেষ্ট এবং সহজ। কিন্তু যে host-এ account বা name LDAP অথবা SSSD থেকে আসে, সেখানে আপনার binary সেগুলো দেখতে পাবে না, যদিও ওই সিস্টেমের অন্য সব program দেখতে পাবে। musl-এর resolver glibc-এর resolver-এর তুলনায়ও নতুন। 512 byte-এর চেয়ে বড় DNS reply-এর জন্য TCP fallback musl 1.2.4-এ 2023 সালে যুক্ত হয়েছে। তাই পুরোনো musl-এর বিরুদ্ধে build করা হলে বড় answer truncated হবে।

dlopen কাজ করে না। Static musl binary-তে dlopen এমন একটি stub, যা সবসময় ব্যর্থ হয়। Runtime-এ code load করে এমন কোনো কিছুই কাজ করবে না। এর মধ্যে plugin system, PAM module, GPU driver এবং glibc-এর নিজস্ব iconv character-set module রয়েছে। আপনার program-এর dlopen প্রয়োজন হলে static linking ব্যবহার করা যাবে না। তখন অন্য তিনটি বিকল্পের একটি নিতে হবে।

Security update-এর দায়িত্ব আপনার। Dynamically linked binary server-এর package upgrade চলার সঙ্গে সঙ্গে libc fix পেয়ে যায়। Static binary কখনো তা পায় না। আপনার libc বা bundled static OpenSSL-এর বিরুদ্ধে কোনো CVE (common vulnerabilities and exposures) entry প্রকাশিত হলে আপনাকে rebuild ও redistribute করতে হবে। ইতিমধ্যে deploy করা প্রতিটি copy কেউ file প্রতিস্থাপন না করা পর্যন্ত vulnerable থাকবে। কোন কোন উপাদান link করেছেন তার record রাখুন। কারণ target system-এর কোনো কিছু administrator-কে জানাতে পারবে না যে আপনার one-file binary-তে দুই বছর আগের library রয়েছে।

Licence পরিবর্তিত হয়। glibc হলো LGPL। Static linking করলে LGPL-এর relinking obligation প্রযোজ্য হয়। Recipients-কে এমন উপাদান দিতে হবে, যা ব্যবহার করে তারা আপনার program-কে ভিন্ন glibc-এর বিরুদ্ধে relink করতে পারে। musl হলো MIT এবং এতে এমন কোনো শর্ত নেই। Single-file binary release করা project-গুলো static glibc-এর পরিবর্তে musl বেছে নেওয়ার এটাই প্রধান কারণ।

Runtime-এর দুটি পার্থক্য বিভ্রান্তিকর crash ঘটায়। musl-এর default thread stack হলো 128 KiB, যেখানে glibc-এ এটি 8 MiB। তাই thread stack-এ বড় buffer রাখলে কোনো message বা log line ছাড়াই code segfault করতে পারে। pthread_attr_setstacksize দিয়ে size নির্দিষ্ট করুন, অথবা buffer-টি heap-এ সরিয়ে নিন। musl-এর allocator-ও একসঙ্গে অনেক thread allocation করার বদলে ছোট size এবং predictable behaviour-এর জন্য লেখা। তাই allocation-heavy threaded program লক্ষণীয়ভাবে ধীর চলতে পারে। কোনো library-এর reputation-এর ওপর নির্ভর না করে নিজের workload benchmark করুন।

বিকল্প 3: loader এবং library একসঙ্গে bundle করুন

সংশ্লিষ্ট loader-সহ library-গুলো binary-এর পাশে রাখুন। এরপর সেই loader-এর মাধ্যমে program চালু করুন।

./ld-linux-x86-64.so.2 --library-path ./lib ./mytool

এটি স্থায়ী করতে patchelf দিয়ে path-গুলো file-এ লিখুন:

patchelf --set-interpreter "$PWD/lib/ld-linux-x86-64.so.2" --set-rpath '$ORIGIN/lib' ./mytool

এটি কাজ করবে কি না, তা একটি নিয়ম নির্ধারণ করে: loader এবং libc.so.6 একই glibc build থেকে আসতে হবে। এগুলো matched pair। host-এর loader-এর সঙ্গে bundled libc মিশিয়ে ব্যবহার করলে পাঠযোগ্য error না দেখিয়ে start-up-এর সময় crash হয়। দুটিই bundle করুন, অথবা কোনোটিই bundle করবেন না।

AppImage হলো এই pattern-এর packaged রূপ। এতে payload একটি squashfs image-এ থাকে এবং একটি ছোট runtime সেটি mount করে। একটি বিষয় অনেকেই উপেক্ষা করেন: AppImage glibc bundle করে না। তাই বর্তমান distribution-এ build করা AppImage পুরোনো server-এ একই version error-এ ব্যর্থ হবে। AppImage-এর নিজস্ব নির্দেশনা হলো আপনি যে base-গুলো support করেন, সেগুলোর মধ্যে সবচেয়ে পুরোনোটিতে build করা। তাই এটি option 1-এর ওপর নির্মিত একটি delivery format, option 1-এর বিকল্প নয়।

Headless server-এ AppImage payload mount করতে FUSE (filesystem in userspace) প্রয়োজন। Minimal VPS image-এ এটি প্রায়ই থাকে না। Failure message-এ libfuse.so.2 উল্লেখ থাকে। ./App.AppImage --appimage-extract-and-run ব্যবহার করে mount সম্পূর্ণ এড়িয়ে যেতে পারেন। এটি payload-কে একটি temporary directory-তে unpack করে এবং সেখান থেকে execute করে।

বিকল্প 4: একটি container image ব্যবহার করুন

প্রোগ্রামের সঙ্গে সম্পূর্ণ userland স্থানান্তর করুন। image-এ নিজস্ব libc থাকে, তাই host-এর glibc আর গুরুত্বপূর্ণ থাকে না; শুধু kernel এবং architecture-এর সামঞ্জস্য থাকতে হয়। এটি সবচেয়ে সরল বিকল্প এবং সমস্যার এই পুরো শ্রেণিটিই দূর করে। তাই অনেক server software এইভাবে বিতরণ করা হয়। এটি ব্যবহার করার প্রচলিত উপায় হলো VPS-এ Docker চালানো

Host kernel এখনও একটি সীমা নির্ধারণ করে। নতুন glibc নতুন system call ব্যবহার করে, আর পুরোনো container host সেগুলো আটকে দিতে পারে: glibc 2.34 এবং পরবর্তী সংস্করণ clone3 ব্যবহার করে, যা পুরোনো default seccomp profile প্রত্যাখ্যান করে। এর লক্ষণ হলো Operation not permitted-সহ তাৎক্ষণিক ব্যর্থতা, কিন্তু কোথাও glibc-এর উল্লেখ থাকে না। Host-এ container runtime upgrade করলে সমস্যা সমাধান হয়, কারণ বাধাটি kernel-এ নয়, runtime-এর syscall filter-এ থাকে।

খরচগুলো সাধারণ। Target system-এ একটি container runtime এবং সেটি ব্যবহারের permission দরকার। Download-এর আকার একটি file থেকে বেড়ে দশ বা শত শত megabyte হতে পারে। এখন একটি base image এবং তার patch schedule-এর দায়িত্বও আপনার। ফলে option 2-এ যে security কাজ এড়ানো হয়েছিল, তা image rebuild হিসেবে আবার ফিরে আসে। দীর্ঘ সময় চলা service-এর ক্ষেত্রে এটি যুক্তিসঙ্গত বিনিময়। কেউ একবার চালাবে এমন command-line tool-এর ক্ষেত্রে নয়।

কোন বিকল্পটি বেছে নেওয়া উচিত?

  • আপনার নিয়ন্ত্রণাধীন সার্ভারগুলোর জন্য একটি অভ্যন্তরীণ tool, যেগুলো একই distribution চালায়: সেই distribution-এ dynamically build করুন এবং সেখানেই থামুন।
  • অপরিচিত ব্যবহারকারীরা download করে চালাবে এমন একটি single file: static musl ব্যবহার করুন, যদি programটির dlopen প্রয়োজন না থাকে এবং NSS-backed lookup না করে।
  • plugins বা GPU access-সহ একটি program: dynamic অবস্থায় থাকুন, পুরোনো base-এ build করুন এবং এটি সরবরাহ করতে option 3 ব্যবহার করুন।
  • ইতিমধ্যে runtime থাকা একটি machine-এ দীর্ঘ সময় চলা service: image ship করুন।

আপনি যে বিকল্পই বেছে নিন, তা লিখে রাখুন এবং যাচাই করুন। Build host-এর glibc এখন আপনার release process-এর অংশ। একটি build machine-কে এক LTS release থেকে পরবর্তীটিতে upgrade করলে ন্যূনতম সামঞ্জস্যের স্তর নীরবে বেড়ে যায়। এতে গত মাসে ঠিকমতো চলা ব্যবহারকারীদের জন্য সমস্যা তৈরি হতে পারে। Build image-কে tag অনুযায়ী pin করুন এবং output-এ সর্বোচ্চ GLIBC_ tag আছে কি না build step হিসেবে assert করুন। তাহলে সমস্যাটি অন্য কারও terminal-এ দেখা দেওয়ার পরিবর্তে আপনার pipeline-এই check ব্যর্থ হবে।

FAQ

আমার সার্ভারে "version GLIBC_2.38 not found" দেখায় কেন?

Binary-টি এমন একটি মেশিনে compile করা হয়েছে, যেখানে আপনার সার্ভারের তুলনায় নতুন glibc ছিল। glibc-এর symbol versioning শুধু forward compatibility দেয়: পুরোনো binary নতুন glibc-তে চলে, কিন্তু নতুন binary পুরোনো glibc-তে চলে না। কারণ loader-এর file-এ সংরক্ষিত সঠিক version tag প্রয়োজন, আর পুরোনো libc-তে সেই tag কখনও ছিল না। সার্ভারে কিছু install করে এটি নিরাপদে ঠিক করা যায় না। পুরোনো base ব্যবহার করে rebuild করুন, static musl build সরবরাহ করুন, matching loader-সহ library bundle করুন, অথবা container image সরবরাহ করুন।

একটি binary-এর কোন glibc version প্রয়োজন তা কীভাবে জানব?

objdump -T ./mytool | grep -o 'GLIBC_[0-9.]*' | sort -Vu | tail -5 দিয়ে file থেকে version tag পড়ুন। শেষ line-এ এটি load করতে পারা সর্বনিম্ন glibc version দেখায়। readelf -V ./mytool একই requirement .gnu.version_r section-এ দেখায় এবং কোন library সেগুলো সরবরাহ করবে সে অনুযায়ী group করে। objdump -T কোনো output না দিলে binary-টি static এবং এর কোনো glibc requirement নেই। ফলাফলটি ldd --version থেকে পাওয়া আপনার সার্ভারের নিজস্ব version-এর সঙ্গে তুলনা করুন।

musl binary কি glibc binary-এর চেয়ে ধীর?

এটি workload-এর ওপর নির্ভর করে। নির্ভরযোগ্য উত্তর পেতে measurement করতে হবে। Static musl binary দ্রুত start হয়, কারণ চালানোর মতো কোনো loader নেই এবং exec সময় relocation-এর কাজও নেই। তবে musl-এর allocator অনেক thread একই সময়ে allocation করার জন্য নয়, বরং ছোট আকার ও পূর্বানুমানযোগ্য আচরণের জন্য তৈরি। glibc-এর তুলনায় musl-এ hand-optimised string ও memory routine-ও কম। তাই allocation-heavy বা string-heavy threaded program লক্ষণীয়ভাবে ধীর হতে পারে। যেকোনো দাবি গ্রহণের আগে নিজের সার্ভারে নিজের program benchmark করুন।

File থাকা সত্ত্বেও bash কেন "No such file or directory" দেখায়?

অনুপস্থিত file-টি আপনার binary নয়, dynamic loader। Kernel ELF header থেকে interpreter path পড়ে এবং path-টি না থাকলে ENOENT ফেরত দেয়। Shell-এর কাছে এটিই একমাত্র বার্তা থাকায় সে একই বার্তা দেখায়। file ./mytool চালিয়ে interpreter field পড়ুন। Debian বা Ubuntu server-এ সেখানে /lib/ld-musl-x86_64.so.1 থাকলে আপনার glibc system-এ musl-linked binary আছে। তাই musl-compatible download অথবা static build প্রয়োজন।

এটি ঠিক করতে কি নতুন সার্ভার থেকে libc.so.6 copy করতে পারি?

না। libc.so.6 এবং ld-linux-x86-64.so.2 একই glibc build-এর matched pair। মেশিনের প্রতিটি process এগুলো ব্যবহার করে। তাই system copy overwrite করলে সার্ভার কোনো কিছু চালাতে নাও পারে, এমনকি পরিবর্তনটি undo করার জন্য প্রয়োজনীয় tool-ও নয়। পুরোনো host-এ একটি নতুন binary চালাতেই হলে নতুন glibc একটি private directory-তে unpack করুন এবং --library-path দিয়ে program-টি তার নিজস্ব loader-এর মাধ্যমে start করুন। এতে শুধু ওই process প্রভাবিত হবে। তবে পুরোনো glibc-এর বিরুদ্ধে rebuild করাই এমন সমাধান, যা ছয় মাস পরেও অপ্রত্যাশিত সমস্যা তৈরি করবে না।

#glibc#musl#static-linking#portability#binaries