如何正确验证 docker 客户端 golang 库到 gcr.io 注册表?

问题描述 投票:0回答:2

我需要使用此包库以编程方式(使用 golang)登录 gcr.io docker 注册表https://godoc.org/github.com/docker/docker/client

我尝试过使用它,我可以成功登录,但是将图像推送到我的 gcr.io 项目注册表后,它说

{"errorDetail":{"message":"unauthorized: You don't have the needed permissions to perform this operation, and you may have invalid credentials. To authenticate your request, follow the steps in: https://cloud.google.com/container-registry/docs/advanced-authentication"},"error":"unauthorized: You don't have the needed permissions to perform this operation, and you may have invalid credentials. To authenticate your request, follow the steps in: https://cloud.google.com/container-registry/docs/advanced-authentication"}

我的代码看起来像这样

package client
import (
    "context"
    "fmt"
    "io"
    "os"

    "github.com/docker/docker/api/types"
    dockerClient "github.com/docker/docker/client"
)

type Service struct{
    DockerClient *dockerClient.Client
}

type CopyImageOptions struct {
    DestRegistryAuth    string
}
type DockerImageService interface {
    CopyImage(ctx context.Context, source, dest string, option CopyImageOptions)
}

// NewDockerClient returns a client
func NewDockerClient() *Service {
    cli, err := dockerClient.NewEnvClient()
    if err != nil {
        panic(err)
    }
    return &Service{DockerClient: cli}
}

func (s *Service) CopyImage(ctx context.Context, source, dest string, option CopyImageOptions) error {

    rc, err := s.DockerClient.ImagePull(ctx, source, types.ImagePullOptions{})

    if err != nil{
        return fmt.Errorf("error when pulling source image. err: %v", err)
    }
    defer rc.Close()

    io.Copy(os.Stdout, rc)


    destClient := NewDockerClient()

    if option.DestRegistryAuth != ""  {
        //current use case we can assume that the dest is on asia.gcr.io
        status, err := destClient.DockerClient.RegistryLogin(ctx, types.AuthConfig{
            Username:      "oauth2accesstoken",
            Password:      option.DestRegistryAuth,
            ServerAddress: "asia.gcr.io",
        })
        if err != nil{
            return fmt.Errorf("error when login to destination image registry. err: %v", err)
        }

        fmt.Println(status)
    }
    err = destClient.DockerClient.ImageTag(ctx, source, dest)
    if err != nil {
        return fmt.Errorf("error when tagging image. err: %v", err)
    }
    rc, err = destClient.DockerClient.ImagePush(ctx, dest, types.ImagePushOptions{
        RegistryAuth: option.DestRegistryAuth,
    })

    if err != nil{
        return fmt.Errorf("error when pushing image to destionation. err: %v", err)
    }
    defer rc.Close()

    io.Copy(os.Stdout, rc)
    return nil
}

您可以查看

CopyImage
方法,其中
option.DestRegistryAuth
与输出
gcloud auth print-access-token
一起分配。用户名设置为“oauth2accesstoken”,因为我遵循了以下说明:https://cloud.google.com/container-registry/docs/advanced-authentication

至于

source
参数,假设它来自公共注册表,如 docker.io/library/alpine:3.10,因此我们可以在不配置任何身份验证令牌的情况下拉取它。然而,对于
dest
参数,目前它是我的私人注册表中的图像,例如:
asia.gcr.io/<gcp-project-id>/alpine:3.10

此外,

gcloud auth print-access-token
是在我执行
gcloud auth login
之后调用的,并且我已经拥有访问我的私人asia.gcr.io注册表的完全权限(在存储桶级别分配)。

现在奇怪的是,我可以在此处描述的

docker push
之后使用
docker login
命令成功推送它https://cloud.google.com/container-registry/docs/advanced-authentication.

有什么建议吗?

docker go google-cloud-platform
2个回答
6
投票

好吧,我刚刚发现上面的代码有什么错误。在查看来自私有注册表的pull图像的示例代码后,我意识到了这一点:https://docs.docker.com/develop/sdk/examples/#pull-an-image-with-authentication

事实证明,types.ImagePush 选项中的

RegistryAuth
arg 需要一个 base64 编码字符串。

因此,使用此代码,我可以成功将本地映像推送到我的私有注册表。

    authConfig := types.AuthConfig{
        Username: "oauth2accesstoken",
        Password: option.DestRegistryAuth,
    }
    encodedJSON, err := json.Marshal(authConfig)
    if err != nil {
        return fmt.Errorf("error when encoding authConfig. err: %v", err)
    }

    authStr := base64.URLEncoding.EncodeToString(encodedJSON)

    rc, err = destClient.DockerClient.ImagePush(ctx, dest, types.ImagePushOptions{
        RegistryAuth: authStr,
    })

0
投票

对于现在接触此问题的任何人来说,Agung 的评论仍然有 90% 正确,但是,他们已将

AuthConfig
移至
registry
类型。所以你现在需要:

import (
  "github.com/docker/docker/api/types/registry"
)

然后在您的代码中,您可以使用:

func YourFunction(username string, password string) {
  // some code
  authConfig := registry.AuthConfig{
    Username: username,
    Password: password,
  }
  // other code
}

© www.soinside.com 2019 - 2024. All rights reserved.