نکات Docker: دستگاه خود را از زباله پاک کنید

نکات Docker: دستگاه خود را از زباله پاک کنید

هی هابر! ترجمه مقاله را مورد توجه شما قرار می دهم "نکات داکر: ماشین محلی خود را تمیز کنید" نویسنده لوک جوگری.

امروز ما در مورد نحوه استفاده Docker از فضای دیسک دستگاه میزبان صحبت خواهیم کرد و همچنین خواهیم فهمید که چگونه این فضا را از تکه های تصاویر و ظروف استفاده نشده آزاد کنیم.


نکات Docker: دستگاه خود را از زباله پاک کنید

کل مصرف

Docker چیز جالبی است، احتمالاً امروز کمتر کسی در آن شک دارد. همین چند سال پیش، این محصول روشی کاملاً جدید برای ساخت، ارائه و اجرای هر محیطی به ما داد و به ما اجازه داد تا به میزان قابل توجهی در منابع CPU و RAM صرفه جویی کنیم. علاوه بر این (و برای برخی این مهمترین چیز خواهد بود) Docker به ما اجازه داده است تا مدیریت چرخه حیات محیط های تولید خود را به طرز باورنکردنی ساده و یکسان کنیم.

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

اگر هرگز به این موضوع فکر نکرده اید که Docker واقعاً چقدر فضای روی دستگاه شما اشغال می کند، ممکن است از خروجی این دستور به طرز ناخوشایندی شگفت زده شوید:

$ docker system df

نکات Docker: دستگاه خود را از زباله پاک کنید

این استفاده از دیسک Docker را در زمینه های مختلف نشان می دهد:

  • تصاویر - اندازه کل تصاویری که از مخازن تصویر دانلود شده و بر روی سیستم شما ساخته شده اند.
  • کانتینرها - مقدار کل فضای دیسک مورد استفاده توسط کانتینرهای در حال اجرا (به معنای حجم کل لایه های خواندن و نوشتن همه کانتینرها).
  • حجم های محلی - حجم ذخیره سازی محلی نصب شده روی ظروف؛
  • build cache – فایل‌های موقتی که توسط فرآیند ساخت تصویر تولید می‌شوند (با استفاده از ابزار BuildKit که با نسخه 18.09 داکر در دسترس است).

شرط می بندم که بعد از این انتقال ساده مشتاق هستید دیسک خود را از زباله پاک کنید و گیگابایت های گرانبها را به زندگی برگردانید (توجه داشته باشید: به خصوص اگر هر ماه اجاره این گیگابایت ها را پرداخت کنید).

استفاده از دیسک توسط کانتینرها

هر بار که یک کانتینر در ماشین میزبان ایجاد می کنید، چندین فایل و دایرکتوری در دایرکتوری /var/lib/docker ایجاد می شود که در میان آنها موارد زیر قابل ذکر است:

  • دایرکتوری /var/lib/docker/containers/container_ID – هنگام استفاده از درایور استاندارد گزارش‌گیری، اینجا جایی است که گزارش‌های رویداد با فرمت JSON ذخیره می‌شوند. گزارش‌های بسیار دقیق، و همچنین گزارش‌هایی که هیچ‌کس آن‌ها را نمی‌خواند یا پردازش نمی‌کند، اغلب باعث پر شدن دیسک‌ها می‌شوند.
  • دایرکتوری /var/lib/docker/overlay2 حاوی لایه های کانتینر خواندن و نوشتن است (overlay2 درایور ترجیحی در اکثر توزیع های لینوکس است). اگر کانتینر داده ها را در سیستم فایل خود ذخیره می کند، در این دایرکتوری است که قرار می گیرد.

بیایید سیستمی را تصور کنیم که روی آن یک Docker بکر نصب شده است، که هرگز در راه اندازی کانتینرها یا ساخت تصاویر نقش نداشته است. گزارش استفاده از فضای دیسک آن به شکل زیر خواهد بود:

$ docker system df
TYPE           TOTAL      ACTIVE     SIZE       RECLAIMABLE
Images         0          0          0B         0B
Containers     0          0          0B         0B
Local Volumes  0          0          0B         0B
Build Cache    0          0          0B         0B

بیایید یک کانتینر را راه اندازی کنیم، به عنوان مثال، NGINX:

$ docker container run --name www -d -p 8000:80 nginx:1.16

چه اتفاقی برای دیسک می افتد:

  • تصاویر 126 مگابایت را اشغال می کنند، این همان NGINX است که ما در ظرف راه اندازی کردیم.
  • ظروف 2 بایت مسخره می گیرند.

$ docker system df
TYPE           TOTAL      ACTIVE     SIZE       RECLAIMABLE
Images         1          1          126M       0B (0%)
Containers     1          1          2B         0B (0%)
Local Volumes  0          0          0B         0B
Build Cache    0          0          0B         0B

با قضاوت بر اساس نتیجه، ما هنوز فضایی نداریم که بتوانیم آن را آزاد کنیم. از آنجایی که 2 بایت کاملاً بیهوده است، بیایید تصور کنیم که NGINX ما به طور غیرمنتظره ای در جایی 100 مگابایت داده نوشته و یک فایل test.img دقیقاً به این اندازه در داخل خود ایجاد کرده است.

$ docker exec -ti www 
  dd if=/dev/zero of=test.img bs=1024 count=0 seek=$[1024*100]

بیایید دوباره میزان استفاده از فضای دیسک در هاست را بررسی کنیم. خواهیم دید که ظرف (ظروف) در آنجا 100 مگابایت اشغال می کند.

$ docker system df
TYPE           TOTAL      ACTIVE     SIZE       RECLAIMABLE
Images         1          1          126M       0B (0%)
Containers     1          1          104.9MB    0B (0%)
Local Volumes  0          0          0B         0B
Build Cache    0          0          0B         0B

فکر می‌کنم مغز کنجکاو شما در حال تعجب است که فایل test.img ما در کجا قرار دارد. بیایید به دنبال آن باشیم:

$ find /var/lib/docker -type f -name test.img
/var/lib/docker/overlay2/83f177...630078/merged/test.img
/var/lib/docker/overlay2/83f177...630078/diff/test.img

بدون پرداختن به جزئیات، می‌توانیم متوجه شویم که فایل test.img به راحتی در سطح خواندن و نوشتن قرار دارد و توسط درایور overlay2 کنترل می‌شود. اگر کانتینر خود را متوقف کنیم، میزبان به ما می گوید که این فضا در اصل می تواند آزاد شود:

# Stopping the www container
$ docker stop www

# Visualizing the impact on the disk usage
$ docker system df
TYPE           TOTAL      ACTIVE     SIZE       RECLAIMABLE
Images         1          1          126M       0B (0%)
Containers     1          0          104.9MB    104.9MB (100%)
Local Volumes  0          0          0B         0B
Build Cache    0          0          0B         0B

ما چطوری می تونیم این کار را انجام بدهیم؟ با حذف ظرف، که مستلزم پاک کردن فضای مربوطه در سطح خواندن و نوشتن است.

با دستور زیر می توانید تمام کانتینرهای نصب شده را به یکباره حذف کنید و دیسک خود را از تمام فایل های خواندن و نوشتن ایجاد شده توسط آنها پاک کنید:

$ docker container prune
WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y
Deleted Containers:
5e7f8e5097ace9ef5518ebf0c6fc2062ff024efb495f11ccc89df21ec9b4dcc2

Total reclaimed space: 104.9MB

بنابراین، با حذف کانتینر، 104,9 مگابایت را آزاد کردیم. اما از آنجایی که ما دیگر از تصویر دانلود شده قبلی استفاده نمی کنیم، این تصویر نیز کاندیدای حذف و آزاد کردن منابع ما می شود:

$ docker system df
TYPE           TOTAL      ACTIVE     SIZE       RECLAIMABLE
Images         1          0          126M       126M (100%)
Containers     0          0          0B         0B
Local Volumes  0          0          0B         0B
Build Cache    0          0          0B         0B

توجه: تا زمانی که تصویر حداقل توسط یک ظرف استفاده می شود، نمی توانید از این ترفند استفاده کنید.

دستور فرعی هرس که در بالا استفاده کردیم فقط روی ظروف متوقف شده تأثیر دارد. اگر بخواهیم نه تنها کانتینرهای متوقف شده بلکه در حال اجرا را نیز حذف کنیم، باید از یکی از این دستورات استفاده کنیم:

# Historical command
$ docker rm -f $(docker ps –aq)

# More recent command
$ docker container rm -f $(docker container ls -aq)

نکات جانبی: اگر از پارامتر -rm هنگام راه‌اندازی یک کانتینر استفاده کنید، پس از توقف آن، تمام فضای دیسکی که اشغال کرده بود آزاد می‌شود.

استفاده از تصاویر دیسک

چند سال پیش، اندازه تصویر چند صد مگابایت کاملاً طبیعی بود: یک تصویر اوبونتو 600 مگابایت وزن داشت و یک تصویر دات نت مایکروسافت چندین گیگابایت وزن داشت. در آن روزهای پشمالو، دانلود فقط یک تصویر می‌تواند آسیب زیادی به فضای آزاد دیسک شما وارد کند، حتی اگر سطوح را بین تصاویر به اشتراک بگذارید. امروزه - ستایش بزرگان - وزن تصاویر بسیار کمتر است، اما با این وجود، اگر برخی اقدامات احتیاطی را انجام ندهید، می توانید به سرعت منابع موجود را پر کنید.

انواع مختلفی از تصاویر وجود دارد که مستقیماً برای کاربر نهایی قابل مشاهده نیستند:

  • تصاویر میانی، که بر اساس آن تصاویر دیگر جمع آوری می شوند - اگر از ظروف بر اساس این تصاویر "سایر" استفاده می کنید، نمی توان آنها را حذف کرد.
  • تصاویر آویزان تصاویر میانی هستند که توسط هیچ یک از کانتینرهای در حال اجرا ارجاع داده نمی شوند - می توان آنها را حذف کرد.
  • با دستور زیر می توانید تصاویر آویزان روی سیستم خود را بررسی کنید:

$ docker image ls -f dangling=true
REPOSITORY  TAG      IMAGE ID         CREATED             SIZE
none      none   21e658fe5351     12 minutes ago      71.3MB

می توانید آنها را به روش زیر حذف کنید:

$ docker image rm $(docker image ls -f dangling=true -q)

همچنین می توانیم از دستور فرعی prune استفاده کنیم:

$ docker image prune
WARNING! This will remove all dangling images.
Are you sure you want to continue? [y/N] y
Deleted Images:
deleted: sha256:143407a3cb7efa6e95761b8cd6cea25e3f41455be6d5e7cda
deleted: sha256:738010bda9dd34896bac9bbc77b2d60addd7738ad1a95e5cc
deleted: sha256:fa4f0194a1eb829523ecf3bad04b4a7bdce089c8361e2c347
deleted: sha256:c5041938bcb46f78bf2f2a7f0a0df0eea74c4555097cc9197
deleted: sha256:5945bb6e12888cf320828e0fd00728947104da82e3eb4452f

Total reclaimed space: 12.9kB

اگر ناگهان بخواهیم همه تصاویر را به طور کامل (و نه فقط آویزان) را با یک دستور حذف کنیم، می توانیم این کار را انجام دهیم:

$ docker image rm $(docker image ls -q)

استفاده از دیسک بر اساس حجم

از ولوم ها برای ذخیره داده های خارج از سیستم فایل کانتینر استفاده می شود. به عنوان مثال، اگر بخواهیم نتایج یک برنامه کاربردی را ذخیره کنیم تا از آنها به طریق دیگری استفاده کنیم. یک مثال رایج، پایگاه های داده است.

بیایید یک کانتینر MongoDB راه‌اندازی کنیم، حجمی را در خارج از کانتینر نصب کنیم و یک نسخه پشتیبان از پایگاه داده را از آن بازیابی کنیم (ما آن را در فایل bck.json در دسترس داریم):

# Running a mongo container
$ docker run --name db -v $PWD:/tmp -p 27017:27017 -d mongo:4.0

# Importing an existing backup (from a huge bck.json file)
$ docker exec -ti db mongoimport 
  --db 'test' 
  --collection 'demo' 
  --file /tmp/bck.json 
  --jsonArray

داده ها بر روی ماشین میزبان در فهرست /var/lib/docker/volumes قرار خواهند گرفت. اما چرا در سطح خواندن و نوشتن ظرف نه؟ زیرا در Dockerfile تصویر MongoDB، پوشه /data/db (که MongoDB داده های خود را به طور پیش فرض ذخیره می کند) به عنوان یک حجم تعریف می شود.

نکات Docker: دستگاه خود را از زباله پاک کنید

نکته جانبی: بسیاری از تصاویری که باید داده تولید کنند از حجم برای ذخیره آن داده ها استفاده می کنند.

وقتی به اندازه کافی با MongoDB بازی می کنیم و کانتینر را متوقف می کنیم (یا حتی حذف می کنیم)، حجم حذف نمی شود. فضای دیسک گرانبهای ما را اشغال می کند تا زمانی که به صراحت آن را با دستوری مانند این حذف کنیم:

$ docker volume rm $(docker volume ls -q)

خوب، یا می توانیم از دستور فرعی prune که قبلاً برای ما آشناست استفاده کنیم:

