在开发docker app的时候,为了共享这个镜像,导出再分发给团队成员是比较麻烦的作法。Docker 提供了一个 Registry 给咱们上传开发好的镜像(相似 maven 的私有仓库),这样须要使用的团队成员去 registry 上下载便可。redis
下面介绍下如何使用docker
1. 下载官方镜像 docker pull registryjson
[root@localhost ~]# docker pull registry Using default tag: latest latest: Pulling from library/registry ab7e51e37a18: Pull complete c8ad8919ce25: Pull complete 5808405bc62f: Pull complete f6000d7b276c: Pull complete f792fdcd8ff6: Pull complete Digest: sha256:9d295999d330eba2552f9c78c9f59828af5c9a9c15a3fbd1351df03eaad04c6a Status: Downloaded newer image for registry:latest [root@localhost ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE registry latest 177391bcf802 6 days ago 33.3MB [root@localhost ~]#
2. 按照官方说明(传送门)启动ubuntu
[root@localhost ~]# docker run -d -p 5000:5000 --name registry registry acff7e5e012f996a7a03c7b7bf26773755cfa908cde3ae1dbdcd8ec970e2dff1 [root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES acff7e5e012f registry "/entrypoint.sh /e..." 6 seconds ago Up 6 seconds 0.0.0.0:5000->5000/tcp registry [root@localhost ~]#
这样私有的 docker registry 就建好了。swift
接下来做为 demo 下载一个简单的 hello-worldapi
[root@localhost ~]# docker pull hello-world Using default tag: latest latest: Pulling from library/hello-world ca4f61b1923c: Pull complete Digest: sha256:be0cd392e45be79ffeffa6b05338b98ebb16c87b255f48e297ec7f98e123905c Status: Downloaded newer image for hello-world:latest [root@localhost ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE registry latest 177391bcf802 6 days ago 33.3MB hello-world latest f2a91732366c 2 weeks ago 1.85kB [root@localhost ~]#
重命名镜像名称 docker tag <镜像名> <仓库地址:端口>/新的镜像名bash
[root@localhost ~]# docker tag hello-world localhost:5000/my-hello-world [root@localhost ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE registry latest 177391bcf802 6 days ago 33.3MB hello-world latest f2a91732366c 2 weeks ago 1.85kB localhost:5000/my-hello-world latest f2a91732366c 2 weeks ago 1.85kB [root@localhost ~]#
上传镜像 docker push <仓库地址:端口>/新的镜像名app
[root@localhost ~]# docker push localhost:5000/my-hello-world The push refers to a repository [localhost:5000/my-hello-world] f999ae22f308: Pushed latest: digest: sha256:8072a54ebb3bc136150e2f2860f00a7bf45f13eeb917cca2430fcd0054c8e51b size: 524 [root@localhost ~]#
删除本地镜像dom
[root@localhost ~]# docker rmi localhost:5000/my-hello-world Untagged: localhost:5000/my-hello-world:latest [root@localhost ~]# docker rmi hello-world Untagged: hello-world:latest Untagged: hello-world@sha256:be0cd392e45be79ffeffa6b05338b98ebb16c87b255f48e297ec7f98e123905c Deleted: sha256:f2a91732366c0332ccd7afd2a5c4ff2b9af81f549370f7a19acd460f87686bc7 Deleted: sha256:f999ae22f308fea973e5a25b57699b5daf6b0f1150ac2a5c2ea9d7fecee50fdf [root@localhost ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE registry latest 177391bcf802 6 days ago 33.3MB [root@localhost ~]#
从仓库下载镜像 docker pull <仓库地址:端口>/镜像名curl
[root@localhost ~]# docker pull localhost:5000/my-hello-world Using default tag: latest latest: Pulling from my-hello-world ca4f61b1923c: Pull complete Digest: sha256:8072a54ebb3bc136150e2f2860f00a7bf45f13eeb917cca2430fcd0054c8e51b Status: Downloaded newer image for localhost:5000/my-hello-world:latest [root@localhost ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE registry latest 177391bcf802 6 days ago 33.3MB localhost:5000/my-hello-world latest f2a91732366c 2 weeks ago 1.85kB [root@localhost ~]#
重命名一下就可使用了
[root@localhost ~]# docker tag localhost:5000/my-hello-world my-hello-world [root@localhost ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE registry latest 177391bcf802 6 days ago 33.3MB my-hello-world latest f2a91732366c 2 weeks ago 1.85kB localhost:5000/my-hello-world latest f2a91732366c 2 weeks ago 1.85kB [root@localhost ~]#
基本概念就是这样,可是还有一些问题。
1. 这样的启动方式,上传的数据都是做为一个 docker volume 存储在宿主机上面。若是这个 registry 容器被删除,那么容器内的数据也会丢失,即咱们上传的镜像。
因此咱们须要将 registry 的镜像地址映射到宿主机上面,registry 在容器内部的存储地址是 /var/lib/registry/, 经过添加 -v 映射到宿主机。
[root@localhost ~]# docker rm -f registry registry [root@localhost ~]# docker run --name registry -d -p 5000:5000 -v /home/saul/registry:/var/lib/registry registry a107eda18508d791085ebcec5cbb9378d496239fba0f7347e998eeda5966dc18 [root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a107eda18508 registry "/entrypoint.sh /e..." 4 seconds ago Up 3 seconds 0.0.0.0:5000->5000/tcp registry [root@localhost ~]#
将原来的容器删除,从新建一个。这里我映射到了 /home/john/registry 这个目录下。
再次上传镜像
[root@localhost registry]# docker push localhost:5000/my-hello-world The push refers to a repository [localhost:5000/my-hello-world] f999ae22f308: Pushed latest: digest: sha256:8072a54ebb3bc136150e2f2860f00a7bf45f13eeb917cca2430fcd0054c8e51b size: 524
2. 如何查看镜像
官网提供了一套操做 registry 的 api (传送门)
查看仓库 GET /v2/_catalog
[root@localhost registry]# curl http://127.0.0.1:5000/v2/_catalog {"repositories":["my-hello-world"]}
查看镜像标签 GET /v2/<name>/tags/list
[root@localhost registry]# curl http://127.0.0.1:5000/v2/my-hello-world/tags/list {"name":"my-hello-world","tags":["latest"]}
如今只有一个 latest 标签,这里 run 下 hello-world,而后提交一个新的版本1.0
[root@localhost registry]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE registry latest 177391bcf802 6 days ago 33.3MB localhost:5000/my-hello-world latest f2a91732366c 2 weeks ago 1.85kB my-hello-world latest f2a91732366c 2 weeks ago 1.85kB [root@localhost registry]# docker run -it my-hello-world Hello from Docker! This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. (amd64) 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash Share images, automate workflows, and more with a free Docker ID: https://cloud.docker.com/ For more examples and ideas, visit: https://docs.docker.com/engine/userguide/ [root@localhost registry]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e023cad89c0d my-hello-world "/hello" 6 seconds ago Exited (0) 5 seconds ago determined_keller a107eda18508 registry "/entrypoint.sh /e..." 8 minutes ago Up 8 minutes 0.0.0.0:5000->5000/tcp registry [root@localhost registry]# docker commit -m "1.0" e023cad89c0d my-hello-world:1.0 sha256:d9f41037af5b7648d4a1bfb0a95b903f16ebc52a23a0883896ae71d7831ee97c [root@localhost registry]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE my-hello-world 1.0 d9f41037af5b 4 seconds ago 1.85kB registry latest 177391bcf802 6 days ago 33.3MB localhost:5000/my-hello-world latest f2a91732366c 2 weeks ago 1.85kB my-hello-world latest f2a91732366c 2 weeks ago 1.85kB [root@localhost registry]#
上传镜像
[root@localhost registry]# docker tag my-hello-world:1.0 localhost:5000/my-hello-world:1.0 [root@localhost registry]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE my-hello-world 1.0 d9f41037af5b About a minute ago 1.85kB localhost:5000/my-hello-world 1.0 d9f41037af5b About a minute ago 1.85kB registry latest 177391bcf802 6 days ago 33.3MB my-hello-world latest f2a91732366c 2 weeks ago 1.85kB localhost:5000/my-hello-world latest f2a91732366c 2 weeks ago 1.85kB [root@localhost registry]# docker push localhost:5000/my-hello-world:1.0 The push refers to a repository [localhost:5000/my-hello-world] f999ae22f308: Layer already exists 1.0: digest: sha256:69b12f1aeee0355bcf803b5159f96f69738f6b002ea3b6861b802aff337d26cf size: 524 [root@localhost registry]#
再次查看仓库的标签
[root@localhost registry]# curl http://127.0.0.1:5000/v2/my-hello-world/tags/list {"name":"my-hello-world","tags":["latest","1.0"]}
能够看到有 latest, 1.0 2个标签
3. 那么怎么删除仓库里的镜像
DELETE /v2/<name>/manifests/<reference>
注:registry 2.3 版本以上 须要在头部添加
Accept: application/vnd.docker.distribution.manifest.v2+json
[root@localhost registry]# curl --header "Accept: application/vnd.docker.distribution.manifest.v2+json" -X DELETE http://127.0.0.1:5000/v2/my-hello-world/manifests/latest {"errors":[{"code":"UNSUPPORTED","message":"The operation is unsupported."}]} [root@localhost registry]#
提示 UNSUPPORTED! 为何?
查阅资料得知 registry 有个配置文件 config.yml 内容以下
version: 0.1 log: accesslog: disabled: true level: debug formatter: text fields: service: registry environment: staging hooks: - type: mail disabled: true levels: - panic options: smtp: addr: mail.example.com:25 username: mailuser password: password insecure: true from: sender@example.com to: - errors@example.com loglevel: debug # deprecated: use "log" storage: filesystem: rootdirectory: /var/lib/registry maxthreads: 100 azure: accountname: accountname accountkey: base64encodedaccountkey container: containername gcs: bucket: bucketname keyfile: /path/to/keyfile rootdirectory: /gcs/object/name/prefix chunksize: 5242880 s3: accesskey: awsaccesskey secretkey: awssecretkey region: us-west-1 regionendpoint: http://myobjects.local bucket: bucketname encrypt: true keyid: mykeyid secure: true v4auth: true chunksize: 5242880 multipartcopychunksize: 33554432 multipartcopymaxconcurrency: 100 multipartcopythresholdsize: 33554432 rootdirectory: /s3/object/name/prefix swift: username: username password: password authurl: https://storage.myprovider.com/auth/v1.0 or https://storage.myprovider.com/v2.0 or https://storage.myprovider.com/v3/auth tenant: tenantname tenantid: tenantid domain: domain name for Openstack Identity v3 API domainid: domain id for Openstack Identity v3 API insecureskipverify: true region: fr container: containername rootdirectory: /swift/object/name/prefix oss: accesskeyid: accesskeyid accesskeysecret: accesskeysecret region: OSS region name endpoint: optional endpoints internal: optional internal endpoint bucket: OSS bucket encrypt: optional data encryption setting secure: optional ssl setting chunksize: optional size valye rootdirectory: optional root directory inmemory: # This driver takes no parameters delete: enabled: false redirect: disable: false cache: blobdescriptor: redis maintenance: uploadpurging: enabled: true age: 168h interval: 24h dryrun: false readonly: enabled: false auth: silly: realm: silly-realm service: silly-service token: realm: token-realm service: token-service issuer: registry-token-issuer rootcertbundle: /root/certs/bundle htpasswd: realm: basic-realm path: /path/to/htpasswd middleware: registry: - name: ARegistryMiddleware options: foo: bar repository: - name: ARepositoryMiddleware options: foo: bar storage: - name: cloudfront options: baseurl: https://my.cloudfronted.domain.com/ privatekey: /path/to/pem keypairid: cloudfrontkeypairid duration: 3000s storage: - name: redirect options: baseurl: https://example.com/ reporting: bugsnag: apikey: bugsnagapikey releasestage: bugsnagreleasestage endpoint: bugsnagendpoint newrelic: licensekey: newreliclicensekey name: newrelicname verbose: true http: addr: localhost:5000 prefix: /my/nested/registry/ host: https://myregistryaddress.org:5000 secret: asecretforlocaldevelopment relativeurls: false tls: certificate: /path/to/x509/public key: /path/to/x509/private clientcas: - /path/to/ca.pem - /path/to/another/ca.pem letsencrypt: cachefile: /path/to/cache-file email: emailused@letsencrypt.com debug: addr: localhost:5001 headers: X-Content-Type-Options: [nosniff] http2: disabled: false notifications: endpoints: - name: alistener disabled: false url: https://my.listener.com/event headers: <http.Header> timeout: 500 threshold: 5 backoff: 1000 ignoredmediatypes: - application/octet-stream redis: addr: localhost:6379 password: asecret db: 0 dialtimeout: 10ms readtimeout: 10ms writetimeout: 10ms pool: maxidle: 16 maxactive: 64 idletimeout: 300s health: storagedriver: enabled: true interval: 10s threshold: 3 file: - file: /path/to/checked/file interval: 10s http: - uri: http://server.to.check/must/return/200 headers: Authorization: [Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==] statuscode: 200 timeout: 3s interval: 10s threshold: 3 tcp: - addr: redis-server.domain.com:6379 timeout: 3s interval: 10s threshold: 3 proxy: remoteurl: https://registry-1.docker.io username: [username] password: [password] compatibility: schema1: signingkeyfile: /etc/registry/key.json validation: enabled: true manifests: urls: allow: - ^https?://([^/]+\.)*example\.com/ deny: - ^https?://www\.example\.com/
能够看到 storage 节点下 delete enabled 默认为 false
storage: delete: enabled: false
那么咱们开启它,docker 容许经过 -e 传入环境变量(变量的格式为 REGISTRY_variable),咱们传入一个 REGISTRY_STORAGE_DELETE_ENABLED=true 。官网说明(传送门)
那么删除原来的 registry 启动方式改成
[root@localhost registry]# docker rm -f registry registry [root@localhost registry]# docker run --name registry -d -p 5000:5000 -v /home/john/registry:/var/lib/registry -e REGISTRY_STORAGE_DELETE_ENABLED=true registry 8af585efa1914c2354def81eb0cbf3f30bf4fe0d5cab24ba7ce2491cfbc0678b
查看仓库
[root@localhost registry]# curl http://127.0.0.1:5000/v2/_catalog {"repositories":["my-hello-world"]}
刚才上传的镜像还在,并无随着容器删除而删除,证实咱们刚才将镜像存在宿主机上的修改是有效的。
再次删除镜像
[root@localhost registry]# curl --header "Accept: application/vnd.docker.distribution.manifest.v2+json" -X DELETE http://127.0.0.1:5000/v2/my-hello-world/manifests/latest {"errors":[{"code":"DIGEST_INVALID","message":"provided digest did not match uploaded content"}]}
提示 DISGEST_INVALID,删除api是 DELETE /v2/<name>/manifests/<reference>,查看官网 For deletes, reference must be a digest or the delete will fail. 必定要是一个 digest。
查阅资料 经过 curl -I 能够查得
[root@localhost registry]# curl --header "Accept: application/vnd.docker.distribution.manifest.v2+json" -I -X GET http://localhost:5000/v2/my-hello-world/manifests/latest HTTP/1.1 200 OK Content-Length: 524 Content-Type: application/vnd.docker.distribution.manifest.v2+json Docker-Content-Digest: sha256:8072a54ebb3bc136150e2f2860f00a7bf45f13eeb917cca2430fcd0054c8e51b Docker-Distribution-Api-Version: registry/2.0 Etag: "sha256:8072a54ebb3bc136150e2f2860f00a7bf45f13eeb917cca2430fcd0054c8e51b" X-Content-Type-Options: nosniff Date: Fri, 08 Dec 2017 08:44:59 GMT [root@localhost registry]#
Docker-Content-Digest 这个就是咱们须要的 digest
再次调用api 删除
[root@localhost registry]# curl --header "Accept: application/vnd.docker.distribution.manifest.v2+json" -X DELETE http://127.0.0.1:5000/v2/my-hello-world/manifests/sha256:8072a54ebb3bc136150e2f2860f00a7bf45f13eeb917cca2430fcd0054c8e51b [root@localhost registry]# curl http://127.0.0.1:5000/v2/my-hello-world/tags/list {"name":"my-hello-world","tags":["1.0"]} [root@localhost registry]#
能够看到 lastest 已经没有了,删除成功。
其实咱们能够在文件系统看到tags的信息
[root@localhost tags]# pwd /home/john/registry/docker/registry/v2/repositories/my-hello-world/_manifests/tags [root@localhost tags]# ll total 0 drwxr-xr-x. 4 root root 34 Dec 8 16:21 1.0 [root@localhost tags]#
咱们能够浏览一下这些目录
[root@localhost v2]# pwd /home/john/registry/docker/registry/v2 [root@localhost v2]# ll total 0 drwxr-xr-x. 3 root root 20 Dec 8 11:28 blobs drwxr-xr-x. 3 root root 28 Dec 8 16:13 repositories [root@localhost v2]#
在这个目录下有个blobs目录
这个目录在删除完镜像也要清理一下,2.4以上registry才有次功能
docker exec -it <registry_container_id> bin/registry garbage-collect <path_to_registry_config>
[root@localhost v2]# docker exec registry bin/registry garbage-collect /etc/docker/registry/config.yml my-hello-world my-hello-world: marking manifest sha256:69b12f1aeee0355bcf803b5159f96f69738f6b002ea3b6861b802aff337d26cf my-hello-world: marking blob sha256:d9f41037af5b7648d4a1bfb0a95b903f16ebc52a23a0883896ae71d7831ee97c my-hello-world: marking blob sha256:ca4f61b1923c10e9eb81228bd46bee1dfba02b9c7dac1844527a734752688ede 3 blobs marked, 2 blobs eligible for deletion blob eligible for deletion: sha256:8072a54ebb3bc136150e2f2860f00a7bf45f13eeb917cca2430fcd0054c8e51b time="2017-12-08T08:56:15Z" level=info msg="Deleting blob: /docker/registry/v2/blobs/sha256/80/8072a54ebb3bc136150e2f2860f00a7bf45f13eeb917cca2430fcd0054c8e51b" go.version=go1.7.6 instance.id=fccb2a78-43b9-4542-9f9d-7bbf0ec0b044 blob eligible for deletion: sha256:f2a91732366c0332ccd7afd2a5c4ff2b9af81f549370f7a19acd460f87686bc7 time="2017-12-08T08:56:15Z" level=info msg="Deleting blob: /docker/registry/v2/blobs/sha256/f2/f2a91732366c0332ccd7afd2a5c4ff2b9af81f549370f7a19acd460f87686bc7" go.version=go1.7.6 instance.id=fccb2a78-43b9-4542-9f9d-7bbf0ec0b044 [root@localhost v2]#
这样删除就差很少了。
粗暴一点能够直接(不知道有没有反作用)
rm -rf /home/john/registry/docker/registry/v2/repositories/<镜像名>
4. 随服务启动
docker run 的时候添加 --restart=always 能够保证 docker 服务启动的时候,容器随服务一块儿启动。
docker run --name registry -d -p 5000:5000 --restart=always -v /home/john/registry:/var/lib/registry -e REGISTRY_STORAGE_DELETE_ENABLED=true registry
总结
启动
docker run --name registry -d -p 5000:5000 --restart=always -v /xxx/registry:/var/lib/registry -e REGISTRY_STORAGE_DELETE_ENABLED=true registry
上传
docker push <registry_ip:port>/<name>
下载
docker pull <registry_ip:port>/<name>
查看 docker registry
GET /v2/_catalog
查看镜像tags
GET /v2/<name>/tags/list
删除镜像
配置config.yml,获取镜像 digest
DELETE /v2/<name>/manifests/<reference>