زمانی که یک کانتینر را درمحیط های development یا production مدیریت می کنیم، مهم ترین پارامتری که باید به آن توجه کنیم وضعیت ( status ) instance کانتینر است. بیشتر مواقع از تصاویر پایه ای استفاده می شود که میتوان بر پایه ی آنها برنامه را دیپلوی کرد. مثلا به همین خاطر تصاویر سیستم عامل Ubuntu به صورت خام بسیار زیاد دانلود می شوند. کاربرد داکر این نیست که روی سیستم عامل بازهم سیستم عامل بالا بیاوریم! و این کار اشتباه است!

البته بر خلاف یک سیستم عامل کامل تصویر کانتینری Ubuntu نسبتا سبک است و بسیاری از پکیج های پیش فرض سیستم عامل روی آن نصب نیست اما یک package system دارد که با استفاده از آن می توان پکیج های بیشتری را به کانتینر اضافه کرد.

توجه داشته باشید که در زمان ساخت تصاویر یکی از اهداف مهم، کاهش حجم تصویر اصلی است. این کار باعث افزایش سرعت دانلود و راه اندازی کانتینر توسط Docker host ها می شود.


در این مثال با تصویر رسمی پایه ای Ubuntu( official Ubuntu base container image ) کارمی کنیم. این تصویر کاربردهای بسیار زیادی دارد و عموما برای ایجاد نسخه( منظور از نسخه instance است) های کانتینرهایی استاده می شود که نیاز به سیستم عامل برای انجام کاری دارند.


مثال داخل مثال:

مثلا فرض کنید یک برنامه ی فلاتر با هدف توسعه ی وب اپلیکیشن تحت مرورگر(با فلاتر میتوان PWA ایجاد کرد) دارید و میخواهید با آپدیت های برنامه ی اصلی، خروجی وبسایت خود را نیز دریافت کنید. با استفاده از Ubuntu به عنوان هسته ی کانتینر میتوانید به راحتی در تمامی سیستم عامل ها و فرآیند های CI/CD این عملیات را به صورت خودکار پیاده سازی کنید.


در این مثال از Ubuntu استفاده می کنیم تا دستورات قسمت قبل را بیشتر بررسی کنیم و کاربرد آنها را در عمل ببینیم. در این مثال از نسخه های Ubuntu 18.04 و Ubuntu 19.04 استفاده می کنیم. مراحل زیر را در ترمینال مورد علاقه ی خود به ترتیب پیاده سازی کنید:

1- از دستور docker pull برای دریافت تصویر کانتینر Ubuntu 18.04 استفاده کنید:

docker pull ubuntu:18.04

در خروجی چیزی مشابه این موارد را مشاهده می کنید:

18.04: Pulling from library/ubuntu

7c457f213c76: Pulling fs layer

7c457f213c76: Verifying Checksum

7c457f213c76: Download complete

7c457f213c76: Pull complete

Digest: sha256:152dc042452c496007f07ca9127571cb9c29697f42acbfad72324b2bb2e43c98

Status: Downloaded newer image for ubuntu:18.04

docker.io/library/ubuntu:18.04

2- با استفاده از دستور docker pull تصویر Ubuntu 19.04 را نیز دانلود کنید:

docker pull ubuntu:19.04

در خروجی نیز چیزی مانند خروجی قبل را برای Ubuntu 19.04 میبینید.

3- دستور docker images را اجرا کنید و کانتینر های خود در local container cache را ببینید:

docker images

در خروجی باید 3 کانتینر را ببینید(من کانتینرهای بیشتری روی سیستمم دارم که اگر پاکشون کنم به لطف اینترنت ایران باید با بدبختی نصبشون کنم):

4- قبل از اجرای این تصاویر، از دستور docker inspect استفاده کنید تا اطلاعات اولیه ی تصاویر را ببینید. در ادامه ی این دستور باید تگ مربوط به تصویر را از خروجی کد قبل بردارید و در ادامه ی docker inspect قرار دهید. دستور زیر را مستقیما کپی نکنید!

docker inspect f9a80a55f492

در خروجی خواهیم داشت:

[

{

"Id": "sha256:f9a80a55f492e823bf5d51f1bd5f87ea3eed1cb31788686aa99a2fb61a

27af6a",

"RepoTags": [

"ubuntu:18.04"

],

"RepoDigests": [

"ubuntu@sha256:152dc042452c496007f07ca9127571cb9c29697f42acbfad72324

b2bb2e43c98"

],

"Parent": "",

"Comment": "",

"Created": "2023-05-30T09:32:09.432301537Z",

"Container": "00da56b63e7a5e6508d4ff7a380a7fb2b4e7ffcb5dcf799d41cb75bf20

f12132",

"ContainerConfig": {

"Hostname": "00da56b63e7a",

"Domainname": "",

"User": "",

"AttachStdin": false,

"AttachStdout": false,

"AttachStderr": false,

"Tty": false,

"OpenStdin": false,

"StdinOnce": false,

"Env": [

"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/b

in"

],

"Cmd": [

"/bin/sh",

"-c",

"#(nop) ",

"CMD [\"/bin/bash\"]"

],

"Image": "sha256:e24e6fe4d70b767b0621c909f548dab783f946ef6d9346ecc22

72730b821a402",

"Volumes": null,

"WorkingDir": "",

"Entrypoint": null,

"OnBuild": null,

"Labels": {

"org.opencontainers.image.ref.name": "ubuntu",

"org.opencontainers.image.version": "18.04"

}

},

"DockerVersion": "20.10.21",

"Author": "",

"Config": {

"Hostname": "",

"Domainname": "",

"User": "",

"AttachStdin": false,

"AttachStdout": false,

"AttachStderr": false,

"Tty": false,

"OpenStdin": false,

"StdinOnce": false,

"Env": [

"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/b

in"

],

"Cmd": [

"/bin/bash"

],

"Image": "sha256:e24e6fe4d70b767b0621c909f548dab783f946ef6d9346ecc22

72730b821a402",

"Volumes": null,

"WorkingDir": "",

"Entrypoint": null,

"OnBuild": null,

"Labels": {

"org.opencontainers.image.ref.name": "ubuntu",

"org.opencontainers.image.version": "18.04"

}

},

"Architecture": "amd64",

"Os": "linux",

"Size": 63156473,

"VirtualSize": 63156473,

"GraphDriver": {

"Data": {

"MergedDir": "/var/lib/docker/overlay2/4afb68221cbe178ab154b7acd

ff71605ecb9291e3fda697a80896a41ff674222/merged",

"UpperDir": "/var/lib/docker/overlay2/4afb68221cbe178ab154b7acdf

f71605ecb9291e3fda697a80896a41ff674222/diff",

"WorkDir": "/var/lib/docker/overlay2/4afb68221cbe178ab154b7acdff

71605ecb9291e3fda697a80896a41ff674222/work"

},

"Name": "overlay2"

},

"RootFS": {

"Type": "layers",

"Layers": [

"sha256:548a79621a426b4eb077c926eabac5a8620c454fb230640253e1b44d

c7dd7562"

]

},

"Metadata": {

"LastTagTime": "0001-01-01T00:00:00Z"

}

}

]

این لیست خیلی بزرگ است و تمام المان های تعریف کننده ی یک کانتینر را به ما نمایش می دهد. مثلا متغیر های محلی ( environment variables ) تعریف شده را در خروجی کد بالا میبینید، یا جزییات لایه های معرف کانتینر را مشاهده می کنید یا حتی جزییات مهم debugging خود کانتینر در خروجی قرار دارند. اگر از این تصویر پایه در کانتینر دیگری استفاده کنید و قصد بروز رسانی آن را داشته باشید این اطلاعات برای بروزرسانی ایمن تر شما بسیار مهم است.

5- همین دستور را برای تصویر Ubuntu 19.04 تکرار کنید:

docker inspect c88ac1f841b7

خروجی را در سیستم خود مشاهده کنید و با خروجی قبلی مقایسه کنید.

بررسی این تصاویر نه تنها بسیار مهم است، بلکه به شما اجازه می دهد تا زمانی که بر پایه ی این تصاویر کانتینرهای پیچیده تری ایجاد می کنید، از حفره های امنیتی( security vulnerability ) نیز اطلاعات بیشتری کسب کنید و بهترین تصمیم را برای ایجاد زیرساخت امن و قابل اطمینان خود بگیرید.

6- بعد از بررسی تاریخ ایجاد هردو تصویر متوجه می شوید که نسخه ی 18.04 به علت LTSبودن خیلی تازه تر از نسخه ی 19.04 بروزرسانی شده است و این نسخه ها مشکلات امنیتی کمتری دارند. به همین خاطر در عموم کارهای واقعی از این نسخه های پایدار و long-term support releases استفاده می کنیم.

7- با دستور docker run نسخه ی 18.04 را اجرا می کنیم:

docker run -d ubuntu:18.04

پرچم(flag) -d که پس از دستور نوشته شده به معنی اجرای کانتینر در حالت Detached یا daemon است. یعنی اینکه این کانتینر در پس زمینه ی سیستم اجرا خواهد شد. اگر این flag را قرار ندهیم، کانتینر ترمینال را در اخیتار خودش قرار میدهد و وقتی ترمینال را ببندیم، کانتینر نیز متوقف( terminate) خواهد شد.

8- وضعیت کانتینر را با دستور docker ps -a بررسی کنید:

docker ps -a

در خروجی چیزی مشابه زیر خواهید داشت:

CONTAINER ID IMAGE COMMAND CREATED

STATUS PORTS NAMES

c139e44193de ubuntu:18.04 '/bin/bash' 6 seconds ago

Exited (0) 4 seconds ago xenodochial_banzai

چرا کانتینر حدود 2 ثانیه بعد از ساخت متوقف شده؟!

اگر به خروجی بخش 4 این مثال را نگاه کنید، میبینید که در قسمت CMD ، پردازش اصلی این تصویر درون /bin/bash قرار دارد. Bash shell برای اجرا به ورودی متنی نیاز دارد و زمانی که این ورودی را در اخیتار کانتینر قرار ندهیم نمیتواند اجرا شود.

9- دوباره docker run را به یک شکل جدید اجرا کنید:

docker run -i -t -d --name ubuntu123 ubuntu:18.04

پرچم -i یک رخداد برنامه( session ) را تعاملی( interactive ) می کند و آن را موظف میکند که منتظر ورودی اطلاعات کاربر برای ادامه باشد و پرچم -t برای در دسترس قراردادن سرویس مدیریت pseudo-tty برای کانتینر استفاده می شود.

سرویس pseudo-tty handler ترمینال کاربر را به یک Bash shell در حال اجرا و قابل تعامل در داخل کانتینر متصل می کند که به ما اجازه می دهد تا Bash را به درستی اجرا کنیم و با کانتینر در تعامل باشیم. ضمنا پرچم --name به ما اجازه میدهد تا خودمان نام کانتینر را تعیین کنیم و دیگر داکر یک نام تصادفی ایجاد نکند.

10- درست حدس زدید! دستور docker ps -a را اجرا کنید:

docker ps -a

در خروجی باید ببینید:

CONTAINER ID IMAGE COMMAND CREATED

STATUS PORTS NAMES

f087d0d92110 ubuntu:18.04 '/bin/bash' 4 seconds ago

Up 2 seconds ubuntu123

c139e44193de ubuntu:18.04 '/bin/bash' 5 minutes ago

Exited (0) 5 minutes ago xenodochial_banzai

11- حالا یک کانتینر اوبونتوی در حال اجرا داریم که فعلا متوقف نمی شود. حالا میخواهیم درون این کانتینر دستوراتی را اجرا کنیم؛ این کار را با دستور docker exec انجام دهید. دستور exec به ما دسترسی به Bash shell را میدهد که الآن فعال و در دسترس است:

docker exec -it ubuntu123 /bin/bash

پرچم -it ترکیبی از دو پرچم -i و -t است و به ما اجازه میدهد تا ارتباط فعلی( session ) به صورت interactive برقرار بماند. دستور /bin/bash نیز Bash shell را داخل کانتینر فراخوانده و فعال می کند. ضمنا به جای اسم نیز میتوانیم از ID استفاده کنیم.(اسم میگذاریم که این کار را نکنیم).

