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

Agu*_*ama 4 go docker google-cloud-platform

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

我试过使用它,我可以成功登录,但是在将图像推送到我的 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"}

Run Code Online (Sandbox Code Playgroud)

我的代码看起来像这样

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
}

Run Code Online (Sandbox Code Playgroud)

您可以查看CopyImage方法,其中option.DestRegistryAuth分配了 output 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 注册表(在存储桶级别分配)的完全权限。

现在奇怪的是,在https://cloud.google.com/container-registry/docs/advanced-authentication 中描述docker push之后,我可以使用命令成功推送它。docker login

有什么建议吗?

Agu*_*ama 5

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

事实证明,RegistryAuthtypes.ImagePush 选项中的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,
    })
Run Code Online (Sandbox Code Playgroud)