Docker实践(16) – 引用特定镜像构建镜像

在你构建镜像大多数时候会引用镜像名称,如“node”或”ubuntu”,这个没有任何问题。
如果你引用镜像名称,它有可能tag名称保持一样而镜像被更改了。看起来这自相矛盾,不过它真实发生了!repository名称仅仅是个引用,它有可能被更改指向一个不同的镜像。指定一个带冒号的tag名称也不会消除这种风险,因为安全更新会使用相同的tag来自动重新构建有漏洞的镜像。
大多数时候你会想让它这样做 – 镜像维护者对镜像有所改进,并修补了安全漏洞是一件好事。不过有时候可能会给你带来痛苦。这不仅仅是一个理论上的风险:这已经出现过很多次了,中断了持续交付且很难调试。在Docker早期,镜像会添加和删除软件包(包括,记忆中消失了的passwd命令),使构建镜像突然地中断。

问题

你想确保镜像的构建始终从一个指定的不会被更改的镜像。

解决方法

从一个指定的镜像ID构建。

讨论

对于你想决定确认从一个指定的镜像构建镜像时,可以在Dockerfile中指定镜像ID.
下面是示例:

  1. FROM 8eaa4ff06b53
  2. RUN echo "Built from image id:" > /etc/buildinfo
  3. RUN echo "8eaa4ff06b53" >> /etc/buildinfo
  4. RUN echo "an ubuntu 14.4.01 image" >> /etc/buildinfo
  5. CMD ["echo","/etc/buildinfo"]

像这样从一个指定的镜像ID构建镜像,这个镜像必须已经保存在了本地。Docker registry不会在Docker Hub搜索这个镜像ID的。
注意你引用的镜像不需要tag。你可以从任意层来构建镜像。

Docker实践(15) – 通过Docker Hub分享镜像

如果你与其他人共享你的镜像,使用描述性名称tag镜像会更有帮助。为了满足这个需求,Docker能够轻松地将镜像移动到其它地方,Docker Inc则创建了免费的Docker Hub服务来鼓励这种共享。

为了使用Docker Hub服务,你需要注册一个Docker Hub帐号来使用docker login登录。注册地址为http://hub.docker.com。

问题

你想公开分享一个Docker镜像。

解决方法

使用Docker Hub registry分享你的镜像。

讨论

