当前位置:首页 > 通信资讯 > 正文

harbor镜像清理(卸载harbor)

harbor镜像清理(卸载harbor)

背景

最近在巡检过程中,发现harbor存储空间使用率已经达到了80%。于是,去看了一下各项目下的镜像标签数。发现有个别项目下的镜像标签数竟然有好几百个。细问之下得知,该项目目前处于调试阶段,每天调试很多次。既然存储空间不多了,那就去harbor上删除掉之前的镜像标签,保留最近的几个就好了。在手动删除的过程中,发现几百个,每页才展示十个。我得先按照推送时间排序,然后一页一页的删除。心想着这种情况经历一次就好了,不要再有下一次。后来,仔细想想,这个也是不好控制的,每次巡检发现了就得手动删除太麻烦。所以就打算写一个脚本,每次通过脚本去删除镜像的标签,保留最近的几个就好了。刚好最近在学习golang,就用它来写就好了。比较尴尬的是,我脚本写完了,测试没问题后,发现新版本harbor已经可以在UI上设置保留策略了。自我安慰一下,就当作是一种练习、尝试好了!

目标

  1. 通过命令行能够查询当前所有的项目、无论是否公开、仓库数量
  2. 通过命令行能够查询项目下的仓库名和镜像名、拉取次数
  3. 在命令行能够指定标签和保留个数进行删除镜像标签
  4. 能够获取镜像的标签数
  5. 删除后,不支持立刻垃圾清理,请手动进行垃圾清理(考虑清理过程中无法推拉镜像)

声明

该脚本纯属个人练习所写,不构成任何建议

初学golang,仅仅是为了实现目标,代码质量极差,请谅解

本次使用的harbor是v2.3.1

全部代码请移步至github

实现

获取harbor中所有的项目,API可通过harbor的 swagger获取

  1. //根据harborswagger测试出来的结果定义要获取的数据结构
  2. typeMetaDatastruct{
  3. Publicstring`json:"public"`
  4. }
  5. typeProjectDatastruct{
  6. MetaDataMetaData`json:"metadata"`
  7. ProjectIdint`json:"project_id"`
  8. Namestring`json:"name"`
  9. RepoCountint`json:"repo_count"`
  10. }
  11. typePData[]ProjectData
  12. //提供harbor地址获取project
  13. funcGetProject(urlstring)[]map[string]string{
  14. //定义url
  15. url=url+"/api/v2.0/projects"
  16. //url=url+"/api/projects"
  17. //构造请求
  18. request,_:=http.NewRequest(http.MethodGet,url,nil)
  19. //取消验证
  20. tr:=&http.Transport{
  21. TLSClientConfig:&tls.Config{InsecureSkipVerify:true},
  22. }
  23. //定义客户端
  24. client:=&http.Client{Timeout:10*time.Second,Transport:tr}
  25. //client:=&http.Client{Timeout:10*time.Second}
  26. request.Header.Set("accept","application/json")
  27. //设置用户和密码
  28. request.SetBasicAuth("admin","Harbor12345")
  29. response,err:=client.Do(request)
  30. iferr!=nil{
  31. fmt.Println("excutefailed")
  32. fmt.Println(err)
  33. }
  34. //获取body
  35. body,_:=ioutil.ReadAll(response.Body)
  36. deferresponse.Body.Close()
  37. ret:=PData{}
  38. json.Unmarshal([]byte(string(body)),&ret)
  39. varps=[]map[string]string{}
  40. //获取返回的数据
  41. fori:=0;i<len(ret);i++{
  42. RData:=make(map[string]string)
  43. RData["name"]=(ret[i].Name)
  44. RData["project_id"]=strconv.Itoa(ret[i].ProjectId)
  45. RData["repo_count"]=strconv.Itoa(ret[i].RepoCount)
  46. RData["public"]=ret[i].MetaData.Public
  47. ps=append(ps,RData)
  48. }
  49. returnps
  50. }

