وبلاگ نت‌آرامآموزش، تجربه و راهکارهای زیرساخت

رفع exec format error در Docker؛ معماری image و سرور چرا با هم نمی‌خواند؟

آموزش مقایسه معماری سرور و image، ساخت نسخه مناسب با buildx و بررسی فایل اجرایی و اسکریپت آغاز Docker.

انتشار:
توسط تیم فنی نت‌آرام
۸ دقیقه زمان مطالعه
۰ دیدگاه
محتوای تخصصی، ساده و کاربردی
هماهنگ با هویت حرفه‌ای نت‌آرام
بازگشت به لیست مقالات
تصویر شاخص مقاله رفع exec format error در Docker؛ معماری image و سرور چرا با هم نمی‌خواند؟ در وبلاگ نت‌آرام
محتوای آموزشی وبلاگ نت‌آرام
یک image روی لپ‌تاپ شما ساخته شده، اما پس از انتقال به سرور، کانتینر با exec format error متوقف می‌شود. یکی از علت‌های رایج، تفاوت معماری پردازنده است: مثلاً فایل اجرایی برای ARM64 ساخته شده اما سرور به اجرای نسخه AMD64 نیاز دارد. البته همین پیام می‌تواند از اسکریپت شروع نامناسب یا فایل اجرایی ناسازگار هم بیاید.
معماری را می‌توان مانند زبان پردازنده در نظر گرفت. فایل آماده‌شده برای یک زبان لزوماً روی پردازنده دیگر اجرا نمی‌شود، مگر محیط اجرای سازگار یا شبیه‌ساز مناسب وجود داشته باشد. در این راهنما معماری سرور، image و فایل داخل آن را جدا بررسی می‌کنیم و سپس راه اصلاح را انتخاب می‌کنیم.
به ترمینال سرور و دسترسی مجاز به Docker نیاز دارید. myapp و registry.example.com/team/myapp:v1 نمونه‌اند و باید با نام واقعی کانتینر و image شما عوض شوند. از image و داده‌های فعلی نسخه قابل بازگشت داشته باشید و آزمایش را ابتدا با نام و tag جداگانه انجام دهید.

۱. خطای واقعی و image مورد استفاده را ببینید

کد / دستورdocker ps -a --filter 'name=myapp'
اگر کانتینر خیلی سریع متوقف شده، ستون STATUS و نام دقیق آن را یادداشت کنید. سپس گزارشش را ببینید:
کد / دستورdocker logs --tail 100 myapp
پیام exec format error و نام فایلی که هنگام شروع خطا داده مهم‌اند. اگر به جای آن permission denied می‌بینید، مجوز اجرای فایل یا سیاست امنیتی مسیر جداگانه‌ای دارد. اگر no such file or directory است، نبودن فایل، مفسر shebang یا کتابخانه لازم هم ممکن است علت باشد.
برای دیدن شناسه image که همین کانتینر واقعاً با آن ساخته شده:
کد / دستورdocker inspect --format '{{.Image}}' myapp
این خروجی شناسه image را می‌دهد. از آن استفاده کنید، چون ممکن است tag پس از ساخته شدن کانتینر تغییر کرده باشد. برای دیدن فرمان و entrypoint تنظیم‌شده:
کد / دستورdocker inspect --format '{{json .Config.Entrypoint}} {{json .Config.Cmd}}' myapp
خروجی می‌تواند مسیرها یا حتی آرگومان‌های حساس داشته باشد؛ قبل از اشتراک‌گذاری آن‌ها را حذف کنید.

۲. معماری سرور و Docker را مقایسه کنید

روی سروری که Docker واقعاً در آن اجرا می‌شود:
کد / دستورuname -m
x86_64 معمولاً به خانواده AMD64 و aarch64 معمولاً به ARM64 اشاره دارد. اکنون معماری و نوع سیستم‌عامل Docker daemon را ببینید:
کد / دستورdocker info --format '{{.OSType}}/{{.Architecture}}'
نام‌ها ممکن است به شکل linux/x86_64 یا قالب دیگر نشان داده شوند. اگر از Docker context راه دور یا Docker Desktop استفاده می‌کنید، uname -m روی رایانه مشتری لزوماً معماری daemon را نشان نمی‌دهد. نام context را کنترل کنید:
کد / دستورdocker context show
اگر context به سرور دیگری وصل است، اطلاعات همان daemon معیار مهم‌تری است. تفاوت Windows containers با Linux containers هم می‌تواند مطرح باشد؛ این راهنما برای کانتینرهای Linux است.