下面有几个术语需要理解,以免造成混乱。

  • Username – Docker registry用户名
  • Registry – registries保存镜像。你可以上传镜像到registry和从它下载镜像。Registries可以是公开或私有的。
  • Registry host – 运行Docker registry的主机
  • Docker Hub – 默认公开的registry,位于https://hub.docker.com
  • Index – 与registry host一样。待废弃的术语。
  • 正如你以前看到的,你可以根据需要对镜像进行多次tag。这对复制镜像是有用的,这样你可以管理它。
    我们假设你Docker Hub的用户名为”adev”。下面的三个命令展示如何复制来自Docker Hub的debian:wheezy镜像到你自己用户下。

    1. docker pull debian:wheezy
    2. docker tag debian:wheezy adev/debian:mywheezy1
    3. docker push adev/debian:mywheezy1

    你现在有一个Debian wheezy镜像的引用,你可以自己维护它了。
    如果你有一个私有的repository需要推送,除了在tag之前需要指定registry的地方外,其它步骤一样。我们假设你repository的地址为http://mycorp.private.dockerregistry。下面的示例tag和推送镜像。

    1. docker pull debian
    2. docker tag debian:wheezy mycorp.private.dockerregistry/adev/debian:mywheezy1
    3. docker push mycorp.private.dockerregistry/adev/debian:mywheezy1

    以上的命令不会把镜像推送到公共的Docker Hub,会推送到你的私有repository,所以有这个repository的访问权限的用户能拉取这个镜像。

    Docker实践(14) – Docker tag

    上一篇文章中你通过docker commit保存了容器的状态,并且得到一个随机的镜像ID。记住和管理巨大数量的镜像ID非常困难。使用Docker的tag功能可以给镜像设置一个可读的名称,提醒你镜像创建的目的是什么。掌握这个技术使你对镜像的用途一目了然,使得管理你机器上的镜像变得非常容易。

    问题

    你想方便地引用和存储一个Docker commit。

    解决方法

    使用docker tag命名你的提交。

    讨论

    tag的基本用法很简单:

    1. $ docker tag 071f6a36c23a19801285b82eafc99333c76f63ea0aa0b44902c6bae482a6e036 imagename

    创建了一个可以引用此镜像的名称,如:

    1. docker run imagename

    这个名称比随机的ID容易记多了。
    如果你想与他人共享你的镜像,还需要了解更多的tag知识。tag的相关术语可能会有点混乱。像image,name和repository有时候可互相交换使用。如下定义:

  • Image – 一个只读层
  • Name – 镜像的名称,如“todoapp”
  • Tag – 作为动词,指的是给镜像设置一个名称,作为名词,是镜像名称的修饰符
  • Repository – 已tag的镜像集合一起组成容器的文件系统
  • 可能最容易引起混乱的术语是image和repository。我们一直使用术语image来宽松地表示产生容器的层集合,但技术上,image是递归地引用其父层的单个层。repository是托管的,意味着它存储在某个地方(不管是在你的Docker daemon或者一个registry上)。此外,repository是tagged的镜像的集合来组成容器的文件系统。
    可以用Git类比帮助我们理解。当克隆一个Git repository时,你check out了当时请求点的文件状态。这类似于image。repository是文件每次提交的整体历史记录。因为check out是指向了最上层。当你克隆时也会包含其它所有层。
    我们来看下Ubuntu镜像。当你拉取Ubuntu镜像并执行docker images时,你会看到如下输出:

    1. $ docker images
    2. REPOSITORY  TAG    IMAGE ID        CREATED       VIRTUAL SIZE
    3. ubuntu    trusty   8eaa4ff06b53    4 weeks ago    192.7 MB
    4. ubuntu    14.04    8eaa4ff06b53    4 weeks ago    192.7 MB
    5. ubuntu    14.04.1  8eaa4ff06b53    4 weeks ago    192.7 MB
    6. ubuntu    latest   8eaa4ff06b53    4 weeks ago    192.7 MB

    Repository列列出托管层集合称为“ubuntu”。通常称为镜像。Tag列列出四个不同的名称(trusty, 14.04, 14.04.1, 和latest)。Image ID列列出相同的镜像ID。因为这些不同的tag名称指向同一个镜像。这说明了你可以对同一个镜像设置多个tag。

    Docker实践(13) – 保存开发环境状态

    如果你曾经开发过软件,你可能至少一次地像这样呼叫过,”奇怪了,之前明明正常的!”不过没办法快速地恢复到之前的正常状态,你只能匆忙地去修改代码以尽快完成任务而不至于延期。这就浪费了许多时间。
    版本控制软件已经能帮助你快速恢复到指定的正常版本,不过但下面的两个特殊情况会存在问题:

  • 代码无法体现你工作环境系统的状态
  • 你可能还不愿意提交代码
  • 第一个问题比第二个值得关注。虽然像Git这样的现代源代码控制工具可以轻松地创建分支,不过捕获整个开发文件系统的状态不是Git的目的。
    Docker通过它的commit功能提供了一个成本低廉和快速的方法来保存容器开发系统的状态,这就是我们下面将要探讨的。

    问题

    你想保存你开发环境的状态。

    解决方法

    使用docker commit保存状态

    讨论

    假如你对你的to-do应用做更改。ToDoCorp的CEO对浏览器显示的标题”Swarm+React – TodoMVC.”不满意,要改为“ToDo- Corp’s ToDo App”。
    你不确定如何完成这个任务,所以你可能需要启动应用,并更改文件做试验看会怎样:

    1. $ docker run -d -p 8000:8000 –name todobug1 dockerinpractice/todoapp  3c3d5d3ffd70d17e7e47e90801af7d12d6fc0b8b14a8b33131fc708423ee4372
    2. $ docker exec -i -t todobug1 /bin/bash

    docker run命令后台(-d)启动to-do应用容器,映射容器的8000端口到主机的8000端口(-p 8000:8000),命名为todobug1(–name todobug1)。
    第二个命令在已运行的容器中启动/bin/bash。-i激活交互模式,-t创建一个TTY。
    现在你已经进入容器了,所以试验前先安装编辑器。我们喜欢用vim,所以用以下命令:

    1. apt-get update
    2. apt-get install vim

    经过了一翻努力你意识到需要更改local.html,因为你更改如下:
    ToDoCorp’s ToDo App
    不过CEO想让标题使小写字符,因为她听说这看起来更现代。你想把现在的更改保存下,在另一个终端执行如下命令:

    1. $ docker commit todobug1
    2. ca76b45144f2cb31fda6a31e55f784c93df8c9d4c96bbeacd73cad9cd55d2970

    你现在已经提交了刚才的更改,所以之后你可以从镜像运行包含此更改的容器。
    下一步你更改local.html:
    todocorp’s todo app
    再次提交:

    1. $ docker commit todobug1
    2. 071f6a36c23a19801285b82eafc99333c76f63ea0aa0b44902c6bae482a6e036

    现在在我们这个示例已经有两个镜像ID(ca76b45144f2cb31fda6a31e55f784c93df8c9d4c96bbeacd73cad9cd55d2970和071f6a36c23a19801285b82eafc99333c76f63ea0aa0b44902c6bae482a6e036)。当CEO来评估她想要哪个时,你可以运行任意一个镜像来让你决定。
    你可以在新终端运行如下命令来启动两个镜像:

    1. $ docker run -p 8001:8000 ca76b45144f2cb31fda6a31e55f784c93df8c9d4c96bbeacd73cad9cd55d2970
    2. $ docker run -p 8002:8000 071f6a36c23a19801285b82eafc99333c76f63ea0aa0b44902c6bae482a6e036

    这样你可以打开http://localhost:8001显示大写的标题页面和http://localhost:8002显示小写页面。
    你肯定想知道有没有更好的方法来引用这两个镜像,而不是需要输入这么长的ID。下一篇文章我们会给这些镜像一个名称来更好的引用它。

    Docker实践(12) – 管理容器服务启动

    当尝试Docker作为VM的替代品在容器内运行多个服务可能会比较方便,或者完成VM到容器的初始转换后,运行重要服务是有必要的。
    不管是什么原因,当想尝试管理容器内的进程时尽量避免重复造轮子。

    问题

    你想管理容器内的多个进程。

    解决方法

    使用Supervisor应用(http://supervisord.org/)来管理你的进程启动。

    讨论

    我们准备演示如何创建一个包含Tomcat和Apache web服务器的容器,并以Supervisor的管理方式启动应用。
    首先在一个新的空的目录创建一个Dockerfile,如下:
    虚拟化技术
    需要一个用来指定启动哪些应用的supervisord配置文件,如下:
    虚拟化技术
    虚拟化技术
    使用刚才创建的Dockerfile生成镜像:

    1. docker build -t supervised .

    开始运行容器:
    虚拟化技术
    如果你打开http://localhost:9000,你应该能看到Apache的默认页面。
    如果要清除容器,执行如下命令:

    1. docker rm -f supervised

    Docker实践(11) – 将系统拆分为微服务容器

    我们已经探讨了如何作为一个整体使用容器(像一个经典的服务器),并解释它可以是一个快速移动系统架构到Docker的好方法。不过在Docker世界中,通常认为最好的做法是尽可能多地分割系统,直到每个容器只运行一个服务,然后通过links连接所有容器。因为这是推荐的Docker方法,你会发现Docker Hub中的大多数容器都是这种方法,理解如何以这种方式构建镜像对于与Docker生态系统进行交互非常重要。
    一个容器一个服务的主要原因是通过单一责任原则更容易分离关注点。
    如果一个容器只做一项工作,那么将更容易地把容器放到开发,测试和生产的软件开发生命周期中,而不用担心它与其它组件的交互。这使得交付更灵活和软件项目更可扩展。不过它增加了维护开销,所以最好考虑在你的用例中是否值得这样做。

    问题

    你希望将你的应用程序分解成更易于管理的服务

    解决方法

    使用Docker将你的应用程序集分解为基于容器的服务

    讨论

    在Docker社区中,关于如何严格地遵循“一容器一服务”规则的一些争论,其中一部分源于对定义的不同意见 – 是一个单独的进程,还是根据需要把一组进程放到一起完成一项服务?它往往归结为一个声明,给予从头重新设计系统的能力,微服务是最可能的选择。但有时候,实用性与理想主义相克 – 当我们为我们的组织评估Docker时,我们发现自己处于必须走整条路线的位置,以便让Docker尽可能快速和轻松地工作。 让我们来看看在Docker中跑多个进程的一个缺点。首先我们需要展示如何创建一个带有数据库,应用和web服务器的容器。

    这些示例是为了阐明目的,所以简化了。尝试直接运行它们不一定能用。

    设置简单的PostgreSQL,NodeJS和Nginx应用:

    1. FROM ubuntu:14.04
    2. RUN apt-get update && apt-get install postgresql nodejs npm nginx
    3. WORKDIR /opt
    4. COPY . /opt/                             # {*}
    5. RUN service postgresql start &&
    6.     cat db/schema.sql | psql &&
    7.     service postgresql stop
    8. RUN cd app && npm install
    9. RUN cp conf/mysite /etc/nginx/sites-available/ &&
    10.     cd /etc/nginx/sites-enabled &&
    11.     ln -s ../sites-available/mysite

    在RUN语句中使用&&有效地确保了几个命令作为一个命令运行。这对于减小你的镜像大小会有用。每个Dockerfile命令都会在上一个层之上创建一个新层。如果你以这种方式 运行软件包更新命令(如apt-get update)和install命令,你可以确保无论何时安装软件包,它们都将来自更新的软件包缓存。

    前面的示例是一个概念上简单的Dockerfile,它在容器中安装我们需要的一切,然后设置数据库,应用程序和Web服务器。不过在你想快速重载容器时会有一个问题 – 对存储库中任何文件的任何更改都将从{*}处开始重建所有内容,因为缓存无法重复使用。如果你的一些步骤需要时间比较久(如数据库创建或npm安装),你可能需要一段时间等待容器重建。
    解决方案是拆分COPY . /opt指令为三部分,对应数据库,应用程序和Web设置。

    1. FROM ubuntu:14.04
    2. RUN apt-get update && apt-get install postgresql nodejs npm nginx
    3. WORKDIR /opt
    4. COPY db /opt/db                                     -+
    5. RUN service postgresql start &&                    |- db setup
    6.     cat db/schema.sql | psql && |
    7.     service postgresql stop                         -+
    8. COPY app /opt/app                                   -+
    9. RUN cd app && npm install                            |- app setup
    10. RUN cd app && ./minify_static.sh                    -+
    11. COPY conf /opt/conf                                 -+
    12. RUN cp conf/mysite /etc/nginx/sites-available/ &&   +
    13.     cd /etc/nginx/sites-enabled &&                  |- web setup
    14.     ln -s ../sites-available/mysite                 -+

    在上面的代码中,COPY命令分成三个单独的指令。这意味着数据库将不会在每次代码更改时重建,因为在COPY app /opt/app之前缓存可以重用。
    不过由于缓存功能相当简单,容器仍然必须在每次对schema.sql进行更改时完全重建 – 解决这个问题的唯一方法是按顺序为三个应用程序分别创建Dockerfile,如下:
    Database Dockerfile

    1. FROM ubuntu:14.04
    2. RUN apt-get update && apt-get install postgresql
    3. WORKDIR /opt
    4. COPY db /opt/db
    5. RUN service postgresql start &&
    6.     cat db/schema.sql | psql &&
    7.     service postgresql stop

    App Dockerfile

    1. FROM ubuntu:14.04
    2. RUN apt-get update && apt-get install nodejs npm
    3. WORKDIR /opt
    4. COPY app /opt/app
    5. RUN cd app && npm install
    6. RUN cd app && ./minify_static.sh

    Web server Dockerfile

    1. FROM ubuntu:14.04
    2. RUN apt-get update && apt-get install nginx
    3. WORKDIR /opt
    4. COPY conf /opt/conf
    5. RUN cp conf/mysite /etc/nginx/sites-available/ &&
    6.     cd /etc/nginx/sites-enabled &&
    7.     ln -s ../sites-available/mysite

    不管何时db,app或conf目录中的哪一个更改,仅仅有一个容器需要重建。当你有三个以上的容器或者需要大量时间的设置步骤时这种方法非常有用 – 你可以在每步中添加最少必要的文件以便获得更有用的Dockerfile缓存。在app Dockerfile中的npm install的操作中,只依赖了package.json文件,所以我们可以更改这个Dockerfile以充分利用dockerfile层缓存。

    1. FROM ubuntu:14.04
    2. RUN apt-get update && apt-get install nodejs npm
    3. WORKDIR /opt
    4. COPY app/package.json /opt/app/package.json
    5. RUN cd app && npm install
    6. COPY app /opt/app
    7. RUN cd app && ./minify_static.sh

    不过事情没有那么简单,从单个dockerfile文件分割为多个dockerfile,增加了不少重复代码。你可以通过添加另一个dockerfile作为基础镜像来部分解决这个问题。此外,启动你的镜像还有一些复杂的问题 – 除了EXPOSE步骤使适当的端口可用于链接和更改Postgres配置之外,你还需要确保在每次启动时链接容器。 幸运的是,有一个叫做docker-compose(以前的fig)的工具来帮我们完成这件事。

    Docker实践(10) – 类主机容器

    我们现在把讨论转到Docker社区最具争议性的领域之一 – 运行一个包含多个进程的类主机镜像。
    这个在Docker社区中部分人认为是一种不好的形式。容器不是虚拟机 – 它们有显著的差异 – 假装不会造成混乱和没有问题。
    不管是好还是坏,本文展示如何运行一个类主机镜像,讨论这其中的一些问题。

    运行一个类主机镜像是一个说服Docker反对者的好方法,Docker很有用。当他们更多地使用Docker,他们会更理解Docker范式,微服务方法对他们更有意义。在我们介绍Docker的公司中,我们发现这种单一的方法是将人们从开发服务器和笔记本电脑上的开发移动到更加包容和可管理的环境的好方法。

    虚拟机与Docker容器的不同之处
    这些是VM和Docker容器之间的一些区别:
    Docker是面向应用的,而VM是面向操作系统的;
    Docker容器与其他Docker容器共享操作系统,相比之下,VM各自有它们自己的操作系统;
    Docker容器设计为运行一个主要进程,而不是管理多个进程集。

    问题

    你需要为容器设置一个类主机的环境,并设置多个进程和服务。

    解决方法

    使用旨在模拟主机的镜像,并为其提供所需的应用程序。

    讨论

    在下面的示例中我们使用phusion/baseimage Docker镜像,一个设计用来运行多个进程的镜像。
    第一步是运行镜像并使用docker exec进入到其bash环境:

    1. user@docker-host$ docker run -d phusion/baseimage
    2. 3c3f8e3fb05d795edf9d791969b21f7f73e99eb1926a6e3d5ed9e1e52d0b446e
    3. user@docker-host$ docker exec -i -t 3c3f8e3fb05d795 /bin/bash
    4. root@3c3f8e3fb05d:/#

    在这段代码中,docker run命令后台启动一个镜像(第一行),默认命令启动镜像并返回了新建容器的ID(第二行)。
    然后传容器ID给docker exec命令(第三),这个命令是在已运行的容器中启动一个新的进程。-i参数允许你与新进程交互,-t参数设置一个TTY,允许你在容器内部创建一个终端(/bin/bash)(第四行)。
    如果你等一分钟然后查看进程列表,输出类似如下:
    虚拟化技术
    虚拟化技术
    你可以看到容器启动起来很像一个主机,初始化服务如cron和sshd使它看起来像一个标准的Linux主机。这对于给新的Docker工程师初始演示很有用。
    这是否构成违反“一个容器一个服务”的微服务原则是Docker社区内部的一个争论。类主机镜像支持者认为这不违反这一原则,因为容器仍然可以实现其运行所在的系统的单个离散函数。

    Docker实践(9) – 虚拟机转换为容器

    Docker Hub没有所有可能的基本镜像,所以对于一些小众的Linux发行版本和用例,人们需要自己来创建它。如果你想把一个存在状态的虚拟机放入Docker上层迭代,或者受益于Docker生态系统,同样的原则也适用。
    理想情况下,你希望使用标准的Docker技术从头开始构建一个等效的VM,例如Dockerfiles与标准配置管理工具。然而现实是,许多VM没有仔细配置管理。这个有可能发生,因为一个VM已经发展成为一个有机体,人们已经在用它了,以一个更结构化的方式来重新创建它的投资可能不值得。

    问题

    你想把一个VM转换为一个Docker镜像

    解决办法

    通过ssh使用qemu-nbd,tar或者其它方法把VM文件系统打包成一个TAR文件,然后在Dockerfile中使用ADD命令添加TAR文件来创建镜像。

    讨论

    首先我们要将虚拟机分为两大类:本地(VM磁盘镜像和VM的执行在你的电脑)和远程(VM磁盘镜像的存储和VM执行在其它地方)。两组虚拟机(和任何你想创建Docker镜像)转换为Docker镜像的原理是一样的 – 打包文件系统为TAR文件并添加TAR文件到scratch镜像的根目录。
    ADD命令 – ADD Dockerfile命令(不像COPY命令)当把TAR文件(也可以是gzipped文件和其它类似的文件类型)放置到镜像时会自动解压。
    SCRATCH镜像 – scratch镜像是你在上面创建镜像的一个零字节的假镜像,通常它用于你想使用Dockerfile复制(或添加)一个完整文件系统到一个镜像的情况。
    我们现在来看一个你有一个本地Virtualbox VM的情况。
    在我们开始之前,你需要做如下事件:

  • 安装qemu-nbd工具(在Ubuntu系统的qemu-utils包里)
  • 记下VM磁盘映像的路径
  • 关闭VM
  • 如果你的VM磁盘映像是.vdi或.vmdk格式,应该能使用qemu-nbd成功挂载。其它的格式也有可能可行。
    以下代码演示了如何将虚拟机文件转换为虚拟磁盘,然后你可以从中复制所有文件:
    虚拟化技术
    如果你的VM是在远程,你可以请求你的运维团队来对你想要的分区作一个转储,或者在VM运行时创建TAR。
    如果你得到一个分区转储,可以很容易的挂载并打包成一个TAR文件:

    1. $ sudo mount -o loop partition.dump /mnt
    2. $ sudo tar cf $(pwd)/img.tar -C /mnt .
    3. $ sudo umount /mnt

    或者你可能在正在运行的系统上创建TAR文件:

    1. $ cd /
    2. $ sudo tar cf /img.tar –exclude=/img.tar –one-file-system /

    你现在得到了包含文件系统的TAR文件,可以通过scp命令传输到其它机器。

    从正在运行的系统上创建TAR文件看起来是一个最简单的方法(不用关机,安装软件或者请求其他团队),不过它有一个严重的缺点 – 你可能会一个不一致的状态下复制文件,这样当使用Docker镜像时会遇到奇怪的问题。如果你必须这样做,那么就尽可能的关闭应用和服务。

    一旦你得到了文件系统TAR文件,你就可以添加到镜像了。这是最简单的一步,只有Dockerfile的两行:

    1. FROM scratch
    2. ADD img.tar /

    然后执行docker build .就生成镜像了。
    现在你得到了一个新的镜像,你可以运行一个容器,然后在上面做你想要的修改,比如删除不需要的包来缩减容器大小并重新导出为一个新的小的镜像,下面是流程图:
    虚拟化技术

    Docker实践(8) – 搜索和运行一个Docker镜像

    Docker registries启用了类似于GitHub的社交编程文化。如果你有兴趣尝试一个新的软件应用,或者搜索一个新的软件用于特定目的。那么Docker镜像可以是一个简单的试验方式,而不会干扰你的主机,调配VM或者担心安装步骤。

    问题

    你想找到以Docker镜像形式的应用或工具,并尝试使用它。

    方法

    使用docker search命令来找到镜像来拉取并运行它。

    讨论

    我们假设你有兴趣尝试Node.js。在下面的命令中我们使用docker search命令来搜索带有node字符的镜像:
    虚拟化技术
    虚拟化技术
    一旦你选择好镜像,你可以通过执行docker pull imagename命令来下载它。
    虚拟化技术
    然后你可以使用-t和-i参数以交互模式运行它。-t参数创建一个tty设备(一个终端),-i参数指定Docker会话为可交互的。

    1. $ docker run -t -i node /bin/bash
    2.         root@c267ae999646:/# node
    3.         > process.version
    4.         ‘v0.12.0’
    5. >

    从镜像维护者经常会有关于如何运行镜像的特别建议。在http://hub.docker.com网站搜索这个镜像会把你带到这个镜像的页面。Description tab会给你更多的信息。

    Docker实践(7) – 设置本地私有库registry

    你看到了Docker官方有一个服务,人们可以公开分享他们的镜像(你可以付费设置为私有)。不过有些理由使你不想通过Hub分享镜像 – 一些企业喜欢把服务尽可能的留在内部,或者可能是你的镜像太大了,通过互联网传输会太慢,或者可能你只是在做试验想暂时保持私有,或者不想付费购买私有权限。不管是什么样的原因,有一个简单的解决方案。

    问题

    你想要一个本地托管你的镜像的方法。

    方法

    在你本地网络设置一个registry服务器。

    讨论

    要运行registry,在一个空间充足的机器执行如下命令:

    1. $ docker run -d -p 5000:5000 -v $HOME/registry:/var/lib/registry registry:2

    此命令设置了docker主机的5000端口作为registry的服务端口并设置容器的/var/lib/registry为registry的存储目录,也就是registry在容器中存储文件的默认目录。
    在需要访问registry服务器的docker机器上,给守护端添加如下选项(HOSTNAME是registry服务器的主机名或IP地址):–insecure-registry HOSTNAME.
    你现在能执行docker push HOSTNAME:5000/image:tag命令把镜像推送到registry服务器。
    如你所见,配置一个镜像存储在$HOME/registry的本地registry只用到了最基本的配置级别,很简单吧。如果你想扩大registry的存储规模和使服务更健壮,可以查看支持的存储驱动(https://github.com/docker/distribution/blob/v2.2.1/docs/storagedrivers.md),如存储到Amazon S3。
    你可能想了解关于–insecure-registry的选项。为什么帮助用户保持服务安全性,Docker只允许你从具有签名HTTPS证书的registrys拉取镜像。我们关闭此安全选项是因为我们认为本地网络是安全的。