Browse Source

fix: 解决应用升级镜像拉取失败导致应用服务异常的问题 (#1921)

pull/1934/head
zhengkunwang 1 year ago committed by GitHub
parent
commit
5bbda8f842
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 38
      backend/app/service/app_utils.go
  2. 15
      backend/buserr/errors.go
  3. 1
      backend/i18n/lang/en.yaml
  4. 1
      backend/i18n/lang/zh-Hant.yaml
  5. 1
      backend/i18n/lang/zh.yaml
  6. 22
      backend/utils/docker/compose.go
  7. 28
      backend/utils/docker/docker.go

38
backend/app/service/app_utils.go

@ -341,6 +341,24 @@ func upgradeInstall(installId uint, detailId uint, backup bool) error {
install.Version = detail.Version
install.AppDetailId = detailId
images, err := getImages(install)
if err != nil {
upErr = err
return
}
dockerCli, err := composeV2.NewClient()
if err != nil {
upErr = err
return
}
for _, image := range images {
if err = dockerCli.PullImage(image, true); err != nil {
upErr = buserr.WithNameAndErr("ErrDockerPullImage", "", err)
return
}
}
if out, err := compose.Down(install.GetComposePath()); err != nil {
if out != "" {
upErr = errors.New(out)
@ -398,6 +416,26 @@ func getContainerNames(install model.AppInstall) ([]string, error) {
return containerNames, nil
}
func getImages(install model.AppInstall) ([]string, error) {
envStr, err := coverEnvJsonToStr(install.Env)
if err != nil {
return nil, err
}
project, err := composeV2.GetComposeProject(install.Name, install.GetPath(), []byte(install.DockerCompose), []byte(envStr), true)
if err != nil {
return nil, err
}
imagesMap := make(map[string]struct{})
for _, service := range project.AllServices() {
imagesMap[service.Image] = struct{}{}
}
var images []string
for k := range imagesMap {
images = append(images, k)
}
return images, nil
}
func coverEnvJsonToStr(envJson string) (string, error) {
envMap := make(map[string]interface{})
_ = json.Unmarshal([]byte(envJson), &envMap)

15
backend/buserr/errors.go

@ -61,3 +61,18 @@ func WithMap(Key string, maps map[string]interface{}, err error) BusinessError {
Err: err,
}
}
func WithNameAndErr(Key string, name string, err error) BusinessError {
paramMap := map[string]interface{}{}
if name != "" {
paramMap["name"] = name
}
if err != nil {
paramMap["err"] = err.Error()
}
return BusinessError{
Msg: Key,
Map: paramMap,
Err: err,
}
}

1
backend/i18n/lang/en.yaml

@ -45,6 +45,7 @@ ErrImagePullTimeOut: 'Image pull timeout'
ErrContainerNotFound: '{{ .name }} container does not exist'
ErrContainerMsg: '{{ .name }} container is abnormal, please check the log on the container page for details'
ErrAppBackup: '{{ .name }} application backup failed err {{.err}}'
ErrImagePull: '{{ .name }} image pull failed err {{.err}}'
#file
ErrFileCanNotRead: "File can not read"

1
backend/i18n/lang/zh-Hant.yaml

@ -45,6 +45,7 @@ ErrImagePullTimeOut: "鏡像拉取超時"
ErrContainerNotFound: '{{ .name }} 容器不存在'
ErrContainerMsg: '{{ .name }} 容器異常,具體請在容器頁面查看日誌'
ErrAppBackup: '{{ .name }} 應用備份失敗 err {{.err}}'
ErrImagePull: '{{ .name }} 鏡像拉取失敗 err {{.err}}'
#file
ErrFileCanNotRead: "此文件不支持預覽"

1
backend/i18n/lang/zh.yaml

@ -45,6 +45,7 @@ ErrImagePullTimeOut: '镜像拉取超时'
ErrContainerNotFound: '{{ .name }} 容器不存在'
ErrContainerMsg: '{{ .name }} 容器异常,具体请在容器页面查看日志'
ErrAppBackup: '{{ .name }} 应用备份失败 err {{.err}}'
ErrImagePull: '镜像拉取失败 {{.err}}'
#file
ErrFileCanNotRead: "此文件不支持预览"

22
backend/utils/docker/compose.go

@ -4,11 +4,7 @@ import (
"context"
"github.com/compose-spec/compose-go/loader"
"github.com/compose-spec/compose-go/types"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/flags"
"github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/compose"
"github.com/docker/docker/client"
"github.com/joho/godotenv"
"path"
"regexp"
@ -21,24 +17,6 @@ type ComposeService struct {
project *types.Project
}
func NewComposeService(ops ...command.DockerCliOption) (*ComposeService, error) {
apiClient, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
return nil, err
}
ops = append(ops, command.WithAPIClient(apiClient), command.WithDefaultContextStoreConfig())
cli, err := command.NewDockerCli(ops...)
if err != nil {
return nil, err
}
cliOp := flags.NewClientOptions()
if err := cli.Initialize(cliOp); err != nil {
return nil, err
}
service := compose.NewComposeService(cli)
return &ComposeService{service, nil}, nil
}
func (s *ComposeService) SetProject(project *types.Project) {
s.project = project
for i, s := range project.Services {

28
backend/utils/docker/docker.go

@ -72,6 +72,22 @@ func (c Client) DeleteImage(imageID string) error {
return nil
}
func (c Client) PullImage(imageName string, force bool) error {
if !force {
exist, err := c.CheckImageExist(imageName)
if err != nil {
return err
}
if exist {
return nil
}
}
if _, err := c.cli.ImagePull(context.Background(), imageName, types.ImagePullOptions{}); err != nil {
return err
}
return nil
}
func (c Client) GetImageIDByName(imageName string) (string, error) {
filter := filters.NewArgs()
filter.Add("reference", imageName)
@ -87,6 +103,18 @@ func (c Client) GetImageIDByName(imageName string) (string, error) {
return "", nil
}
func (c Client) CheckImageExist(imageName string) (bool, error) {
filter := filters.NewArgs()
filter.Add("reference", imageName)
list, err := c.cli.ImageList(context.Background(), types.ImageListOptions{
Filters: filter,
})
if err != nil {
return false, err
}
return len(list) > 0, nil
}
func (c Client) NetworkExist(name string) bool {
var options types.NetworkListOptions
options.Filters = filters.NewArgs(filters.Arg("name", name))

Loading…
Cancel
Save