Docker registry 改造--同时作为rpm源,helm chart仓库

为什么还要改造doker registry?

Docker registry 是一个轻量级的镜像仓库,说到这里不得不提一下另外一个企业级的镜像仓库---harbor,

harbor 是在Docker Registry上进行了相应的企业级扩展,从而获得了更加广泛的应用,这些新的企业级特性包括:管理用户界面,基于角色的访问控制 ,AD/LDAP集成以及审计日志等。

harbor什么都好,就是太重了;在资源很有限的情况下,还是用docker registry 合适一些.

有了 registry 镜像仓库的问题解决了,通常,在部署一个离线的微服务环境前,还要做一些前置工作,比如设置rpm 源,下载一些安装包,还有和镜像仓库配套的helm chart 仓库.

这些工作都有对应的工具,但是不能 通用,导致管理起来复杂; 同时这些服务,底层要么是一个文件服务,要么是文件服务+自建索引, 所以这些都是可以在registry 中建立一个文件服务搞定的.

所以这个实现的总体思路是这样的

  1. 实现一个golang的文件服务,因为registry是golang实现的,需要在它里面集成文件服务
  2. registry 源码编译.
  3. 将文件服务添加到registry的http句柄中
  4. 修改后重新编译打包

1.文件服务的 golang 实现,很简单

核心其实只有一句
http.Handle("/prefix/", http.StripPrefix("/prefix/", http.FileServer(http.Dir("/filesdir"))))

package main

import (
    "log"
    "net/http"
)

func main() {
    http.Handle("/prefix/", http.StripPrefix("/prefix/", http.FileServer(http.Dir("/filesdir"))))
    err := http.ListenAndServe(":8080", nil)
    if err != nil {
        log.Fatal("ListenAndServe: ", err)
    }    
}

registry 源码编译

github地址
gitee地址

代码中提供的编译文档 https://gitee.com/mirrors/distribution/blob/main/BUILDING.md ,需要本地搭建golang 环境。

其实源码中提供了一种基于docker编译环境的构建,就在https://gitee.com/mirrors/distribution/blob/main/Dockerfile 中

FROM golang:1.11-alpine AS build

ENV DISTRIBUTION_DIR /go/src/github.com/docker/distribution
ENV BUILDTAGS include_oss include_gcs

ARG GOOS=linux
ARG GOARCH=amd64
ARG GOARM=6

RUN set -ex \
    && apk add --no-cache make git file

WORKDIR $DISTRIBUTION_DIR
COPY . $DISTRIBUTION_DIR
RUN CGO_ENABLED=0 make PREFIX=/go clean binaries && file ./bin/registry | grep "statically linked"

FROM alpine
COPY cmd/registry/config-dev.yml /etc/docker/registry/config.yml
COPY --from=build /go/src/github.com/docker/distribution/bin/registry /bin/registry
VOLUME ["/var/lib/registry"]
EXPOSE 5000
ENTRYPOINT ["registry"]
CMD ["serve", "/etc/docker/registry/config.yml"]

简单说明一下这个Dockerfile
基于golang的alpine 操作系统,安装了make git 等软件

然后在基础的编译镜像中编译

编译后的二进制从编译镜像中拷贝出来到实际的运行镜像中运行

两个镜像中拷贝的过程在下一句中体现:

COPY --from=build /go/src/github.com/docker/distribution/bin/registry /bin/registry

然而在国内直接运行这个会报网络连接错误,因为alpine 默认的源不能访问

所以替换一下源即可

FROM golang:1.11-alpine AS build

ENV DISTRIBUTION_DIR /go/src/github.com/docker/distribution
ENV BUILDTAGS include_oss include_gcs

ARG GOOS=linux
ARG GOARCH=amd64
ARG GOARM=6


RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories
RUN set -ex \
    && apk add --no-cache make git file
#--update-cache --repository http://mirrors.ustc.edu.cn/alpine/v3.4/main/ --allow-untrusted    

WORKDIR $DISTRIBUTION_DIR
COPY . $DISTRIBUTION_DIR
RUN CGO_ENABLED=0 make PREFIX=/go clean binaries && file ./bin/registry | grep "statically linked"

FROM alpine
COPY cmd/registry/config-dev.yml /etc/docker/registry/config.yml
COPY --from=build /go/src/github.com/docker/distribution/bin/registry /bin/registry
VOLUME ["/var/lib/registry"]
EXPOSE 5000
ENTRYPOINT ["registry"]
CMD ["serve", "/etc/docker/registry/config.yml"]

解决了编译问题,剩下的就是修改代码了。

添加文件服务

项目的入口在 cmd/main.go 里面,只有一行代码

func main() {
    registry.RootCmd.Execute()
}

这里指向 registry模块的 RootCmd ,RootCmd 有对ServeCmd命令的调用,在init函数中 RootCmd.AddCommand(ServeCmd),ServerCmd会运行 NewRegistry,在NewRegistry中有httpserver 的启动,所以我们将会在NewRegistry里添加我们写的文件服务。

文件服务还有两个需要考虑的事情是:
一个是 url 访问的路由
一个是 文件存储的路径

url 的访问路径可以自定义,因为会存储很多源文件就叫"/repos/",文件存储路径最好是配置的镜像路径的子路径,避免需要多配置。

所以先要取镜像的配置路径,再创建子目录,xxx/repos ,xxx代表之前配置的目录。
于是乎添加了下面一段代码在NewRegistry 函数中

    reposDir, _ := config.Storage["filesystem"]["rootdirectory"].(string)
    reposDir = reposDir + "/repos/"
    os.MkdirAll(reposDir, os.ModePerm)

加入到http 的处理中

handler = repos("/repos/", reposDir, handler)

其中repos 的实现如下

// repos simply wraps the handler with a repos filesystem
func repos(path string, reposDir string, other http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        if strings.HasPrefix(r.RequestURI, "/repos/") {
            head := http.FileServer(http.Dir(reposDir))
            headServer := http.StripPrefix("/repos/", head)
            headServer.ServeHTTP(w, r)
        } else {
            other.ServeHTTP(w, r)
        }
    })
}

修改前后的差异如图


NewRegistry.png

repos.png

再次编译,生成的新的registry 可执行文件,启动后就会在配置的存储路径下多出来一个repos 文件夹,使用 htttp://ip:5000/repos/就可以取出来。

你可能感兴趣的:(Docker registry 改造--同时作为rpm源,helm chart仓库)