• Go image registry



    0. 前言

    OpenShift image registry 概述 介绍了 OpenShift 平台上 registry 的基本结构。进一步地,本文将介绍在 Kubernetes 平台上,如何使用 Go 实现 image 的 push 操作。

    1. 本地 CLI push image

    在本地将 image tar 包(image 的静态文件形式) push 到 registry:

    // 将 repo image ubuntu 存储到本地
    [root@chunqiu tarball]# docker images | grep ubuntu
    ubuntu                                                                         latest        ba6acccedd29   2 months ago    72.8MB
    [root@chunqiu tarball]# docker save ubuntu -o ubuntu:latest.tar
    [root@chunqiu tarball]# ls
    ubuntu:latest.tar
    
    // 删除仓库 image,重新上传本地 tar 到 repo
    [root@chunqiu tarball]# docker rmi ubuntu
    Untagged: ubuntu:latest
    Untagged: ubuntu@sha256:626ffe58f6e7566e00254b638eb7e0f3b11d4da9675088f4781a50ae288f3322
    Deleted: sha256:ba6acccedd2923aee4c2acc6a23780b14ed4b8a5fa4e14e252a23b846df9b6c1
    Deleted: sha256:9f54eef412758095c8079ac465d494a2872e02e90bf1fb5f12a1641c0d1bb78b
    
    [root@chunqiu tarball]# docker images | grep ubuntu
    
    [root@chunqiu tarball]# docker load -i ubuntu\:latest.tar
    9f54eef41275: Loading layer [==================================================>]  75.16MB/75.16MB
    Loaded image: ubuntu:latest
    
    [root@chunqiu tarball]# docker images | grep ubuntu
    ubuntu                                                                         latest         ba6acccedd29   2 months ago    72.8MB
    
    // 将 repo 的 image push 到 registry
    // 提示 push 失败,是因为并未在 docker registry 认证
    [root@chunqiu tarball]# docker push ubuntu:latest
    The push refers to repository [docker.io/library/ubuntu]
    9f54eef41275: Layer already exists
    errors:
    denied: requested access to the resource is denied
    unauthorized: authentication required
    

    注意:

    1. 不能直接将 tar 包 push 到 registry:

      [root@chunqiu tarball]# docker push ubuntu:latest.tar
      The push refers to repository [docker.io/library/ubuntu]
      An image does not exist locally with the tag: ubuntu
      
    2. 关于 registry,repo 的关系可看这段解释:

      Registries, Repositories, Images, and Tags
      
      There is a hierarchical system for storing images. The following terminology is used:
      
      Registry: A service responsible for hosting and distributing images. The default registry is the Docker Hub.
      
      Repository: A collection of related images (usually providing different versions of the same application or service).
      

    2. Go push image

    过了上节的流程,再看 Go 中是怎么 push image 到 repo 的。

    2.1 tarball

    首先用 tarball 将本地 tar 包转为 v1.Image,然后对 v1.Image 进行操作,这里举个例子,将本地 tar 包重新转换成不同 tag:

    func main() {
            tag, err := name.NewTag("ubuntu")
            if err != nil {
                panic(err)
            }
    
            downloadPath := fmt.Sprintf("/home/hxia/vsWorkspace/studyGo/lib/tarball/ubuntu:latest.tar")
            img, err := tarball.ImageFromPath(downloadPath, &tag)
            if err != nil {
                panic(err)
            }
    
            // Write that tarball with a different tag.
            newTag, err := name.NewTag("ubuntu:newest")
            if err != nil {
                panic(err)
            }
            f, err := os.Create("chunqiu")
            if err != nil {
                panic(err)
            }
            defer f.Close()
    
            if err := tarball.Write(newTag, img, f); err != nil {
                panic(err)
            }
    }
    

    运行上述代码,发现本地路径生成名为 chunqiu 的 tar 包,将该包 load 到 repo 发现 tag 转换为 newest:

    [root@chunqiu tarball]# go run main.go
    [root@chunqiu tarball]# ls
    chunqiu  go.mod  go.sum  main.go  ubuntu:latest.tar
    
    [root@chunqiu tarball]# docker load -i chunqiu
    9f54eef41275: Loading layer [==================================================>]   31.8MB/31.8MB
    Loaded image: ubuntu:newest
    
    [root@chunqiu tarball]# docker images | grep ubuntu
    ubuntu                                                                         newest        ba6acccedd29   2 months ago    72.8MB
    

    2.2 remote push image

    将 image push 到远端 registry,需要用到 go-containerregistry ,它是对容器 registries 处理的 golang 包实现。

    代码实现如下:

    import (
        "github.com/google/go-containerregistry/pkg/name"
        "github.com/google/go-containerregistry/pkg/v1/remote"
        "github.com/google/go-containerregistry/pkg/v1/remote/transport"
    )
    
    ref, err := name.ParseReference(src, name.StrictValidation)
    if err != nil {
        return err
    }
    
    options := make([]remote.Option, 0)
    options = append(options, remote.WithAuthFromKeychain(authn.DefaultKeychain))
    
    if auth != nil {
        options = append(options, remote.WithAuth(auth))
    }
    
    trs, err := transport.New(ref.Context().Registry, auth, &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}, nil)
    if err != nil {
        return err
    }
    options = append(options, remote.WithTransport(trs))
    
    return remote.Write(ref, img, options...)
    

    这里省去了部分代码实现,重点关注:

    1. name.ParseReference 对 src(registry+RepoTag) 进行解析,并且以格式 name.StrictValidation 方式解析;
    2. remote.WithAuthFromKeychain 定义 client 和远端 registry 交互的认证方式。其中,认证方式添加到 remote.Option 作为 remote.Write 的入参实现认证;
    3. remote.Write 需要搭配 transport 包处理 the authentication handshake and structured errors.

    2.3 附录

    应用层上调用各种框架实现功能是在学,在用。这不是核心,要抓核心,抓主要矛盾,核心在于内部实现,过程,原理以及模式。image 数据是怎么传到 remote 的,中间经历了什么,代码是怎么实现的,本地 client 和远端是怎么交互的,这是内核,是要深挖的东西。这里只讲用,后续会深挖这方面内容,敬请期待。


    芝兰生于空谷,不以无人而不芳。
  • 相关阅读:
    fiddler居然有mac版本了
    java学习笔记02 导入,方法调用,私有公有,静态非静态
    apscheduler笔记
    java学习笔记01 类型,List,Set,循环
    fiddler笔记
    为什么有些端口不能用?
    ubuntu借网
    filecoin
    django密码生成
    python-panda
  • 原文地址:https://www.cnblogs.com/xingzheanan/p/15708614.html
Copyright © 2020-2023  润新知