Persisting Database - named volume

Persisting Database - named volume

named volume چیست؟

 پایدارکردن دیتابیس (Persisting Database) برنامه ی داکری

اگر تا الان متوجه نشده اید باید بگویم که Todo لیست مان با هربار راه اندازی کانتینر به صورت کامل پاک می شود. چرا اینطور می شود 🤔؟! بیایید شیرجه بزنیم داخل این که کانتینر چطوری کار میکند.

فایل سیستم کانتینر

وقتی یک کانتینر درحال اجراست، از لایه های متفاوتی از یک image برای فایل سیستم استفاده میکند. همچنین هر کانتینر یک فضای چرک نویس (scratch space) هم برای ایجاد ، به روزرسانی و حذف فایل ها دارد. هیچکدام از این تغییرات توسط کانتینرهای دیگر قابل مشاهده نیست، حتی اگر آن ها از یک image مشترک استفاده کنند.

بیایید این موضوع را در قالب یک تمرین ببینیم.

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

  1. یک کانتینر ubuntu را راه اندازی می کنیم که داخل آن یک فایل /data.txt است  و حاوی عددی تصادفی بین 1 تا 10000 خواهد بود.
docker run -d ubuntu bash -c "shuf -i 1-10000 -n 1 -o /data.txt && tail -f /dev/null"

درصورتی که درباره ی بخش های مختلف این دستور کنجکاو هستید، باید بگویم که ما یک دستور bash درست کردیم که دو دستور را اجرا می کند. دو دستور با && از هم جدا شده اند. تکه ی اول یک عدد تصادفی را انتخاب می کند و در فایل /data.txt می نویسد(shuf -i 1-10000 -n 1 -o /data.txt). و دستور دوم هم به سادگی یک فایل را در زمانی که کانتینر در حال اجرا است مشاهده می کند و تغییرات آن را نشان میدهد(tail -f /dev/null).

خب برای اینکه مطمئن شویم همه چیز درست پیش رفته است، باید خروجی exec در کانتینر را مشاهده کنیم. 

برای این کار اگر مثل من ترجیح می دهید از command line استفاده کنید می توانید با دستور docker exec، دستوری را داخل یک کانتینر اجرا کنید. برای این دستور احتیاج دارید id کانتینری که می خواهید داخل آن دستور را اجرا کنید داشته باشید. برای مشاهده ی اطلاعات و البته id کانتینرهای درحال اجرا، می توانید از دستور docker ps استفاده کنید. برای گرفتن محتویات آن فایل به راحتی دستور زیر را اجرا کنید.

docker exec <container-id> cat /data.txt

شما باید یک عدد تصادفی را در نتیجه ی این دستورات ببینید.

همچنین می توانیم از داشبرد داکر استفاده کنیم و در قسمت کانتینرها روی اولین قابلیتی که در اختیارمان گذاشته است کلیک کنیم.

نمایی از برنامه ی داشبرد داکر
نمایی از برنامه ی داشبرد داکر

 

در نتیجه ی این کار یک ترمینال برایتان باز میشود که دستورات شما را در داخل کانتینر ubuntu اجرا می کند. دستور زیر را در آن وارد کنید تا بتوانیم محتویات فایل /data.txt را مشاهده کنید.

cat /data.txt

حالا ترمینال را ببندید. 

  1. حالا برویم سراغ راه اندازی کانتینر ubuntu دوم از روی همان image قبلی و مشاهده خواهیم کرد که همان فایل با همان مقدار در این کانتینر وجود ندارد.
docker run -it ubuntu ls /

همانطور که می بینید با اینکه در کانتینر قبلی که از روی همین image ساخته بودیم فایل data.txt را ایجاد کرده ایم، ولی کانتینرهای بعدی که از روی همان image ساخته شده اند دیگر آن فایل را ندارند. دلیل این موضوع آن است که کانتینر نخست، آن فایل را در فضای اسکرچ یا چرک نویس خودش نوشته بود.

  1. حالا کانتینرتان را با دستور docker rm -f پاک کنید.

 

حافظه ی (volumes) کانتینر

طبق آزمایشی که انجام دادیم ، دیدیم که هر کانتینر با هر بار راه اندازی از روی image، به صورت تمیز راه اندازی می شود. درحالی که کانتینرها می توانند فایل هایی را ایجاد کنند، حذف کنند یا ویرایش کنند ولی همه ی این تغییرات با حذف کانتینر از بین می روند و تمام این تغییرات، فقط به همان کانتینر محدود شده است. با volumeها می توانیم این شرایط را تغییر دهیم.

Volumeها شرایطی را فراهم می کنند که بتوانیم به بخش خاصی از فایل سیستم ماشین میزبان وصل شویم. اگر یک مسیر(آدرس یک پوشه) در کانتینر mount شده باشد، هر تغییری در آن، در مسیر ماشین میزبان هم قابل مشاهده است. اگر وقتی که دوباره خواستیم کانتینری را راه اندازی کنیم همان مسیر را mount کنیم، تمام تغییرات را در کانتینر جدید هم خواهیم داشت.

دو نوع volume اصلی داریم که در نهایت هر دوی آنها را یاد خواهیم گرفت ولی در ابتدا قصد داریم با named volume ها شروع کنیم.

داده های برنامه ی Todo را حفظ کنیم.

به صورت پیش فرض برنامه ی Todo اطلاعاتش را در دیتابیس SQLite در آدرس /etc/todos/todo.db ذخیره می کند. اگر با SQLite آشنایی ندارید، نگران نباشید. به زبان ساده یک دیتابیس رابطه ایست که همه ی اطلاعات را در یک فایل ذخیره می کند. در حالی که این دیتابیس برای برنامه های بزرگ مناسب نیست ولی برای برنامه های کوچک یا دموهایی از برنامه، بسیار مفید و مناسب است. ما در ادامه ی آموزش ها، به مرحله ای می رسیم که این دیتابیس را با دیتابیس دیگری جایگزین خواهیم کرد.

