Làm thế nào để xóa hình ảnh từ một đăng ký docker tư nhân?


162

Tôi chạy một đăng ký docker riêng và tôi muốn xóa tất cả các hình ảnh trừ latestkho lưu trữ. Tôi không muốn xóa toàn bộ kho lưu trữ, chỉ một số hình ảnh bên trong nó. Các tài liệu API không đề cập đến một cách để làm điều này, nhưng chắc chắn là có thể?


1
Câu trả lời được chấp nhận là không chính xác nữa (mặc dù chắc chắn rất tốt). Bạn có thể xóa hình ảnh bằng cách sử dụng DELETE / v2 / <name> / manifest / < Reference
Michael Zelensky

Câu trả lời:


116

Hiện tại bạn không thể sử dụng API đăng ký cho tác vụ đó. Nó chỉ cho phép bạn xóa một kho lưu trữ hoặc một thẻ cụ thể.

Nói chung, xóa một kho lưu trữ có nghĩa là tất cả các thẻ liên quan đến repo này sẽ bị xóa.

Xóa thẻ có nghĩa là liên kết giữa hình ảnh và thẻ bị xóa.

Không ai ở trên sẽ xóa một hình ảnh duy nhất. Chúng được để lại trên đĩa của bạn.


Giải pháp thay thế

Đối với cách giải quyết này, bạn cần lưu trữ hình ảnh docker cục bộ.

Một cách giải quyết cho giải pháp của bạn là xóa tất cả trừ các thẻ mới nhất và do đó có khả năng xóa tham chiếu đến các hình ảnh liên quan. Sau đó, bạn có thể chạy tập lệnh này để xóa tất cả các hình ảnh, không được tham chiếu bởi bất kỳ thẻ hoặc tổ tiên của bất kỳ hình ảnh được sử dụng.

Thuật ngữ (hình ảnh và thẻ)

Hãy xem xét một đồ thị hình ảnh như thế này mà các chữ in hoa ( A, B, ...) đại diện cho ID hình ảnh ngắn và <-phương tiện mà hình ảnh được dựa trên hình ảnh khác:

 A <- B <- C <- D

Bây giờ chúng tôi thêm các thẻ vào hình ảnh:

 A <- B <- C <- D
           |    |
           |    <version2>
           <version1>

Ở đây, thẻ <version1>tham chiếu hình ảnh Cvà thẻ <version2>tham chiếu hình ảnh D.

Tinh chỉnh câu hỏi của bạn

Trong câu hỏi của bạn, bạn nói rằng bạn muốn loại bỏ

tất cả hình ảnh nhưng latest

. Bây giờ, thuật ngữ này không hoàn toàn chính xác. Bạn đã trộn lẫn hình ảnh và thẻ. Nhìn vào biểu đồ tôi nghĩ bạn sẽ đồng ý rằng thẻ <version2>đại diện cho phiên bản mới nhất. Trong thực tế, theo câu hỏi này, bạn có thể có một thẻ đại diện cho phiên bản mới nhất:

 A <- B <- C <- D
           |    |
           |    <version2>
           |    <latest>
           <version1>

<latest>thẻ tham chiếu hình ảnh Dtôi hỏi bạn: bạn có thực sự muốn xóa tất cả trừ hình ảnh Dkhông? Chắc là không!

Điều gì xảy ra nếu bạn xóa một thẻ?

Nếu bạn xóa thẻ <version1>bằng API Docker REST, bạn sẽ nhận được điều này:

 A <- B <- C <- D
                |
                <version2>
                <latest>

Hãy nhớ rằng: Docker sẽ không bao giờ xóa một hình ảnh! Ngay cả nếu có, trong trường hợp này, nó không thể xóa một hình ảnh, vì hình ảnh Clà một phần của tổ tiên cho hình ảnh Dđược gắn thẻ.

Ngay cả khi bạn sử dụng tập lệnh này , sẽ không có hình ảnh nào bị xóa.

Khi một hình ảnh có thể bị xóa

Trong điều kiện bạn có thể kiểm soát khi ai đó có thể kéo hoặc đẩy vào sổ đăng ký của bạn (ví dụ: bằng cách vô hiệu hóa giao diện REST). Bạn có thể xóa một hình ảnh khỏi biểu đồ hình ảnh nếu không có hình ảnh nào khác dựa trên nó và không có thẻ nào đề cập đến nó.

Chú ý rằng trong đồ thị dưới đây, hình ảnh Dđược không dựa trên Cnhưng trên B. Do đó, Dkhông phụ thuộc vào C. Nếu bạn xóa thẻ <version1>trong biểu đồ này, hình ảnh Csẽ không được sử dụng bởi bất kỳ hình ảnh nào và tập lệnh này có thể xóa nó.

 A <- B <--------- D
      \            |
       \           <version2>
        \          <latest>
         \ <- C
              |
              <version1>

Sau khi dọn dẹp đồ thị hình ảnh của bạn trông như thế này:

 A <- B <- D
           |
           <version2>
           <latest>

Đây có phải là những gì bạn muốn?


Bạn đã đúng - xóa các thẻ không thực sự xóa các hình ảnh liên quan. Có cách nào để xóa các hình ảnh đã cho ssh truy cập vào hộp không?
Leo

1
Tôi đã chỉnh sửa câu trả lời của mình với một cách giải quyết phù hợp với tôi. Tôi hy vọng nó sẽ giúp.
Konrad Kleine

Chính xác là như vậy - tôi hiểu rằng hình ảnh được xây dựng tăng dần, nhưng tôi cần một cách để cắt tỉa những nhánh chết đó. Cảm ơn!
Leo

@KonradKleine làm thế nào để bạn tạo biểu đồ hình ảnh ra khỏi danh sách hình ảnh bạn nhận được từ sổ đăng ký?
Rafael Barros

9
Thu gom rác cuối cùng đã đến Cơ quan đăng ký v2.4.0 docs.docker.com/registry/garbage-collection
Markus Lindberg

68

Tôi đã gặp vấn đề tương tự với đăng ký của mình sau đó tôi đã thử giải pháp được liệt kê bên dưới từ một trang blog. Nó hoạt động.

Bước 1: Liệt kê danh mục

Bạn có thể liệt kê danh mục của bạn bằng cách gọi url này:

http://YourPrivateRegistyIP:5000/v2/_catalog

Phản hồi sẽ ở định dạng sau:

{
  "repositories": [
    <name>,
    ...
  ]
}

Bước 2: Danh sách thẻ cho danh mục liên quan

Bạn có thể liệt kê các thẻ của danh mục của bạn bằng cách gọi url này:

http://YourPrivateRegistyIP:5000/v2/<name>/tags/list

Phản hồi sẽ ở định dạng sau:

{
"name": <name>,
"tags": [
    <tag>,
    ...
]

}

Bước 3: Liệt kê giá trị tệp kê khai cho thẻ liên quan

Bạn có thể chạy lệnh này trong container đăng ký docker:

curl -v --silent -H "Accept: application/vnd.docker.distribution.manifest.v2+json" -X GET http://localhost:5000/v2/<name>/manifests/<tag> 2>&1 | grep Docker-Content-Digest | awk '{print ($3)}'

Phản hồi sẽ ở định dạng sau:

sha256:6de813fb93debd551ea6781e90b02f1f93efab9d882a6cd06bbd96a07188b073

Chạy lệnh được đưa ra dưới đây với giá trị tệp kê khai:

curl -v --silent -H "Accept: application/vnd.docker.distribution.manifest.v2+json" -X DELETE http://127.0.0.1:5000/v2/<name>/manifests/sha256:6de813fb93debd551ea6781e90b02f1f93efab9d882a6cd06bbd96a07188b073

Bước 4: Xóa các bảng kê khai được đánh dấu

Chạy lệnh này trong container đăng ký docker của bạn:

bin/registry garbage-collect  /etc/docker/registry/config.yml  

Đây là config.yml của tôi

root@c695814325f4:/etc# cat /etc/docker/registry/config.yml
version: 0.1
log:
  fields:
  service: registry
storage:
    cache:
        blobdescriptor: inmemory
    filesystem:
        rootdirectory: /var/lib/registry
    delete:
        enabled: true
http:
    addr: :5000
    headers:
        X-Content-Type-Options: [nosniff]
health:
  storagedriver:
    enabled: true
    interval: 10s
    threshold: 3

Các lệnh đã thành công, bao gồm các thông báo về " Deleteing blob: /docker/..." nhưng nó không thay đổi không gian đĩa được sử dụng. Sử dụng bin / registry github.com/docker/distribution v2.4.1 .
JamesThomasMoon1979

3
để xóa một hình ảnh, bạn nên chạy bộ chứa đăng ký với REGISTRY_STORAGE_DELETE_ENABLED = tham số đúng.
Adil

3
Tôi đặt giá trị "xóa: đã bật" thành đúng trong tệp /etc/docker/registry/config.yml. Đối với cấu hình này, không cần đặt biến REGISTRY_STORAGE_DELETE_ENABLED @AdilIlhan
Yavuz Sert

re: bước 3, "Docker-Content-Digest" phải nằm trong tiêu đề? (không nhìn thấy nó trong đầu ra curl). Tôi có thể xem kết quả đánh dấu một bảng kê khai trước khi xóa (các) bảng kê khai được đánh dấu để biết tôi đã đánh dấu thành công không? Nó dường như cho tôi một phản hồi 202 cho dù tôi gửi nó như thế nào.
SteveW

các Docker-Content-Digestphần phải ở trong chữ thường (thử nghiệm trên động cơ v18.09.2 Docker) tứccurl -v --silent -H "Accept: application/vnd.docker.distribution.manifest.v2+json" -X GET http://localhost:5000/v2/<name>/manifests/<tag> 2>&1 | grep docker-content-digest | awk '{print ($3)}'
Muhammad Abdurrahman

63

Sổ v2đăng ký hiện tại hỗ trợ xóa quaDELETE /v2/<name>/manifests/<reference>

Xem: https://github.com/docker/distribution/blob/master/docs/spec/api.md#deleting-an-image

Cách sử dụng: https://github.com/byrnedo/docker-reg-tool

Chỉnh sửa: Tệp kê khai <reference>ở trên có thể được truy xuất từ ​​yêu cầu đến

GET /v2/<name>/manifests/<tag>

và kiểm tra Docker-Content-Digesttiêu đề trong phản hồi.

Chỉnh sửa 2: Bạn có thể phải chạy đăng ký của mình với bộ env sau:

REGISTRY_STORAGE_DELETE_ENABLED="true"

Chỉnh sửa 3: Bạn có thể phải chạy bộ sưu tập rác để giải phóng không gian đĩa này: https://docs.docker.com/registry/garbage-collection/


3
Một số câu trả lời khác ở đây cho thấy làm thế nào để trích xuất hàm băm tham chiếu. Điều này là cần thiết để dịch một thẻ thành một cái gì đó để chuyển đến DELETE.
JamesThomasMoon1979

Nhận lỗi không được hỗ trợ. Tôi đã đưa ra giá trị tiêu hóa thích hợp như là tài liệu tham khảo.
Winster

1
@ JamesThomasMoon1979 được cập nhật với các hướng dẫn về cách lấy băm tham chiếu.
byrnedo

11
trên V2 cũng vậy và gặp lỗi{"errors":[{"code":"UNSUPPORTED","message":"The operation is unsupported."}]}
Gadelkareem

1
Kiểm tra chỉnh sửa @Gadelkareem
byrnedo

17

Vấn đề 1

Bạn đã đề cập nó là đăng ký docker riêng của bạn, vì vậy bạn có thể cần kiểm tra API Registry thay vì tài liệu API đăng ký Hub , đây là liên kết bạn cung cấp.

Vấn đề 2

API đăng ký docker là một giao thức máy khách / máy chủ, tùy thuộc vào việc thực hiện của máy chủ về việc có xóa các hình ảnh trong back-end hay không. (Tôi đoán)

DELETE /v1/repositories/(namespace)/(repository)/tags/(tag*)

Giải thích chi tiết

Dưới đây tôi giới thiệu cách nó hoạt động bây giờ từ mô tả của bạn như sự hiểu biết của tôi cho câu hỏi của bạn.

Bạn chạy bạn chạy đăng ký docker riêng, tôi sử dụng mặc định và nghe trong 5000cổng

docker run -d -p 5000:5000 registry

Sau đó, tôi gắn thẻ hình ảnh địa phương và đẩy vào nó.

$ docker tag ubuntu localhost:5000/ubuntu
$ docker push localhost:5000/ubuntu
The push refers to a repository [localhost:5000/ubuntu] (len: 1)
Sending image list
Pushing repository localhost:5000/ubuntu (1 tags)
511136ea3c5a: Image successfully pushed
d7ac5e4f1812: Image successfully pushed
2f4b4d6a4a06: Image successfully pushed
83ff768040a0: Image successfully pushed
6c37f792ddac: Image successfully pushed
e54ca5efa2e9: Image successfully pushed
Pushing tag for rev [e54ca5efa2e9] on {http://localhost:5000/v1/repositories/ubuntu/tags/latest}

Sau đó, bạn có thể sử dụng API đăng ký để kiểm tra xem nó có tồn tại trong sổ đăng ký docker riêng của bạn không

$ curl -X GET localhost:5000/v1/repositories/ubuntu/tags
{"latest": "e54ca5efa2e962582a223ca9810f7f1b62ea9b5c3975d14a5da79d3bf6020f37"}

Bây giờ tôi có thể xóa thẻ bằng API đó !!

$ curl -X DELETE localhost:5000/v1/repositories/ubuntu/tags/latest
true

Kiểm tra lại, thẻ không tồn tại trong máy chủ đăng ký riêng của bạn

$ curl -X GET localhost:5000/v1/repositories/ubuntu/tags/latest
{"error": "Tag not found"}

2
Xin vui lòng, xem câu trả lời của tôi dưới đây để được giải thích tại sao lệnh này không giúp đỡ.
Konrad Kleine

2
Bạn xóa các thẻ nhưng không phải dữ liệu hình ảnh. Cái sau được thực hiện bởi tập lệnh tôi tham chiếu sau khi bạn đã xóa một thẻ. Tôi cũng sử dụng API đăng ký để xóa thẻ.
Konrad Kleine

3
tùy theo triển khai của mỗi máy chủ API, theo quan điểm của giao thức, nó không tồn tại.
Larry Cai

Bạn nói đúng là tùy vào việc triển khai - nhưng tôi đã / đang tìm cách xóa dữ liệu hình ảnh khỏi registryhình ảnh chính tắc . SSH vào và chạy một kịch bản hoạt động, ngay cả khi nó không lý tưởng. Là một lưu ý phụ tôi vẫn nghĩ đó là một API chưa hoàn chỉnh - bạn có thể xóa các thẻ, nhưng nếu bạn NHẬN /imagesbạn vẫn thấy tất cả dữ liệu hình ảnh còn sót lại.
Leo

Cảm ơn bạn đã đề cập đến API đăng ký, đã tìm cách XÓA hình ảnh trong sổ đăng ký riêng. Phương pháp này là đủ tốt cho tôi ngay cả khi nó chỉ là 'tháo gỡ' mà không thực sự giải phóng không gian đĩa.
Howard Lee

16

Điều này thực sự xấu nhưng nó hoạt động, văn bản được kiểm tra trên registry: 2.5.1. Tôi đã không quản lý để xóa hoạt động trơn tru ngay cả sau khi cập nhật cấu hình để cho phép xóa. ID rất khó lấy, phải đăng nhập để lấy, có thể là một số hiểu lầm. Dù sao, các công việc sau đây:

  1. Đăng nhập vào container

    docker exec -it registry sh
    
  2. Xác định các biến khớp với phiên bản vùng chứa và vùng chứa của bạn:

    export NAME="google/cadvisor"
    export VERSION="v0.24.1"
    
  3. Di chuyển đến thư mục đăng ký:

    cd /var/lib/registry/docker/registry/v2
    
  4. Xóa các tệp liên quan đến hàm băm của bạn:

    find . | grep `ls ./repositories/$NAME/_manifests/tags/$VERSION/index/sha256`| xargs rm -rf $1
    
  5. Xóa các bảng kê khai:

    rm -rf ./repositories/$NAME/_manifests/tags/$VERSION
    
  6. Đăng xuất

    exit
    
  7. Chạy GC:

    docker exec -it registry  bin/registry garbage-collect  /etc/docker/registry/config.yml
    
  8. Nếu tất cả đã được thực hiện đúng, một số thông tin về các đốm bị xóa được hiển thị.


tôi đã làm theo các bước tương tự được đề cập ở trên, nhưng khi tôi kiểm tra việc sử dụng đĩa docker registry {container} thì nó vẫn hiển thị giống như trước khi thực hiện các bước ... có ý tưởng nào không?
Savio Mathew

không hoạt động. Dễ dàng kiểm tra. Khi bạn thực hiện các bước sau và đẩy lại repo, nó báo "064794e955a6: Lớp đã tồn tại"
Oduvan

8

Có một số khách hàng (bằng Python, Ruby, v.v.) thực hiện chính xác điều đó. Theo sở thích của tôi, việc cài đặt thời gian chạy (ví dụ Python) trên máy chủ đăng ký của tôi là không bền vững, chỉ để quản lý sổ đăng ký của tôi!


deckschrubberGiải pháp của tôi cũng vậy :

go get github.com/fraunhoferfokus/deckschrubber
$GOPATH/bin/deckschrubber

hình ảnh cũ hơn một độ tuổi nhất định sẽ tự động bị xóa. Tuổi thể được chỉ định sử dụng -year, -month, -day, hoặc sự kết hợp của chúng:

$GOPATH/bin/deckschrubber -month 2 -day 13 -registry http://registry:5000

CẬP NHẬT : đây là một giới thiệu ngắn về Deckschrubber.


1
deckschrubberlà khá tốt - rất dễ cài đặt (nhị phân đơn) và cho phép bạn xóa hình ảnh theo tên (với kết hợp regex) cũng như độ tuổi.
RichVel

ERRO[0000] Could not delete image! repo=.... tag=latest: /
scythargon

@scythargon không thể nói rằng thông số kỹ thuật của bạn là chính xác.
jitter

Cảnh báo: không có nghĩa đen gì trên kho lưu trữ của tôi.
Richard Warburton

Thật không may, nó sẽ không xóa hình ảnh không có thẻ. Vì vậy, nếu bạn tiếp tục đẩy hình ảnh trên một thẻ, nó sẽ chỉ kiểm tra cái được gắn thẻ chứ không phải cái khác.
Kirtian

1

Tóm tắt;

1) Bạn phải gõ lệnh sau cho RepoDigests của một docko repo;

## docker inspect <registry-host>:<registry-port>/<image-name>:<tag>
> docker inspect 174.24.100.50:8448/example-image:latest


[
    {
        "Id": "sha256:16c5af74ed970b1671fe095e063e255e0160900a0e12e1f8a93d75afe2fb860c",
        "RepoTags": [
            "174.24.100.50:8448/example-image:latest",
            "example-image:latest"
        ],
        "RepoDigests": [
            "174.24.100.50:8448/example-image@sha256:5580b2110c65a1f2567eeacae18a3aec0a31d88d2504aa257a2fecf4f47695e6"
        ],
...
...

$ {digest} = sha256: 5580b2110c65a1f2567eeacae18a3aec0a31d88d2504aa257a2fecf4f47695e6

2) Sử dụng API REST đăng ký

  ##curl -u username:password -vk -X DELETE registry-host>:<registry-port>/v2/<image-name>/manifests/${digest}


  >curl -u example-user:example-password -vk -X DELETE http://174.24.100.50:8448/v2/example-image/manifests/sha256:5580b2110c65a1f2567eeacae18a3aec0a31d88d2504aa257a2fecf4f47695e6

Bạn sẽ nhận được 202 Chấp nhận cho một cuộc gọi thành công.

3-) Chạy Trình thu gom rác

docker exec registry bin/registry garbage-collect --dry-run /etc/docker/registry/config.yml

đăng ký - tên container đăng ký.

Để biết thêm chi tiết giải thích nhập mô tả liên kết ở đây



0

Bên dưới Bash Script Xóa tất cả các thẻ nằm trong sổ đăng ký ngoại trừ mới nhất.

for D in /registry-data/docker/registry/v2/repositories/*; do
if [ -d "${D}" ]; then
    if [ -z "$(ls -A ${D}/_manifests/tags/)" ]; then
        echo ''
    else
        for R in $(ls -t ${D}/_manifests/tags/ | tail -n +2); do
            digest=$(curl -k -I -s -H -X GET http://xx.xx.xx.xx:5000/v2/$(basename  ${D})/manifests/${R} -H 'accept: application/vnd.docker.distribution.manifest.v2+json'  | grep Docker-Content-Digest | awk '{print $2}' )
            url="http://xx.xx.xx.xx:5000/v2/$(basename  ${D})/manifests/$digest"
            url=${url%$'\r'}
            curl -X DELETE -k -I -s   $url -H 'accept: application/vnd.docker.distribution.manifest.v2+json' 
        done
    fi
fi
done

Sau này chạy

docker exec $(docker ps | grep registry | awk '{print $1}') /bin/registry garbage-collect /etc/docker/registry/config.yml

Bạn có thể giải thích thêm một chút về cách sử dụng tập lệnh tốt này không?
Khalil Gharbaoui

0

Kịch bản ruby ​​đơn giản dựa trên câu trả lời này : registry_cleaner .

Bạn có thể chạy nó trên máy cục bộ:

./registry_cleaner.rb --host=https://registry.exmpl.com --repository=name --tags_count=4

Và sau đó trên máy đăng ký loại bỏ các đốm màu với /bin/registry garbage-collect /etc/docker/registry/config.yml.


0

Đây là một kịch bản dựa trên câu trả lời của Yavuz Sert. Nó xóa tất cả các thẻ không phải là phiên bản mới nhất và thẻ của chúng lớn hơn 950.

#!/usr/bin/env bash


CheckTag(){
    Name=$1
    Tag=$2

    Skip=0
    if [[ "${Tag}" == "latest" ]]; then
        Skip=1
    fi
    if [[ "${Tag}" -ge "950" ]]; then
        Skip=1
    fi
    if [[ "${Skip}" == "1" ]]; then
        echo "skip ${Name} ${Tag}"
    else
        echo "delete ${Name} ${Tag}"
        Sha=$(curl -v -s -H "Accept: application/vnd.docker.distribution.manifest.v2+json" -X GET http://127.0.0.1:5000/v2/${Name}/manifests/${Tag} 2>&1 | grep Docker-Content-Digest | awk '{print ($3)}')
        Sha="${Sha/$'\r'/}"
        curl -H "Accept: application/vnd.docker.distribution.manifest.v2+json" -X DELETE "http://127.0.0.1:5000/v2/${Name}/manifests/${Sha}"
    fi
}

ScanRepository(){
    Name=$1
    echo "Repository ${Name}"
    curl -s http://127.0.0.1:5000/v2/${Name}/tags/list | jq '.tags[]' |
    while IFS=$"\n" read -r line; do
        line="${line%\"}"
        line="${line#\"}"
        CheckTag $Name $line
    done
}


JqPath=$(which jq)
if [[ "x${JqPath}" == "x" ]]; then
  echo "Couldn't find jq executable."
  exit 2
fi

curl -s http://127.0.0.1:5000/v2/_catalog | jq '.repositories[]' |
while IFS=$"\n" read -r line; do
    line="${line%\"}"
    line="${line#\"}"
    ScanRepository $line
done
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.