۳. image محلی برای چه معماری ثبت شده است؟

شناسه‌ای را که در مرحله اول گرفتید به جای IMAGE_ID بگذارید:
کد / دستورdocker image inspect IMAGE_ID --format '{{.Os}}/{{.Architecture}}'
اگر سرور linux/amd64 است و image فقط linux/arm64 نشان می‌دهد، ناسازگاری معماری یک احتمال قوی است. اگر یک tag در registry چند معماری دارد، فهرست آن را نیز می‌توانید ببینید:
کد / دستورdocker buildx imagetools inspect registry.example.com/team/myapp:v1
این دستور از registry اطلاعات می‌خواند و ممکن است به دسترسی شبکه و ورود مجاز نیاز داشته باشد. در بخش platform دنبال linux/amd64 یا linux/arm64 مناسب بگردید. اگر Buildx در نسخه شما موجود نیست، docker manifest inspect --verbose نیز در نسخه‌های پشتیبانی‌شده می‌تواند اطلاعات manifest را نشان دهد.
نکته مهم: برچسب معماری image به‌تنهایی ثابت نمی‌کند همه فایل‌های داخل آن برای همان معماری ساخته شده‌اند. ممکن است image با برچسب AMD64 ساخته شده باشد اما یک فایل ARM از لپ‌تاپ داخل آن کپی شده باشد.

۴. اگر نسخه مناسب در registry موجود است

اگر image رسمی یا image خودتان برای معماری سرور منتشر شده، نسخه مناسب را از منبع معتبر دریافت کنید. نمونه زیر برای سرور AMD64 است:
کد / دستورdocker pull --platform linux/amd64 registry.example.com/team/myapp:v1
این فرمان image را در cache محلی دریافت می‌کند و ممکن است tag محلی را تغییر دهد؛ پیش از آن مطمئن شوید tag، digest و برنامه بازگشت را می‌شناسید. در سرور ARM64 از linux/arm64 استفاده کنید. با docker image inspect معماری image دریافت‌شده را ببینید و سپس در محیط آزمایشی، با تنظیمات برنامه و داده آزمایشی اجرا کنید. کانتینر تولیدی را فقط پس از تأیید، طبق روش استقرار خود جایگزین کنید.
اگر registry نسخه مناسب ندارد، تغییر نام tag یا نوشتن --platform به‌تنهایی فایل ARM را به AMD تبدیل نمی‌کند. باید سازنده، نسخه سازگار منتشر کند یا شما آن را از منبع معتبر برای معماری مقصد بسازید.

۵. اگر خودتان image می‌سازید

در پوشه پروژه ابتدا قابلیت builder را ببینید:
کد / دستورdocker buildx version کد / دستورdocker buildx inspect --bootstrap
خروجی دوم می‌تواند builder را آماده کند و پلتفرم‌های قابل استفاده آن را نشان دهد؛ در محیط مدیریت‌شده پیش از راه‌اندازی builder اثر آن را بررسی کنید. برای ساخت یک نسخه آزمایشی AMD64 با tag تازه:
کد / دستورdocker buildx build --platform linux/amd64 -t myapp:architecture-test --load .
--load در این مثال نتیجه تک‌معماری را به image store محلی می‌آورد. نقطه آخر یعنی Dockerfile و context از پوشه فعلی خوانده می‌شوند. مطمئن شوید tag آزمایشی از قبل به image مهمی اشاره ندارد؛ build می‌تواند tag محلی را به نتیجه تازه تغییر دهد. سپس:
کد / دستورdocker image inspect myapp:architecture-test --format '{{.Os}}/{{.Architecture}}'
باید معماری موردنظر را ببینید. اگر Dockerfile در مرحله ساخت فایل آماده‌ای را از بیرون کپی می‌کند، آن فایل هم باید برای همان معماری باشد؛ تنظیم platform برچسب فایل اشتباه را اصلاح نمی‌کند.
برای پروژه Go که از cross-compilation بدون وابستگی C پشتیبانی می‌کند، نمونه ساخت فایل Linux AMD64 در پوشه پروژه چنین است:
کد / دستورGOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o app-linux-amd64 .
این دستور به Go و منبع سازگار نیاز دارد. اگر برنامه به CGO یا کتابخانه‌های بومی وابسته است، CGO_ENABLED=0 ممکن است مناسب نباشد؛ از روش build مستند همان پروژه استفاده کنید. برای هدف ARM64، مقدار GOARCH را arm64 بگذارید. فایل ساخته‌شده را پیش از انتقال کنترل کنید:
کد / دستورfile app-linux-amd64
خروجی باید فایل Linux ELF با معماری موردنظر را نشان دهد. ابزار file ممکن است روی برخی سیستم‌ها نصب نباشد. مطمئن شوید Dockerfile واقعاً همین خروجی جدید را وارد image می‌کند.

