Skip to content

Commit

Permalink
feature: 自定义标签
Browse files Browse the repository at this point in the history
  • Loading branch information
togettoyou committed Jul 28, 2023
1 parent c338ff5 commit c76c3b6
Show file tree
Hide file tree
Showing 8 changed files with 259 additions and 905 deletions.
12 changes: 7 additions & 5 deletions .github/ISSUE_TEMPLATE/hub-mirror.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ labels: ["hub-mirror"]

{
"hub-mirror": [
"格式:你需要转换的镜像$自定义镜像名",
"实例1:ghcr.io/jenkins-x/jx-boot:3.10.3",
"实例2:ghcr.io/jenkins-x/jx-boot:3.10.3$jx-boot",
"格式:你需要转换的镜像$自定义镜像名:自定义标签名",
"$自定义镜像名:自定义标签名 是可选的",
"示例1:registry.k8s.io/kube-apiserver:v1.27.4",
"示例2:registry.k8s.io/kube-apiserver:v1.27.4$my-kube-apiserver",
"示例3:registry.k8s.io/kube-apiserver:v1.27.4$my-kube-apiserver:mytag",
"要求:hub-mirror 标签是必选的,标题随意,每次最多支持转换 11 个镜像",
"建议:修改这个 json",
"......"
"建议:按照这个 json 格式修改",
"请确保 json 格式是正确的,比如这里最后一个是没有逗号的"
]
}
4 changes: 2 additions & 2 deletions .github/workflows/hub-mirror.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ name: hub-mirror
# 当新建或者修改 issues 时,触发当前 workflow
on:
issues:
types: [opened, edited]
types: [ opened, edited ]

# 需要执行的任务列表
jobs:
Expand All @@ -23,7 +23,7 @@ jobs:
- name: Setup go
uses: actions/setup-go@v2
with:
go-version: 1.17
go-version: 1.20
# 3. 运行 go 代码
- name: Run code
run: go run main.go --username=${{ secrets.DOCKER_USERNAME }} --password=${{ secrets.DOCKER_TOKEN }} --repository=${{ secrets.DOCKER_REPOSITORY }} --content='${{ github.event.issue.body }}' --maxContent=11 --outputPath=output.sh
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2022 寻寻觅觅的Gopher
Copyright (c) 2022 togettoyou

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
16 changes: 10 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
module github.com/togettoyou/hub-mirror

go 1.17
go 1.20

require (
github.com/docker/docker v20.10.12+incompatible
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.7.0
)

require (
github.com/Microsoft/go-winio v0.4.17 // indirect
github.com/containerd/containerd v1.5.9 // indirect
github.com/docker/distribution v2.7.1+incompatible // indirect
github.com/Microsoft/go-winio v0.5.2 // indirect
github.com/containerd/containerd v1.5.17 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/docker/distribution v2.8.2+incompatible // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-units v0.4.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
Expand All @@ -21,12 +23,14 @@ require (
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 // indirect
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 // indirect
golang.org/x/net v0.0.0-20210610124326-52da8fb2a613 // indirect
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect
google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a // indirect
google.golang.org/grpc v1.43.0 // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
gotest.tools/v3 v3.1.0 // indirect
)
803 changes: 12 additions & 791 deletions go.sum

Large diffs are not rendered by default.

135 changes: 35 additions & 100 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,23 @@ package main

import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"os"
"strings"
"sync"
"text/template"

"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
"github.com/spf13/pflag"
"github.com/togettoyou/hub-mirror/pkg"
)

var (
content = pflag.StringP("content", "", "", "原始镜像,格式为:{ \"hub-mirror\": [] }")
maxContent = pflag.IntP("maxContent", "", 10, "原始镜像个数限制")
username = pflag.StringP("username", "", "", "docker hub 用户名")
password = pflag.StringP("password", "", "", "docker hub 密码")
maxContent = pflag.IntP("maxContent", "", 11, "原始镜像个数限制")
repository = pflag.StringP("repository", "", "", "推送仓库地址,为空默认为 hub.docker.com")
username = pflag.StringP("username", "", "", "仓库用户名")
password = pflag.StringP("password", "", "", "仓库密码")
outputPath = pflag.StringP("outputPath", "", "output.sh", "结果输出路径")
repository = pflag.StringP("repository", "", "", "仓库地址,如果为空,默认推到dockerHub")
)

