极狐GitLab 镜像仓库

众所周知,极狐GitLab 是一个成熟、安全的一体化 DevOps 平台,其自身内置了容器镜像仓库功能,也即极狐GitLab Container Registry,用户可以将自身需要的镜像推送至极狐GitLab 镜像仓库,而无需自建镜像仓库或者使用已经采取了各种限制措施的 dockerhub。

极狐GitLab 的镜像仓库服务有三个不同级别:实例级别、项目级别(Project)以及群组(Group)级别。实例级别需要管理员权限,而项目和群组级别则可以不需要管理员权限即可使用。下面分别介绍极狐GitLab 镜像仓库的使用和 API 等内容。

极狐GitLab 镜像仓库的使用

首先来看项目(Project)级别的镜像仓库使用。

项目级别的镜像仓库使用

可以通过每个项目的 Packages & Registries –> Container Registry 来找到针对每个项目的镜像仓库的使用。如下图:

jh-gitlab-cr

首先需要登录极狐GitLab 镜像仓库,使用如下命令:

$ docker login registry.gitlab.cn

在出现的对话框中输入用户名和密码即可登录成功。

密码可以是极狐GitLab 用户的登录密码,也可以是极狐GitLab 的 Personal Access Token。

然后可以写一个简单的 Dockerfile 来构建镜像做镜像推送和使用测试:

FROM golang:1.12.9-alpine3.9 as builder
WORKDIR /tmp
COPY main.go /tmp
RUN go build main.go

FROM alpine:latest
WORKDIR /usr/src/app/
COPY --from=builder /tmp/main /usr/src/app/
CMD ["./main"]

其中 main.go 的内容就是输出一个 Hello, 极狐GitLab,我是小马哥!!!

package main

import (
    "fmt"
    "log"
    "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello,极狐GitLab,我是小马哥!!!")
}

func main() {
    http.HandleFunc("/jihu", handler)
    log.Fatal(http.ListenAndServe(":9999", nil))
}

将上述两个文件放在一个新建的空文件目录下,执行如下命令即可开始镜像构建:

$ docker build -t registry.gitlab.cn/majinghe/devops:0.0.1 .

上述几个参数的含义:

需要注意的是,镜像名称的层级最多能达到三层,也就是从项目名称开始,后面最多只能是两层。下面几种是有效的镜像名称写法

registry.gitlab.cn/majinghe/devops:0.0.1
registry.gitlab.cn/majinghe/devops/my:0.0.2
registry.gitlab.cn/majinghe/devops/my/image:0.0.2

registry.gitlab.cn/majinghe/devops/my/image/test:0.0.2

是无效的,因为 devops/my/image/test 是四层,超过了三层,推送的时候会提示denied: requested access to the resource is denied

$ docker push registry.gitlab.cn/majinghe/devops/my/image/test:0.0.2
The push refers to repository [registry.gitlab.cn/majinghe/devops/my/image/test]
27ce44cf221c: Preparing
9cb8bafb4446: Preparing
e2eb06d8af82: Preparing
denied: requested access to the resource is denied

填写正确的镜像名称,则可以看到如下构建输出:

[+] Building 2.5s (13/13) FINISHED
 => [internal] load build definition from Dockerfile                                                                                           0.0s
 => => transferring dockerfile: 235B                                                                                                           0.0s
 => [internal] load .dockerignore                                                                                                              0.0s
 => => transferring context: 2B                                                                                                                0.0s
 => [internal] load metadata for docker.io/library/alpine:latest                                                                               1.2s
 => [internal] load metadata for docker.io/library/golang:1.12.9-alpine3.9                                                                     2.3s
 => [builder 1/4] FROM docker.io/library/golang:1.12.9-alpine3.9@sha256:f6ea65be78b15375bf709cda1f32a4182d0b6a9f26d3dbd76685f5a32966e868       0.0s
 => [internal] load build context                                                                                                              0.0s
 => => transferring context: 29B                                                                                                               0.0s
 => [stage-1 1/3] FROM docker.io/library/alpine:latest@sha256:e1c082e3d3c45cccac829840a25941e679c25d438cc8412c2fa221cf1a824e6a                 0.0s
 => CACHED [stage-1 2/3] WORKDIR /usr/src/app/                                                                                                 0.0s
 => CACHED [builder 2/4] WORKDIR /tmp                                                                                                          0.0s
 => CACHED [builder 3/4] COPY main.go /tmp                                                                                                     0.0s
 => CACHED [builder 4/4] RUN go build main.go                                                                                                  0.0s
 => [stage-1 3/3] COPY --from=builder /tmp/main /usr/src/app/                                                                                  0.0s
 => exporting to image                                                                                                                         0.0s
 => => exporting layers                                                                                                                        0.0s
 => => writing image sha256:25e31514018235303abbd36f36c39b45ac4896889ab9bc7f4e66b9a3d9f1e27a                                                   0.0s
 => => naming to registry.gitlab.cn/majinghe/devops:0.0.1

然后即可将上述镜像推送至 devops 这个项目所对应的项目级别的镜像仓库:

$ docker push registry.gitlab.cn/majinghe/devops:0.0.1
The push refers to repository [registry.gitlab.cn/majinghe/devops]
27ce44cf221c: Pushed
9cb8bafb4446: Pushed
e2eb06d8af82: Pushed
0.0.1: digest: sha256:a15f3f2cd7b283a53eee53bb74a726b74f28b1488f0a3bc37b80d408fc54e4e1 size: 946

可以在其他服务器上用如下命令拉去存储在极狐GitLab 镜像仓库中的上述镜像来做测试:

$ docker run --rm -d -p 9999:9999 registry.gitlab.cn/majinghe/devops:0.0.1
fd4a8aed1938b5ab27265bf7023b9420614dd7ec4ef38e70bad55450cf828c42

然后在浏览器中输入localhost:9999/jihu 或者使用 curl 命令,可查看输出结果

$ curl localhost:9999/jihu
Hello,极狐GitLab,我是小马哥!!!

可以看到存储在极狐GitLab devops项目所对应的镜像仓库中的镜像是可以被使用的。

群组级别的镜像仓库使用

群组级别的镜像仓库使用和项目级别的镜像仓库使用时类似的,可以在 Group –> Packages & Registries –> Container Registry 找到群组级别的镜像仓库服务。登录方式可项目级别的是一致的,即

$ docker login registry.gitlab.cn

重点在于构建镜像时的镜像名称有所不同,针对群租级别的镜像仓库,其镜像构建时的镜像名称格式如下:

$ registry.gitlab.cn/group-name/project-name:tag

比如,有一个名为 xiaomage 的群组,下面有一个 cr-demo 的项目,则构建命令为:

$ docker build -t registry.gitlab.cn/xiaomage/cr-demo:0.0.1 .

推送命令为

$ docker push registry.gitlab.cn/xiaomage/cr-demo:0.0.1

针对于不同项目,只需要替换项目名称和 tag 即可完成镜像构建和推送。最后,可以在群组的镜像仓库中看到推送上来的镜像:

group-cr

可以看到有两个镜像 cr-demovar-demo,分别对应项目 cr-demovar-demo

一个有趣的测试:前面两个项目都存在于 xiaomage 这个群组下面的,如果要推送镜像至群组中不存在的项目下会怎么样呢?

$ docker build -t registry.gitlab.cn/xiaomage/cr1-demo:0.0.1 .
$ docker push registry.gitlab.cn/xiaomage/cr1-demo:0.0.1
The push refers to repository [registry.gitlab.cn/xiaomage/cr1-demo]
27ce44cf221c: Preparing
9cb8bafb4446: Preparing
e2eb06d8af82: Preparing
denied: requested access to the resource is denied

其中 cr1-demo 这个项目在群组 xiaomage 下面是不存在的,构建可以成功,但是推送的时候提示 denied: requested access to the resource is denied。说明如果在群组中不存在某个项目,则用某个项目名称构建的景象是无法推送至极狐GitLab 群组级别的镜像仓库中的。

和极狐GitLab CI 的集成使用

可以在极狐GitLab CI 中来使用极狐GitLab 镜像仓库,完成镜像的构建、推送以及使用。整个过程是用到了极狐GitLab 镜像仓库的一些预定义环境变量。关于极狐GitLab 预定义和自定义的环境变量,可以查看过往公众号文章极狐GitLab CI/CD 变量黑魔法你知道多少?(上)极狐GitLab CI/CD 变量黑魔法你知道多少?(下)

在 .gitlab-ci.yml 文件中写入如下内容

build:
  stage: build
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

即可完成镜像仓库的登陆、镜像构建和推送。控制台的构建日志如下:

image-build-1

image-build-2

极狐GitLab 镜像仓库 API

极狐GitLab 提供了丰富的镜像仓库 API 来对镜像仓库执行相关操作。

list 项目内的镜像仓库

$ curl --header "PRIVATE-TOKEN: MY-极狐GitLab-Personal-Token" "https://jihulab.com/api/v4/projects/9106/registry/repositories?tags=1&tags_count=true"

返回结果为:

[
    {
        "id":157,
        "name":"",
        "path":"majinghe/devops",
        "project_id":9106,
        "location":"registry.gitlab.cn/majinghe/devops",
        "created_at":"2021-10-08T16:28:25.319+08:00",
        "cleanup_policy_started_at":null,
        "tags_count":1,
        "tags":[
            {
                "name":"0.0.1",
                "path":"majinghe/devops:0.0.1",
                "location":"registry.gitlab.cn/majinghe/devops:0.0.1"
            }
        ]
    }
]

可以看到镜像仓库内镜像的详细内容。

delete 项目内的镜像仓库

$ curl --request DELETE --header "PRIVATE-TOKEN: MY-极狐GitLab-Personal-Token" \
>      "https://jihulab.com/api/v4/projects/project-id/registry/repositories/repositories-id"

成功的话返回结果为 202,随后,再用 list API 进行测试:

$ curl --header "PRIVATE-TOKEN: MY-极狐GitLab-Personal-Token" "https://jihulab.com/api/v4/projects/9106/registry/repositories?tags=1&tags_count=true&name=true"
[]

可以看到,返回结果为空。

list 群组下面的镜像仓库

$ curl --header "PRIVATE-TOKEN: MY-极狐GitLab-Personal-Token" \
     "https://jihulab.com/api/v4/groups/group-id/registry/repositories?tags=1&tags_count=true"

返回结果如下:

[
    {
        "id":158,
        "name":"",
        "path":"xiaomage/var-demo",
        "project_id":9693,
        "location":"registry.gitlab.cn/xiaomage/var-demo",
        "created_at":"2021-10-08T16:35:45.257+08:00",
        "cleanup_policy_started_at":null,
        "tags_count":1,
        "tags":[
            {
                "name":"0.0.1",
                "path":"xiaomage/var-demo:0.0.1",
                "location":"registry.gitlab.cn/xiaomage/var-demo:0.0.1"
            }
        ]
    },
    {
        "id":159,
        "name":"",
        "path":"xiaomage/cr-demo",
        "project_id":9786,
        "location":"registry.gitlab.cn/xiaomage/cr-demo",
        "created_at":"2021-10-08T16:42:58.681+08:00",
        "cleanup_policy_started_at":null,
        "tags_count":1,
        "tags":[
            {"name":"0.0.1",
            "path":"xiaomage/cr-demo:0.0.1",
            "location":"registry.gitlab.cn/xiaomage/cr-demo:0.0.1"
            }
        ]
    },
    {
        "id":160,
        "name":"my/demo-image",
        "path":"xiaomage/cr-demo/my/demo-image",
        "project_id":9786,
        "location":"registry.gitlab.cn/xiaomage/cr-demo/my/demo-image",
        "created_at":"2021-10-08T16:59:06.896+08:00",
        "cleanup_policy_started_at":null,
        "tags_count":1,
        "tags":[
            {
                "name":"0.0.1",
                "path":"xiaomage/cr-demo/my/demo-image:0.0.1",
                "location":"registry.gitlab.cn/xiaomage/cr-demo/my/demo-image:0.0.1"
            }
        ]
    }
]

可以看到群组 xiaomage 下面有三个 repository,id 分别为:158159160。每个 repository 都有 1 个镜像。

delete 群组下面的镜像仓库

由于群组下面的镜像仓库其实最终映射到了群组下面的项目中,所以删除群组下面的镜像仓库和删除某个项目下面的镜像仓库的 API 是一样的:

$ curl --request DELETE --header "PRIVATE-TOKEN: MY-极狐GitLab-Personal-Token" \
>      "https://jihulab.com/api/v4/projects/project-id/registry/repositories/repositories-id"

成功的话返回结果为 202

获取某个镜像的详细内容

$ curl --header "PRIVATE-TOKEN: MY-极狐GitLab-Personal-Token" \
>      "https://jihulab.com/api/v4/projects/project-id/registry/repositories/repository-id/tags/tag"

返回结果如下:

{
    "name":"0.0.1",
    "path":"xiaomage/var-demo:0.0.1",
    "location":"registry.gitlab.cn/xiaomage/var-demo:0.0.1",
    "revision":"25e31514018235303abbd36f36c39b45ac4896889ab9bc7f4e66b9a3d9f1e27a",
    "short_revision":"25e315140",
    "digest":"sha256:a15f3f2cd7b283a53eee53bb74a726b74f28b1488f0a3bc37b80d408fc54e4e1",
    "created_at":"2021-10-08T08:21:55.701+00:00","total_size":6591030
}

删除指定 tag 的镜像

$ curl --request DELETE --header "PRIVATE-TOKEN: AdrW3vvLyWNyxnKUcwwv" \
>      "https://jihulab.com/api/v4/projects/9693/registry/repositories/158/tags/0.0.1"

成功的话,返回值为200

可以用 list API 查看一下镜像

$ curl --header "PRIVATE-TOKEN: AdrW3vvLyWNyxnKUcwwv" \
>      "https://jihulab.com/api/v4/projects/9693/registry/repositories/158/tags/0.0.1"

返回结果如下:

{"message":"404 Tag Not Found"}

也可以在镜像仓库的界面上看到,镜像已经被删除了

image-delete

当然,极狐GitLab 镜像仓库还有很多其他的 API,感兴趣的小伙伴可以查看 API 官方文档

总结

极狐GitLab 镜像仓库使用方便,API 丰富,能够为用户提供灵活的镜像仓库解决方案。当然,镜像存储不仅仅是极狐GitLab 镜像仓库的功能,还有镜像扫描功能,将在后续为大家陆续揭秘。

60天免费试用极狐GitLab专业版

极狐GitLab不仅是源代码管理或CI/CD工具,它是一个覆盖完整软件开发生命周期和DevOps的开放式一体化平台。

企业版试用
售前咨询
联系电话
在线支持
预约演示