获取项目下的repo

  1. //定义要获取的数据结构
  2. typeReposiDatastruct{
  3. Idint`json:"id"`
  4. Namestring`json:"name"`
  5. ProjectIdint`json:"project_id"`
  6. PullCountint`json:"pull_count"`
  7. }
  8. typeRepoData[]ReposiData
  9. //通过提供harbor地址和对应的项目来获取项目下的repo
  10. funcGetRepoData(urlstring,projstring)[]map[string]string{
  11. ///api/v2.0/projects/goharbor/repositories
  12. url=url+"/api/v2.0/projects/"+proj+"/repositories"
  13. //构造请求
  14. request,_:=http.NewRequest(http.MethodGet,url,nil)
  15. //忽略认证
  16. tr:=&http.Transport{
  17. TLSClientConfig:&tls.Config{InsecureSkipVerify:true},
  18. }
  19. client:=&http.Client{Timeout:10*time.Second,Transport:tr}
  20. request.Header.Set("accept","application/json")
  21. //设置用户名和密码
  22. request.SetBasicAuth("admin","Harbor12345")
  23. response,err:=client.Do(request)
  24. iferr!=nil{
  25. fmt.Println("excutefailed")
  26. fmt.Println(err)
  27. }
  28. //获取body
  29. body,_:=ioutil.ReadAll(response.Body)
  30. deferresponse.Body.Close()
  31. ret:=RepoData{}
  32. json.Unmarshal([]byte(string(body)),&ret)
  33. varps=[]map[string]string{}
  34. //获取返回的数据
  35. fori:=0;i<len(ret);i++{
  36. RData:=make(map[string]string)
  37. RData["name"]=(ret[i].Name)
  38. pId:=strconv.Itoa(ret[i].ProjectId)
  39. RData["project_id"]=pId
  40. RData["id"]=(strconv.Itoa(ret[i].Id))
  41. RData["pullCount"]=(strconv.Itoa(ret[i].PullCount))
  42. ps=append(ps,RData)
  43. }
  44. returnps
  45. }