$ docker volume prune
WARNING! This will remove all local volumes not used by at least one container.
Are you sure you want to continue? [y/N] y
Deleted Volumes:
d50b6402eb75d09ec17a5f57df4ed7b520c448429f70725fc5707334e5ded4d5
8f7a16e1cf117cdfddb6a38d1f4f02b18d21a485b49037e2670753fa34d115fc
599c3dd48d529b2e105eec38537cd16dac1ae6f899a123e2a62ffac6168b2f5f
...
732e610e435c24f6acae827cd340a60ce4132387cfc512452994bc0728dd66df
9a3f39cc8bd0f9ce54dea3421193f752bda4b8846841b6d36f8ee24358a85bae
045a9b534259ec6c0318cb162b7b4fca75b553d4e86fc93faafd0e7c77c79799
c6283fe9f8d2ca105d30ecaad31868410e809aba0909b3e60d68a26e92a094da

Total reclaimed space: 25.82GB
luc@saturn:~$

استفاده از دیسک برای کش ساخت تصویر

در Docker 18.09، فرآیند ایجاد تصویر به لطف ابزار BuildKit دستخوش تغییراتی شده است. این امر باعث افزایش سرعت فرآیند و بهینه سازی ذخیره سازی داده ها و مدیریت امنیت می شود. در اینجا ما تمام جزئیات این ابزار شگفت‌انگیز را در نظر نخواهیم گرفت، ما فقط بر نحوه رسیدگی به مسائل مربوط به استفاده از فضای دیسک تمرکز خواهیم کرد.

فرض کنید یک برنامه کاملاً ساده Node.Js داریم:

  • فایل index.js یک سرور HTTP ساده را راه اندازی می کند که با یک خط به هر درخواست دریافت شده پاسخ می دهد:
  • فایل package.json وابستگی ها را تعریف می کند که فقط expressjs برای اجرای سرور HTTP استفاده می شود:

$ cat index.js
var express = require('express');
var util    = require('util');
var app = express();
app.get('/', function(req, res) {
  res.setHeader('Content-Type', 'text/plain');
  res.end(util.format("%s - %s", new Date(), 'Got Request'));
});
app.listen(process.env.PORT || 80);

$ cat package.json
    {
      "name": "testnode",
      "version": "0.0.1",
      "main": "index.js",
      "scripts": {
        "start": "node index.js"
      },
      "dependencies": {
        "express": "^4.14.0"
      }
    }

Dockerfile برای ساخت تصویر به شکل زیر است:

FROM node:13-alpine
COPY package.json /app/package.json
RUN cd /app && npm install
COPY . /app/
WORKDIR /app
EXPOSE 80
CMD ["npm", "start"]

بیایید تصویر را به روش معمول و بدون استفاده از BuildKit بسازیم:

$ docker build -t app:1.0 .

اگر میزان استفاده از فضای دیسک را بررسی کنیم، می بینیم که فقط تصویر پایه (node:13-alpine) و تصویر مقصد (app:1.0) فضا را اشغال می کنند:

TYPE           TOTAL      ACTIVE     SIZE       RECLAIMABLE
Images         2          0          109.3MB    109.3MB (100%)
Containers     0          0          0B         0B
Local Volumes  0          0          0B         0B
Build Cache    0          0          0B         0B

بیایید نسخه دوم برنامه خود را با استفاده از BuildKit بسازیم. برای انجام این کار، فقط باید متغیر DOCKER_BUILDKIT را روی 1 تنظیم کنیم:

$ DOCKER_BUILDKIT=1 docker build -t app:2.0 .

اگر اکنون میزان استفاده از دیسک را بررسی کنیم، خواهیم دید که کش ساخت (buid-cache) اکنون در آنجا درگیر است:

$ docker system df
TYPE           TOTAL      ACTIVE     SIZE       RECLAIMABLE
Images         2          0          109.3MB    109.3MB (100%)
Containers     0          0          0B         0B
Local Volumes  0          0          0B         0B
Build Cache    11         0          8.949kB    8.949kB

برای پاک کردن آن از دستور زیر استفاده کنید:

$ docker builder prune
WARNING! This will remove all dangling build cache.
Are you sure you want to continue? [y/N] y
Deleted build cache objects:
rffq7b06h9t09xe584rn4f91e
ztexgsz949ci8mx8p5tzgdzhe
3z9jeoqbbmj3eftltawvkiayi

Total reclaimed space: 8.949kB

همه را پاک کن!

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

$ docker system prune
WARNING! This will remove:
  - all stopped containers
  - all networks not used by at least one container
  - all dangling images
  - all dangling build cache

Are you sure you want to continue? [y/N]

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

منبع: www.habr.com

اضافه کردن نظر