روش نوشتن یک Dockerfile

یکی از بهترین روشهای تولید یک تصویر داکر (docker image)، نوشتن یک Dockerfile و سپس استفاده از دستور docker build است. این روش به دلیل سادگی و سازگاری با متدولوژی زیرساخت به صورت کد (Infrastructure as Code) به متداولترین راه برای تولید تصاویر داکر تبدیل شده است.

جهت اجرای دستورات گفته شده در این مقاله نیاز دارید قبلا داکر را نصب کرده باشید. روش نصب داکر روی ویندوز یا لینوکس CentOS را میتوانید در همین سایت مطالعه کنید. همچنین برای یادگیری بهتر این مطلب ممکن است آشنایی با مفاهیم پایه ای داکر به شما کمک کند.

ساده ترین Dockerfile

ساده ترین Dockerfile میتواند تنها شامل یک خط باشد که مشخص میکند کدام تصویر قرار است به عنوان تصویر پایه برای تولید یک تصویر جدید بکار گرفته شود. به عنوان مثال کافیست در یک پوشه فایلی با این محتویات و با نام Dockerfile ایجاد کنید:

    FROM debian:wheezy

سپس میتوانید با اجرای دستور docker build -t my-first-image $PWD در همان پوشه، اولین تصویر داکر خود را بسازید. در این حالت تصویر جدید کاملا مشابه تصویر پایه خواهد بود، که در این مثال نسخه Wheezy از سیستم عامل Debian است.

در نهایت با اجرای دستور docker images میتوانید تمامی تصاویر موجود روی ماشین داکر خودتان را لیست کنید که شامل تصویر جدید نیز میشود:

    $ docker images
    REPOSITORY         TAG       IMAGE ID       CREATED        SIZE
    debian             wheezy    2e9c7e5da19c   12 days ago    84.92 MB
    my-first-image     latest    2e9c7e5da19c   12 days ago    84.92 MB

همانطور که مشاهده میکنید شناسه های (ID) هر دو این تصاویر دقیقا یکسان هستند و حتی با اینکه تصویر جدید لحظاتی قبل تولید شده است، زمان ایجاد آن چند روز قبل و همزمان با تصویر پایه نشان داده میشود. این بدین دلیل است که دستور docker build‍ تشخیص میدهد که تصویر جدید هیچ تغییراتی نسبت به تصویر پایه ندارد و بنابراین نیازی به اختصاص فضا و شناسه جدید نیست. در واقع با این کار تنها یک نام جدید برای همان تصویر قبلی تولید شده است که این کار را میتوان با کمک دستور docker tag نیز به سادگی و بدون نیاز به Dockerfile انجام داد.

اضافه کردن فایل به تصویر

اگر فایلی مثلا به نام test.sh در همان پوشه داشته باشید میتوانید با اضافه کردن یک خط دیگر در Dockerfile این فایل را به مجموعه فایلهای موجود در تصویر خود اضافه کنید:

    FROM debian:wheezy
    COPY test.sh /test.sh

در این حالت خروجی دستور docker build به صورت زیر خواهد بود:

    $ docker build -t my-second-image .
    Sending build context to Docker daemon  2.56 kB
    Step 1 : FROM debian:wheezy
    ---> 2e9c7e5da19c
    Step 2 : COPY test.sh /test.sh
    ---> 0ff656c325b7
    Removing intermediate container 32821b2cd6d4
    Successfully built 0ff656c325b7

نکته قابل توجه در این خروجی وجود دو مرحله در ساخت این تصویر جدید است. حالا اگر لیست تصاویر موجود را مجددا بررسی کنید متوجه خواهید شد که تصویر جدید، به نام my-second-image، شناسه ای متفاوت از تصویر پایه دارد و در زمان جدیدتری نیز ساخته شده است:

   $ docker images
   REPOSITORY         TAG       IMAGE ID       CREATED        SIZE
   my-second-image    latest    0ff656c325b7   7 minutes ago  84.92 MB
   debian             wheezy    2e9c7e5da19c   12 days ago    84.92 MB
   my-first-image     latest    2e9c7e5da19c   12 days ago    84.92 MB

مشابه همین روش را میتوانید برای اضافه کردن یک پوشه به تصویر بکار ببرید. دقت کنید که حجم تصویر جدید بسته به تعداد و اندازه فایلهای اضافه شده بزرگتر از تصویر پایه خواهد شد.

نکته: اگر بدون هیچ تغییری در هیچ یک از فایلها، دوباره اقدام به ساخت همین تصویر کنید متوجه خواهید شد که دفعه دوم فرآیند ساخت بسیار سریعتر و تقریبا به صورت آنی تمام میشود. علت این امر آن است که داکر برای هر مرحله یک تصویر میانی میسازد و تمامی این تصاویر میانی را به صورت موقت نگهداری میکند تا فرآیند ساخت را تسریع کند.

برای اینکه محتویات تصویر جدید را مشاهده کنید و از وجود فایلهای خود مطمئن شوید میتوانید اقدام به اجرای یک پوسته (shell) در یک کانتینر از این تصویر کنید:

   $ docker run --rm -ti my-second-image /bin/sh
   # ls -l /test.sh
   -rw-r--r-- 1 root root 0 May 16 13:32 /test.sh