镜像tag操作

  1. //定义要获取的tag数据结构
  2. typeTagstruct{
  3. ArtifactIdint`json:"artifact_id"`
  4. Idint`json:"id"`
  5. Namestring`json:"name"`
  6. RepositoryIdint`json:"repository_id"`
  7. PushTimtestring`json:"push_time"`
  8. }
  9. typeTag2struct{
  10. ArtifactIdstring`json:"artifact_id"`
  11. Idstring`json:"id"`
  12. Namestring`json:"name"`
  13. RepositoryIdstring`json:"repository_id"`
  14. PushTimtestring`json:"push_time"`
  15. }
  16. typeTag2s[]Tag2
  17. //deletetagbyspecifiedcount,这里通过count先获取要删除的tag列表
  18. funcDeleTagsByCount(tags[]map[string]string,countint)[]string{
  19. varre[]string
  20. tt:=tags[0]["tags"]
  21. ss:=Tag2s{}
  22. json.Unmarshal([]byte(tt),&ss)
  23. //haveasort
  24. fori:=0;i<len(ss);i++{
  25. forj:=i+1;j<len(ss);j++{
  26. //根据pushtime进行排序
  27. ifss[i].PushTimte>ss[j].PushTimte{
  28. ss[i],ss[j]=ss[j],ss[i]
  29. }
  30. }
  31. }
  32. //getalltags
  33. fori:=0;i<len(ss);i++{
  34. re=append(re,ss[i].Name)
  35. }
  36. //返回count个会被删除的tag,
  37. returnre[0:count]
  38. }
  39. //deletetagbyspecifiedtag删除指定的tag
  40. funcDelTags(urlstring,projectstring,repostring,tagstring)(int,map[string]interface{}){
  41. url=url+"/api/v2.0/projects/"+project+"/repositories/"+repo+"/artifacts/"+tag+"/tags/"+tag
  42. request,_:=http.NewRequest(http.MethodDelete,url,nil)
  43. tr:=&http.Transport{
  44. TLSClientConfig:&tls.Config{InsecureSkipVerify:true},
  45. }
  46. client:=&http.Client{Timeout:10*time.Second,Transport:tr}
  47. request.Header.Set("accept","application/json")
  48. request.SetBasicAuth("admin","Pwd123456")
  49. //执行删除tag
  50. response,_:=client.Do(request)
  51. deferresponse.Body.Close()
  52. varresultmap[string]interface{}
  53. bd,err:=ioutil.ReadAll(response.Body)
  54. iferr==nil{
  55. err=json.Unmarshal(bd,&result)
  56. }
  57. returnresponse.StatusCode,result
  58. }
  59. //定义要获取的tag数据结构
  60. typeArtiDatastruct{
  61. Idint`json:"id"`
  62. ProjectIdint`json:"project_id"`
  63. RepositoryIdint`json:"repository_id"`
  64. //Digeststring`json:"digest"`
  65. Tags[]Tag`json:"tags"`
  66. }
  67. typeAData[]ArtiData
  68. //根据harbor地址、project和repo获取tag数据
  69. funcGetTags(urlstring,projectstring,repostring)[]map[string]string{
  70. url=url+"/api/v2.0/projects/"+project+"/repositories/"+repo+"/artifacts"
  71. request,_:=http.NewRequest(http.MethodGet,url,nil)
  72. tr:=&http.Transport{
  73. TLSClientConfig:&tls.Config{InsecureSkipVerify:true},
  74. }
  75. client:=&http.Client{Timeout:10*time.Second,Transport:tr}
  76. request.Header.Set("accept","application/json")
  77. request.Header.Set("X-Accept-Vulnerabilities","application/vnd.scanner.adapter.vuln.report.harbor+json;version=1.0")
  78. request.SetBasicAuth("admin","Harbor12345")
  79. //获取tag
  80. response,err:=client.Do(request)
  81. iferr!=nil{
  82. fmt.Println("excutefailed")
  83. fmt.Println(err)
  84. }
  85. body,_:=ioutil.ReadAll(response.Body)
  86. deferresponse.Body.Close()
  87. ret:=AData{}
  88. json.Unmarshal([]byte(string(body)),&ret)
  89. varps=[]map[string]string{}
  90. sum:=0
  91. RData:=make(map[string]string)
  92. RData["name"]=repo
  93. //获取返回的数据
  94. fori:=0;i<len(ret);i++{
  95. RData["id"]=(strconv.Itoa(ret[i].Id))
  96. RData["project_id"]=(strconv.Itoa(ret[i].ProjectId))
  97. RData["repository_id"]=(strconv.Itoa(ret[i].RepositoryId))
  98. //RData["digest"]=ret[i].Digest
  99. vartdata=[]map[string]string{}
  100. sum=len((ret[i].Tags))
  101. //获取tag
  102. forj:=0;j<len((ret[i].Tags));j++{
  103. TagData:=make(map[string]string)
  104. TagData["artifact_id"]=strconv.Itoa((ret[i].Tags)[j].ArtifactId)
  105. TagData["id"]=strconv.Itoa((ret[i].Tags)[j].Id)
  106. TagData["name"]=(ret[i].Tags)[j].Name
  107. TagData["repository_id"]=strconv.Itoa((ret[i].Tags)[j].RepositoryId)
  108. TagData["push_time"]=(ret[i].Tags)[j].PushTimte
  109. tdata=append(tdata,TagData)
  110. }
  111. RData["count"]=strconv.Itoa(sum)
  112. ss,err:=json.Marshal(tdata)
  113. iferr!=nil{
  114. fmt.Println("failed")
  115. os.Exit(2)
  116. }
  117. RData["tags"]=string(ss)
  118. ps=append(ps,RData)
  119. }
  120. returnps
  121. }