۶. اگر معماری image درست است، فایل شروع را بررسی کنید

اگر entrypoint یک اسکریپت است، خط اول آن باید مفسری را مشخص کند که داخل image وجود دارد؛ برای مثال #!/bin/sh وقتی آن پوسته در image موجود است. نبودن shebang یا فرمت نامناسب اسکریپت می‌تواند باعث شکست اجرا شود. اسکریپتی که در Windows با پایان خط CRLF ذخیره شده، گاهی باعث خطای پیدا نشدن مفسر می‌شود؛ این پیام دقیقاً همیشه exec format error نیست.
روی فایل منبع پروژه:
کد / دستورhead -n 1 entrypoint.sh | cat -A
دیدن ^M پیش از $ می‌تواند نشان‌دهنده CRLF باشد. در ویرایشگر فایل را با پایان خط LF ذخیره کنید، مطمئن شوید shebang و مفسر صحیح‌اند و پس از نسخه پشتیبان یا کنترل نسخه، image را دوباره بسازید. مجوز اجرای اسکریپت نیز باید در image درست باشد؛ خطای مجوز را با خطای معماری اشتباه نگیرید.
اگر image برچسب درست دارد ولی فایل اجرایی داخل آن مشکوک است، در یک محیط آزمایشی و با روش ایمن آن را از image بررسی کنید یا مرحله build را طوری تنظیم کنید که معماری فایل ساخته‌شده در خروجی build نمایش داده شود. اسکریپت‌های ناشناس را صرفاً برای امتحان روی سرور اصلی اجرا نکنید.

۷. معماری چندگانه و بررسی نهایی

برای انتشار یک tag چندمعماری، builder باید بتواند برای هر معماری بسازد؛ بسته به محیط، این کار با چند node بومی، cross-compilation یا emulation انجام می‌شود. شبیه‌سازی ممکن است کندتر باشد و همه برنامه‌ها رفتار یکسانی نداشته باشند. دستور زیر فقط یک نمونه است و image را به registry می‌فرستد؛ آن را فقط با مخزن و tag متعلق به خودتان، پس از آزمون و مجوز انتشار اجرا کنید:
کد / دستورdocker buildx build --platform linux/amd64,linux/arm64 -t registry.example.com/team/myapp:test --push .
با docker buildx imagetools inspect دوباره فهرست معماری‌ها را ببینید و هر نسخه را روی محیط سازگار آزمایش کنید. در نهایت هم شروع کانتینر، لاگ‌ها و کار واقعی برنامه را بررسی کنید؛ نشان دادن معماری درست در inspect به‌تنهایی کافی نیست.
این اصول هنگام انتقال برنامه به سرور مجازی ایران یا سرور اختصاصی ایران کاربرد دارند. اگر کانتینر اجرا می‌شود اما آزمون سلامت آن شکست می‌خورد، راهنمای وضعیت unhealthy در Docker مسئله دیگری را توضیح می‌دهد. جزئیات روش‌های ساخت را در مستند image چندپلتفرمی Docker ببینید.
اشتراک‌گذاری:
لینکدینتلگرامایکس
مقاله قبلی
مقاله قبلی وجود ندارد.

دیدگاه‌ها (۰)

دیدگاه‌های تاییدشده و پاسخ‌های تیم نت‌آرام