如何搭建及使用 docker registry

作者:腾讯云高级工程师董晓杰

本文通过Docker Compose搭建了一个简单的registry环境,使用的是docker hub官方镜像,registry镜像版本registry:2.5.0, nginx镜像版本nginx:1.11.5。主要介绍了registry环境的搭建及使用,更详细的企业级Registry服务器的搭建可参考开源的Harbor

亲自动手实验一下会理解更深刻,动手吧!

使用腾讯云容器服务无须自建registry,快速使用安全可靠的镜像仓库

registry是什么?

registry是Docker的镜像存储服务,docker hub上的registry镜像见Registry官方镜像,更多详细信息请参见源码

搭建registry

  • 在服务器上执行如下命令安装docker,这里选择腾讯云(Ubuntu Server 14.04.1 LTS 64位)镜像来创建服务器

curl -fsSL https://get.docker.com/ | sh

  • 安装docker-compose

Docker Compose是一个定义及运行多个Docker容器的工具。使用Docker Compose只需要在一个配置文件中定义多个Docker容器,然后使用一条命令将多个容器启动,Docker Compose会通过解析容器间的依赖关系,按先后顺序启动所定义的容器。详见Docker Compose

curl -L https://github.com/docker/compose/releases/download/1.8.0/docker-compose-$(uname -s)-$(uname -m) > /usr/local/bin/docker-compose
chmod a+x /usr/local/bin/docker-compose
  • 启动registry服务,此例中包含nginx和registry两个容器,涉及的配置文件请参见附录,部署好后,直接执行如下命令即可创建服务。 docker-compose up -d
  • 停止服务 docker-compose stop
  • 重启服务 docker-compose restart
  • 下线服务 docker-compose down

上传镜像

  • 因为上面搭建的registry服务是http的,所以docker启动参数需要配置--insecure-registry localhost选项,修改/etc/default/docker文件 DOCKER_OPTS="--insecure-registry localhost"
  • 重启docker service docker restart
  • 拉取上传镜像 docker pull;docker tag;docker push(tag默认为latest) docker pull hello-world docker tag hello-world localhost/library/hello-world docker push localhost/library/hello-world

下载镜像

docker pull localhost/library/hello-world

删除镜像

docker rmi localhost/library/hello-world

获取镜像仓库列表

# curl http://localhost/v2/_catalog
{"repositories":["library/hello-world"]}

未上传镜像前的输出如下:

# curl http://localhost/v2/_catalog
{"repositories":[]}

获取镜像tag列表

# curl -X GET http://localhost/v2/library/hello-world/tags/list
{"name":"library/hello-world","tags":["latest"]}

获取镜像manifests信息

# curl -H "Accept: application/vnd.docker.distribution.manifest.v2+json"  -X GET http://localhost/v2/library/hello-world/manifests/latest
{
   "schemaVersion": 2,
   "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
   "config": {
      "mediaType": "application/vnd.docker.container.image.v1+json",
      "size": 1473,
      "digest": "sha256:c54a2cc56cbb2f04003c1cd4507e118af7c0d340fe7e2720f70976c4b75237dc"
   },
   "layers": [
      {
         "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
         "size": 974,
         "digest": "sha256:c04b14da8d1441880ed3fe6106fb2cc6fa1c9661846ac0266b8a5ec8edf37b7c"
      }
   ]
}

其中 c54a2cc56cbb2f04003c1cd4507e118af7c0d340fe7e2720f70976c4b75237dc即为执行docker images时看到的IMAGE ID。

layers表示了镜像的层次关系,可以通过layers中的digest来拉取blob,见下面获取镜像blob

获取镜像blob

在上面获取hello-world:latest镜像的manifests信息中可以看到其只有一个layer,以此为例来看如何获取镜像blob。从拉取的结果可以看到获取的blob与文件sha256是一致的。执行docker pull实际上就是首先获取到镜像的manifests信息后,再拉取blob的

