1
1
package dockergc
2
2
3
3
import (
4
- "context"
5
4
"fmt"
6
5
"io"
7
6
"os"
@@ -11,15 +10,14 @@ import (
11
10
"strings"
12
11
"time"
13
12
13
+ "github.com/golang/glog"
14
14
"github.com/spf13/cobra"
15
15
16
16
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
17
17
kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
18
18
19
- dockerapi "github.com/docker/engine-api/client"
20
19
dockertypes "github.com/docker/engine-api/types"
21
20
dockerfilters "github.com/docker/engine-api/types/filters"
22
- configcmd "github.com/openshift/origin/pkg/config/cmd"
23
21
"github.com/openshift/origin/pkg/oc/cli/util/clientcmd"
24
22
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
25
23
)
@@ -31,12 +29,14 @@ const (
31
29
32
30
var (
33
31
DefaultMinimumGCAge = metav1.Duration {Duration : time .Hour }
32
+
33
+ dockerTimeout = time .Duration (2 * time .Minute )
34
34
)
35
35
36
36
// DockerGCConfigCmdOptions are options supported by the dockergc admin command.
37
37
type dockerGCConfigCmdOptions struct {
38
- Action configcmd. BulkAction
39
-
38
+ // DryRun is true if the command was invoked with --dry-run=true
39
+ DryRun bool
40
40
// MinimumGCAge is the minimum age for a container or unused image before
41
41
// it is garbage collected.
42
42
MinimumGCAge metav1.Duration
68
68
69
69
func NewCmdDockerGCConfig (f * clientcmd.Factory , parentName , name string , out , errout io.Writer ) * cobra.Command {
70
70
options := & dockerGCConfigCmdOptions {
71
- Action : configcmd.BulkAction {
72
- Out : out ,
73
- ErrOut : errout ,
74
- },
71
+ DryRun : false ,
75
72
MinimumGCAge : DefaultMinimumGCAge ,
76
73
ImageGCHighThresholdPercent : DefaultImageGCHighThresholdPercent ,
77
74
ImageGCLowThresholdPercent : DefaultImageGCLowThresholdPercent ,
@@ -93,8 +90,7 @@ func NewCmdDockerGCConfig(f *clientcmd.Factory, parentName, name string, out, er
93
90
cmd .Flags ().DurationVar (& options .MinimumGCAge .Duration , "minimum-ttl-duration" , options .MinimumGCAge .Duration , "Minimum age for a container or unused image before it is garbage collected. Examples: '300ms', '10s' or '2h45m'." )
94
91
cmd .Flags ().Int32Var (& options .ImageGCHighThresholdPercent , "image-gc-high-threshold" , options .ImageGCHighThresholdPercent , "The percent of disk usage after which image garbage collection is always run." )
95
92
cmd .Flags ().Int32Var (& options .ImageGCLowThresholdPercent , "image-gc-low-threshold" , options .ImageGCLowThresholdPercent , "The percent of disk usage before which image garbage collection is never run. Lowest disk usage to garbage collect to." )
96
-
97
- options .Action .BindForOutput (cmd .Flags ())
93
+ cmd .Flags ().BoolVar (& options .DryRun , "dry-run" , options .DryRun , "Run in single-pass mode with no effect." )
98
94
99
95
return cmd
100
96
}
@@ -150,8 +146,8 @@ func parseDockerTimestamp(s string) (time.Time, error) {
150
146
return time .Parse (time .RFC3339Nano , s )
151
147
}
152
148
153
- func doGarbageCollection (ctx context. Context , client * dockerapi. Client , options * dockerGCConfigCmdOptions , rootDir string ) error {
154
- fmt . Println ("gathering disk usage data" )
149
+ func doGarbageCollection (client * dockerClient , options * dockerGCConfigCmdOptions , rootDir string ) error {
150
+ glog . Infof ("gathering disk usage data" )
155
151
capacityBytes , usageBytes , err := getRootDirInfo (rootDir )
156
152
if err != nil {
157
153
return err
@@ -160,97 +156,100 @@ func doGarbageCollection(ctx context.Context, client *dockerapi.Client, options
160
156
highThresholdBytes := capacityBytes * int64 (options .ImageGCHighThresholdPercent ) / 100
161
157
lowThresholdBytes := capacityBytes * int64 (options .ImageGCLowThresholdPercent ) / 100
162
158
if usageBytes < highThresholdBytes {
163
- fmt . Printf ("usage is under high threshold (%vMB < %vMB)\n " , bytesToMB (usageBytes ), bytesToMB (highThresholdBytes ))
159
+ glog . Infof ("usage is under high threshold (%vMB < %vMB)" , bytesToMB (usageBytes ), bytesToMB (highThresholdBytes ))
164
160
return nil
165
161
}
166
162
167
163
attemptToFreeBytes := usageBytes - lowThresholdBytes
168
164
freedBytes := int64 (0 )
169
- fmt . Printf ("usage exceeds high threshold (%vMB > %vMB), attempting to free %vMB\n " , bytesToMB (usageBytes ), bytesToMB (highThresholdBytes ), bytesToMB (attemptToFreeBytes ))
165
+ glog . Infof ("usage exceeds high threshold (%vMB > %vMB), attempting to free %vMB" , bytesToMB (usageBytes ), bytesToMB (highThresholdBytes ), bytesToMB (attemptToFreeBytes ))
170
166
171
167
// conatiners
172
168
exitedFilter := dockerfilters .NewArgs ()
173
169
exitedFilter .Add ("status" , "exited" )
174
- containers , err := client .ContainerList (ctx , dockertypes.ContainerListOptions {All : true , Filter : exitedFilter })
175
- if ctx .Err () == context .DeadlineExceeded {
176
- return ctx .Err ()
177
- }
170
+ containers , err := client .ContainerList (dockertypes.ContainerListOptions {All : true , Filter : exitedFilter })
178
171
if err != nil {
179
172
return err
180
173
}
181
- fmt . Println ( len ( containers ), " exited containers found" )
174
+ glog . Infof ( "%d exited containers found", len ( containers ) )
182
175
sort .Sort (oldestContainersFirst (containers ))
183
176
for _ , c := range containers {
184
177
if freedBytes > attemptToFreeBytes {
185
- fmt . Printf ("usage is below low threshold, freed %vMB\n " , bytesToMB (freedBytes ))
178
+ glog . Infof ("usage is below low threshold, freed %vMB" , bytesToMB (freedBytes ))
186
179
return nil
187
180
}
188
181
age := time .Now ().Sub (time .Unix (c .Created , 0 ))
189
182
if age < options .MinimumGCAge .Duration {
190
- fmt . Println ("remaining containers are too young" )
183
+ glog . Infof ("remaining containers are too young" )
191
184
break
192
185
}
193
- fmt .Printf ("removing container %v (size: %v, age: %v)\n " , c .ID , c .SizeRw , age )
194
- err := client .ContainerRemove (ctx , c .ID , dockertypes.ContainerRemoveOptions {RemoveVolumes : true })
186
+ glog .Infof ("removing container %v (size: %v, age: %v)" , c .ID , c .SizeRw , age )
187
+ var err error
188
+ if ! options .DryRun {
189
+ err = client .ContainerRemove (c .ID , dockertypes.ContainerRemoveOptions {RemoveVolumes : true })
190
+ }
195
191
if err != nil {
196
- fmt . Printf ("unable to remove container: %v" , err )
192
+ glog . Infof ("unable to remove container: %v" , err )
197
193
} else {
198
194
freedBytes += c .SizeRw
199
195
}
200
196
}
201
197
202
198
// images
203
- images , err := client .ImageList (ctx , dockertypes.ImageListOptions {})
204
- if ctx .Err () == context .DeadlineExceeded {
205
- return ctx .Err ()
206
- }
199
+ images , err := client .ImageList (dockertypes.ImageListOptions {})
207
200
if err != nil {
208
201
return err
209
202
}
210
203
sort .Sort (oldestImagesFirst (images ))
204
+ glog .Infof ("%d images found" , len (images ))
211
205
for _ , i := range images {
212
206
if freedBytes > attemptToFreeBytes {
213
- fmt . Printf ("usage is below low threshold, freed %vMB\n " , bytesToMB (freedBytes ))
207
+ glog . Infof ("usage is below low threshold, freed %vMB" , bytesToMB (freedBytes ))
214
208
return nil
215
209
}
216
210
// filter openshift infra images
217
211
if len (i .RepoTags ) > 0 {
218
212
if strings .HasPrefix (i .RepoTags [0 ], "registry.ops.openshift.com/openshift3" ) ||
219
213
strings .HasPrefix (i .RepoTags [0 ], "docker.io/openshift" ) {
220
- fmt . Println ("skipping infra image" , i .RepoTags [0 ])
214
+ glog . Infof ("skipping infra image: %v " , i .RepoTags [0 ])
221
215
continue
222
216
}
223
217
}
224
218
// filter young images
225
219
age := time .Now ().Sub (time .Unix (i .Created , 0 ))
226
220
if age < options .MinimumGCAge .Duration {
227
- fmt . Println ("remaining images are too young" )
221
+ glog . Infof ("remaining images are too young" )
228
222
break
229
223
}
230
- fmt .Printf ("removing image %v (size: %v, age: %v)\n " , i .ID , i .Size , age )
231
- _ , err := client .ImageRemove (ctx , i .ID , dockertypes.ImageRemoveOptions {PruneChildren : true })
224
+ glog .Infof ("removing image %v (size: %v, age: %v)" , i .ID , i .Size , age )
225
+ var err error
226
+ if ! options .DryRun {
227
+ err = client .ImageRemove (i .ID , dockertypes.ImageRemoveOptions {PruneChildren : true })
228
+ }
232
229
if err != nil {
233
- fmt . Printf ("unable to remove container : %v" , err )
230
+ glog . Infof ("unable to remove image : %v" , err )
234
231
} else {
235
232
freedBytes += i .Size
236
233
}
237
234
}
235
+ glog .Infof ("unable to get below low threshold, %vMB freed" , bytesToMB (freedBytes ))
238
236
239
237
return nil
240
238
}
241
239
242
240
// Run runs the dockergc command.
243
241
func Run (f * clientcmd.Factory , options * dockerGCConfigCmdOptions , cmd * cobra.Command , args []string ) error {
244
- fmt .Println ("docker build garbage collection daemon" )
245
- fmt .Printf ("MinimumGCAge: %v, ImageGCHighThresholdPercent: %v, ImageGCLowThresholdPercent: %v\n " , options .MinimumGCAge , options .ImageGCHighThresholdPercent , options .ImageGCLowThresholdPercent )
246
- client , err := dockerapi .NewEnvClient ()
242
+ glog .Infof ("docker build garbage collection daemon" )
243
+ if options .DryRun {
244
+ glog .Infof ("Running in dry-run mode" )
245
+ }
246
+ glog .Infof ("MinimumGCAge: %v, ImageGCHighThresholdPercent: %v, ImageGCLowThresholdPercent: %v" , options .MinimumGCAge , options .ImageGCHighThresholdPercent , options .ImageGCLowThresholdPercent )
247
+ client , err := newDockerClient (dockerTimeout )
247
248
if err != nil {
248
249
return err
249
250
}
250
- timeout := time .Duration (2 * time .Minute )
251
- ctx , cancel := context .WithTimeout (context .Background (), timeout )
252
- defer cancel ()
253
- info , err := client .Info (ctx )
251
+
252
+ info , err := client .Info ()
254
253
if err != nil {
255
254
return err
256
255
}
@@ -263,11 +262,13 @@ func Run(f *clientcmd.Factory, options *dockerGCConfigCmdOptions, cmd *cobra.Com
263
262
}
264
263
265
264
for {
266
- err := doGarbageCollection (ctx , client , options , rootDir )
265
+ err := doGarbageCollection (client , options , rootDir )
267
266
if err != nil {
268
- return err
267
+ glog .Errorf ("garbage collection attempt failed: %v" , err )
268
+ }
269
+ if options .DryRun {
270
+ return nil
269
271
}
270
272
<- time .After (time .Minute )
271
- return nil
272
273
}
273
274
}
0 commit comments