152 lines
4.7 KiB
Go
152 lines
4.7 KiB
Go
package main
|
||
|
||
import (
|
||
"fmt"
|
||
"io/ioutil"
|
||
"os"
|
||
"os/exec"
|
||
"path/filepath"
|
||
"strings"
|
||
"time"
|
||
|
||
"gopkg.in/yaml.v2"
|
||
)
|
||
|
||
type Tag struct {
|
||
Tag string `yaml:"tag"`
|
||
Platforms []string `yaml:"platforms"`
|
||
}
|
||
|
||
type Image struct {
|
||
Name string `yaml:"name"`
|
||
From string `yaml:"from,omitempty"` // `from` 为可选字段
|
||
Tags []Tag `yaml:"tags"`
|
||
}
|
||
|
||
type Config struct {
|
||
Target string `yaml:"target"`
|
||
Images []Image `yaml:"images"`
|
||
}
|
||
|
||
func main() {
|
||
// 记录开始时间
|
||
startTime := time.Now()
|
||
|
||
// 创建日志文件名
|
||
logFileName := fmt.Sprintf("build_%s.log", startTime.Format("20060102"))
|
||
logFile, err := os.OpenFile(logFileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
|
||
if err != nil {
|
||
logErrorInfo(logFile, time.Now(),
|
||
fmt.Sprintf("Error opening log file: %v", err))
|
||
return
|
||
}
|
||
defer logFile.Close()
|
||
|
||
// 记录程序启动时间
|
||
logStartTime(logFile, startTime)
|
||
|
||
// 读取 YAML 文件
|
||
data, err := ioutil.ReadFile("images.yaml")
|
||
if err != nil {
|
||
logErrorInfo(logFile, time.Now(),
|
||
fmt.Sprintf("Error reading YAML file: %v", err))
|
||
return
|
||
}
|
||
|
||
// 解析 YAML 文件
|
||
var config Config
|
||
if err := yaml.Unmarshal(data, &config); err != nil {
|
||
logErrorInfo(logFile, time.Now(),
|
||
fmt.Sprintf("Error parsing YAML: %v", err))
|
||
return
|
||
}
|
||
|
||
totalImages := 0
|
||
totalTags := 0
|
||
|
||
// 遍历每个镜像信息
|
||
for _, image := range config.Images {
|
||
// 如果 `from` 字段为空,则将其设置为 `name`(Docker Hub 官方镜像)
|
||
if image.From == "" {
|
||
image.From = image.Name
|
||
}
|
||
|
||
imageBuilt := false // 记录是否构建过该镜像
|
||
for _, tag := range image.Tags {
|
||
totalTags++
|
||
// 根据镜像生成 Dockerfile
|
||
dockerfilePath := filepath.Join(".", fmt.Sprintf("Dockerfile.%s:%s", image.Name, tag.Tag))
|
||
if err := generateDockerfile(image.From, tag.Tag, dockerfilePath); err != nil {
|
||
logErrorInfo(logFile, time.Now(),
|
||
fmt.Sprintf("Error generating Dockerfile for %s:%s: %v", image.Name, tag.Tag, err))
|
||
continue
|
||
}
|
||
|
||
// 合并所有平台为一个字符串
|
||
platforms := strings.Join(tag.Platforms, ",")
|
||
// 构建 Docker 镜像命令,添加 target
|
||
buildCmd := exec.Command("docker", "buildx", "build", "--push", "--platform", platforms, "-t", fmt.Sprintf("%s/%s:%s", config.Target, image.Name, tag.Tag), "-f", dockerfilePath, ".")
|
||
buildCmd.Stdout = os.Stdout
|
||
buildCmd.Stderr = os.Stderr
|
||
|
||
// 记录开始构建时间
|
||
buildStartTime := time.Now()
|
||
if err := buildCmd.Run(); err != nil {
|
||
logErrorInfo(logFile, time.Now(),
|
||
fmt.Sprintf("Error building image %s:%s for platforms %s: %v", image.Name, tag.Tag, platforms, err))
|
||
continue
|
||
}
|
||
// 记录构建结束时间
|
||
buildEndTime := time.Now()
|
||
|
||
// 记录构建日志
|
||
logBuildInfo(logFile, buildStartTime, image.Name, tag.Tag, platforms, config.Target, buildEndTime.Sub(buildStartTime))
|
||
imageBuilt = true // 标记该镜像已成功构建
|
||
|
||
// 删除生成的 Dockerfile
|
||
if err := os.Remove(dockerfilePath); err != nil {
|
||
logErrorInfo(logFile, time.Now(),
|
||
fmt.Sprintf("Error deleting Dockerfile %s: %v", dockerfilePath, err))
|
||
}
|
||
}
|
||
if imageBuilt {
|
||
totalImages++ // 仅在成功构建过一次时增加镜像计数
|
||
}
|
||
}
|
||
|
||
// 计算总时间
|
||
elapsedTime := time.Since(startTime)
|
||
logCompletion(logFile, elapsedTime, totalImages, totalTags)
|
||
}
|
||
|
||
// 记录程序启动时间
|
||
func logStartTime(logFile *os.File, startTime time.Time) {
|
||
logFile.WriteString(fmt.Sprintf("Process started at: %s\n", startTime.Format(time.RFC3339)))
|
||
}
|
||
|
||
// 记录构建信息
|
||
func logBuildInfo(logFile *os.File, startTime time.Time, imageName, tag string, platforms string, target string, duration time.Duration) {
|
||
logFile.WriteString(fmt.Sprintf("%s | Image: %s | Tag: %s | Platforms: %s | Pushed to: %s/%s:%s | Duration: %v\n",
|
||
startTime.Format(time.RFC3339), imageName, tag, platforms, target, imageName, tag, duration))
|
||
}
|
||
|
||
// 记录报错
|
||
func logErrorInfo(logFile *os.File, startTime time.Time, errorMessage string) {
|
||
logFile.WriteString(fmt.Sprintf("%s | %s\n",
|
||
startTime.Format(time.RFC3339), errorMessage))
|
||
}
|
||
|
||
// 记录完成时间和统计信息
|
||
func logCompletion(logFile *os.File, elapsedTime time.Duration, totalImages, totalTags int) {
|
||
logFile.WriteString(fmt.Sprintf("Build completed at: %s\n", time.Now().Format(time.RFC3339)))
|
||
logFile.WriteString(fmt.Sprintf("Total images built: %d\n", totalImages))
|
||
logFile.WriteString(fmt.Sprintf("Total tags processed: %d\n", totalTags))
|
||
logFile.WriteString(fmt.Sprintf("Total execution time: %v\n", elapsedTime))
|
||
}
|
||
|
||
// 生成 Dockerfile
|
||
func generateDockerfile(fromImage, tag, filePath string) error {
|
||
dockerfileContent := fmt.Sprintf("FROM %s:%s\n", fromImage, tag)
|
||
return ioutil.WriteFile(filePath, []byte(dockerfileContent), 0644)
|
||
}
|