# curl -s -X GET http://localhost/v2/library/hello-world/blobs/sha256:c04b14da8d1441880ed3fe6106fb2cc6fa1c9661846ac0266b8a5ec8edf37b7c -o hello-world.blob
# ls -l hello-world.blob 
-rw-r--r-- 1 root root 974 Nov 23 09:56 hello-world.blob
# sha256sum hello-world.blob 
c04b14da8d1441880ed3fe6106fb2cc6fa1c9661846ac0266b8a5ec8edf37b7c  hello-world.blob    

删除镜像(soft delete)

首先通过 curl -i 参数获取到镜像的 Docker-Content-Digest ,registry 2.3及以后的版本必须在header中指定Accept: application/vnd.docker.distribution.manifest.v2+json,否则默认返回的是schema1的digest,其与schema2的digest不同,使用不指定上述头信息返回的digest删除时会返回404。

# curl -i -H "Accept: application/vnd.docker.distribution.manifest.v2+json"  -X GET http://localhost/v2/library/hello-world/manifests/latest

HTTP/1.1 200 OK
Server: nginx/1.11.5
Date: Wed, 23 Nov 2016 02:17:51 GMT
Content-Type: application/vnd.docker.distribution.manifest.v2+json
Content-Length: 524
Connection: keep-alive
Docker-Content-Digest: sha256:a18ed77532f6d6781500db650194e0f9396ba5f05f8b50d4046b294ae5f83aa4
Docker-Distribution-Api-Version: registry/2.0
Etag: "sha256:a18ed77532f6d6781500db650194e0f9396ba5f05f8b50d4046b294ae5f83aa4"

{
   "schemaVersion": 2,
   "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
   "config": {
      "mediaType": "application/vnd.docker.container.image.v1+json",
      "size": 1473,
      "digest": "sha256:c54a2cc56cbb2f04003c1cd4507e118af7c0d340fe7e2720f70976c4b75237dc"
   },
   "layers": [
      {
         "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
         "size": 974,
         "digest": "sha256:c04b14da8d1441880ed3fe6106fb2cc6fa1c9661846ac0266b8a5ec8edf37b7c"
      }
   ]
}

根据上一步返回的Docker-Content-Digest删除,返回202表示删除成功

# curl -k -v -s -X DELETE http://localhost/v2/library/hello-world/manifests/sha256:a18ed77532f6d6781500db650194e0f9396ba5f05f8b50d4046b294ae5f83aa4

