در این سری مقالهها قصد دارم به صورت کامل در مورد داکر و دستوراتی که برای آن وجود دارد صحبت کنم و آرشیوی کلی از داکر و نکات مهم اولیه ای که لازم است را بنویسم. موارد و نکاتی که برای یادگیری عمیق تر داکر لازم و ضروری است.
داکر چیست؟!
Docker مجموعه ای از محصولات پلت فرم به عنوان سرویس (Platform as a service = PaaS) است که از مجازی سازی در سطح سیستم عامل برای ارائه نرم افزار در بسته هایی به نام کانتینر استفاده می کند. نرم افزاری که کانتینرها را میزبانی می کند Docker Engine نامیده می شود. اولین بار در سال ۲۰۱۳ شروع شد و توسط Docker, Inc توسعه یافته است. (ویکیپدیا)
داکر چگونه کار میکند؟!
تصور کنید که که ما اپلیکیشنی که داریم را در یک محیط داکرایز قرار دادیم در این صورت اپلیکیشن ما به صورت یک پکیج بسته بندی شده در اختیار بقیه قرار میگیرد و حتی میتوانیم از این پکیج نمونه های دیگری را هم کپی بگیریم. همه این نمونه ها و این پکیج بر روی کرنل لینوکس قرار میگیرند و داکر با استفاده از ۲ ویژگی که کرنل لینوکس ارایه میدهد این کار را انجام میدهد.
- Linux Namespace: each process sees its own personal view of the system (files, process, network interface, hostname,…)
- Linux control Groups: limit the number of resources the process can consume (CPU, memory, network bandwidth,…)
پس در واقع وقتی از داکر استفاده میکنیم، قطعا از کرنل لینوکس استفاده میکند و اگر روی سیستم عاملهای دیگری بخواهیم از داکر استفاده کنیم ابزارهایی هستند که در بکگراوند برای راه اندازی داکر کرنل لینوکس را ابتدا فراهم میکنند که بتوانیم از داکر استفاده کنیم.
Docker Registry
همانطور که ما برای پکیج های مختلف پروژه ها به زبانهای مختلف از سیستمهایی همچون پکیج منیجر استفاده میکنیم برای اینکه ما برای داکر بتوانیم پکیجهایی که داریم را در اختیار بقیه قرار دهیم از Registry استفاده میکنیم. برای اینکار ابتدا از پکیج Build میگیریم و سپس یک image از آن میسازیم و این image فایلی است که قابل حمل است و از آن نمونه میگیریم و میتوانیم از آن استفاده کنیم. وقتی که ما image را در resistry قرار دهیم و آن را push کنیم هر شخصی میتواند از آن استفاده کند یعنی آن را pull میکند و برای استفاده در نرم افزار خودش آن را Deploy میکند، همانطور که ما میتوانیم imageهایی که لازم داریم را از آنجا pull و در نهایت Deploy کنیم.
در واقع وقتی ما Image را Deploy میکنیم و یک نمونه از Image را در نرم افزار خود استفاده میکنیم، یک container از آن میسازیم و container اجرا میشود. همچنین ما میتوانیم همزمان چندین نمونه از container را اجرا کنیم و در طول کل اجرا ما درگیر جزئیات نحوه اجرای نرم افزار نمیشویم و همه موارد داخل پکیج و image لحاظ شده است. این همان کاری است که Docker برای ما انجام میدهد. در واقع ما درگیر Dependencyها و اینکه چه نسخه ای از نرم افزارها را نصب کنیم و این نرم افزارها در همه محیطهای development و production یکی باشد نخواهیم بود و با استفاده از داکر هم میتوانیم این محیط یکسان را داشته باشیم و هم به روند توسعه راحتتر پروژه و تخصیص منابع و بهینه سازی بهتر پروژه کمک کنیم.
وقتی میخواهیم یک image نصب کنیم و از دستورات داکر استفاده میکنیم به صورت پیشفرض منبع و سورس image داکرهاب درنظر گرفته میشود مگر اینکه آدرس image و رجستری را بنویسیم و وقتی که میخواهیم image را از داکرهاب نصب کنیم مشخصات لاگین با اکانت توی داکرهاب را باید وارد کنیم که برای دفعات بعد این مشخصات ذخیره میشود.
برای pullکردن یک image دستور زیرا در محیط ترمینال اجرا میکنیم، برای هر image معمولا Version tagهایی وجود دارد که اگر آن را ننویسیم به صورت پیشفرض آخرین ورژن pull میشود
docker pull image_name:tag
اگر دستور زیر را در محیط ترمینال خود اجرا کنید، یک container nginx ایجاد و اجرا میشود اما چگونه؟!
docker container run --publish 80:80 nginx
داکر در پشت پرده دنبال یک image به اسم nginx میگردد، اگر آن را در کش لوکال پیدا کند از آن استفاده میکند در غیر اینصورت آخرین ورژن آن را از Registry دانلود میکند، در قدم بعدی یک container از آن میسازد و آن را run میکند و در واقع بخش publish آن پورت ۸۰ لوکالهاست من را به پورت ۸۰ داخل container وصل میکند و به صورت اتوماتیک همه ترافیکهایی که روی پورت ۸۰ لوکال من قرار میگیرد به پورت ۸۰ داخل container انتقال داده میشود. بعد از اجرای دستور فوق با باز کردن localhost خود روی مرورگر میتوانید پیام nginx را مشاهده کنید.
(اگر میخواهید از محیط اجرا خارج شوید با فشار دادن دکمه های Ctr + c میتوانید آن را متوقف کنید.)
اگر میخواهید دستور فوق را در بکگراوند اجرا کنید، یعنی container در حال اجرا باشد ولی از محیط اجرای contsiner روی ترمینال خارج شوید به کامند فوق –detach را اضافه کنید.
docker container run --publish 80:80 --detach nginx
بعد از اجرای دستور فوق یک Unique Container ID چاپ میشود.
نکته: همانطور که قبلا اشاره کردم، ما میتوانیم یک image ایجاد کنیم و آن را توی Docker Registry قرار دهیم، وقتی که ما برای ایجاد image موردنیازمون از سایر imageهایی که داخل Docker Registry وجود دارد استفاده میکنیم و به نوعی برای آن Dependencyهایی ایجاد میکنیم، وقتی که میخواهیم imageی که ایجاد کردیم را push کنیم این imageهایی که قبلا استفاده کردیم همراه image ما push نمیشود و فقط اسم و مشخصات آن قرار میگیرد و در حین استفاده و نصب مجدد docker از registry آن را دانلود میکند، دقیقا مثل نصب پکیجهای php که داخل vendorقرار میگیرند و یا پکیجهای node_modules…
تفاوت image و container
- یک image در واقع اپلیکیشنی است که ما میخواهیم اجرا کنیم.
- یک container در واقع یک نمونه از imageی است که میخواهیم آن را اجرا کنیم.
- ما میتوانیم تعداد زیادی container داشته باشیم که از یک image ساخته شده اند.
همانطور که ما برای پروژهها و پکیجهای مختلف ورژن کنترلی مانند github داریم برای imageهایی هم که موجود هستند از Docker Hub استفاده میکنیم.
نکته: وقتی میخواهیم یک image نصب کنیم به صورت پیشفرض منبع و سورس image داکرهاب درنظر گرفته میشود مگر اینکه آدرس image و رجستری را بنویسیم و وقتی که میخواهیم image را از داکرهاب نصب کنیم مشخصات لاگین با اکانت توی داکرهاب را باید وارد کنیم که برای دفعات بعد این مشخصات ذخیره میشود. برای هر image معمولا Version tagهایی وجود دارد که اگر آن را ننویسیم به صورت پیشفرض آخرین ورژن pull می شود.
دستورات داکر Docker
نمایش ورژن داکر
docker --version
/// output: Docker version 17.12.0-ce, build c97c6d6
نمایش ورژن داکر به همراه جزئیات بیشتر
docker version
// Output
Client: Docker Engine - Community
Version: 18.09.0
API version: 1.39
Go version: go1.10.4
Git commit: 4d60db4
Built: Wed Nov 7 00:47:43 2018
OS/Arch: darwin/amd64
Experimental: false
نمایش اطلاعات با جزئیات در مورد داکر
docker info
// Output
Containers: 0
Running: 0
Paused: 0
Stopped: 0
Images: 0
Server Version: 17.12.0-ce
Storage Driver: overlay2
...
تفاوت run و start موقع اجرای یک container
ما میتوانیم به دو صورت زیر یک container را اجرا کنیم، تفاوت این دو دستور چیست؟
docker container run IMAGE_NAME
docker container start IMAGE_NAME
وقتی از run استفاده میکنیم، همیشه یک container جدید ساخته میشود ولی وقتی از start استفاده میکنیم containerی که وجود دارد و قبلا stop شده است اجرا میشود.
نمایش لیست imageهای داکر
docker image ls
نمایش لیست تمام imageهای داکر
docker container ls -a / docker image ls --all
نمایش لیست containerها
docker container ls ## running container
docker container ls --all / docker container ls -a ## list of the all containe
docker container ls -aq ## all container ID in quiet mode
مشاهده لاگهای یک container
docker container logs CONTAINER_NAME
(Show logs for a specific container)
مشاهده پردازشهای یک container
docker container top CONTAINER_NAME
(Display the running processes of a container)
حذف یک container
به صورت پیشفرض ما فقط میتوانیم containerی را که در حالت اجرا نیست حذف کنیم ولی با اضافه کردن کامند -f میتوانیم آن را force کنیم که حذف شود.
docker container rm CONTAINER_NAME
docker container rm -f CONTAINER_NAME
مشاهده config یک container با جزئیات آن
وقتی بخواهیم کانفیگ یک کانتینر را بررسی کنیم از جمله network, valum,… و همه مواردی که وجود دارد با استفاده از inspect اینکار را انجام میدهیم.
docker container inspect CONTAINER_NAME
(Details of a container configuration)
نمایش پرفرمنس و میزان مصرف containerها
طبق تجربه ای که قبلا داشتم برای یکی از APIهایی که توی پروژه داشتیم به خاطر query سنگینی که توی دیتابیس داشتیم خطای پرشدن مصرف مموری را توی لاگ خطاهای پروژه داشتیم یکی از کارهایی که کردم مانیتور container و بهبود و مقایسه میزان مصرف مموری طی هر ریفکتور بود.
docker container stats
(Display performance states for all containers)
اجرای دستورات داخل container
در ابتدا قبل از اینکه استفاده از option مورد نظر یعنی -it رو توضیح بدیم با استفاده از کامند –help ساختار کامند داکر را بررسی کنیم:
با اجرای دستور docker container run –help لیستی از optionهایی که میتوانیم از آنها استفاده کنیم و هچنین ساختار دستور را مشاهده میکنیم.
اگر سکرول کنیم پایینتر توضیحات آپشنهای -i و -t را مشاهده میکنیم.
h
اجرای یک container و وارد شدن به محیط آن جهت اجرا دستورات
با اجرای دستور زیر میتوانیم همزمان هم ccontainer را اجرا کنیم و هم ترمینال داخل container را جهت اجرای دستورات bash باز نگه داریم.
docker container run -it --name nginx_server nginx bash
برای مثال ما میتوانیم یک image خاص مثل alpine یا ubuntu را اجرا کنیم و با استفاده از bash وارد ان شویم و ان را آپدیت کنیم و پکیج های مختلف نصب کنیم و …
نکته: با استفاده از دکمه های Ctr + d میتوانیم از محیط container خارج شویم.
وارد شدن به محیط container که قبلا ایجاد شده است
در کامندهای قبل ما همزمان با ایجاد یک container وارد محیط آن هم شدیم و bash را اجرا کردیم. حالا اگر بخواهیم آن را start کنیم با استفاده از راهنمای داکر آن را مشاهده کنیم:
حال اگر بخواهیم وارد محیط یک container شویم که قبلا ایجاد شده است و دستوراتی را اجرا کنیم به صورت زیر اقدام میکنیم:
docker container start -ai ubuntu
اجرای دستورات جدید داخل containerی که در حال اجرا است
همانطور که در دستورات قبل دیدیم با استفاده از run -it میتوانیم همزمان container را ایجاد و با اضافه کردن کامند وارد محیط کانتینر شویم ولی اگر یک container در حال اجرا داشته باشیم و بخواهیم یک command به آن اضافه کنیم بدون اینکه آن را stop و دوباره start کنیم از دستور زیر استفاده میکنیم:
docker container exec -it CONTAINER_NAME COMMAND