获取用户命令行输入,列出harbor中所有的项目

  1. //定义获取harbor中project的相关命令操作
  2. varprojectCmd=&cobra.Command{
  3. Use:"project",
  4. Short:"tooperatorproject",
  5. Run:func(cmd*cobra.Command,args[]string){
  6. output,err:=ExecuteCommand("harbor","project",args...)
  7. iferr!=nil{
  8. Error(cmd,args,err)
  9. }
  10. fmt.Fprint(os.Stdout,output)
  11. },
  12. }
  13. //projectlist
  14. varprojectLsCmd=&cobra.Command{
  15. Use:"ls",
  16. Short:"listallproject",
  17. Run:func(cmd*cobra.Command,args[]string){
  18. url,_:=cmd.Flags().GetString("url")
  19. iflen(url)==0{
  20. fmt.Println("urlisnull,pleasespecifiedtheharborurlfirst!!!!")
  21. os.Exit(2)
  22. }
  23. //获取所有的project
  24. output:=harbor.GetProject(url)
  25. fmt.Println("项目名访问级别仓库数量")
  26. fori:=0;i<len(output);i++{
  27. fmt.Println(output[i]["name"],output[i]["public"],output[i]["repo_count"])
  28. }
  29. },
  30. }
  31. //init
  32. funcinit(){
  33. //./harborprojectls-uhttps://
  34. rootCmd.AddCommand(projectCmd)
  35. projectCmd.AddCommand(projectLsCmd)
  36. projectLsCmd.Flags().StringP("url","u","","defaults:[https://127.0.0.1]")
  37. }

获取repo列表

  1. //repocommand
  2. varrepoCmd=&cobra.Command{
  3. Use:"repo",
  4. Short:"tooperatorrepository",
  5. Run:func(cmd*cobra.Command,args[]string){
  6. output,err:=ExecuteCommand("harbor","repo",args...)
  7. iferr!=nil{
  8. Error(cmd,args,err)
  9. }
  10. fmt.Fprint(os.Stdout,output)
  11. },
  12. }
  13. //repolist
  14. varrepoLsCmd=&cobra.Command{
  15. Use:"ls",
  16. Short:"listproject'srepository",
  17. Run:func(cmd*cobra.Command,args[]string){
  18. url,_:=cmd.Flags().GetString("url")
  19. project,_:=cmd.Flags().GetString("project")
  20. iflen(project)==0{
  21. fmt.Println("sorry,youmustspecifiedtheprojectwhichyouwanttoshowrepository!!!")
  22. os.Exit(2)
  23. }
  24. //getallrepo
  25. output:=harbor.GetRepoData(url,project)
  26. //展示数据
  27. fmt.Println("仓库名----------拉取次数")
  28. fori:=0;i<len(output);i++{
  29. fmt.Println(output[i]["name"],output[i]["pullCount"])
  30. }
  31. },
  32. }
  33. funcinit(){
  34. //./harborrepols-uhttps://-pxxx
  35. rootCmd.AddCommand(repoCmd)
  36. repoCmd.AddCommand(repoLsCmd)
  37. repoLsCmd.Flags().StringP("url","u","","defaults:[https://127.0.0.1]")
  38. repoLsCmd.Flags().StringP("project","p","","theproject")
  39. }

tag操作

  1. //tagcommand
  2. vartagCmd=&cobra.Command{
  3. Use:"tag",
  4. Short:"tooperatorimage",
  5. Run:func(cmd*cobra.Command,args[]string){
  6. output,err:=ExecuteCommand("harbor","tag",args...)
  7. iferr!=nil{
  8. Error(cmd,args,err)
  9. }
  10. fmt.Fprint(os.Stdout,output)
  11. },
  12. }
  13. //tagls
  14. vartagLsCmd=&cobra.Command{
  15. Use:"ls",
  16. Short:"listalltagsoftherepositoryyouhavespecifiedwhichyoushouldspecifiedprojectatthesametime",
  17. Run:func(cmd*cobra.Command,args[]string){
  18. url,_:=cmd.Flags().GetString("url")
  19. project,_:=cmd.Flags().GetString("project")
  20. repo,_:=cmd.Flags().GetString("repo")
  21. //getalltags
  22. ss:=harbor.GetTags(url,project,repo)
  23. fori:=0;i<len(ss);i++{
  24. count,_:=strconv.Atoi((ss[i])["count"])
  25. fmt.Printf("therepo%shas%dimages\n",repo,count)
  26. }
  27. },
  28. }
  29. //tagdelbytagorthenumberofimageyouwanttosave
  30. vartagDelCmd=&cobra.Command{
  31. Use:"del",
  32. Short:"deletethetagsoftherepositoryyouhavespecifiedwhichyoushouldspecifiedprojectatthesametime",
  33. Run:func(cmd*cobra.Command,args[]string){
  34. //获取用户输入并转格式
  35. url,_:=cmd.Flags().GetString("url")
  36. project,_:=cmd.Flags().GetString("project")
  37. repo,_:=cmd.Flags().GetString("repo")
  38. tag,_:=cmd.Flags().GetString("tag")
  39. count,_:=cmd.Flags().GetString("count")
  40. ret,_:=strconv.Atoi(count)
  41. iflen(tag)!=0&&ret!=0{
  42. fmt.Println("Youcan'tchoosebothbetweencountandtag")
  43. os.Exit(2)
  44. }elseiflen(tag)==0&&ret!=0{
  45. //getalltags
  46. retu:=harbor.GetTags(url,project,repo)
  47. //deletetagbyyouhsvespeciedthenumberoftheimagesyouwanttosave
  48. rTagCount,_:=strconv.Atoi((retu[0])["count"])
  49. //根据用户输入的count和实际tag数进行对比,决定是否去执行删除tag
  50. ifret==rTagCount{
  51. fmt.Printf("therepository%softheproject%sonlyhave%dtags,soyoucan'tdeletetagsandwewilldonothing!!\n",repo,project,ret)
  52. }elseifret>rTagCount{
  53. fmt.Printf("therepository%softheproject%sonlyhave%dtags,butyouwanttodelete%dtags,sowesuggestyoutohavearestandwewilldonothing!!\n",repo,project,rTagCount,ret)
  54. }else{
  55. //可以执行删除tag
  56. fmt.Printf("wewillsavethelatest%dtagsanddeleteother%dtags!!!\n",ret,(rTagCount-ret))
  57. tags:=harbor.GetTags(url,project,repo)
  58. retu:=harbor.DeleTagsByCount(tags,(rTagCount-ret))
  59. fori:=0;i<len(retu);i++{
  60. //todeletetag
  61. code,msg:=harbor.DelTags(url,project,repo,retu[i])
  62. fmt.Printf("thetag%sisdeleted,statuscodeis%d,msgis%s\n",retu[i],code,msg)
  63. }
  64. }
  65. }else{
  66. //deletetagbyyouspeciedtag
  67. code,msg:=harbor.DelTags(url,project,repo,tag)
  68. fmt.Println(code,msg["errors"])
  69. }
  70. },
  71. }
  72. funcinit(){
  73. //./harbortagls-u-p-r
  74. rootCmd.AddCommand(tagCmd)
  75. tagCmd.AddCommand(tagLsCmd)
  76. tagLsCmd.Flags().StringP("url","u","","defaults:[https://127.0.0.1]")
  77. tagLsCmd.Flags().StringP("project","p","","theproject")
  78. tagLsCmd.Flags().StringP("repo","r","","therepository")
  79. //./harbortagdel-u-p-r[-t|-c]
  80. tagCmd.AddCommand(tagDelCmd)
  81. tagDelCmd.Flags().StringP("url","u","","defaults:[https://127.0.0.1]")
  82. tagDelCmd.Flags().StringP("project","p","","theprojectwhichyoushouldspecifiedifyouwanttodeletethetagofanyrepository")
  83. tagDelCmd.Flags().StringP("repo","r","","therepositorywhichyoushouldspecifiedifyouwanttodeletethetag")
  84. tagDelCmd.Flags().StringP("tag","t","","thetag,Youcan'tchooseitwithtagtogether")
  85. tagDelCmd.Flags().StringP("count","c","","thetotalnumberyouwanttosave.forexample:youset--count=10,wewillsavethe10latesttagsbyusepush_timetosort,can'tchooseitwithtagtogether")
  86. }

