• docker run ubuntu चलाने पर भी यह host Linux kernel को share करता है, और Ubuntu सिर्फ user-space tools देता है
  • uname -r का परिणाम host kernel version दिखाता है, जबकि सिर्फ /etc/os-release में Ubuntu की जानकारी दिखाई देती है
  • VM के पास अपना अलग kernel होता है और boot होने में कई मिनट लग सकते हैं, लेकिन container milliseconds में start होता है और hardware virtualization के बिना OS-level isolation के जरिए host kernel share करने से overhead कम रहता है
  • Linux system call ABI की stability के कारण अलग-अलग distribution containers एक ही kernel पर चल सकते हैं
  • 16GB RAM वाले environment में lightweight containers की व्यावहारिक सीमा 50-100, medium scale के लिए 10-30, और large containers के लिए लगभग 5-10 है
  • इस architecture को समझना इसलिए ज़रूरी है क्योंकि kernel vulnerabilities सभी containers को प्रभावित कर सकती हैं, और base image selection compatibility और security पर सीधे असर डालती है

“Ubuntu चलाना” का मतलब

  • docker run ubuntu:22.04 चलाने पर Ubuntu जैसा bash prompt मिलता है और apt update व package install करना संभव होता है
  • लेकिन container के अंदर uname -r चलाने पर host kernel version (जैसे 6.5.0-44-generic) दिखाई देता है
  • /etc/os-release फ़ाइल Ubuntu 22.04 दिखाती है, लेकिन kernel host machine का ही होता है, और "Ubuntu" वाला हिस्सा सिर्फ user space बनाने वाला filesystem है

Container vs Virtual Machine: architecture की तुलना

  • VM hardware को virtualize करता है, जबकि container operating system को virtualize करता है
  • मुख्य अंतर:
    • Kernel: VM के पास अपना kernel होता है, container host kernel share करता है
    • Boot time: VM में मिनट लगते हैं, container milliseconds में शुरू होता है
    • Memory overhead: VM में 512MB-4GB, container में 1-10MB
    • Disk usage: VM में 10-100GB, container image में 10-500MB
    • Isolation level: VM hardware level पर, container process level पर
    • Performance: VM में लगभग 5-10% overhead, container में native के क़रीब performance

Base image के असली components

  • ubuntu:22.04 pull करने पर download होने वाले tarball में ये चीज़ें होती हैं:
  • 1. ज़रूरी binaries (/bin, /usr/bin)

    • /bin/bash (shell), /bin/ls (फ़ाइल सूची), /bin/cat (फ़ाइल दिखाना)
    • /usr/bin/apt (package manager), /usr/bin/dpkg (Debian package tools)
  • 2. Shared libraries (/lib, /usr/lib)

    • glibc और वे shared libraries जिनसे दूसरे programs link होते हैं
    • /lib/x86_64-linux-gnu/libc.so.6 (C library - सभी C programs की बुनियाद)
    • libpthread.so.0, libm.so.6 जैसी ज़रूरी libraries
  • 3. Configuration files (/etc)

    • /etc/apt/sources.list (package repository)
    • /etc/passwd (user database)
    • /etc/resolv.conf (DNS configuration, आमतौर पर host से mount किया जाता है)
  • 4. Package database

    • /var/lib/dpkg/status (installed packages)
    • /var/lib/apt/lists/ (available packages cache)
  • इसमें kernel, bootloader, drivers शामिल नहीं होते

Kernel वही रहता है, बाकी सब बदलता है

  • Linux kernel जिन functions को provide करता है: process scheduling, memory management, filesystem operations, network stack, device drivers, system calls
  • जब container process open(), read(), fork() call करता है, तो वह सीधे host kernel तक जाता है
  • Kernel को यह न तो पता होता है और न फ़र्क पड़ता है कि process “Ubuntu container” में है या “Alpine container” में
  • System call interface की stability

    • Linux syscall ABI बहुत stable है
    • glibc 2.31 (Ubuntu 20.04) पर compile किया गया binary Ubuntu 24.04 kernel पर भी चलने का कारण:
      • kernel backward compatibility बनाए रखता है
      • system call numbers नहीं बदलते
      • नए features जुड़ते हैं, लेकिन पुराने features शायद ही हटाए जाते हैं
    • यही वजह है कि kernel 6.5 चलाने वाले host पर Ubuntu 18.04 container चल सकता है

ख़ुद करके देखें: एक ही kernel, अलग user space

  • अलग-अलग base images में वही kernel query चलाने पर यह दिखता है कि सभी images host kernel share करती हैं
  • ubuntu:22.04, debian:12, alpine:3.19, fedora:39, archlinux:latest — सभी में वही kernel version (6.5.0-44-generic) दिखेगा
  • containers के बीच फ़र्क uname binary, libc जैसी userland composition का होता है

Containers इतने efficient क्यों होते हैं

  • 1. Kernel duplication नहीं

    • VM हर instance में पूरा kernel memory में load करता है (लगभग 100-500MB)
    • 10 VM मतलब memory में 10 kernels, जबकि 10 containers में सिर्फ एक kernel
  • 2. तुरंत start

    • VM boot sequence: BIOS → bootloader → kernel → init system → services
    • container सिर्फ fork() और exec() calls से milliseconds में process बन जाता है
    • सामान्य VM boot: 30-60 सेकंड / container start: लगभग 0.347 सेकंड
  • 3. Shared image layers

    • ubuntu:22.04 से 100 containers चलाने पर base image layer disk पर सिर्फ एक बार रहती है
    • हर container सिर्फ बदलावों के लिए पतली copy-on-write layer लेता है
  • 4. Kernel के जरिए memory sharing

    • kernel का page cache share होता है
    • 50 containers अगर एक ही फ़ाइल पढ़ें, तो kernel उसे सिर्फ एक बार cache करता है
    • वही shared library इस्तेमाल होने पर copy-on-write के जरिए memory pages share की जा सकती हैं

Container चलाने की सीमा कैसे निकालें

  • Memory analysis (16GB RAM VM के आधार पर)

    • कुल RAM: 16,384 MB
    • Host OS overhead: -1,024 MB
    • Docker daemon: -256 MB
    • Container runtime overhead: -512 MB
    • Containers के लिए उपलब्ध: 14,592 MB
  • Container type के हिसाब से memory usage

    • Minimum (sleep): लगभग 1MB
    • Alpine + छोटा app: लगभग 25MB
    • Ubuntu + Python app: लगभग 120MB
    • Ubuntu + Java app: लगभग 500MB
    • Node.js service: लगभग 200MB
  • Theoretical maximum

    • Minimum container (1MB): 14,592
    • Alpine + छोटा app (25MB): 583
    • Ubuntu + Python (120MB): 121
    • Java microservice (500MB): 29
  • वास्तविक सीमा

    • Memory के अलावा ये बातें भी मायने रखती हैं:
      • CPU scheduling: बहुत ज़्यादा containers compete करें तो latency spikes हो सकते हैं
      • File descriptors: default ulimit 1024
      • Network ports: port mapping में सिर्फ 65,535 ports उपलब्ध
      • PIDs: /proc/sys/kernel/pid_max limit (default: 32,768)
      • Disk I/O: OverlayFS overhead, कई layers में lookup की ज़रूरत
    • 16GB VM पर real workloads चलाने में practical limit:
      • Lightweight containers (API, worker): 50-100
      • Medium containers (DB, cache): 10-30
      • Large containers (ML models, JVM apps): 5-10

Linux distribution compatibility

  • Kernel ABI promise

    • Linux stable syscall interface बनाए रखता है
    • पुराने kernel के लिए compiled binaries नए kernel पर भी चल सकते हैं
    • Ubuntu 18.04 binary kernel 6.5 पर सामान्य रूप से चल सकता है
  • Compatibility कब टूटती है

    • Kernel feature requirements: जब container को ऐसा feature चाहिए जो kernel में हो ही नहीं (जैसे io_uring के लिए kernel 5.1+ चाहिए)
    • Kernel module dependency: Wireguard के लिए wireguard kernel module चाहिए, NVIDIA container के लिए nvidia kernel driver चाहिए
    • Seccomp/capability restrictions: जब host container को चाहिए syscall block कर दे (जैसे ptrace के लिए --cap-add SYS_PTRACE चाहिए)

Base image चुनने की guide

Base image Size Package manager Use case
scratch 0 MB none statically compiled Go/Rust binary
alpine 7 MB apk minimal container, musl libc
distroless 20 MB none security-focused, shell/package manager नहीं
debian-slim 80 MB apt size और compatibility का balance
ubuntu 78 MB apt development-friendly
fedora 180 MB dnf latest packages, SELinux
  • कौन-सी image कब इस्तेमाल करें

    • scratch: statically compiled binaries के लिए, इसमें binary के अलावा कोई OS component नहीं होता
    • alpine: shell access चाहिए तो minimal image, लेकिन glibc की जगह musl libc होने से कुछ compatibility issues हो सकते हैं
    • distroless: security-focused production image, shell और package manager नहीं होने से debugging कठिन, लेकिन ज़्यादा सुरक्षित

