feat: 构建环境添加 kaniko 字段

This commit is contained in:
zze 2023-12-12 14:45:07 +08:00
parent 3cb8e8be5f
commit 5534401f16
12 changed files with 52 additions and 25 deletions

View File

@ -18,10 +18,11 @@
- [x] 运行流水线 & 构建流水线客户端镜像
- [x] 流水线运行历史展示
- [x] 获取流水线运行日志
- [x] 支持挂载 PVC 以持久化构建数据
- [x] 支持终止执行中的构建任务
- [x] 流水线参数化支持
- [x] 支持克隆流水线
- [ ] 支持挂载多种类型的卷以持久化构建数据
- [ ] 支持 kaniko 构建上传镜像
## 预览地址

View File

@ -4,6 +4,7 @@ import (
"devops-super/api"
"devops-super/internal/model/entity"
"devops-super/internal/model/mid"
"github.com/gogf/gf/v2/container/gmap"
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/frame/g"
)
@ -64,7 +65,7 @@ type GetConfigReq struct {
type GetConfigRes struct {
Config *gjson.Json `json:"config"`
EnvMap map[int]string `json:"envMap"`
EnvMap gmap.IntAnyMap `json:"envMap"`
}
type RunReq struct {

View File

@ -2,12 +2,12 @@ package ci_pipeline
import (
"context"
"devops-super/api/ci_pipeline/v1"
"devops-super/internal/model/do"
"devops-super/internal/model/entity"
"devops-super/internal/model/mid"
"devops-super/internal/service"
"devops-super/api/ci_pipeline/v1"
"github.com/gogf/gf/v2/frame/g"
)
func (c *ControllerV1) GetConfig(ctx context.Context, req *v1.GetConfigReq) (res *v1.GetConfigRes, err error) {
@ -17,7 +17,6 @@ func (c *ControllerV1) GetConfig(ctx context.Context, req *v1.GetConfigReq) (res
entityMap map[int]*entity.CiEnv
)
res = new(v1.GetConfigRes)
res.EnvMap = make(map[int]string, 0)
ePipeline, err = service.CiPipeline().Get(ctx, &do.CiPipeline{Id: req.Id})
if err != nil {
return
@ -30,7 +29,7 @@ func (c *ControllerV1) GetConfig(ctx context.Context, req *v1.GetConfigReq) (res
entityMap, err = service.CiEnv().GetEntityMap(ctx, config.GetEnvIds())
for id, e := range entityMap {
res.EnvMap[id] = e.Name
res.EnvMap.Set(id, g.Map{"name": e.Name, "isKaniko": e.IsKaniko})
}
return

View File

@ -25,6 +25,7 @@ type CiEnvColumns struct {
Image string // 镜像
SecretName string // Kubernetes Secret 名称,拉取镜像使用
PersistenceConfig string // 持久化配置
IsKaniko string // 是否是 kaniko 客户端
UpdatedAt string // 更新时间
}
@ -35,6 +36,7 @@ var ciEnvColumns = CiEnvColumns{
Image: "image",
SecretName: "secret_name",
PersistenceConfig: "persistence_config",
IsKaniko: "is_kaniko",
UpdatedAt: "updated_at",
}

View File

@ -77,7 +77,7 @@ func (*sCiEnv) GetEntityMap(ctx context.Context, ids []int) (out map[int]*entity
return
}
var es []*entity.CiEnv
if err = dao.CiEnv.Ctx(ctx).WhereIn(cols.Id, ids).Limit(1).Scan(&es); err != nil {
if err = dao.CiEnv.Ctx(ctx).WhereIn(cols.Id, ids).Scan(&es); err != nil {
return
}

View File

@ -4,4 +4,6 @@ image.push:
rm -f devops-super-cli && go env -w 'GOPROXY=https://goproxy.cn,direct' && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o devops-super-cli
docker build --platform linux/amd64 -t registry.cn-shenzhen.aliyuncs.com/zze/devops-super-ci-client:$(DATE) .
docker push registry.cn-shenzhen.aliyuncs.com/zze/devops-super-ci-client:$(DATE)
docker tag registry.cn-shenzhen.aliyuncs.com/zze/devops-super-ci-client:$(DATE) registry.cn-shenzhen.aliyuncs.com/zze/devops-super-ci-client:latest
docker push registry.cn-shenzhen.aliyuncs.com/zze/devops-super-ci-client:latest
rm -f devops-super-cli

View File

@ -12,6 +12,7 @@ import (
"devops-super/utility/thirdclients/kubernetes"
"devops-super/utility/util"
"fmt"
"github.com/gogf/gf/v2/container/gset"
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
@ -21,6 +22,7 @@ import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
"strings"
"time"
)
@ -69,6 +71,7 @@ func (s *sCiPipeline) Run(ctx context.Context, id int, params *gjson.Json) (err
for _, envItem := range arrangeConfig {
envItem.Image = envMap[envItem.Id].Image
envItem.SecretName = envMap[envItem.Id].SecretName
envItem.IsKaniko = envMap[envItem.Id].IsKaniko
for _, stageItem := range envItem.Stages {
for _, taskItem := range stageItem.Tasks {
@ -292,9 +295,11 @@ WATCH:
// 创建 ci pod
func createCiPod(kubeClient *kubernetes.Client, namespace, name string, arrangeConfig mid.CiPipelineConfig, envMap map[int]*entity.CiEnv) error {
var (
containers []corev1.Container
initContainers []corev1.Container
volumes []corev1.Volume
containers []corev1.Container
initContainers []corev1.Container
volumes []corev1.Volume
imagePullSecretNames = gset.New()
imagePullSecrets []corev1.LocalObjectReference
)
var createEnvs = func(envs map[string]string) []corev1.EnvVar {
@ -306,16 +311,9 @@ func createCiPod(kubeClient *kubernetes.Client, namespace, name string, arrangeC
}
for idx, envItem := range arrangeConfig {
stagesJson, err := gjson.EncodeString(envItem.Stages)
if err != nil {
return err
}
container := corev1.Container{
Name: fmt.Sprintf("env-%d", idx),
Image: arrangeConfig[0].Image,
Env: createEnvs(map[string]string{
consts.CI_CLIENT_POD_CONTAINER_STAGES_ENV_NAME: stagesJson,
}),
Name: fmt.Sprintf("env-%d", idx),
Image: envItem.Image,
ImagePullPolicy: corev1.PullAlways,
VolumeMounts: []corev1.VolumeMount{
{
@ -324,6 +322,17 @@ func createCiPod(kubeClient *kubernetes.Client, namespace, name string, arrangeC
},
},
}
if envItem.IsKaniko {
container.Args = strings.Split(envItem.Params, " ")
} else {
stagesJson, err := gjson.EncodeString(envItem.Stages)
if err != nil {
return err
}
container.Env = createEnvs(map[string]string{
consts.CI_CLIENT_POD_CONTAINER_STAGES_ENV_NAME: stagesJson,
})
}
// 判断该环境启用了持久化
var persistenceConfig mid.CiEnvPersistenceConfig
@ -369,6 +378,13 @@ func createCiPod(kubeClient *kubernetes.Client, namespace, name string, arrangeC
}
}
if !gutil.IsEmpty(envItem.SecretName) {
imagePullSecretNames.Add(envItem.SecretName)
}
}
for _, imageSecretName := range imagePullSecretNames.Slice() {
imagePullSecrets = append(imagePullSecrets, corev1.LocalObjectReference{Name: imageSecretName.(string)})
}
pod := &corev1.Pod{
@ -377,8 +393,9 @@ func createCiPod(kubeClient *kubernetes.Client, namespace, name string, arrangeC
Namespace: namespace,
},
Spec: corev1.PodSpec{
InitContainers: initContainers,
Containers: containers,
ImagePullSecrets: imagePullSecrets,
InitContainers: initContainers,
Containers: containers,
Volumes: append(volumes, corev1.Volume{
Name: consts.CI_CLIENT_POD_WORKSPACE_VOLUME_NAME,
VolumeSource: corev1.VolumeSource{

View File

@ -101,9 +101,9 @@ WATCH:
podInfo = event.Object.(*corev1.Pod)
// 如果 Pod 运行失败了,直接输出当前容器的日志然后中断
if podInfo.Status.Phase == corev1.PodFailed {
if err := wsCtx.tailLog(logIndex); err != nil {
return err
}
//if err := wsCtx.tailLog(logIndex); err != nil {
// return err
//}
break WATCH
}
for _, status := range append(podInfo.Status.InitContainerStatuses, podInfo.Status.ContainerStatuses...) {
@ -117,7 +117,7 @@ WATCH:
}
// 最后一个容器日志获取完毕才终止监听
if logIndex == len(podInfo.Status.InitContainerStatuses)+len(podInfo.Status.ContainerStatuses)-1 {
if logIndex == len(podInfo.Status.InitContainerStatuses)+len(podInfo.Status.ContainerStatuses)-1 && podInfo.Status.Phase != corev1.PodRunning {
break WATCH
}
logIndex++

View File

@ -18,5 +18,6 @@ type CiEnv struct {
Image interface{} // 镜像
SecretName interface{} // Kubernetes Secret 名称,拉取镜像使用
PersistenceConfig *gjson.Json // 持久化配置
IsKaniko interface{} // 是否是 kaniko 客户端
UpdatedAt *gtime.Time // 更新时间
}

View File

@ -16,5 +16,6 @@ type CiEnv struct {
Image string `json:"image" description:"镜像"` // 镜像
SecretName string `json:"secretName" description:"Kubernetes Secret 名称,拉取镜像使用"` // Kubernetes Secret 名称,拉取镜像使用
PersistenceConfig *gjson.Json `json:"persistenceConfig" description:"持久化配置"` // 持久化配置
IsKaniko bool `json:"isKaniko" description:"是否是 kaniko 客户端"` // 是否是 kaniko 客户端
UpdatedAt *gtime.Time `json:"updatedAt" description:"更新时间"` // 更新时间
}

View File

@ -6,6 +6,7 @@ type CiEnv struct {
Name string `v:"required|max-length:30" json:"name"`
Image string `v:"required" json:"image"`
SecretName string `json:"secretName"`
IsKaniko bool `json:"isKaniko"`
PersistenceConfig *gjson.Json `json:"persistenceConfig"`
}

View File

@ -23,6 +23,8 @@ type CiPipelineConfigItem struct {
Id int `json:"id" yaml:"id"`
Image string `json:"image" yaml:"image"`
SecretName string `json:"secretName" yaml:"secretName"`
IsKaniko bool `json:"isKaniko" yaml:"isKaniko"`
Params string `json:"params" yaml:"params"`
Stages []*CiPipelineConfigEnvStageItem `json:"stages" yaml:"stages"`
}