Mẹo về Docker: Dọn sạch rác trong máy của bạn

Mẹo về Docker: Dọn sạch rác trong máy của bạn

Này Habr! Tôi trình bày với bạn chú ý bản dịch của bài báo "Mẹo về Docker: Dọn dẹp máy cục bộ của bạn" tác giả Lục tung hứng.

Hôm nay chúng ta sẽ nói về cách Docker sử dụng dung lượng ổ đĩa của máy chủ và chúng ta cũng sẽ tìm ra cách giải phóng không gian này khỏi các hình ảnh và vùng chứa không được sử dụng.


Mẹo về Docker: Dọn sạch rác trong máy của bạn

Tổng mức tiêu thụ

Docker là một thứ hay ho, có lẽ ngày nay ít người nghi ngờ điều đó. Chỉ vài năm trước, sản phẩm này đã mang đến cho chúng tôi một cách hoàn toàn mới để xây dựng, cung cấp và chạy bất kỳ môi trường nào, cho phép chúng tôi tiết kiệm đáng kể tài nguyên CPU và RAM. Ngoài điều này (và đối với một số người, điều này sẽ là điều quan trọng nhất) Docker đã cho phép chúng tôi đơn giản hóa và thống nhất một cách đáng kinh ngạc việc quản lý vòng đời của môi trường sản xuất của mình.

Tuy nhiên, tất cả những thú vui của cuộc sống hiện đại đều có giá của nó. Khi chúng tôi chạy vùng chứa, tải xuống hoặc tạo hình ảnh của riêng mình và triển khai các hệ sinh thái phức tạp, chúng tôi phải trả tiền. Và chúng tôi trả tiền, trong số những thứ khác, bằng dung lượng ổ đĩa.

Nếu bạn chưa bao giờ nghĩ về việc Docker thực sự chiếm bao nhiêu dung lượng trên máy của mình, thì bạn có thể ngạc nhiên một cách khó chịu trước kết quả của lệnh này:

$ docker system df

Mẹo về Docker: Dọn sạch rác trong máy của bạn

Điều này cho thấy mức sử dụng đĩa của Docker trong các ngữ cảnh khác nhau:

  • hình ảnh – tổng kích thước của hình ảnh được tải xuống từ kho hình ảnh và được tạo trên hệ thống của bạn;
  • bộ chứa – tổng dung lượng ổ đĩa được sử dụng bởi các bộ chứa đang chạy (có nghĩa là tổng khối lượng lớp đọc-ghi của tất cả các bộ chứa);
  • khối lượng cục bộ – khối lượng lưu trữ cục bộ được gắn vào container;
  • build cache – các tệp tạm thời được tạo bởi quá trình xây dựng hình ảnh (sử dụng công cụ BuildKit, có sẵn bắt đầu với Docker phiên bản 18.09).

Tôi cá rằng sau lần chuyển đơn giản này, bạn sẽ sẵn sàng dọn sạch ổ đĩa rác của mình và khôi phục lại hàng gigabyte quý giá (lưu ý: đặc biệt nếu bạn trả tiền thuê những gigabyte này hàng tháng).

Mức sử dụng đĩa theo vùng chứa

Mỗi khi bạn tạo một vùng chứa trên máy chủ, một số tệp và thư mục sẽ được tạo trong thư mục /var/lib/docker, trong đó cần lưu ý những điều sau:

  • Thư mục /var/lib/docker/containers/container_ID – khi sử dụng trình điều khiển ghi nhật ký tiêu chuẩn, đây là nơi lưu nhật ký sự kiện ở định dạng JSON. Nhật ký quá chi tiết, cũng như nhật ký không ai đọc hoặc xử lý, thường khiến đĩa bị đầy.
  • Thư mục /var/lib/docker/overlay2 chứa các lớp đọc-ghi vùng chứa (overlay2 là trình điều khiển ưa thích trong hầu hết các bản phân phối Linux). Nếu vùng chứa lưu trữ dữ liệu trong hệ thống tệp của nó thì dữ liệu sẽ được đặt trong thư mục này.

Hãy tưởng tượng một hệ thống được cài đặt Docker nguyên sơ, chưa bao giờ tham gia vào việc khởi chạy các container hoặc xây dựng hình ảnh. Báo cáo sử dụng dung lượng ổ đĩa của nó sẽ trông như thế này:

$ 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

Hãy khởi chạy một số container, ví dụ: NGINX:

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

Điều gì xảy ra với đĩa:

  • hình ảnh chiếm 126 MB, đây chính là NGINX mà chúng tôi đã khởi chạy trong vùng chứa;
  • container chiếm 2 byte vô lý.

$ 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

Đánh giá theo kết luận, chúng tôi vẫn chưa có khoảng trống nào có thể giải phóng. Vì 2 byte là hoàn toàn phù phiếm, hãy tưởng tượng rằng NGINX của chúng tôi bất ngờ ghi vào đâu đó 100 Megabyte dữ liệu và tạo một tệp test.img có kích thước chính xác như vậy bên trong chính nó.

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

Hãy kiểm tra lại việc sử dụng dung lượng ổ đĩa trên máy chủ. Chúng ta sẽ thấy container (container) chiếm 100 Megabyte ở đó.

$ 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

Tôi nghĩ bộ não tò mò của bạn đang tự hỏi tệp test.img của chúng tôi nằm ở đâu. Hãy tìm kiếm nó:

$ 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

Không đi sâu vào chi tiết, chúng ta có thể lưu ý rằng tệp test.img nằm ở vị trí thuận tiện ở cấp độ đọc-ghi, được điều khiển bởi trình điều khiển Overlay2. Nếu chúng tôi dừng vùng chứa của mình, máy chủ sẽ cho chúng tôi biết rằng về nguyên tắc, không gian này có thể được giải phóng:

# 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

Làm thế nào chúng ta có thể làm điều này? Bằng cách xóa vùng chứa, điều này sẽ đòi hỏi phải xóa không gian tương ứng ở cấp độ đọc-ghi.

Với lệnh sau, bạn có thể xóa tất cả các vùng chứa đã cài đặt trong một lần và xóa tất cả các tệp đọc-ghi do chúng tạo ra trên đĩa của bạn:

$ 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

Vì vậy, chúng tôi đã giải phóng 104,9 Megabyte bằng cách xóa vùng chứa. Nhưng vì chúng tôi không còn sử dụng hình ảnh đã tải xuống trước đó nữa nên nó cũng trở thành ứng cử viên để xóa và giải phóng tài nguyên của chúng tôi:

$ 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

Lưu ý: Miễn là hình ảnh được ít nhất một vùng chứa sử dụng thì bạn sẽ không thể sử dụng thủ thuật này.

Lệnh con Prune mà chúng tôi sử dụng ở trên chỉ có tác dụng đối với các vùng chứa đã dừng. Nếu chúng ta muốn xóa không chỉ các vùng chứa đã dừng mà còn cả các vùng chứa đang chạy, chúng ta nên sử dụng một trong các lệnh sau:

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

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

Lưu ý bên lề: nếu bạn sử dụng tham số -rm khi khởi động một vùng chứa, thì khi nó dừng, tất cả dung lượng ổ đĩa mà nó chiếm giữ sẽ được giải phóng.

Sử dụng hình ảnh đĩa

Vài năm trước, kích thước hình ảnh vài trăm megabyte là hoàn toàn bình thường: một hình ảnh Ubuntu nặng 600 megabyte và một hình ảnh Microsoft .Net nặng vài gigabyte. Trong những ngày tồi tệ đó, việc tải xuống chỉ một hình ảnh có thể tiêu tốn nhiều dung lượng đĩa trống của bạn, ngay cả khi bạn đang chia sẻ cấp độ giữa các hình ảnh. Ngày nay - khen ngợi những điều tuyệt vời - hình ảnh nhẹ hơn nhiều, nhưng ngay cả như vậy, bạn vẫn có thể nhanh chóng lấp đầy các tài nguyên sẵn có nếu không thực hiện một số biện pháp phòng ngừa.

Có một số loại hình ảnh mà người dùng cuối không thể nhìn thấy trực tiếp:

  • hình ảnh trung gian, trên cơ sở đó các hình ảnh khác được thu thập - chúng không thể bị xóa nếu bạn sử dụng vùng chứa dựa trên những hình ảnh “khác” này;
  • hình ảnh lơ lửng là hình ảnh trung gian không được tham chiếu bởi bất kỳ vùng chứa đang chạy nào - chúng có thể bị xóa.
  • Với lệnh sau, bạn có thể kiểm tra các hình ảnh treo lơ lửng trên hệ thống của mình:

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

Bạn có thể loại bỏ chúng theo cách sau:

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

Chúng ta cũng có thể sử dụng lệnh con 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

Nếu chúng ta đột nhiên muốn xóa tất cả các hình ảnh (và không chỉ treo lủng lẳng) bằng một lệnh, thì chúng ta có thể thực hiện việc này:

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

Mức sử dụng đĩa theo ổ đĩa

Các ổ đĩa được sử dụng để lưu trữ dữ liệu bên ngoài hệ thống tệp của vùng chứa. Ví dụ: nếu chúng ta muốn lưu kết quả của một ứng dụng để sử dụng chúng theo cách khác. Một ví dụ phổ biến là cơ sở dữ liệu.

Hãy khởi chạy bộ chứa MongoDB, gắn một ổ đĩa bên ngoài vào bộ chứa và khôi phục bản sao lưu cơ sở dữ liệu từ nó (chúng tôi có sẵn nó trong tệp 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

Dữ liệu sẽ được đặt trên máy chủ trong thư mục /var/lib/docker/volumes. Nhưng tại sao không ở cấp độ đọc-ghi của vùng chứa? Bởi vì trong Dockerfile của image MongoDB, thư mục /data/db (nơi MongoDB lưu trữ dữ liệu theo mặc định) được xác định là một ổ đĩa.

Mẹo về Docker: Dọn sạch rác trong máy của bạn

Lưu ý phụ: nhiều hình ảnh phải tạo ra dữ liệu sẽ sử dụng khối lượng để lưu trữ dữ liệu đó.

Khi chúng ta chơi đủ với MongoDB và dừng (hoặc thậm chí có thể xóa) vùng chứa, ổ đĩa sẽ không bị xóa. Nó sẽ tiếp tục chiếm dung lượng ổ đĩa quý giá của chúng ta cho đến khi chúng ta xóa nó một cách rõ ràng bằng lệnh như sau:

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

Chà, hoặc chúng ta có thể sử dụng lệnh con Prune đã quen thuộc với chúng ta:

$ 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:~$

Sử dụng đĩa để tạo bộ đệm xây dựng hình ảnh

Trong Docker 18.09, quá trình tạo image đã trải qua một số thay đổi nhờ công cụ BuildKit. Điều này làm tăng tốc độ của quá trình và tối ưu hóa việc lưu trữ dữ liệu và quản lý bảo mật. Ở đây chúng tôi sẽ không xem xét tất cả các chi tiết của công cụ tuyệt vời này; chúng tôi sẽ chỉ tập trung vào cách nó giải quyết các vấn đề về sử dụng dung lượng ổ đĩa.

Giả sử chúng ta có một ứng dụng Node.Js hoàn toàn đơn giản:

  • tệp index.js khởi động một máy chủ HTTP đơn giản phản hồi bằng một dòng cho mỗi yêu cầu nhận được:
  • tệp pack.json xác định các phần phụ thuộc, trong đó chỉ expressjs được sử dụng để chạy máy chủ 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 để xây dựng hình ảnh trông như thế này:

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

Hãy xây dựng hình ảnh theo cách thông thường, không cần sử dụng BuildKit:

$ docker build -t app:1.0 .

Nếu kiểm tra mức sử dụng dung lượng ổ đĩa, chúng tôi có thể thấy rằng chỉ có hình ảnh cơ sở (nút: 13-alpine) và hình ảnh đích (ứng dụng: 1.0) đang chiếm dung lượng:

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

Hãy xây dựng phiên bản thứ hai của ứng dụng của chúng ta bằng BuildKit. Để làm điều này, chúng ta chỉ cần đặt biến DOCKER_BUILDKIT thành 1:

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

Nếu bây giờ chúng ta kiểm tra việc sử dụng đĩa, chúng ta sẽ thấy rằng bộ đệm xây dựng (buid-cache) hiện có liên quan ở đó:

$ 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

Để xóa nó, sử dụng lệnh sau:

$ 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

Làm sạch tất cả!

Vì vậy, chúng tôi đã xem xét việc dọn dẹp dung lượng ổ đĩa bị chiếm giữ bởi các vùng chứa, hình ảnh và ổ đĩa. Tiểu ban Prune giúp chúng ta điều này. Nhưng nó cũng có thể được sử dụng ở cấp hệ thống docker và nó sẽ dọn sạch mọi thứ có thể:

$ 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]

Nếu vì lý do nào đó mà bạn đang tiết kiệm dung lượng ổ đĩa trên máy chạy Docker thì việc chạy lệnh này định kỳ sẽ trở thành thói quen.

Nguồn: www.habr.com

Thêm một lời nhận xét