User space और kernel की boundary

  • Base image से क्या आता है (user space)

    • shell (/bin/bash, /bin/sh)
    • C library (glibc, musl)
    • package managers (apt, apk, yum)
    • core utilities (ls, cat, grep)
    • init system configuration (आमतौर पर systemd खुद नहीं)
    • default users और groups (/etc/passwd)
    • library paths और settings
  • Host से क्या आता है (kernel)

    • process scheduling और memory management
    • network stack (TCP/IP, routing)
    • filesystem operations (read, write, mount)
    • security features (namespaces, cgroups, seccomp)
    • device drivers (GPU, network, storage)
    • time और clock management
    • encryption और random number generation
  • Namespaces जो illusion बनाते हैं

    • kernel namespaces देता है, जिससे container खुद को isolated महसूस करता है
    • container के अंदर PID 1 दिखने वाला process, host पर ज़्यादा बड़े PID (जैसे 45678) के रूप में मौजूद हो सकता है
    • kernel यह mapping बनाए रखता है: container PID 1 → host PID 45678
    • virtualization के बिना isolation के काम करने का यही तरीका है

Production environment में इसका मतलब

  • 1. Kernel vulnerability सभी containers को प्रभावित करती है

    • host kernel में vulnerability हो तो सभी containers expose हो जाते हैं
    • host patching बनाए रखना अनिवार्य है
  • 2. Host kernel ही container features की सीमा तय करता है

    • io_uring इस्तेमाल करने के लिए host kernel 5.1+ चाहिए
    • eBPF features के लिए kernel 4.15+ चाहिए, और कुछ specific options enabled होने चाहिए
  • 3. glibc vs musl का महत्व

    • Alpine musl libc इस्तेमाल करता है
    • glibc के लिए compiled कुछ binaries शायद न चलें
    • उदाहरण: Alpine में glibc binary चलाते समय /lib/x86_64-linux-gnu/libc.so.6 missing file error आ सकता है
  • 4. Container “OS” सिर्फ organization की अवधारणा है

    • kernel के नज़रिए से “Ubuntu container” और “Debian container” में कोई अंतर नहीं
    • दोनों बस syscall करने वाले processes हैं

आम ग़लतफ़हमियाँ

  • ❌ "Containers lightweight VM हैं": container असल में advanced isolation वाले processes हैं; VM hardware virtualize करते हैं और अलग kernel चलाते हैं
  • ❌ "हर container का अपना kernel होता है": सभी containers host kernel share करते हैं; container का “OS” सिर्फ user-space files है
  • ❌ "Ubuntu container चलाना = Ubuntu चलाना": आप host kernel के ऊपर Ubuntu tools चला रहे होते हैं; अगर host Debian है, तो असल में Debian kernel ही चल रहा है
  • ❌ "Base image में पूरा operating system होता है": base image में सिर्फ minimal user-space tools होते हैं, kernel/bootloader/drivers नहीं
  • ❌ "ज़्यादा containers = ज़्यादा memory": shared layers और kernel page caching की वजह से containers अक्सर memory को कुशलता से share करते हैं

मुख्य सार

  • Docker base image Linux distribution के user-space components का filesystem snapshot होती है
    • यानी वे binaries, libraries और settings जो Ubuntu को Ubuntu जैसा महसूस कराते हैं
  • असली operating system यानी kernel host के साथ share होता है
  • इस architecture से ये संभव होता है:
    • Milliseconds में startup (क्योंकि kernel boot नहीं होता)
    • न्यूनतम memory overhead (एक kernel, shared pages)
    • उच्च density (एक host पर सैकड़ों containers)
    • Native के क़रीब performance (kernel को direct syscall)
  • इसका trade-off यह है कि isolation, VM की तुलना में कमज़ोर है — containers kernel share करते हैं, इसलिए kernel exploit सभी containers को प्रभावित कर सकता है
  • ज़्यादातर workloads के लिए यह trade-off काफ़ी फ़ायदेमंद है

अभी कोई टिप्पणी नहीं है.

अभी कोई टिप्पणी नहीं है.