gitlab-janitor 0.0.3 → 1.0.2.92939
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/Dockerfile +29 -4
- data/Gemfile +0 -3
- data/Gemfile.lock +7 -2
- data/README.md +150 -31
- data/bin/gitlab-janitor +80 -32
- data/docker-compose.yml +4 -0
- data/gitlab-janitor.gemspec +7 -4
- data/lib/gitlab-janitor.rb +2 -5
- data/lib/{gitlab-janitor/base-cleaner.rb → gitlab_janitor/base_cleaner.rb} +13 -5
- data/lib/gitlab_janitor/cache_cleaner.rb +24 -0
- data/lib/gitlab_janitor/container_cleaner.rb +120 -0
- data/lib/gitlab_janitor/image_cleaner/store.rb +66 -0
- data/lib/gitlab_janitor/image_cleaner.rb +140 -0
- data/lib/{gitlab-janitor → gitlab_janitor}/utils.rb +16 -21
- data/lib/gitlab_janitor/version.rb +6 -0
- data/lib/gitlab_janitor/volume_cleaner.rb +120 -0
- data/lib/gitlab_janitor.rb +8 -0
- metadata +50 -18
- data/lib/gitlab-janitor/container-cleaner.rb +0 -114
- data/lib/gitlab-janitor/version.rb +0 -5
- data/lib/gitlab-janitor/volume-cleaner.rb +0 -90
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 754be135680d4f02cc976507e6909cad85fa9610ba686be487517a64ac205b85
|
4
|
+
data.tar.gz: a849dcf8db984238cd90084df0601ada8c16c8e3d1fc012da434d2a754c6fe4d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cbf5f383e72d1aeda4fc8426997633035b79db4111d41c5a6afa2743856ad2d0e5d03b14a0d8802a54c42442b740f46facfa641f40bf7129833ae851e6dfd258
|
7
|
+
data.tar.gz: 6fe45e92c6488892fa1838c654c535f394775b844bc7e999eee51248379bec91cdf7c4984eaacb636e309c4a9bdcc1c7bbb6b4779a8ad6afa3679d88607d844a
|
data/Dockerfile
CHANGED
@@ -11,23 +11,48 @@ RUN mkdir -p /usr/local/etc \
|
|
11
11
|
} >> /usr/local/etc/gemrc \
|
12
12
|
&& echo 'gem: --no-document' > ~/.gemrc
|
13
13
|
|
14
|
-
|
15
|
-
|
14
|
+
RUN set -ex \
|
15
|
+
&& apk add --no-cache docker-cli
|
16
|
+
|
16
17
|
|
17
|
-
ADD Gemfile Gemfile.lock /home/app/
|
18
|
+
ADD Gemfile Gemfile.lock gitlab-janitor.gemspec /home/app/
|
19
|
+
ADD lib/gitlab_janitor/version.rb /home/app/lib/gitlab_janitor/
|
18
20
|
|
19
21
|
RUN set -ex \
|
20
22
|
&& gem install bundler && gem update bundler \
|
21
23
|
&& bundle config set --local system 'true' \
|
24
|
+
&& bundle config set --local without 'development' \
|
22
25
|
&& bundle install --jobs=3 \
|
26
|
+
&& bundle clean --force \
|
23
27
|
&& rm -rf /tmp/* /var/tmp/* /usr/src/ruby /root/.gem /usr/local/bundle/cache
|
24
28
|
|
25
29
|
ADD . /home/app/
|
26
30
|
|
27
31
|
RUN set -ex \
|
28
32
|
&& bundle install --jobs=3 \
|
33
|
+
&& bundle clean --force \
|
29
34
|
&& rm -rf /tmp/* /var/tmp/* /usr/src/ruby /root/.gem /usr/local/bundle/cache
|
30
35
|
|
31
|
-
|
36
|
+
ARG \
|
37
|
+
CREATED="2022-08-05 15:22:36+03:00" \
|
38
|
+
VERSION="unknown" \
|
39
|
+
REVISION="unknown" \
|
40
|
+
REFNAME="unknown"
|
41
|
+
|
42
|
+
LABEL \
|
43
|
+
org.opencontainers.image.created="${CREATED}" \
|
44
|
+
org.opencontainers.image.authors="Samoylenko Yuri <kinnalru@yandex.ru>" \
|
45
|
+
org.opencontainers.image.url="https://github.com/RND-SOFT/gitlab-janitor" \
|
46
|
+
org.opencontainers.image.documentation="https://github.com/RND-SOFT/gitlab-janitor" \
|
47
|
+
org.opencontainers.image.source="https://github.com/RND-SOFT/gitlab-janitor" \
|
48
|
+
org.opencontainers.image.version="${VERSION}" \
|
49
|
+
org.opencontainers.image.revision="${REVISION}" \
|
50
|
+
org.opencontainers.image.vendor="RNDSOFT" \
|
51
|
+
org.opencontainers.image.licenses="MIT" \
|
52
|
+
org.opencontainers.image.ref.name="${REFNAME}" \
|
53
|
+
org.opencontainers.image.title="GitLab Janitor is a tool to automatically manage stalled and dangling resources when using Docker in Gitlab CI/CD" \
|
54
|
+
org.opencontainers.image.description="GitLab Janitor is a tool to automatically manage stalled and dangling resources when using Docker in Gitlab CI/CD"
|
55
|
+
|
56
|
+
CMD ["bundle", "exec", "bin/gitlab-janitor"]
|
32
57
|
|
33
58
|
|
data/Gemfile.lock
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
gitlab-janitor (
|
4
|
+
gitlab-janitor (1.0.2.92939)
|
5
5
|
activesupport (~> 6.0)
|
6
6
|
docker-api
|
7
7
|
fugit
|
8
8
|
optparse
|
9
|
+
redis
|
10
|
+
tzinfo-data
|
9
11
|
|
10
12
|
GEM
|
11
13
|
remote: https://rubygems.org/
|
@@ -37,6 +39,7 @@ GEM
|
|
37
39
|
optparse (0.2.0)
|
38
40
|
raabro (1.4.0)
|
39
41
|
rake (13.0.6)
|
42
|
+
redis (4.7.1)
|
40
43
|
rspec (3.11.0)
|
41
44
|
rspec-core (~> 3.11.0)
|
42
45
|
rspec-expectations (~> 3.11.0)
|
@@ -66,6 +69,8 @@ GEM
|
|
66
69
|
unicode-display_width (>= 1.1.1, < 3)
|
67
70
|
tzinfo (2.0.5)
|
68
71
|
concurrent-ruby (~> 1.0)
|
72
|
+
tzinfo-data (1.2022.1)
|
73
|
+
tzinfo (>= 1.0.0)
|
69
74
|
unicode-display_width (2.2.0)
|
70
75
|
zeitwerk (2.6.0)
|
71
76
|
|
@@ -83,4 +88,4 @@ DEPENDENCIES
|
|
83
88
|
simplecov-console
|
84
89
|
|
85
90
|
BUNDLED WITH
|
86
|
-
2.3.
|
91
|
+
2.3.11
|
data/README.md
CHANGED
@@ -1,52 +1,171 @@
|
|
1
1
|
# gitlab-janitor
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
3
|
+
<div align="center">
|
4
|
+
|
5
|
+
[](https://rubygems.org/gems/gitlab-janitor)
|
6
|
+
[](https://rubygems.org/gems/gitlab-janitor/versions)
|
7
|
+
[](http://www.rubydoc.info/gems/gitlab-janitor)
|
8
|
+
|
9
|
+
[](https://hub.docker.com/r/rnds/gitlab-janitor/)
|
10
|
+
[](https://hub.docker.com/r/rnds/gitlab-janitor/)
|
11
|
+
|
12
|
+
</div>
|
13
|
+
|
14
|
+
Gitlab Janitor это утилита для автоматической очистки зависших и брошенных ресурсов при использовании Docker в `Gitlab` CI/CD. Проект вдохновлён утилитой [GitLab Runner Docker Cleanup](https://gitlab.com/gitlab-org/gitlab-runner-docker-cleanup).
|
15
|
+
|
16
|
+
---
|
17
|
+
|
18
|
+
GitLab Janitor is a tool to automatically manage stalled and dangling resources when using Docker in `Gitlab` CI/CD. Project inpired by [GitLab Runner Docker Cleanup](https://gitlab.com/gitlab-org/gitlab-runner-docker-cleanup).
|
19
|
+
|
20
|
+
Возможности / Features
|
21
|
+
|
22
|
+
- Удаление повисших контейнеров / Remove dangling containers
|
23
|
+
- Удаление неиспользуемых хранилищ / Remove unused anonymous volumes
|
24
|
+
- Удаление неиспользуемых образов / Remove unused images
|
25
|
+
- Отслеживание вререни использвоания образов / Track image usage timestamp
|
26
|
+
- Очистка кешей Docker (build cache) / Cleanup docker build cache
|
27
|
+
- Готовый [docker-образ](https://hub.docker.com/r/rnds/gitlab-janitor) / Production ready [docker image](https://hub.docker.com/r/rnds/gitlab-janitor)
|
28
|
+
|
29
|
+
## Установка / Installation
|
30
|
+
|
31
|
+
```sh
|
32
|
+
$ gem install gitlab-janitor
|
33
|
+
```
|
34
|
+
|
35
|
+
При установке `Gitlab Janitor` через bundler добавте следующую строку в `Gemfile`, установив `require` параметр в `false`:
|
36
|
+
|
37
|
+
---
|
38
|
+
|
39
|
+
If you'd rather install `Gitlab Janitor` using bundler, add a line for it in your `Gemfile` (but set the `require` option to `false`, as it is a standalone tool):
|
40
|
+
|
41
|
+
```sh
|
42
|
+
gem 'rubocop', require: false
|
43
|
+
```
|
44
|
+
|
45
|
+
Для установки с помощью docker контейнера [скачайте образ](https://hub.docker.com/r/rnds/gitlab-janitor):
|
46
|
+
|
47
|
+
---
|
48
|
+
|
49
|
+
To install as docker container just [pull the image](https://hub.docker.com/r/rnds/gitlab-janitor):
|
50
|
+
|
51
|
+
|
52
|
+
```sh
|
53
|
+
docker pull rnds/gitlab-janitor:latest
|
54
|
+
```
|
55
|
+
|
56
|
+
## Быстрый запуск / Quickstart
|
57
|
+
|
58
|
+
Запустите `gitlab-janitor` и смотрите за процессом или запустите docker:
|
59
|
+
|
60
|
+
---
|
61
|
+
|
62
|
+
Just type `gitlab-janitor` and watch the magic happen or run in docker:
|
63
|
+
|
64
|
+
```sh
|
65
|
+
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock rnds/gitlab-janitor:latest
|
20
66
|
```
|
21
67
|
|
68
|
+
## Документация / Documentation
|
69
|
+
|
70
|
+
Параметры командной строки, переменные окружения и занчения по-умолчанию:
|
71
|
+
|
72
|
+
Commain line options, environment variables and default values:
|
73
|
+
|
74
|
+
```sh
|
75
|
+
$ gitlab-janitor --help
|
76
|
+
|
77
|
+
Usage: gitlab-janitor [options]
|
78
|
+
--clean-delay=30m ENV[CLEAN_DELAY] Delay between clean operation.
|
79
|
+
--include=*units* ENV[INCLUDE] <List> Include container for removal.
|
80
|
+
--exclude=*gitlab* ENV[EXCLUDE] <List> Exclude container from removal by name.
|
81
|
+
--container-deadline=1h10m ENV[CONTAINER_DEADLINE] Maximum container run duration.
|
82
|
+
--volume-include=runner*cache*
|
83
|
+
ENV[VOLUME_INCLUDE] <List> Include volumes for removal.
|
84
|
+
--volume-deadline=2d6h ENV[VOLUME_DEADLINE] Maximum volume life duration.
|
85
|
+
--image-deadline=20d ENV[IMAGE_DEADLINE] Maximum image life duration.
|
86
|
+
--image-store=./images.txt ENV[IMAGE_STORE] File to store images timestamps.
|
87
|
+
--cache-size=10G ENV[CACHE_SIZE] Size of docker cache to keep.
|
88
|
+
--remove ENV[REMOVE] Real remove instead of dry run.
|
89
|
+
--docker=unix:///tmp/mysock ENV[DOCKER_HOST] Docker api endpoint.
|
90
|
+
--debug ENV[LOG_LEVEL] Verbose logs. ENV values: debug, info, warn, error
|
91
|
+
```
|
22
92
|
|
23
|
-
|
93
|
+
### Удаление зависших контейнеров / Removing stalled containers
|
24
94
|
|
25
95
|
Порядок определения контейнреов для удаления:
|
26
96
|
|
27
|
-
- `include
|
28
|
-
- `exclude
|
97
|
+
- `include=[*units*]` - в список на удаление включаются контейнеры удовлетворябющие шаблону;
|
98
|
+
- `exclude=[*gitlab*]` - из спсика исключаются контейнеры по шаблону;
|
29
99
|
- `container-deadline=[1h10m]` - результирующий список проверяется на длительность запуска контенйра;
|
30
100
|
|
31
|
-
|
101
|
+
---
|
32
102
|
|
33
|
-
|
103
|
+
Containers deleted when:
|
34
104
|
|
35
|
-
-
|
105
|
+
- `include=[*units*]` - select containers by matching name by pattern;
|
106
|
+
- `exclude=[*gitlab*]` - **reject** containers by matching name by pattern;
|
107
|
+
- `container-deadline=[1h10m]` - when container lifetime exceeding the deadline it is removed;
|
108
|
+
|
109
|
+
### Удаление ненужных volumes / Removing unused volumes
|
110
|
+
|
111
|
+
Порядок определения вольюмов для удаления:
|
112
|
+
|
113
|
+
- на удаление попадают вольюмы, не являющиеся именованными;
|
114
|
+
- `volume-include=[runner*cache*]`- дополнительные волюмы для удаления;
|
36
115
|
- `volume-deadline=[2d6h]` - результирующий список проверяется на длительность существования вольюма;
|
37
116
|
|
38
|
-
|
117
|
+
---
|
118
|
+
|
119
|
+
Volumes deleted when:
|
120
|
+
|
121
|
+
- select all anonymous volumes;
|
122
|
+
- `volume-include=[runner*cache*]`- add volumes by matching name by pattern;
|
123
|
+
- `volume-deadline=[2d6h]` - when volume lifetime exceeding the deadline it is removed;
|
39
124
|
|
40
|
-
|
125
|
+
### Removing images / Удаление образов
|
41
126
|
|
42
|
-
|
127
|
+
Docker не сохраняет временную метку образа при скачивании (pull), таким образом используя средства `Docker API` невозможно понять как давно образ был скачан и когда его пора удалять. Для решения этой задачи сервис сохраняет информацию о скачанных образах, отслеживая таким образом интервалы устаревания.
|
43
128
|
|
44
|
-
|
129
|
+
Порядок определения образов для удаления:
|
130
|
+
|
131
|
+
- При первой встрече нового образа врменная метка сохраняется в локальное хранилище (файл);
|
132
|
+
- При достижении лимита хранения образ удаляется;
|
133
|
+
- При обнаружении запущенного контейнера временная метка для соответствующего образа обнуляется;
|
45
134
|
- `image-deadline=[20d]` - результирующий список проверяется на длительность существования образа;
|
46
135
|
|
47
136
|
|
48
|
-
|
137
|
+
---
|
138
|
+
|
139
|
+
Docker don't track timestamp when puling image, so there is impossible track lifetime through `Docker API`. To solve this problem, the service saves information about downloaded images, thus keeping track of lifetime deadline.
|
140
|
+
|
141
|
+
Images deleted when:
|
142
|
+
|
143
|
+
- When a new image is first encountered, the timestamp is stored in local storage (file);
|
144
|
+
- When a running container is found, the timestamp for the corresponding image is reset to zero;
|
145
|
+
- `image-deadline=[20d]` - when lifetime exceeding the deadline image it is removed (`docker rmi <image>`);
|
146
|
+
|
147
|
+
## Приеры / Examples
|
148
|
+
|
149
|
+
Конфиг для продуктового режима / Production ready config:
|
150
|
+
|
151
|
+
```sh
|
152
|
+
REMOVE=true INCLUDE="*integr*, *units*" EXCLUDE="*gitlab*" CONTAINER_DEADLINE="1h10m" VOLUME_DEADLINE="3d" IMAGE_DEADLINE="20d" gitlab-janitor
|
153
|
+
```
|
154
|
+
|
155
|
+
## Запуск в докере / Running in docker
|
156
|
+
|
157
|
+
```sh
|
158
|
+
docker run --rm \
|
159
|
+
-v /var/run/docker.sock:/var/run/docker.sock \
|
160
|
+
-e REMOVE=true \
|
161
|
+
-e INCLUDE="*integr*, *units*" \
|
162
|
+
-e EXCLUDE="*gitlab*" \
|
163
|
+
-e CONTAINER_DEADLINE="1h10m" \
|
164
|
+
-e VOLUME_DEADLINE="3d" \
|
165
|
+
-e IMAGE_DEADLINE="20d" \
|
166
|
+
rnds/gitlab-janitor:latest
|
167
|
+
```
|
168
|
+
|
169
|
+
## Лицензия / License
|
49
170
|
|
50
|
-
|
51
|
-
REMOVE=true INCLUDE="*integr*, *units*" EXCLUDE="*gitlab*" CONTAINER_DEADLINE="1h10m" VOLUME_DEADLINE="3d" IMAGE_DEADLINE="20d" ./main.rb
|
52
|
-
```
|
171
|
+
[MIT](./LICENSE)
|
data/bin/gitlab-janitor
CHANGED
@@ -1,19 +1,18 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
#cwd = __dir__
|
4
|
-
|
5
|
-
|
3
|
+
# cwd = __dir__
|
4
|
+
# $root = "#{cwd}/"
|
5
|
+
# $: << $root
|
6
6
|
|
7
|
-
#lib = File.expand_path('lib', __dir__)
|
8
|
-
|
7
|
+
# lib = File.expand_path('lib', __dir__)
|
8
|
+
# $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
9
9
|
|
10
10
|
|
11
|
-
#require 'rubygems'
|
12
|
-
#require 'bundler'
|
13
|
-
#require 'bundler/setup'
|
14
|
-
#Bundler.require(:default)
|
11
|
+
# require 'rubygems'
|
12
|
+
# require 'bundler'
|
13
|
+
# require 'bundler/setup'
|
14
|
+
# Bundler.require(:default)
|
15
15
|
|
16
|
-
require 'active_support/all'
|
17
16
|
require 'docker-api'
|
18
17
|
require 'fugit'
|
19
18
|
require 'optparse'
|
@@ -25,80 +24,129 @@ UTIL = File.basename(__FILE__)
|
|
25
24
|
GitlabJanitor::Util.setup
|
26
25
|
|
27
26
|
@opts = {
|
28
|
-
includes: [ENV.fetch('INCLUDE', '*units*')],
|
29
|
-
excludes: [ENV.fetch('EXCLUDE', '*gitlab*')],
|
30
|
-
clean_delay: ENV.fetch('CLEAN_DELAY', '
|
27
|
+
includes: [ENV.fetch('INCLUDE', '*units*').split(/[,;]/)].flatten.compact,
|
28
|
+
excludes: [ENV.fetch('EXCLUDE', '*gitlab*').split(/[,;]/)].flatten.compact,
|
29
|
+
clean_delay: ENV.fetch('CLEAN_DELAY', '10m'),
|
31
30
|
container_deadline: ENV.fetch('CONTAINER_DEADLINE', '1h10m'),
|
32
|
-
|
33
|
-
|
31
|
+
volume_includes: [ENV.fetch('IMAGE_INCLUDE', 'runner*cache*').split(/[,;]/)].flatten.compact,
|
32
|
+
volume_deadline: ENV.fetch('VOLUME_DEADLINE', '3d'),
|
33
|
+
image_deadline: ENV.fetch('IMAGE_DEADLINE', '14d'),
|
34
|
+
image_store: ENV.fetch('IMAGE_STORE', './images.txt'),
|
35
|
+
cache_size: ENV.fetch('CACHE_SIZE', '10G'),
|
34
36
|
remove: ENV.fetch('REMOVE', 'false').to_bool,
|
35
|
-
|
37
|
+
log_level: ENV.fetch('LOG_LEVEL', ::Logger::INFO),
|
38
|
+
docker_host: ENV.fetch('DOCKER_HOST', 'unix:///var/run/docker.sock'),
|
39
|
+
redis_url: ENV.fetch('REDIS_URL', 'redis://127.0.0.1:6379/0')
|
36
40
|
}
|
37
41
|
|
38
42
|
parser = OptionParser.new do |o|
|
39
43
|
o.banner = "Usage: #{UTIL} [options] "
|
40
44
|
|
41
|
-
o.on("--clean-delay=#{@opts[:clean_delay]}",
|
45
|
+
o.on("--clean-delay=#{@opts[:clean_delay]}",
|
46
|
+
'ENV[CLEAN_DELAY]'.ljust(25) + 'Delay between clean operation.') do |pattern|
|
42
47
|
@opts[:clean_delay] = pattern.strip
|
43
48
|
end
|
44
49
|
|
45
|
-
o.on("--include=#{@opts[:includes].join(',')}",
|
50
|
+
o.on("--include=#{@opts[:includes].join(',')}",
|
51
|
+
'ENV[INCLUDE]'.ljust(25) + '<List> Include container for removal.') do |pattern|
|
46
52
|
@opts[:includes] += pattern.split(/[,;]/)
|
47
53
|
end
|
48
54
|
|
49
|
-
o.on("--exclude=#{@opts[:excludes].join(',')}",
|
55
|
+
o.on("--exclude=#{@opts[:excludes].join(',')}",
|
56
|
+
'ENV[EXCLUDE]'.ljust(25) + '<List> Exclude container from removal by name.') do |pattern|
|
50
57
|
@opts[:excludes] += pattern.split(/[,;]/)
|
51
58
|
end
|
52
59
|
|
53
|
-
o.on("--container-deadline=#{@opts[:container_deadline]}",
|
60
|
+
o.on("--container-deadline=#{@opts[:container_deadline]}",
|
61
|
+
'ENV[CONTAINER_DEADLINE]'.ljust(25) + 'Maximum container run duration.') do |pattern|
|
54
62
|
@opts[:container_deadline] = pattern.strip
|
55
63
|
end
|
56
64
|
|
57
|
-
o.on("--volume-
|
65
|
+
o.on("--volume-include=#{@opts[:volume_includes].join(',')}",
|
66
|
+
'ENV[VOLUME_INCLUDE]'.ljust(25) + '<List> Include volumes for removal.') do |pattern|
|
67
|
+
@opts[:volume_includes] += pattern.split(/[,;]/)
|
68
|
+
end
|
69
|
+
|
70
|
+
o.on("--volume-deadline=#{@opts[:volume_deadline]}",
|
71
|
+
'ENV[VOLUME_DEADLINE]'.ljust(25) + 'Maximum volume life duration.') do |pattern|
|
58
72
|
@opts[:volume_deadline] = pattern.strip
|
59
73
|
end
|
60
74
|
|
61
|
-
o.on("--image-deadline=#{@opts[:image_deadline]}",
|
75
|
+
o.on("--image-deadline=#{@opts[:image_deadline]}",
|
76
|
+
'ENV[IMAGE_DEADLINE]'.ljust(25) + 'Maximum image life duration.') do |pattern|
|
62
77
|
@opts[:image_deadline] = pattern.strip
|
63
78
|
end
|
64
79
|
|
65
|
-
o.on("--
|
80
|
+
o.on("--image-store=#{@opts[:image_store]}",
|
81
|
+
'ENV[IMAGE_STORE]'.ljust(25) + 'File to store images timestamps.') do |value|
|
82
|
+
@opts[:image_store] = value.strip
|
83
|
+
end
|
84
|
+
|
85
|
+
o.on("--cache-size=#{@opts[:cache_size]}",
|
86
|
+
'ENV[CACHE_SIZE]'.ljust(25) + 'Size of docker cache to keep.') do |value|
|
87
|
+
@opts[:cache_size] = value.strip
|
88
|
+
end
|
89
|
+
|
90
|
+
o.on('--remove', 'ENV[REMOVE]'.ljust(25) + 'Real remove instead of dry run.') do |value|
|
66
91
|
@opts[:remove] = value.strip.to_bool
|
67
92
|
end
|
68
93
|
|
69
|
-
o.on("--docker=#{@opts[:docker_host]}", 'Docker api endpoint.
|
70
|
-
@opts[:docker_host] =
|
94
|
+
o.on("--docker=#{@opts[:docker_host]}", 'ENV[DOCKER_HOST]'.ljust(25) + 'Docker api endpoint.') do |url|
|
95
|
+
@opts[:docker_host] = url.strip
|
96
|
+
end
|
97
|
+
|
98
|
+
o.on("--redis=#{@opts[:redis_url]}", 'ENV[REDIS_URL]'.ljust(25) + 'Redis endpoint.') do |url|
|
99
|
+
@opts[:redis_url] = url.strip
|
71
100
|
end
|
72
101
|
|
102
|
+
o.on('--debug', 'ENV[LOG_LEVEL]'.ljust(25) + 'Verbose logs. ENV values: debug, info, warn, error') do
|
103
|
+
@opts[:log_level] = ::Logger::DEBUG
|
104
|
+
end
|
73
105
|
end
|
74
106
|
parser.parse!
|
75
107
|
|
76
108
|
Docker.url = @opts[:docker_host]
|
77
109
|
|
78
|
-
GitlabJanitor::Util
|
110
|
+
GitlabJanitor::Util.logger.level = @opts[:log_level]
|
111
|
+
|
112
|
+
GitlabJanitor::Util.logger.debug do
|
79
113
|
"Config: #{JSON.pretty_generate(@opts)}"
|
80
114
|
end
|
81
115
|
|
82
116
|
containers = GitlabJanitor::ContainerCleaner.new(
|
83
|
-
delay: Fugit::Duration.parse(@opts[:clean_delay]).to_sec,
|
84
117
|
includes: @opts[:includes],
|
85
118
|
excludes: @opts[:excludes],
|
119
|
+
delay: Fugit::Duration.parse(@opts[:clean_delay]).to_sec,
|
86
120
|
deadline: Fugit::Duration.parse(@opts[:container_deadline]).to_sec
|
87
121
|
)
|
88
122
|
|
89
123
|
volumes = GitlabJanitor::VolumeCleaner.new(
|
90
|
-
|
124
|
+
includes: @opts[:volume_includes],
|
125
|
+
delay: Fugit::Duration.parse(@opts[:clean_delay]).to_sec,
|
91
126
|
deadline: Fugit::Duration.parse(@opts[:volume_deadline]).to_sec
|
92
127
|
)
|
93
128
|
|
129
|
+
images = GitlabJanitor::ImageCleaner.new(
|
130
|
+
image_store: File.expand_path(@opts[:image_store]),
|
131
|
+
redis: @opts[:redis_url],
|
132
|
+
delay: Fugit::Duration.parse(@opts[:clean_delay]).to_sec,
|
133
|
+
deadline: Fugit::Duration.parse(@opts[:image_deadline]).to_sec
|
134
|
+
)
|
135
|
+
|
136
|
+
cache = GitlabJanitor::CacheCleaner.new(
|
137
|
+
keep_size: @opts[:cache_size],
|
138
|
+
delay: Fugit::Duration.parse(@opts[:clean_delay]).to_sec,
|
139
|
+
deadline: Fugit::Duration.parse(@opts[:image_deadline]).to_sec
|
140
|
+
)
|
141
|
+
|
142
|
+
until GitlabJanitor::Util.exiting?
|
143
|
+
File.write('/tmp/service.pid', Process.pid)
|
94
144
|
|
95
|
-
while !$exiting do
|
96
145
|
containers.clean(remove: @opts[:remove])
|
97
146
|
volumes.clean(remove: @opts[:remove])
|
147
|
+
images.clean(remove: @opts[:remove])
|
148
|
+
cache.clean(remove: @opts[:remove])
|
98
149
|
|
99
150
|
sleep 3
|
100
151
|
end
|
101
152
|
|
102
|
-
|
103
|
-
|
104
|
-
|
data/docker-compose.yml
CHANGED
@@ -9,6 +9,10 @@ services:
|
|
9
9
|
context: .
|
10
10
|
args:
|
11
11
|
RUBY_VERSION: 3.1
|
12
|
+
CREATED: ${OC_IMAGE_CREATED-2022-08-05 15:22:36+03:00}
|
13
|
+
VERSION: ${OC_IMAGE_VERSION-unknown}
|
14
|
+
REVISION: ${OC_IMAGE_REVISION-unknown}
|
15
|
+
REFNAME: ${OC_IMAGE_REFNAME-unknown}
|
12
16
|
image: ${SERVICE_IMAGE-rnds/gitlab-janitor}:${SERVICE_TAG-latest}
|
13
17
|
working_dir: /home/app
|
14
18
|
tmpfs: /tmp
|
data/gitlab-janitor.gemspec
CHANGED
@@ -2,32 +2,35 @@ lib = File.expand_path('lib', __dir__)
|
|
2
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
3
|
|
4
4
|
# Maintain your gem's version:
|
5
|
-
require '
|
5
|
+
require 'gitlab_janitor/version'
|
6
6
|
|
7
7
|
Gem::Specification.new 'gitlab-janitor' do |spec|
|
8
|
-
spec.version = ENV['BUILDVERSION'].to_i > 0 ? "#{
|
8
|
+
spec.version = ENV['BUILDVERSION'].to_i > 0 ? "#{GitlabJanitor::VERSION}.#{ENV['BUILDVERSION'].to_i}" : GitlabJanitor::VERSION
|
9
9
|
spec.authors = ['Samoilenko Yuri']
|
10
10
|
spec.email = ['kinnalru@gmail.com']
|
11
11
|
spec.description = spec.summary = 'GitLab Janitor is a tool to automatically manage stalled containers when using Docker.'
|
12
12
|
spec.homepage = 'https://github.com/RnD-Soft/gitlab-janitor'
|
13
13
|
spec.license = 'MIT'
|
14
14
|
|
15
|
-
spec.files = Dir['bin/**/*', 'lib/**/*', 'Gemfile*', 'LICENSE', 'README.md',
|
15
|
+
spec.files = Dir['bin/**/*', 'lib/**/*', 'Gemfile*', 'LICENSE', 'README.md',
|
16
|
+
'Dockerfile*', 'docker-compose.yml', '*.gemspec']
|
16
17
|
spec.bindir = 'bin'
|
17
18
|
spec.executables = spec.files.grep(%r{^bin/gitlab-janitor}) {|f| File.basename(f) }
|
18
19
|
spec.require_paths = ['lib']
|
19
20
|
|
21
|
+
spec.add_development_dependency 'awesome_print'
|
20
22
|
spec.add_development_dependency 'bundler', '~> 2.0', '>= 2.0.1'
|
21
23
|
spec.add_development_dependency 'rake'
|
22
24
|
spec.add_development_dependency 'rspec'
|
23
25
|
spec.add_development_dependency 'rspec_junit_formatter'
|
24
26
|
spec.add_development_dependency 'simplecov'
|
25
27
|
spec.add_development_dependency 'simplecov-console'
|
26
|
-
spec.add_development_dependency 'awesome_print'
|
27
28
|
|
28
29
|
spec.add_runtime_dependency 'activesupport', '~> 6.0'
|
29
30
|
spec.add_runtime_dependency 'docker-api'
|
30
31
|
spec.add_runtime_dependency 'fugit'
|
32
|
+
spec.add_runtime_dependency 'redis'
|
31
33
|
spec.add_runtime_dependency 'optparse'
|
34
|
+
spec.add_runtime_dependency 'tzinfo-data'
|
32
35
|
end
|
33
36
|
|
data/lib/gitlab-janitor.rb
CHANGED
@@ -1,5 +1,2 @@
|
|
1
|
-
require_relative '
|
2
|
-
|
3
|
-
require_relative 'gitlab-janitor/base-cleaner'
|
4
|
-
require_relative 'gitlab-janitor/container-cleaner'
|
5
|
-
require_relative 'gitlab-janitor/volume-cleaner'
|
1
|
+
require_relative './gitlab_janitor'
|
2
|
+
|
@@ -2,9 +2,11 @@ module GitlabJanitor
|
|
2
2
|
class BaseCleaner
|
3
3
|
|
4
4
|
class Model
|
5
|
+
|
5
6
|
attr_reader :model
|
6
|
-
|
7
|
-
|
7
|
+
|
8
|
+
def initialize(model)
|
9
|
+
@model = model
|
8
10
|
end
|
9
11
|
|
10
12
|
def method_missing(method, *args, &block)
|
@@ -20,11 +22,12 @@ module GitlabJanitor
|
|
20
22
|
def respond_to_missing?(method_name, include_private = false)
|
21
23
|
model.send(:respond_to_missing?, method_name, include_private) || super
|
22
24
|
end
|
25
|
+
|
23
26
|
end
|
24
27
|
|
25
28
|
attr_reader :delay, :deadline, :logger
|
26
29
|
|
27
|
-
def initialize
|
30
|
+
def initialize(delay: 10, deadline: 1.second, logger: GitlabJanitor::Util.logger, **_args)
|
28
31
|
@delay = delay
|
29
32
|
@deadline = deadline
|
30
33
|
@logger = logger.tagged(self.class.to_s)
|
@@ -36,7 +39,11 @@ module GitlabJanitor
|
|
36
39
|
do_clean(remove: remove)
|
37
40
|
|
38
41
|
@cleaned_at = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
39
|
-
|
42
|
+
true
|
43
|
+
end
|
44
|
+
|
45
|
+
def exiting?
|
46
|
+
GitlabJanitor::Util.exiting?
|
40
47
|
end
|
41
48
|
|
42
49
|
def log_exception(text)
|
@@ -47,4 +54,5 @@ module GitlabJanitor
|
|
47
54
|
end
|
48
55
|
|
49
56
|
end
|
50
|
-
end
|
57
|
+
end
|
58
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
3
|
+
module GitlabJanitor
|
4
|
+
class CacheCleaner < BaseCleaner
|
5
|
+
|
6
|
+
def initialize(**kwargs)
|
7
|
+
super(**kwargs)
|
8
|
+
end
|
9
|
+
|
10
|
+
def do_clean(keep_size: '10G', remove: false)
|
11
|
+
logger.info 'Removing cache...'
|
12
|
+
if remove
|
13
|
+
out, _status = Open3.capture2e("docker builder prune --keep-storage #{keep_size} -f")
|
14
|
+
logger.info(out)
|
15
|
+
else
|
16
|
+
logger.info 'Skip removal due to dry run'
|
17
|
+
end
|
18
|
+
out, _status = Open3.capture2e('docker system df')
|
19
|
+
logger.info(out)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|