我需要使用此包库以编程方式(使用 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.
有什么建议吗?
好吧,我刚刚发现上面的代码有什么错误。在查看来自私有注册表的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,
})
对于现在接触此问题的任何人来说,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
}