در صورت نیاز برای آشنایی بیشتر با فرامین داکر میتوانید دستورات پرکاربرد داکر را مطالعه کنید.

همچنین لازم به ذکر است که دستور COPY مشابه قدیمی تری به نام ADD دارد که در حال حاضر کمتر استفاده میشود. این دو دستور تفاوتهایی با یکدیگر دارند، مانند اینکه در دستور ADD میتوان یک آدرس وب را بجای مبدا برای اضافه کردن یک فایل به تصویر استفاده کرد.

نصب برنامه ها روی تصویر

با استفاده از دستور RUN در یک Dockerfile میتوانید برنامه هایی را که در حال حاضر روی تصویر شما نصب نیستند به آن اضافه کنید. این دستور به طور کلی برای اجرای هر برنامه ای در زمان ساخت تصویر کاربرد دارد. به عنوان مثال Dockerfile زیر برنامه unzip را روی یک تصویر پایه نصب میکند:

    FROM debian:wheezy
    RUN apt-get update
    RUN apt-get install -y --no-install-recommends unzip
    RUN rm -rf /var/lib/apt/lists/*

نکته: هدف از خط آخر که دستور rm را اجرا میکند حذف فایلهای غیرضروری از تصویر ساخته شده پس از نصب برنامه هاست تا حجم آن بیش از حد افزایش پیدا نکند. اما از آنجایی که هر دستور RUN در Dockerfile یک لایه جدید به تصویر اضافه میکند، بدون اینکه هیچ تغییری در لایه های قبلی بدهد، این هدف با این روش محقق نمیشود.

اگر این تصویر را با اجرای دستور docker build -t my-unzip-image $PWD بسازید متوجه خواهید شد که ۴ مرحله طی میشود که منجر به ساخت ۴ لایه جدید خواهد شد. این روش در زمان توسعه یک Dockerfile بسیار مفید است زیرا هر بار که تغییری در فایلی بدهید و بخواهید تصویر خود را مجددا بسازید تنها دستوراتی که تغییر کرده اند اجرا خواهند شد و به این ترتیب فرآیند توسعه و عیب یابی با سرعت بیشتری پیش خواهد رفت. اما پس از اینکه از درستی فایل خود مطمئن شدید بهتر است برای بهینه کردن این تصویر آن را به صورت زیر بازنویسی کنید تا تنها یک دستور RUN در آن بکار گرفته شود:

   FROM debian:wheezy
   RUN apt-get update && \
       apt-get install -y --no-install-recommends unzip && \
       rm -rf /var/lib/apt/lists/*

این روش تنها یک لایه به تصویر پایه اضافه میکند که منجر به ساخت تصویری کوچکتر با تعداد لایه های کمتر خواهد شد که برای انتشار و استفاده کاربران مناسبتر است.

مشخص کردن یک برنامه پیش فرض برای کانتینر

در مدل توصیه شده داکر، هر کانتینر بناست فقط پردازه هایی از یک نوع برنامه اجرایی را شامل شود. با کمک دستور CMD که معمولا در انتهای Dockerfile آورده میشود میتوان یک دستور اجرایی را به صورت پیش فرض برای یک تصویر مشخص کرد که این دستور در نهایت در زمان اجرای یک کانتینر از روی تصویر ساخته شده استفاده خواهد شد. به عنوان مثال Dockerfile زیر دستور unzip را برای اجرا روی تصویر مشخص میکند:

   FROM debian:wheezy
   RUN apt-get update && \
       apt-get install -y --no-install-recommends unzip && \
       rm -rf /var/lib/apt/lists/*
   CMD ["unzip"]

پس از ساختن یک تصویر از روی این فایل با دستور docker build -t my-unzip-image $PWD و سپس اجرای یک کانتینر روی آن، خروجی به صورت زیر خواهد بود که نشان میدهد برنامه unzip با موفقیت اجرا شده است:

   $ docker run --rm -ti my-unzip-image
   UnZip 6.00 of 20 April 2009, by Debian. Original by Info-ZIP.
   Usage: unzip [-Z] [-opts[modifiers]] file[.zip] [list] [-x xlist] [-d exdir]
     Default action is to extract files in list, except those in xlist, to exdir;
     file[.zip] may be a wildcard.  -Z => ZipInfo mode ("unzip -Z" for usage).
   ...

دقت کنید که شما همچنان میتوانید در صورت نیاز برنامه های دیگری را به سادگی روی این تصویر اجرا کنید. برای این کار کافیست در انتهای دستور docker run‍ نام برنامه اجرایی مورد نظرتان را ذکر کنید تا به جای دستور پیش فرض اجرا شود.

نکته: دستور مشابه دیگری به نام ENTRYPOINT نیز برای مشخص کردن برنامه پیش فرض وجود دارد که تنها برای کاربردهای پیچیده تر توصیه میشود.

در انتها اگر تمایل دارید با یک کاربرد واقعی از ‌Dockerfile آشنا شوید میتوانید شیوه استفاده از داکر برای اجرای یک برنامه تحت وب جاوا را مطالعه کنید.