在開發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>