* Hostname was NOT found in DNS cache
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 80 (#0)
> DELETE /v2/library/hello-world/manifests/sha256:a18ed77532f6d6781500db650194e0f9396ba5f05f8b50d4046b294ae5f83aa4 HTTP/1.1
> User-Agent: curl/7.35.0
> Host: localhost
> Accept: */*
> 
< **HTTP/1.1 202 Accepted**
* Server nginx/1.11.5 is not blacklisted
< Server: nginx/1.11.5
< Date: Wed, 23 Nov 2016 02:29:59 GMT
< Content-Type: text/plain; charset=utf-8
< Content-Length: 0
< Connection: keep-alive
< Docker-Distribution-Api-Version: registry/2.0
< 
* Connection #0 to host localhost left intact

确认结果

# curl -X GET http://localhost/v2/library/hello-world/tags/list
{"name":"library/hello-world","tags":null}

删除镜像(hard delete)

在上一步中,只是删除了镜像的manifests信息,解引用的blob还在占用磁盘空间,执行如下命令可以查看可以删除的blob

docker exec -it myregistry_registry_1 /bin/registry garbage-collect --dry-run /etc/registry/config.yml

要删除blob,释放磁盘空间,需要执行下面的命令。需要特别注意的是在执行下面的命令时registry必须是只读模式(只读模式可在registry配置文件中设置),否则可能会导致数据不一致。

docker exec -it myregistry_registry_1 /bin/registry garbage-collect /etc/registry/config.yml

附录

目录结构

.
|-- config
|   |-- nginx
|   |   `-- nginx.conf
|   `-- registry
|       `-- config.yml
`-- docker-compose.yml

nginx.conf

worker_processes auto;

events {
  worker_connections 1024;
  use epoll;
  multi_accept on;
}

http {
  tcp_nodelay on;

  # this is necessary for us to be able to disable request buffering in all cases
  proxy_http_version 1.1;


  upstream registry {
    server registry:5000;
  }


  server {
    listen 80;

    # disable any limits to avoid HTTP 413 for large image uploads
    client_max_body_size 0;

    location /v1/ {
      return 404;
    }

    location /v2/ {
      proxy_pass http://registry/v2/;
      proxy_set_header Host $http_host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

      # When setting up Harbor behind other proxy, such as an Nginx instance, remove the below line if the proxy already has similar settings.
      proxy_set_header X-Forwarded-Proto $scheme;

      proxy_buffering off;
      proxy_request_buffering off;

    }

  }
}

config.yml

version: 0.1
log:
  level: debug
  fields:
    service: registry
storage:
    cache:
        layerinfo: inmemory
    filesystem:
        rootdirectory: /var/lib/registry
    maintenance:
        uploadpurging:
            enabled: false
        readonly:
            enabled: false
    delete:
        enabled: true
http:
    addr: :5000
    secret: yoursecret

docker-comose.yaml

version: '2'
services:
  registry:
    image: library/registry:2.5.0
    restart: always
    volumes:
      - /data/registry:/var/lib/registry
      - ./config/registry/:/etc/registry/
    environment:
      - GODEBUG=netdns=cgo
    command:
      ["serve", "/etc/registry/config.yml"]
  proxy:
    image: library/nginx:1.11.5
    restart: always
    volumes:
      - ./config/nginx:/etc/nginx
    ports:
      - 80:80
      - 443:443
    depends_on:
      - registry

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏七夜安全博客

OD常用断点之CC断点

1002
来自专栏青枫的专栏

Tomcat的Start可以启动起来,但是Debug启动突然启动不起来,一直停在 Class<T>.getDeclaredConstructors0(boolean) line: not availa

Tomcat的Start模式可以启动起来,但是Debug模式启动突然启动不起来,一直停在 Class<T>.getDeclaredConstructors0(b...

662
来自专栏Python小屋

Python使用扩展库pywin32实现批量文档打印

本文代码需要正确安装Python扩展库pywin32,建议下载whl文件进行离线安装。然后调用win32api的ShellExecute()函数来实现文档打印,...

3254
来自专栏木子昭的博客

webpack多入口多出口的实现

对古老的网站进行维护, 短时间内用react或vue组件化重写全部页面不太现实,但用webpack做个打包, 还是可行性的, 配置好webpack多入口多出口,...

1074
来自专栏Vamei实验室

Python基础01 Hello World!

简单的‘Hello World!’ Python命令行 假设你已经安装好了Python, 那么在Linux命令行输入: $python 将直接进入python。...

1759
来自专栏IT民工生存指南

从0开始Vue.js 和 Webpack 4 [1]

1345
来自专栏IMWeb前端团队

跨平台web调试代理工具--whistle

whistle是基于Node实现的跨平台web调试代理工具,支持windows、mac、linux等所有安装了Node的操作系统,可以部署在本地机器、虚拟机或远...

2096
来自专栏前端菜鸟变老鸟

ESLint报错解决方案(error: No ESLint configuration found)

在项目部署中出现报错error: No ESLint configuration found,编辑器vscode。

2432
来自专栏赵俊的Java专栏

Python 文件操作

1733
来自专栏前端技术总结

TypeScript入门教程(一)

本文是TypeScript的入门文章,将分别从下面四点对TypeScript进行介绍:

1.3K54

扫码关注云+社区