func main() {
Expand All @@ -36,123 +32,61 @@ func main() {
if err != nil {
panic(err)
}

if len(hubMirrors.Content) > *maxContent {
panic("content is too long.")
panic("提交的原始镜像个数超出了最大限制")
}

fmt.Printf("%+v\n", hubMirrors)

fmt.Println("连接 Docker")
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
fmt.Println("初始化 Docker 客户端")
cli, err := pkg.NewCli(context.Background(), *repository, *username, *password)
if err != nil {
panic(err)
}

fmt.Println("验证 Docker 用户名密码")
if *username == "" || *password == "" {
panic("username or password cannot be empty.")
}
authConfig := types.AuthConfig{
Username: *username,
Password: *password,
ServerAddress: *repository,
}
encodedJSON, err := json.Marshal(authConfig)
if err != nil {
panic(err)
}
authStr := base64.URLEncoding.EncodeToString(encodedJSON)
_, err = cli.RegistryLogin(context.Background(), authConfig)
if err != nil {
panic(err)
}

fmt.Println("开始转换镜像")
output := make([]struct {
Source string
Target string
Repository string
}, 0)

outputs := make([]*pkg.Output, 0)
mu := sync.Mutex{}
wg := sync.WaitGroup{}

for _, source := range hubMirrors.Content {
source := source

if source == "" {
continue
}

target := source
// 查看是否配置自定义镜像名,如果配置的话使用自定义镜像名
if strings.Contains(source, "$") {
str1 := strings.Split(source, "$")
repository := strings.Split(str1[0], ":")
target = str1[1] + ":" + repository[len(repository)-1]
source = str1[0]
}

// 如果为空,默认推送到 DockerHub 用户名 下
// 如果指定了值,则推动到指定的仓库下,用户名不一定与repository后缀相同
if *repository == "" {
target = *username + "/" + strings.ReplaceAll(target, "/", ".")
} else {
target = *repository + "/" + strings.ReplaceAll(target, "/", ".")
}

fmt.Println("开始转换镜像", source)
wg.Add(1)
go func(source, target, repository string) {
go func() {
defer wg.Done()

fmt.Println("开始转换", source, "=>", target)
ctx := context.Background()

// 拉取镜像
pullOut, err := cli.ImagePull(ctx, source, types.ImagePullOptions{})
output, err := cli.PullTagPushImage(context.Background(), source)
if err != nil {
panic(err)
return
}
defer pullOut.Close()
io.Copy(os.Stdout, pullOut)

// 重新标签
err = cli.ImageTag(ctx, source, target)
if err != nil {
panic(err)
}

// 上传镜像
pushOut, err := cli.ImagePush(ctx, target, types.ImagePushOptions{
RegistryAuth: authStr,
})
if err != nil {
panic(err)
}
defer pushOut.Close()
io.Copy(os.Stdout, pushOut)

output = append(output, struct {
Source string
Target string
Repository string
}{Source: source, Target: target, Repository: repository})
fmt.Println("转换成功", source, "=>", target)
}(source, target, *repository)
mu.Lock()
defer mu.Unlock()
outputs = append(outputs, output)
}()
}

wg.Wait()

if len(output) == 0 {
panic("output is empty.")
if len(outputs) == 0 {
panic("没有转换成功的镜像")
}

tmpl, err := template.New("pull_images").Parse(`{{- range . -}}
{{if .Repository}}
# if your repository is private,please login...
# docker login {{ .Repository }} --username={your username}
{{end}}
docker pull {{ .Target }}
docker tag {{ .Target }} {{ .Source }}
{{ end -}}`)
{{if .Repository}}
# if your repository is private,please login...
# docker login {{ .Repository }} --username={your username}
{{end}}
docker pull {{ .Target }}
docker tag {{ .Target }} {{ .Source }}
{{ end -}}`)
if err != nil {
panic(err)
}
Expand All @@ -161,9 +95,10 @@ docker tag {{ .Target }} {{ .Source }}
panic(err)
}
defer outputFile.Close()
err = tmpl.Execute(outputFile, output)

err = tmpl.Execute(outputFile, outputs)
if err != nil {
panic(err)
}
fmt.Println(output)
fmt.Println(outputs)
}
Loading

0 comments on commit c76c3b6

Please sign in to comment.