测试

  1. //获取帮助
  2. harbor%./harbor-hhttps://harbor.zaizai.com
  3. Usage:
  4. harbor[flags]
  5. harbor[command]
  6. AvailableCommands:
  7. completiongeneratetheautocompletionscriptforthespecifiedshell
  8. helpHelpaboutanycommand
  9. projecttooperatorproject
  10. repotooperatorrepository
  11. tagtooperatorimage
  12. Flags:
  13. -h,--helphelpforharbor
  14. Use"harbor[command]--help"formoreinformationaboutacommand.
  15. //列出所有project
  16. harbor%./harborprojectls-uhttps://harbor.zaizai.com
  17. 项目名访问级别仓库数量
  18. goharborfalse3
  19. librarytrue0
  20. publictrue1
  21. //列出所有repo
  22. harbor%./harborrepols-uhttps://harbor.zaizai.com-pgoharbor
  23. 仓库名----------拉取次数
  24. goharbor/harbor-portal0
  25. goharbor/harbor-db1
  26. goharbor/prepare0
  27. //列出tagsharbor%./harbortagls-uhttps://harbor.zaizai.com-pgoharbor-rharbor-db
  28. therepoharbor-dbhas9images
  29. //通过保留最近20个镜像去删除tag
  30. harbor%./harbortagdel-uhttps://harbor.zaizai.com-pgoharbor-rharbor-db-c20
  31. therepositoryharbor-dboftheprojectgoharboronlyhave9tags,butyouwanttodelete20tags,sowesuggestyoutohavearestandwewilldonothing!!
  32. //通过保留最近10个镜像去删除tag
  33. harbor%./harbortagdel-uhttps://harbor.zaizai.com-pgoharbor-rharbor-db-c10
  34. therepositoryharbor-dboftheprojectgoharboronlyhave9tags,butyouwanttodelete10tags,sowesuggestyoutohavearestandwewilldonothing!!
  35. //通过保留最近5个镜像去删除tag
  36. harbor%./harbortagdel-uhttps://harbor.zaizai.com-pgoharbor-rharbor-db-c5
  37. wewillsavethelatest5tagsanddeleteother4tags!!!
  38. thetagv2.3.9isdeleted,statuscodeis200,msgismap[]
  39. thetagv2.3.10isdeleted,statuscodeis200,msgismap[]
  40. thetagv2.3.8isdeleted,statuscodeis200,msgismap[]
  41. thetagv2.3.7isdeleted,statuscodeis200,msgismap[]
  42. //指定tag进行删除
  43. caicloud@MacBook-Pro-2harbor%./harbortagdel-uhttps://harbor.zaizai.com-pgoharbor-rharbor-db-tv2.3.6
  44. 200<nil>
  45. !!!!最后需要手动去harborUI上进行垃圾回收!!!

参考

https://github.com/spf13/cobra

harbor swagger

原文链接:https://mp.weixin.qq.com/s/64D9omkJx7MJaksOwVnb8g

如果您对该产品感兴趣,请填写办理(客服微信:xiaoxiongyidong)

为您推荐:

发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。