پس از اجرای دستور بالا شکل ورودی ترمینال شما به شکل زیر تغییر می کند:

root@cfaa37795a7b:/#

حالا داخل Bash shell هستیم! Host این ترمینال( cfaa37795a7b )یک عدد رندوم نیست و در واقع 12 کاراکتر اول ID کانتینر است.

12- بیایید چند دستور ساده بنویسیم:

root@cfaa37795a7b:/# echo 'Hello world from ubuntu123' > hello-world.txt

داخل کانتینر ابزار کمتر نسبت به VM(ماشین مجازی) و نسخه های BareMetal(روی سخت افزار واقعی) در دسترس است و المان ها و دستورات کمتری را در اخیتار داریم. تصاویر کانتینر بسیار مینیمال و حداقلی هستند و پکیج های زیادی هست که روی آنها نصب نشده است. دستور echo در این لحظه در دسترس است با این دستور میتوانیم یک محتوا را به صورت متنی روی یک فایل بنویسیم.

13- از داخل Bash shell فعلی با دستور exit خارج شوید. خروجی بخش 11 به شکل قبل باز می گردد:

root@cfaa37795a7b:/# exit

14- مراحل 9 تا 13 را برای اون یکی Ubuntu یعنی 19.04 تکرار کنید:

docker run -i -t -d --name ubuntu456 ubuntu:19.04

15 - دوباره دستور docker exec را برای دسترسی به /bin/bash و استفاده از Bash shell بنویسید.

docker exec -it ubuntu456 /bin/bash

تغییر خروجی ترمینال را ببینید:

root@875cad5c4dd8:/#

16- دستور echo را برای کانتینر جدید بنویسید:

root@875cad5c4dd8:/# echo 'Hello-world from ubuntu456!' > hello-world.txt

حالا با exit خارج شوید.

17- در حال حاضر دو کانتینر Ubuntu داریم که در Docker environment سیستم ما با دو فایل hello-world متفاوت در دایرکتوری اصلی( home ) مربوط به اکانت root (مثل Administrator در ویندوز : این اکانت بالاترین سطح دسترسی در سیستم عامل لینوکس را دارد) وجود دارند.

دستور docker ps را اجرا کنید:

docker ps

در خروجی چیزی مشابه این را میبینید:

CONTAINER ID IMAGE COMMAND CREATED

STATUS PORTS NAMES

875cad5c4dd8 ubuntu:19.04 '/bin/bash' 3 minutes ago

Up 3 minutes ubuntu456

cfaa37795a7b ubuntu:18.04 '/bin/bash' 15 minutes ago

Up 15 minutes ubuntu123

18- بیایید از یک دستور دیگر استفاده کنیم:

docker exec -it ubuntu123 cat hello-world.txt

به جای استفاده از docker exec برای دسترسی به shell داخل کانتینر، از این دستور برای بکارگیری دستور cat در کانتینر استفاده می کنیم تا محتوای فایل hello-world.txt را در خروجی ببینیم:

Hello world from ubuntu123

با اینکه از پرچم های -it پس از اجرای دستور cat بلافاصله به ترمینال اصلی سیستم برگشتیم! این به خاطر است که docker exec یک session است و تا زمانی وجود دارد که دستوری که در ادامه ی آن می نویسید در حال اجرا باشد.

19- حالا همین کار را برای اون یکی می کنیم:

docker exec -it ubuntu456 cat hello-world.txt

در خروجی داریم:

Hello-world from ubuntu456!

20- همانطور که دستور exec را بکار میگیریم تا داخل کانتینر یک دستور دیگر را اجرا کنیم، دستورات دیگری نیز وجود دارند که 3 عمل stop ، start و restart کانتینر را برای ما انجام میدهند. کانتینر بدتر(19.04) را با دستور docker stop متوقف کنید:

docker stop ubuntu456

21- با دستور docker ps کانتینرهای در حال اجرا( running ) خود را ببینید:

docker ps

در خروجی خواهیم داشت:

CONTAINER ID IMAGE COMMAND CREATED

STATUS PORTS NAMES

cfaa37795a7b ubuntu:18.04 '/bin/bash' 26 minutes ago

Up 26 minutes ubuntu123

22- با دستور docker ps -a تمام instance های کانتینری خود را فارق از وضعیت اجرای آن ها ببینید:

docker ps -a

در خروجی خواهیم داشت:

CONTAINER ID IMAGE COMMAND CREATED

STATUS PORTS NAMES

cfaa37795a7b ubuntu:18.04 '/bin/bash' 27 minutes ago

Up 27 minutes ubuntu1

875cad5c4dd8 ubuntu:19.04 '/bin/bash' 14 minutes ago

Exited (0) 6 seconds ago ubuntu2

23- با دستور docker start یا docker restart کانتینر نسخه ی19.04 را دوباره فعال کنید:

docker start ubuntu456

این دستور گاهی ID کانتینر را باز می گرداند ولی در نسخه های مختلف داکر برای سیستم عامل های مختلف ممکن است چیزی نبینید، در این لحظه این خروجی مهم نیست!

24 - با دستور docker ps کانتینرهای در حال اجرا( running ) خود را ببینید:

CONTAINER ID IMAGE COMMAND CREATED

STATUS PORTS NAMES

875cad5c4dd8 ubuntu:19.04 '/bin/bash' 17 minutes ago

Up 10 second ubuntu456

cfaa37795a7b ubuntu:18.04 '/bin/bash' 29 minutes ago

Up 29 minutes ubuntu123

دقت کنید! کانیتینر تنها مدت کوتاهی در حال اجرا(Up ) است اما 17 دقیقه ی پیش (برای شما فرق میکند) یک container instance برای آن ایجاد شده(CREATED) است.

25 - آخرین مرحله ی چرخه ی حیات یک کانتینر مرحله ی نظافت( prune ) است. در این مرحله کانتینرهایی که طول عمرشان به پایان رسیده اما متوقف نشده اند را متوقف میکنیم، آن ها را حذف میکنیم و نسخه های قدیمی تصاویریشان را نیز حذف میکنیم.

docker stop ubuntu123

26- همین کار رو برای اون یکی می کنیم.

docker stop ubuntu456

27- حالا که هردو کانیتنر متوقف شده اند با دستور docker rm به داکر میگوییم که instance کانتینرها را پاک کند. اول کانتینر بد(بکار بردن کلمه ی بد برای این است که بدانید بهتر است از نسخه های LTS استفاده کنید) را پاک می کنیم:

docker rm ubuntu456

و بعد کانتینر خوب:

docker rm ubuntu123

28- حالا دستور docker ps -a را اجرا کنید. کانتینر hello-world را هم پاک کنید ( ما به آن نیازی نداریم) این کار را میتوانید با استفاده از ID به جای نام کانتینر نیز انجام دهید.

29- حالا که قصد داریم محیط را پاکسازی کنیم و برای قسمت بعدی آماده شویم، دستور docker images را اجرا کنید و اطلاعات تصاویر را نیز دریافت کنید:

docker images

30- به نوبت تصاویر را با استفاده از دستور docker rmi و قرار دادن ID پاک کنید:

مثلا اگر ID تصویر hello-world برابر با bf756fb1ae65 است به این شکل عمل کنید:

docker rmi 4e5021d210f6

مشابه دستور docker pull ، دستور docker rmi برای پاک کردن تصاویر به صورت لایه لایه عملیات پاک کردن را انجام میدهد.


در حین آموزش و تست مهم است که برای کاهش فضای اشغال شده(حافظه و رم ) مرتبا کانیتنرهای غیرضروری و تصاویر کانتینری بدون کاربرد را پاک کنید. برای این کار دستور دیگری نیز وجود دارد به نام prune که کانتینرهای غیر فعال و تصاویر پایه ای بدون کاربرد را پاک میکند:

docker system prune -fa


با عرض شرمندگی از طولانی شدن این مثال به سراغ قسمت بعدی بروید! در ابتدای کار مثل چرخ های کمکی دوچرخه همراهتان هستیم ولی این چرخ ها به آرامی باز خواهند شد و خودتان خواهید دید که میتوانید.