با توجه به اینکه دیتابیس ما یک فایل است، اگر بتوانیم آن فایل را روی هاست ماندگار (Persist) کنیم و شرایطی را فراهم کنیم که کانتینر بعدی هم به آن دسترسی داشته باشد، اطلاعات برنامه ی ما (همان اطلاعاتی که در دیتابیس ذخیره شده است) باید در زمانی که کانتینر اول خاموش است یا پاک شده است هم قابل استفاده باشد. با ایجاد یک volume و وصل کردن (معمولا به این کار mountکردن گفته می شود.) آن به پوشه ای که دیتا در آن ذخیره شده است، ما می توانیم دیتاها را ماندگار کنیم. هر زمانی که کانتینر ما اطلاعاتی را در todo.db بنویسد، این اطلاعات در volume مشخص شده در Host (سیستم خودمان یا سرور) ماندگار می شود.

همانطور که قبلا هم اشاره شد، ما قصد داریم از named volume استفاده کنیم. یک named volume را به سادگی به عنوان سطلی از دیتا درنظر بگیرید. داکر یک موقعیت فیزیکی روی هارد دیسک را در نظر می گیرد و شما کافیست اسم آن volume را یادتان باشد. هربار که از volume ای استفاده می کنید، داکر اطمینان حاصل می کند که داده ی درست را برایتان فرآهم کرده است.

  1. با دستور docker create volume یک volume بسازید
Docker volume create todo-db
  1. کانتینر برنامه را متوقف و حذف کنید. این کار را به راحتی می توانید با دستور <docker rm -f <id انجام دهید.
  2. حالا کانتینر برنامه را دوباره راه اندازی کنید، اینبار پرچم -v را هم اضافه کنید تا یک volume مشخص را به آن اختصاص بدهیم. ما می خواهیم از یک named volume استفاده کنیم و آن را به /etc/todos وصل (mount) کنیم. تا تمام فایل های ایجاد شده و تغییر کرده در آن را ذخیره کند.
docker run -dp 3000:3000 -v todo-db:/etc/todos getting-started
  1. وقتی که کانتینر اجرا شد، برنامه را باز کنید و تعدادی آیتم به لیست تان اضافه کنید.
نمایی از برنامه ی ToDo List
نمایی از برنامه ی ToDo List
  1. حالا کانتینر را حذف کنید. دستور حذف را هم که یادتان هست <docker rm -f <id . برای بدست آوردن id کانتینر هم به سادگی از طریق دستور docker ps تمام اطلاعات کانتینر های درحال اجرا را بدست بیاورید.
  2. حالا دوباره با همان دستوری که دربالا گفتیم کانتینر جدیدی را راه اندازی کنید.
  3. برنامه را دوباره راه اندازی کنید. شما باید تمام آیتم هایی که به لیست اضافه کرده بودید را ببینید.

هووورررااا!🎉 شما توانستید داده هایتان را ماندگار کنید.

💡نکته ی حرفه ای

درحالی که موتور داکر (docker engine) به صورت پیشفرض از named volume ها و bind mount ها به عنوان دو نوع اصلی volume پشتیبانی می کند، تعداد زیادی پلاگین جهت پشتیبانی از NFS، SFTP، NetApp و ... هم در دسترس هستند. این نکته وقتی خیلی مهم می شود که کانتینرهایی، روی چندین Host در یک محیط خوشه ای (clustered environment) با Swarm ،  Kubernetes یا چیزهایی مثل اینها اجرا می کنید.

 

شیرجه در volume

افراد زیادی مکرر می پرسند که وقتی ما از named volume استفاده می کنیم داکر اطلاعات ما را واقعا کجا ذخیره می کند؟

اگر بخواهید جواب این سوال را بدانید، می توانید از دستور docker volume inspect استفاده کنید.

docker volume inspect todo-db
[
    {
       "CreatedAt": "2019-09-26T02:18:36Z",
       "Driver": "local",
       "Labels": {},
       "Mountpoint": "/var/lib/docker/volumes/todo-db/_data",
       "Name": "todo-db",
       "Options": {},
       "Scope": "local"
    }
]

در mountpoint شما می توانید آدرس دقیق جایی که named volume ذخیره شده است را مشاهده کنید. توجه داشته باشید که در بیشتر ماشین ها، برای دسترسی پیدا کردن به این دایرکتوری شما نیاز دارید دسترسی Root داشته باشید. به هرحال، اطلاعات در این آدرس ماشین میزبان ذخیره می شود.

دسترسی مستقیم به داده های volume در Docker Desktop

زمانی که شما Docker Desktop را اجرا می کنید، دستورات داکر، درواقع داخل یک ماشین مجازی اجرا می شود. اگر بخواهید محتوای واقعی مسیر گفته شده در Mountpoint را مشاهده کنید، باید ابتدا داخل VM بروید.

خلاصه

در این درس، کاری کردیم که عملکردها و اطلاعات برنامه از دست restart جان سالم به در ببرند!

جلوتر دیدیم که بازسازی imageها برای هر تغییری در برنامه می تواند وقت گیر باشد. راه بهتری برای اعمال تغییرات وجود دارد که bind mountها هستند. در بخش بعدی به این موضوع خواهیم پرداخت.

دوره در دست تالیف است ... rocket
نظرات
اگر login نکردی برامون ایمیلت رو بنویس: