gitlab-janitor 0.0.3 → 1.0.2.92939
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Gem Version](https://badge.fury.io/rb/gitlab-janitor.svg)](https://rubygems.org/gems/gitlab-janitor)
|
6
|
+
[![Gem](https://img.shields.io/gem/dt/gitlab-janitor.svg)](https://rubygems.org/gems/gitlab-janitor/versions)
|
7
|
+
[![YARD](https://badgen.net/badge/YARD/doc/blue)](http://www.rubydoc.info/gems/gitlab-janitor)
|
8
|
+
|
9
|
+
[![Docker Pulls](https://badgen.net/docker/pulls/rnds/gitlab-janitor?icon=docker&label=pulls)](https://hub.docker.com/r/rnds/gitlab-janitor/)
|
10
|
+
[![Docker Stars](https://badgen.net/docker/stars/rnds/gitlab-janitor?icon=docker&label=stars)](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
|
+
|