docker-cleaner 0.4.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +17 -0
- data/.github/workflows/dependabot.yml +17 -0
- data/.gitignore +4 -0
- data/.sclng/metadata.toml +7 -0
- data/Gemfile +5 -1
- data/Gemfile.lock +11 -8
- data/README.md +34 -0
- data/docker-cleaner.gemspec +1 -1
- data/lib/docker_cleaner/containers.rb +36 -36
- data/lib/docker_cleaner/images.rb +90 -90
- data/lib/docker_cleaner/version.rb +1 -1
- metadata +12 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9245c57a0622e847a3c14b3bbcf81d98db2c0a538729da29cbfef0ca21f6a4c3
|
4
|
+
data.tar.gz: cabe356f1d6fe998b4d0000b80d4cbd90f1d0e7d7e8e04ccd17776a4718320d8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 64c3d9a8953e7718b4bebd0050aef32510e955494d1945c0bda06c0a4b8a60065f38b14bae8b8eb4b309343815b7ffceaddeba653a34dd9f23592f535830d146
|
7
|
+
data.tar.gz: b7050f77ed5bd4880c4ecc83c2eaaaa20b7dcd8f7098927e8c12146adac5c6d75d06f7a125d99712eea8166fb9877ea011981431c2b711f8de1dfdb50e675a3c
|
@@ -0,0 +1,17 @@
|
|
1
|
+
version: 2
|
2
|
+
updates:
|
3
|
+
- package-ecosystem: "bundler"
|
4
|
+
directory: "/"
|
5
|
+
allow:
|
6
|
+
- dependency-type: "all"
|
7
|
+
versioning-strategy: lockfile-only
|
8
|
+
schedule:
|
9
|
+
interval: "monthly"
|
10
|
+
reviewers:
|
11
|
+
- "leo-scalingo"
|
12
|
+
- package-ecosystem: "github-actions"
|
13
|
+
directory: "/"
|
14
|
+
schedule:
|
15
|
+
interval: "monthly"
|
16
|
+
reviewers:
|
17
|
+
- "leo-scalingo"
|
@@ -0,0 +1,17 @@
|
|
1
|
+
name: Dependabot auto-approve
|
2
|
+
on: pull_request
|
3
|
+
|
4
|
+
permissions:
|
5
|
+
# Mandatory for both the auto-merge enabling and approval steps
|
6
|
+
pull-requests: write
|
7
|
+
# Mandatory for the auto-merge enabling step
|
8
|
+
contents: write
|
9
|
+
|
10
|
+
jobs:
|
11
|
+
dependabot:
|
12
|
+
runs-on: ubuntu-latest
|
13
|
+
steps:
|
14
|
+
- name: Automatically merge Dependabot PRs
|
15
|
+
uses: scalingo/ghaction-dependabot-automerge@v1
|
16
|
+
env:
|
17
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,24 +1,27 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
docker-cleaner (0.
|
5
|
-
docker-api (~>
|
4
|
+
docker-cleaner (0.7.0)
|
5
|
+
docker-api (~> 2.0)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
|
-
docker-api (
|
11
|
-
excon (>= 0.
|
10
|
+
docker-api (2.4.0)
|
11
|
+
excon (>= 0.64.0)
|
12
12
|
multi_json
|
13
|
-
excon (
|
14
|
-
|
13
|
+
excon (1.3.0)
|
14
|
+
logger
|
15
|
+
logger (1.7.0)
|
16
|
+
multi_json (1.15.0)
|
15
17
|
|
16
18
|
PLATFORMS
|
17
19
|
ruby
|
18
20
|
|
19
21
|
DEPENDENCIES
|
20
|
-
docker-api
|
22
|
+
docker-api
|
21
23
|
docker-cleaner!
|
24
|
+
multi_json (= 1.15)
|
22
25
|
|
23
26
|
BUNDLED WITH
|
24
|
-
|
27
|
+
2.2.17
|
data/README.md
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# Docker Cleaner v0.6.0
|
2
|
+
|
3
|
+
Small ruby script to remove old containers and old images.
|
4
|
+
|
5
|
+
For containers, this removes containers that have been stopped for more than 2 hours.
|
6
|
+
For images, this removes unused and untagged images.
|
7
|
+
|
8
|
+
## Release a New Version
|
9
|
+
|
10
|
+
Bump new version number in:
|
11
|
+
- README.md
|
12
|
+
- lib/docker_cleaner/version.rb
|
13
|
+
- Gemfile.lock (docker-cleaner specs entry)
|
14
|
+
|
15
|
+
Commit, tag and create a new release:
|
16
|
+
```shell
|
17
|
+
version="0.6.0"
|
18
|
+
|
19
|
+
git switch --create release/${version}
|
20
|
+
git add Gemfile.lock README.md lib/docker_cleaner/version.rb
|
21
|
+
git commit -m "release: Bump v${version}"
|
22
|
+
git push --set-upstream origin release/${version}
|
23
|
+
gh pr create --reviewer=EtienneM --title "$(git log -1 --pretty=%B)"
|
24
|
+
```
|
25
|
+
|
26
|
+
Once the pull request merged, you can tag the new release.
|
27
|
+
|
28
|
+
```shell
|
29
|
+
git tag v${version}
|
30
|
+
git push origin master v${version}
|
31
|
+
gh release create v${version}
|
32
|
+
```
|
33
|
+
|
34
|
+
The title of the release should be the version number.
|
data/docker-cleaner.gemspec
CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.description = "Small utility to clean old docker data, containers according to some settings"
|
13
13
|
s.license = "MIT"
|
14
14
|
|
15
|
-
s.add_dependency "docker-api", "~>
|
15
|
+
s.add_dependency "docker-api", "~> 2.0"
|
16
16
|
|
17
17
|
s.files = `git ls-files`.split("\n")
|
18
18
|
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
@@ -1,46 +1,46 @@
|
|
1
1
|
module DockerCleaner
|
2
|
-
class Containers
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
def remove(container)
|
9
|
-
@logger.info "Remove #{container.id[0...10]} - #{container.info["Image"]} - #{container.info["Names"][0]}"
|
10
|
-
container.remove v: true
|
11
|
-
@logger.info "Remove #{container.id[0...10]} - #{container.info["Image"]} - #{container.info["Names"][0]}... OK"
|
12
|
-
end
|
2
|
+
class Containers
|
3
|
+
def initialize(logger, opts = {})
|
4
|
+
@logger = logger
|
5
|
+
@delay = opts.fetch(:delay, 0)
|
6
|
+
end
|
13
7
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
status = container.info["Status"]
|
19
|
-
(status == "Created" && container.info["Created"].to_i < two_hours_ago) ||
|
20
|
-
(status.include?("Exited (") && container.info["Created"].to_i < two_hours_ago)
|
21
|
-
}.each do |container|
|
22
|
-
remove(container)
|
23
|
-
sleep(@delay)
|
8
|
+
def remove(container)
|
9
|
+
@logger.info "Remove #{container.id[0...10]} - #{container.info["Image"]} - #{container.info["Names"][0]}"
|
10
|
+
container.remove v: true
|
11
|
+
@logger.info "Remove #{container.id[0...10]} - #{container.info["Image"]} - #{container.info["Names"][0]}... OK"
|
24
12
|
end
|
25
13
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
containers_per_app[app] << container
|
35
|
-
end
|
36
|
-
}
|
37
|
-
containers_per_app.each do |app, containers|
|
38
|
-
containers.shift
|
39
|
-
containers.each do |container|
|
14
|
+
def run
|
15
|
+
# Remove stopped container which stopped with code '0'
|
16
|
+
two_hours_ago = Time.now.to_i - 2 * 3600
|
17
|
+
Docker::Container.all(all: true).select{ |container|
|
18
|
+
status = container.info["Status"]
|
19
|
+
(status == "Created" && container.info["Created"].to_i < two_hours_ago) ||
|
20
|
+
(status.include?("Exited (") && container.info["Created"].to_i < two_hours_ago)
|
21
|
+
}.each do |container|
|
40
22
|
remove(container)
|
41
23
|
sleep(@delay)
|
42
24
|
end
|
25
|
+
|
26
|
+
containers_per_app = {}
|
27
|
+
Docker::Container.all(all: true).select{ |container|
|
28
|
+
container.info["Status"].include?("Exited")
|
29
|
+
}.each{ |container|
|
30
|
+
app = container.info["Image"].split(":", 2)[0]
|
31
|
+
if containers_per_app[app].nil?
|
32
|
+
containers_per_app[app] = [container]
|
33
|
+
else
|
34
|
+
containers_per_app[app] << container
|
35
|
+
end
|
36
|
+
}
|
37
|
+
containers_per_app.each do |app, containers|
|
38
|
+
containers.shift
|
39
|
+
containers.each do |container|
|
40
|
+
remove(container)
|
41
|
+
sleep(@delay)
|
42
|
+
end
|
43
|
+
end
|
43
44
|
end
|
44
45
|
end
|
45
46
|
end
|
46
|
-
end
|
@@ -1,117 +1,117 @@
|
|
1
1
|
module DockerCleaner
|
2
|
-
class Images
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
2
|
+
class Images
|
3
|
+
def initialize(registries, prefix, logger, opts = {})
|
4
|
+
@prefix = prefix || ""
|
5
|
+
@registries = registries
|
6
|
+
@logger = logger
|
7
|
+
@delay = opts.fetch(:delay, 0)
|
8
|
+
@retention = Time.now.to_i - opts.fetch(:retention, 6) * 3600
|
9
|
+
end
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
11
|
+
def run
|
12
|
+
clean_old_images
|
13
|
+
clean_unnamed_images
|
14
|
+
clean_unused_images
|
15
|
+
end
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
17
|
+
def clean_unnamed_images
|
18
|
+
Docker::Image.all.select do |image|
|
19
|
+
image.info["RepoTags"].nil? || image.info["RepoTags"][0] == "<none>:<none>"
|
20
|
+
end.each do |image|
|
21
|
+
@logger.info "Remove unnamed image #{image.id[0...10]}"
|
22
|
+
begin
|
23
|
+
image.remove
|
24
|
+
sleep(@delay)
|
25
|
+
rescue Docker::Error::NotFoundError
|
26
|
+
rescue Docker::Error::ConflictError => e
|
27
|
+
@logger.warn "Conflict when removing #{image.id[0...10]}"
|
28
|
+
@logger.warn " ! #{e.message}"
|
29
|
+
end
|
29
30
|
end
|
30
31
|
end
|
31
|
-
end
|
32
32
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
33
|
+
def clean_old_images
|
34
|
+
apps = images_with_latest
|
35
|
+
apps.each do |app, images|
|
36
|
+
if app =~ /.*-tmax$/
|
37
|
+
next
|
38
|
+
end
|
39
|
+
images.each do |i|
|
40
|
+
unless i.info["Created"] == apps["#{app}-tmax"]
|
41
|
+
@logger.info "Remove #{i.info['RepoTags'][0]} => #{i.id[0...10]}"
|
42
|
+
begin
|
43
|
+
i.remove
|
44
|
+
sleep(@delay)
|
45
|
+
rescue Docker::Error::NotFoundError
|
46
|
+
rescue Docker::Error::ConflictError => e
|
47
|
+
@logger.warn "Conflict when removing #{i.info['RepoTags'][0]} - ID: #{i.id[0...10]}"
|
48
|
+
@logger.warn " ! #{e.message}"
|
49
|
+
end
|
49
50
|
end
|
50
51
|
end
|
51
52
|
end
|
52
53
|
end
|
53
|
-
end
|
54
54
|
|
55
|
-
|
56
|
-
|
57
|
-
|
55
|
+
def images_with_latest
|
56
|
+
images ||= Docker::Image.all
|
57
|
+
apps = {}
|
58
58
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
59
|
+
images.each do |i|
|
60
|
+
# RepoTags can be nil sometimes, in this case we ignore the image
|
61
|
+
next if i.info["RepoTags"].nil?
|
62
|
+
if registries_include?(i.info["RepoTags"][0])
|
63
|
+
name = i.info["RepoTags"][0].split(":")[0]
|
64
|
+
tmax = "#{name}-tmax"
|
65
65
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
66
|
+
if apps[name].nil?
|
67
|
+
apps[name] = [i]
|
68
|
+
else
|
69
|
+
apps[name] << i
|
70
|
+
end
|
71
71
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
72
|
+
if apps[tmax].nil?
|
73
|
+
apps[tmax] = i.info["Created"]
|
74
|
+
elsif apps[tmax] < i.info["Created"]
|
75
|
+
apps[tmax] = i.info["Created"]
|
76
|
+
end
|
76
77
|
end
|
77
78
|
end
|
79
|
+
apps
|
78
80
|
end
|
79
|
-
apps
|
80
|
-
end
|
81
81
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
82
|
+
def clean_unused_images
|
83
|
+
used_images = Docker::Container.all.map{|c| c.info["Image"]}.select{|i| registries_include?(i) }.uniq
|
84
|
+
# Images older than 2 months
|
85
|
+
images = Docker::Image.all.select{|i| i.info["RepoTags"] && registries_include?(i.info["RepoTags"][0]) && i.info["Created"] < @retention }
|
86
|
+
image_repos = images.map{|i| i.info["RepoTags"][0]}
|
87
|
+
unused_images = image_repos - used_images
|
88
88
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
89
|
+
unused_images.each do |i|
|
90
|
+
image = images.select{|docker_image| docker_image.info["RepoTags"][0] == i}[0]
|
91
|
+
@logger.info "Remove unused image #{image.info['RepoTags'][0]} => #{image.id[0...10]}"
|
92
|
+
begin
|
93
|
+
image.remove
|
94
|
+
sleep(@delay)
|
95
|
+
rescue Docker::Error::NotFoundError
|
96
|
+
rescue Docker::Error::ConflictError => e
|
97
|
+
@logger.warn "Conflict when removing #{image.info['RepoTags'][0]} - ID: #{image.id[0...10]}"
|
98
|
+
@logger.warn " ! #{e.message}"
|
99
|
+
end
|
99
100
|
end
|
100
101
|
end
|
101
|
-
end
|
102
102
|
|
103
|
-
|
103
|
+
protected
|
104
104
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
105
|
+
def registries_include?(image)
|
106
|
+
if image.nil? || image == ''
|
107
|
+
return false
|
108
|
+
end
|
109
|
+
@registries.each do |registry|
|
110
|
+
if image =~ /^#{registry}\/#{@prefix}/
|
111
|
+
return true
|
112
|
+
end
|
112
113
|
end
|
114
|
+
return false
|
113
115
|
end
|
114
|
-
return false
|
115
116
|
end
|
116
117
|
end
|
117
|
-
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: docker-cleaner
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Leo Unbekandt
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-08-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: docker-api
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '2.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '2.0'
|
27
27
|
description: Small utility to clean old docker data, containers according to some
|
28
28
|
settings
|
29
29
|
email:
|
@@ -33,9 +33,13 @@ executables:
|
|
33
33
|
extensions: []
|
34
34
|
extra_rdoc_files: []
|
35
35
|
files:
|
36
|
+
- ".github/dependabot.yml"
|
37
|
+
- ".github/workflows/dependabot.yml"
|
36
38
|
- ".gitignore"
|
39
|
+
- ".sclng/metadata.toml"
|
37
40
|
- Gemfile
|
38
41
|
- Gemfile.lock
|
42
|
+
- README.md
|
39
43
|
- bin/docker-cleaner
|
40
44
|
- docker-cleaner.gemspec
|
41
45
|
- lib/docker_cleaner.rb
|
@@ -46,7 +50,7 @@ homepage: https://github.com/Scalingo/docker-cleaner
|
|
46
50
|
licenses:
|
47
51
|
- MIT
|
48
52
|
metadata: {}
|
49
|
-
post_install_message:
|
53
|
+
post_install_message:
|
50
54
|
rdoc_options: []
|
51
55
|
require_paths:
|
52
56
|
- lib
|
@@ -61,8 +65,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
61
65
|
- !ruby/object:Gem::Version
|
62
66
|
version: '0'
|
63
67
|
requirements: []
|
64
|
-
rubygems_version: 3.
|
65
|
-
signing_key:
|
68
|
+
rubygems_version: 3.5.11
|
69
|
+
signing_key:
|
66
70
|
specification_version: 4
|
67
71
|
summary: Small utility to clean old containers and images
|
68
72
|
test_files: []
|