Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 9c292be

Browse files
fix: Optimize container cleanup mechanism (1Panel-dev#9795)
Refs 1Panel-dev#7444 涉及到容器、镜像、网络、存储卷、构建缓存清理
1 parent ba4307c commit 9c292be

File tree

25 files changed

+279
-168
lines changed

25 files changed

+279
-168
lines changed

‎agent/app/api/v2/container.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ func (b *BaseApi) ContainerUpgrade(c *gin.Context) {
315315
// @Summary Clean container
316316
// @Accept json
317317
// @Param request body dto.ContainerPrune true "request"
318-
// @Success 200 {object} dto.ContainerPruneReport
318+
// @Success 200
319319
// @Security ApiKeyAuth
320320
// @Security Timestamp
321321
// @Router /containers/prune [post]
@@ -326,12 +326,11 @@ func (b *BaseApi) ContainerPrune(c *gin.Context) {
326326
return
327327
}
328328

329-
report, err := containerService.Prune(req)
330-
if err != nil {
329+
if err := containerService.Prune(req); err != nil {
331330
helper.InternalServer(c, err)
332331
return
333332
}
334-
helper.SuccessWithData(c, report)
333+
helper.Success(c)
335334
}
336335

337336
// @Tags Container

‎agent/app/api/v2/image.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ func (b *BaseApi) ImagePush(c *gin.Context) {
138138
// @Summary Delete image
139139
// @Accept json
140140
// @Param request body dto.BatchDelete true "request"
141-
// @Success 200 {object} dto.ContainerPruneReport
141+
// @Success 200
142142
// @Security ApiKeyAuth
143143
// @Security Timestamp
144144
// @Router /containers/image/remove [post]
@@ -149,13 +149,12 @@ func (b *BaseApi) ImageRemove(c *gin.Context) {
149149
return
150150
}
151151

152-
data, err := imageService.ImageRemove(req)
153-
if err != nil {
152+
if err := imageService.ImageRemove(req); err != nil {
154153
helper.InternalServer(c, err)
155154
return
156155
}
157156

158-
helper.SuccessWithData(c, data)
157+
helper.Success(c)
159158
}
160159

161160
// @Tags Container Image

‎agent/app/dto/container.go

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -174,15 +174,11 @@ type ContainerCommit struct {
174174
}
175175

176176
type ContainerPrune struct {
177+
TaskID string `json:"taskID"`
177178
PruneType string `json:"pruneType" validate:"required,oneof=container image volume network buildcache"`
178179
WithTagAll bool `json:"withTagAll"`
179180
}
180181

181-
type ContainerPruneReport struct {
182-
DeletedNumber int `json:"deletedNumber"`
183-
SpaceReclaimed int `json:"spaceReclaimed"`
184-
}
185-
186182
type Network struct {
187183
ID string `json:"id"`
188184
Name string `json:"name"`
@@ -227,8 +223,9 @@ type VolumeCreate struct {
227223
}
228224

229225
type BatchDelete struct {
230-
Force bool `json:"force"`
231-
Names []string `json:"names" validate:"required"`
226+
TaskID string `json:"taskID"`
227+
Force bool `json:"force"`
228+
Names []string `json:"names" validate:"required"`
232229
}
233230

234231
type ComposeInfo struct {

‎agent/app/service/container.go

Lines changed: 101 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ type IContainerService interface {
8282
CreateVolume(req dto.VolumeCreate) error
8383
TestCompose(req dto.ComposeCreate) (bool, error)
8484
ComposeUpdate(req dto.ComposeUpdate) error
85-
Prune(req dto.ContainerPrune) (dto.ContainerPruneReport, error)
85+
Prune(req dto.ContainerPrune) error
8686

8787
LoadUsers(req dto.OperationWithName) []string
8888

@@ -417,66 +417,93 @@ func (u *ContainerService) Inspect(req dto.InspectReq) (string, error) {
417417
return string(bytes), nil
418418
}
419419

420-
func (u *ContainerService) Prune(req dto.ContainerPrune) (dto.ContainerPruneReport, error) {
421-
report := dto.ContainerPruneReport{}
420+
func (u *ContainerService) Prune(req dto.ContainerPrune) error {
422421
client, err := docker.NewDockerClient()
423422
if err != nil {
424-
return report, err
423+
return err
425424
}
426425
defer client.Close()
427-
pruneFilters := filters.NewArgs()
428-
if req.WithTagAll {
429-
pruneFilters.Add("dangling", "false")
430-
if req.PruneType != "image" {
431-
pruneFilters.Add("until", "24h")
432-
}
433-
}
426+
name := ""
434427
switch req.PruneType {
435428
case "container":
436-
rep, err := client.ContainersPrune(context.Background(), pruneFilters)
437-
if err != nil {
438-
return report, err
439-
}
440-
report.DeletedNumber = len(rep.ContainersDeleted)
441-
report.SpaceReclaimed = int(rep.SpaceReclaimed)
429+
name = "Container"
442430
case "image":
443-
rep, err := client.ImagesPrune(context.Background(), pruneFilters)
444-
if err != nil {
445-
return report, err
446-
}
447-
report.DeletedNumber = len(rep.ImagesDeleted)
448-
report.SpaceReclaimed = int(rep.SpaceReclaimed)
449-
case "network":
450-
rep, err := client.NetworksPrune(context.Background(), pruneFilters)
451-
if err != nil {
452-
return report, err
453-
}
454-
report.DeletedNumber = len(rep.NetworksDeleted)
431+
name = "Image"
455432
case "volume":
456-
versions, err := client.ServerVersion(context.Background())
457-
if err != nil {
458-
return report, err
459-
}
460-
if common.ComparePanelVersion(versions.APIVersion, "1.42") {
461-
pruneFilters.Add("all", "true")
462-
}
463-
rep, err := client.VolumesPrune(context.Background(), pruneFilters)
464-
if err != nil {
465-
return report, err
466-
}
467-
report.DeletedNumber = len(rep.VolumesDeleted)
468-
report.SpaceReclaimed = int(rep.SpaceReclaimed)
433+
name = "Volume"
469434
case "buildcache":
470-
opts := build.CachePruneOptions{}
471-
opts.All = true
472-
rep, err := client.BuildCachePrune(context.Background(), opts)
473-
if err != nil {
474-
return report, err
475-
}
476-
report.DeletedNumber = len(rep.CachesDeleted)
477-
report.SpaceReclaimed = int(rep.SpaceReclaimed)
435+
name = "BuildCache"
436+
case "network":
437+
name = "Network"
478438
}
479-
return report, nil
439+
taskItem, err := task.NewTaskWithOps(i18n.GetMsgByKey(name), task.TaskClean, task.TaskScopeContainer, req.TaskID, 1)
440+
if err != nil {
441+
global.LOG.Errorf("new task for create container failed, err: %v", err)
442+
return err
443+
}
444+
445+
taskItem.AddSubTask(i18n.GetMsgByKey("TaskClean"), func(t *task.Task) error {
446+
pruneFilters := filters.NewArgs()
447+
if req.WithTagAll {
448+
pruneFilters.Add("dangling", "false")
449+
if req.PruneType != "image" {
450+
pruneFilters.Add("until", "24h")
451+
}
452+
}
453+
DeletedNumber := 0
454+
SpaceReclaimed := 0
455+
switch req.PruneType {
456+
case "container":
457+
rep, err := client.ContainersPrune(context.Background(), pruneFilters)
458+
if err != nil {
459+
return err
460+
}
461+
DeletedNumber = len(rep.ContainersDeleted)
462+
SpaceReclaimed = int(rep.SpaceReclaimed)
463+
case "image":
464+
rep, err := client.ImagesPrune(context.Background(), pruneFilters)
465+
if err != nil {
466+
return err
467+
}
468+
DeletedNumber = len(rep.ImagesDeleted)
469+
SpaceReclaimed = int(rep.SpaceReclaimed)
470+
case "network":
471+
rep, err := client.NetworksPrune(context.Background(), pruneFilters)
472+
if err != nil {
473+
return err
474+
}
475+
DeletedNumber = len(rep.NetworksDeleted)
476+
case "volume":
477+
versions, err := client.ServerVersion(context.Background())
478+
if err != nil {
479+
return err
480+
}
481+
if common.ComparePanelVersion(versions.APIVersion, "1.42") {
482+
pruneFilters.Add("all", "true")
483+
}
484+
rep, err := client.VolumesPrune(context.Background(), pruneFilters)
485+
if err != nil {
486+
return err
487+
}
488+
DeletedNumber = len(rep.VolumesDeleted)
489+
SpaceReclaimed = int(rep.SpaceReclaimed)
490+
case "buildcache":
491+
opts := build.CachePruneOptions{}
492+
opts.All = true
493+
rep, err := client.BuildCachePrune(context.Background(), opts)
494+
if err != nil {
495+
return err
496+
}
497+
DeletedNumber = len(rep.CachesDeleted)
498+
SpaceReclaimed = int(rep.SpaceReclaimed)
499+
}
500+
taskItem.Log(i18n.GetMsgWithMap("PruneHelper", map[string]interface{}{"name": i18n.GetMsgByKey(name), "count": DeletedNumber, "size": common.LoadSizeUnit2F(float64(SpaceReclaimed))}))
501+
return nil
502+
}, nil)
503+
go func() {
504+
_ = taskItem.Execute()
505+
}()
506+
return nil
480507
}
481508

482509
func (u *ContainerService) LoadResourceLimit() (*dto.ResourceLimit, error) {
@@ -1241,29 +1268,29 @@ func checkImageExist(client *client.Client, imageItem string) bool {
12411268
}
12421269

12431270
func checkImageLike(client *client.Client, imageName string) bool {
1244-
if client == nil {
1245-
var err error
1246-
client, err = docker.NewDockerClient()
1247-
if err != nil {
1248-
return false
1249-
}
1250-
}
1251-
images, err := client.ImageList(context.Background(), image.ListOptions{})
1252-
if err != nil {
1253-
return false
1254-
}
1255-
1256-
for _, img := range images {
1257-
for _, tag := range img.RepoTags {
1258-
parts := strings.Split(tag, "/")
1259-
imageNameWithTag := parts[len(parts)-1]
1260-
1261-
if imageNameWithTag == imageName {
1262-
return true
1263-
}
1264-
}
1265-
}
1266-
return false
1271+
if client == nil {
1272+
var err error
1273+
client, err = docker.NewDockerClient()
1274+
if err != nil {
1275+
return false
1276+
}
1277+
}
1278+
images, err := client.ImageList(context.Background(), image.ListOptions{})
1279+
if err != nil {
1280+
return false
1281+
}
1282+
1283+
for _, img := range images {
1284+
for _, tag := range img.RepoTags {
1285+
parts := strings.Split(tag, "/")
1286+
imageNameWithTag := parts[len(parts)-1]
1287+
1288+
if imageNameWithTag == imageName {
1289+
return true
1290+
}
1291+
}
1292+
}
1293+
return false
12671294
}
12681295

12691296
func pullImages(task *task.Task, client *client.Client, imageName string) error {

‎agent/app/service/image.go

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/1Panel-dev/1Panel/agent/constant"
2222
"github.com/1Panel-dev/1Panel/agent/global"
2323
"github.com/1Panel-dev/1Panel/agent/i18n"
24+
"github.com/1Panel-dev/1Panel/agent/utils/common"
2425
"github.com/1Panel-dev/1Panel/agent/utils/docker"
2526
"github.com/docker/docker/api/types/build"
2627
"github.com/docker/docker/api/types/container"
@@ -41,7 +42,7 @@ type IImageService interface {
4142
ImageLoad(req dto.ImageLoad) error
4243
ImageSave(req dto.ImageSave) error
4344
ImagePush(req dto.ImagePush) error
44-
ImageRemove(req dto.BatchDelete) (dto.ContainerPruneReport, error)
45+
ImageRemove(req dto.BatchDelete) error
4546
ImageTag(req dto.ImageTag) error
4647
}
4748

@@ -386,34 +387,44 @@ func (u *ImageService) ImagePush(req dto.ImagePush) error {
386387
return nil
387388
}
388389

389-
func (u *ImageService) ImageRemove(req dto.BatchDelete) (dto.ContainerPruneReport, error) {
390-
report := dto.ContainerPruneReport{}
390+
func (u *ImageService) ImageRemove(req dto.BatchDelete) error {
391391
client, err := docker.NewDockerClient()
392392
if err != nil {
393-
return report, err
393+
return err
394394
}
395395
defer client.Close()
396+
taskItem, err := task.NewTaskWithOps(task.TaskScopeImage, task.TaskDelete, task.TaskScopeContainer, req.TaskID, 1)
397+
if err != nil {
398+
global.LOG.Errorf("new task for create container failed, err: %v", err)
399+
return err
400+
}
401+
396402
for _, id := range req.Names {
397-
imageItem, _, err := client.ImageInspectWithRaw(context.TODO(), id)
398-
if err != nil {
399-
return report, err
400-
}
401-
if _, err := client.ImageRemove(context.TODO(), id, image.RemoveOptions{Force: req.Force, PruneChildren: true}); err != nil {
402-
if strings.Contains(err.Error(), "image is being used") || strings.Contains(err.Error(), "is using") {
403-
if strings.Contains(id, "sha256:") {
404-
return report, buserr.New("ErrObjectInUsed")
405-
}
406-
return report, buserr.WithDetail("ErrInUsed", id, nil)
403+
taskItem.AddSubTask(i18n.GetMsgByKey("TaskDelete")+id, func(t *task.Task) error {
404+
imageItem, err := client.ImageInspect(context.TODO(), id)
405+
if err != nil {
406+
return err
407407
}
408-
if strings.Contains(err.Error(), "image has dependent") {
409-
return report, buserr.New("ErrObjectBeDependent")
408+
if _, err := client.ImageRemove(context.TODO(), id, image.RemoveOptions{Force: req.Force, PruneChildren: true}); err != nil {
409+
if strings.Contains(err.Error(), "image is being used") || strings.Contains(err.Error(), "is using") {
410+
if strings.Contains(id, "sha256:") {
411+
return buserr.New("ErrObjectInUsed")
412+
}
413+
return buserr.WithDetail("ErrInUsed", id, nil)
414+
}
415+
if strings.Contains(err.Error(), "image has dependent") {
416+
return buserr.New("ErrObjectBeDependent")
417+
}
418+
return err
410419
}
411-
return report, err
412-
}
413-
report.DeletedNumber++
414-
report.SpaceReclaimed += int(imageItem.Size)
420+
taskItem.Log(i18n.GetMsgWithMap("ImageRemoveHelper", map[string]interface{}{"name": id, "size": common.LoadSizeUnit2F(float64(imageItem.Size))}))
421+
return nil
422+
}, nil)
415423
}
416-
return report, nil
424+
go func() {
425+
_ = taskItem.Execute()
426+
}()
427+
return nil
417428
}
418429

419430
func formatFileSize(fileSize int64) (size string) {

‎agent/app/task/task.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ const (
6565
TaskPull = "TaskPull"
6666
TaskCommit = "TaskCommit"
6767
TaskPush = "TaskPush"
68+
TaskClean = "TaskClean"
6869
TaskHandle = "TaskHandle"
6970
)
7071

‎agent/i18n/lang/en.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,11 @@ ErrObjectInUsed: 'The object is in use and cannot be deleted'
173173
ErrObjectBeDependent: 'This image depends on other images and cannot be deleted'
174174
ErrPortRules: 'Port number does not match, please re-enter!'
175175
ErrPgImagePull: 'Image pull timed out, please configure image acceleration or manually pull the {{ .name }} image and try again'
176+
PruneHelper: "This cleanup removed {{ .name }} {{ .count }} items, freeing {{ .size }} disk space"
177+
ImageRemoveHelper: "Deleted image {{ .name }}, freeing {{ .size }} disk space"
178+
BuildCache: "Build cache"
179+
Volume: "Storage volume"
180+
Network: "Network"
176181

177182
#runtime
178183
ErrFileNotExist: '{{ .detail }} file does not exist! Please check the integrity of the source file!'
@@ -290,6 +295,7 @@ TaskPull: 'Pull'
290295
TaskCommit: 'Commit'
291296
TaskBuild: 'Build'
292297
TaskPush: 'Push'
298+
TaskClean: "Cleanup"
293299
TaskHandle: 'Execute'
294300
Website: 'Website'
295301
App: 'Application'

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /