我是基于ChatGPT-turbo-3.5实现的AI助手,在此网站上负责整理和概括文章

本文介绍了Docker,一种基于Linux内核的容器虚拟化技术,利用命名空间、控制组和联合文件系统实现资源隔离和高效管理。Docker的优势包括高效资源利用、快速启动、环境一致性,便于持续集成和部署。其核心架构采用客户端-服务器模式,并强调了安全防护措施。文章还涵盖了镜像、容器和仓库等基本概念,展示了其在现代软件开发中的实用价值。

# Docker简介

# 什么是 Docker

Docker 最初是 dotCloud 公司创始人 Solomon Hykes 在法国期间发起的一个公司内部项目,它是基于 dotCloud 公司多年云服务技术的一次革新,并于 2013 年 3 月以 Apache 2.0 授权协议开源,主要项目代码在 GitHub 上进行维护。Docker 项目后来还加入了 Linux 基金会,并成立推动 开放容器联盟(OCI)。

Docker 自开源后受到广泛的关注和讨论,至今其 GitHub 项目 已经超过 5 万 7 千个星标和一万多个 fork。甚至由于 Docker 项目的火爆,在 2013 年底,dotCloud 公司决定改名为 Docker。Docker 最初是在 Ubuntu 12.04 上开发实现的;Red Hat 则从 RHEL 6.5 开始对 Docker 进行支持;Google 也在其 PaaS 产品中广泛应用 Docker。

Docker 使用 Google 公司推出的 Go 语言 进行开发实现,基于 Linux 内核的 cgroup,namespace,以及 OverlayFS 类的 Union FS 等技术,对进程进行封装隔离,属于 操作系统层面的虚拟化技术。由于隔离的进程独立于宿主和其它的隔离的进程,因此也称其为容器。最初实现是基于 LXC,从 0.7 版本以后开始去除 LXC,转而使用自行开发的 libcontainer,从 1.11 版本开始,则进一步演进为使用 runC 和 containerd。

  • runc 是一个 Linux 命令行工具,用于根据 OCI容器运行时规范 创建和运行容器。

  • containerd 是一个守护程序,它管理容器生命周期,提供了在一个节点上执行容器和管理镜像的最小功能集。

  • Docker 在容器的基础上,进行了进一步的封装,从文件系统、网络互联到进程隔离等等,极大的简化了容器的创建和维护。使得 Docker 技术比虚拟机技术更为轻便、快捷。

# Docker 和传统虚拟化

传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;而容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。

  • 传统虚拟化

  • Docker

# 为什么要使用 Docker

作为一种新兴的虚拟化方式,Docker 跟传统的虚拟化方式相比具有众多的优势。

  1. 更高效的利用系统资源

    • 由于容器不需要进行硬件虚拟以及运行完整操作系统等额外开销,Docker 对系统资源的利用率更高。无论是应用执行速度、内存损耗或者文件存储速度,都要比传统虚拟机技术更高效。因此,相比虚拟机技术,一个相同配置的主机,往往可以运行更多数量的应用。
  2. 更快速的启动时间

    • 传统的虚拟机技术启动应用服务往往需要数分钟,而 Docker 容器应用,由于直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时间。大大的节约了开发、测试、部署的时间。
  3. 一致的运行环境

    • 开发过程中一个常见的问题是环境一致性问题。由于开发环境、测试环境、生产环境不一致,导致有些 bug 并未在开发过程中被发现。而 Docker 的镜像提供了除内核外完整的运行时环境,确保了应用运行环境一致性,从而不会再出现 「这段代码在我机器上没问题啊」 这类问题。
  4. 持续交付和部署

    • 对开发和运维(DevOps)人员来说,最希望的就是一次创建或配置,可以在任意地方正常运行。

    • 使用 Docker 可以通过定制应用镜像来实现持续集成、持续交付、部署。开发人员可以通过Dockerfile 来进行镜像构建,并结合 持续集成(Continuous Integration) 系统进行集成测试,而运维人员则可以直接在生产环境中快速部署该镜像,甚至结合 持续部署(Continuous Delivery/Deployment) 系统进行自动部署。

    • 而且使用 Dockerfile使镜像构建透明化,不仅仅开发团队可以理解应用运行环境,也方便运维团队理解应用运行所需条件,帮助更好的生产环境中部署该镜像。

  5. 更轻松的迁移

    • 由于 Docker 确保了执行环境的一致性,使得应用的迁移更加容易。Docker 可以在很多平台上运行,无论是物理机、虚拟机、公有云、私有云,甚至是笔记本,其运行结果是一致的。因此用户可以很轻易的将在一个平台上运行的应用,迁移到另一个平台上,而不用担心运行环境的变化导致应用无法正常运行的情况。
  6. 更轻松的维护和扩展

    • Docker 使用的分层存储以及镜像的技术,使得应用重复部分的复用更为容易,也使得应用的维护更新更加简单,基于基础镜像进一步扩展镜像也变得非常简单。此外,Docker 团队同各个开源项目团队一起维护了一大批高质量的 官方镜像,既可以直接在生产环境使用,又可以作为基础进一步定制,大大的降低了应用服务的镜像制作成本。

# 对比传统虚拟机总结

特性 容器 虚拟机
启动 秒级 分钟级
硬盘使用 一般为 MB 一般为 GB
性能 接近原生 弱于
系统支持量 单机支持上千个容器 一般几十个

# 基本架构

  • Docker目前采用了标准的C/S架构。客户端和服务端既可以运行在一个机器上,也可以运行在不同机器上,通过socket或RESTful API来进行通信。

# 服务端

  • Docker Daemon一般在宿主主机后台运行,作为服务端接受来自客户的请求,并处理这些请求(创建、运行、分发容器)。

  • 在设计上,Docker Daemon是一个模块化的架构,通过专门的Engine模块来分发管理各个来自客户端的任务。Docker服务端默认监听本地的unix:///var/run/docker.sock套接字,只允许本地的root用户或docker用户组成员访问。可以通过 -H 选项来修改docker daemon监听的目标。

  • 例如,让服务端监听本地的TCP连接1234端口:

    docker daemon -H 0.0.0.0:1234
  • 此外,Docker也支持通过HTTPS认证方式来验证访问。

    • unix:///var/run/docker.sock是Unix域套接字,是本机进程间通信的一种方式。
    • 创建一个Unix域套接字时,需要指定一个文件地址,对于docker来说,这个地址就是/var/run/docker.sock。
    • 由于docker daemon监听这个套接字,因此直接向这个套接字写入命令即可操作Docker。
    • 因此在本机启动用于Docker管理的Container时,都会看到这样的参数:-v /var/run/docker.sock:/var/run/docker.sock,即将本机的docker.sock挂在到容器中,从而使容器可以直接向本机Docker发送命令。
    • 对于不同OS,docker daemon启动时的初始配置文件位置不同,对于使用systemd管理启动服务的系统,配置文件在 /etc/systemd/system/docker.service.d/docker.conf
  • 参考:

# 客户端

  • Docker客户端为用户提供一系列可执行命令,用户用这些命令与Docker Daemon交互。
  • 客户端默认通过本地的unix:///var/run/docker.sock套接字向服务端发送命令。
  • 如果服务端没有监听在默认的地址,则需要客户端在执行命令时显式指定服务端地址。

# 新的架构设计

  • 原架构的缺点:Docker Daemon责任太重,既然响应API请求,又要管理容器。

  • 新架构:在1.11.0+之后的版本中,管理容器的任务被放到了一个单独的组件containerd中,减少了daemon的工作。

# Docker核心实现技术

  • 作为一种容器虚拟化技术,Docker深度应用了操作系统的多项底层支持技术。

  • 早期版本的Docker是基于已经成熟的Linux Container(LXC)技术实现的。自Docker 0.9版本起,Docker逐渐从LXC转移到新的libcontainer上,并且积极推动开放容器规范runc,视图打造更通用的底层容器虚拟化库。

  • 从操作系统功能上看,目前Docker底层依赖的核心技术主要包括Linux操作系统的:

    • 命名空间(Namespace)
    • 控制组(Control Group)
    • 联合文件系统(Union File System)
    • Linux网络虚拟化支持

# 命名空间

  • 命名空间(namespace)是Linux内核的一个强大特性。
  • 每个容器都拥有自己单独的命令控件,运行在其中的应用都像是在独立的操作系统环境中一样。
  • 命名空间机制保证了容器之间资源隔离,彼此互不影响。

# 控制组

  • 控制组(CGroups)是Linux内核的一个特性,主要用来对共享资源进行隔离、限制、审计等。

  • 控制组可以提供对容器的内存、CPU、磁盘IO等资源进行限制和计费管理。

  • 具体来看,控制组提供:

    • 资源限制:比如容器能使用的内存限制。
    • 优先级:CPU优先级。
    • 资源审计:用来统计系统实际上把多少资源用到适合的目的上。
    • 隔离:为组隔离命名空间,这样一个组不会看到另一个组的进程、网络连接和文件系统。
    • 控制:挂起、恢复和重启动等操作。
  • Docker的控制组相关信息保存在 /sys/fs/cgroup/memory/docker/ 目录下。如下图:

    • 其中白色的文件为全局配置,修改这些文件会影响所有Container。
    • 的文件夹代表每个容器,其中包含各个容器的配置。但是不应修改其中的文件,只是查看容器状态时可以读取其中文件。
  • 可以在创建或启动容器时为每个容器指定资源限制,例如:

    • -c | --cpu-shares=XXX 调整容器使用CPU的权重。
    • -m | --memory=XXX 调整容器使用内存的大小。

# 联合文件系统

  • 联合文件系统(UnionFS)是一种轻量级的高性能分层文件系统,它支持将文件系统中的修改信息作为一次提交,并层层叠加,同时可以将不同目录挂载到同一个虚拟文件系统下,应用看到的是挂载的最终结果。

  • 联合文件系统是实现Docker镜像的技术基础。Docker镜像可以通过分层来继承,不同镜像可共享相同的层,从而减小镜像大小。

# Docker存储

  • 一个Docker镜像自身是由多个文件层组成的,每一层有唯一的编号(层ID)。

  • 可以通过 docker history 查看一个本地镜像由哪些层组成。例:

  • 构成Docker镜像的各个文件层内容都是只读的、不可修改的。而当Docker利用镜像启动一个容器时,将在镜像文件系统的最顶端再挂在一个新的可读可写层给容器

  • 容器中的内容更新只会发生在该读写层。当需要修改底层文件层中的某个文件时,需要先将该文件复制到读写层,然后在读写层修改(写时复制,copy on write)。

  • 当修改的目标文件较大时,性能比较差。因此,一般推荐将容器修改的数据通过Volume方式挂在,而不是直接修改镜像内的数据。

  • 另外,对于频繁启停的Docker容器,文件系统本身的IO性能也十分关键。

  • 具体来说,Docker相关的所有文件都存储在 var/lib/docker 目录下,里面包含Docker镜像和容器运行相关的所有文件。

  • 而镜像文件系统相关的内容,则根据使用的文件系统的不同,存储在不同的文件夹下,即/var/lib/docker/{driver-name}。

    • 如果使用的是aufs(ubuntu常用),则在aufs文件夹下;
    • 如果是deveice mapper,则在devicemapper文件系统下。
    • 不同文件系统内,存储镜像文件系统的方式不同。
    • 但通常都有一个/mnt/目录,代表各个容器运行时的最终挂载点。

# 多种文件系统比较

  • Docker支持多种联合文件系统,在启动时按照以下优先级选择:
    • overlay2
    • aufs
    • devicemapper
    • btrfs
    • vfs

# Linux网络虚拟化

# 基本原理

  • 直观上看,要实现网络通信,机器需要至少一个网络接口(物理接口或虚拟接口)与外界相通,并可以收发数据包;此外,如果不同子网之间要进行通信,需要额外的路由机制。

  • Docker中的网络接口默认都是虚拟的接口。虚拟接口的最大优势就是转发效率极高。这是因为Linux通过在内核中进行数据复制来实现虚拟接口之间的数据转发,即发送接口的发送缓存中的数据包将被直接复制到接收接口的接收缓存中,而无须通过外部物理网络设备进行交换。

  • 本地系统和容器内系统来看,虚拟接口跟一个正常的以太网网卡相比并无区别,只是它速度要快得多。

  • Docker的容器网络就很好地利用了Linux虚拟网络技术

    • Docker启动时会在主机上自动创建一个docker0虚拟网桥,实际上是一个Linux网桥,可以理解为一个软件交换机,它会在挂载其上的接口之间进行数据转发。 同时Docker随机分配一个本地未占用的私有网段(在RFC1918中定义)中的一个地址给docker0接口

    • 当创建一个Docker容器时,同时会创建一对veth pair接口当数据包发送到一个接口时,另外一个接口也可以收到相同的数据包

    • 这对接口一端在容器内,即eth0,另一端在本地并被挂载到docker0网桥
      名称以veth开头,通过这种方式,主机可以跟容器通讯,容器之间也可以相互通信。
      如此一来,Docker就创建了在主机和所有容器之间的一个虚拟共享网络。

# 网络创建过程

  • 在使用docker run命令启动容器的时候,可以通过 --net 参数来指定容器的网络配置:
    • --net=bridge :默认值,在Docker网桥docker0上位容器创建新的网络栈。(网桥docker0相当于一台交换机,每个容器相当于一台电脑,各个容器通过交换机连接在一起)
    • --net=container:NAME_or_ID :让Docker将新建容器的进程放到一个已存在的容器的网络栈中,新容器进程有自己的文件系统、进程列表和资源列表,但会和已存在的容器共享IP地址和端口等网络资源,两者进程可以直接通过lo环回接口通信。
    • --net=host :告诉Docker不要将容器网络放到隔离的命名空间中,即不要容器化容器内的网络。此时容器使用本地主机的网络,它拥有完全的本地主机接口访问权限。这样做存在很大的安全风险。
    • --net=none :让Docker将新容器放到隔离的网络栈中,但是不进行网络配置。之后用户可以自行进行配置。
    • --net=user_defined_network :用户先自行用network相关命令创建一个网络,然后通过这种方式将容器链接到指定的已创建网络上。

# 安全防护与配置

Docker是基于Linux操作系统实现的应用虚拟化。运行在容器内的进程,跟运行在本地系统中的进程本质上并无区别,配置不合适的安全策略将可能给本地系统带来安全风险。

# 命名空间隔离的安全

  • 当用户用docker run命令启动一个容器时,Docker将在后台为容器创建一个独立的命名空间。命名空间提供了最基础也是最直接的隔离,在容器中运行的进程不会被运行在本地主机上的进程和其他容器通过正常渠道发现和影响。

  • 与虚拟机方式相比,通过命名空间来实现的隔离并不是那么绝对。运行在容器中的应用可以直接访问系统内核和部分系统文件。因此,用户必须保证容器中应用是安全可信的(这跟保证运行在系统中的软件是可信的一样),否则本地系统将可能受到威胁。总之,必须保证镜像的来源和自身可靠

  • Docker自1.3.0版本起对镜像管理引入了签名系统,加强了对镜像安全性的防护。用户可以通过签名来验证镜像的完整性和正确性。

# 控制组资源控制的安全

  • 当用户执行docker run命令启动一个Docker容器时,Docker将通过Linux相关的调用,在后台为容器创建一个独立的控制组策略集合,该集合将限制容器内应用对资源的消耗。

  • 控制组提供了很多有用的特性。它确保各个容器可以公平地分享主机的内存、CPU、磁盘IO等资源。当然,更重要的是,通过控制组,可以限制容器对资源的占用,确保了当某个容器对资源消耗过大时,不会影响到本地主机系统和其他容器。

  • 尽管控制组不负责隔离容器之间相互访问、处理数据和进程,但是它在防止恶意攻击、特别是DDoS方面是是否有效的。

  • 对于支持多用户的服务平台(比如公有的各种Paas、容器云),控制组尤其重要。例如,当个别应用容器出现异常时,可以保证本地系统和其他容器正常运行而不受影响,从而避免引发“雪崩”灾难。

# 内核的能力机制

  • 能力机制(Capability)是Linux内核一个强大的特性,可以提供细粒度的权限访问控制。

  • 以前Linux系统对进程权限只有根权限和非根权限两种粗粒度的区别。Linux内核自2.2版本起支持能力机制,它将权限划分为更加细粒度的操作能力,既可以作用在进程上,也可以作用在文件上。

  • 默认情况下,Docker启动的容器被严格限制只允许使用内核的一部分能力。用户可以根据自生需求来为Docker容器启动额外的权限。

# Docker服务端的防护

  • 使用Docker容器的核心是Docker服务端。Docker服务的运行目前还需要root权限的支持,因此服务端安全性十分关键。

  • 首先,必须确保只有可信的用户才可以访问到Docker服务。Docker允许用户在主机和容器间共享文件夹,同时不需要限制容器的访问权限,这就容易让容器突破资源限制。

  • 容器中的进程和宿主机器上的其进程是没有区别的,他们使用的是同一个内核,受同一个内核管理权限,如果说容器中的进程是root权限,那么也就意味这这个进程在宿主机器上其实也是root权限。如果资源被挂载到容器中,那么意味着容器中的进程能够获取,修改,删除这些资源,因为它是root权限。

    • 例如,恶意用户可以在启动容器时将本地根目录挂载到容器中,那么就可以在容器中任意修改主机内容了。因此,当提供容器创建服务时(例如通过一个Web服务器),要注意参数的安全检查,防止恶意用户用特定的参数来创建一些有破坏性的容器。
  • 用户可以通过基于HTTP的REST API来访问Docker服务端。建议使用安全机制,确保只有可信的网络或VPN网络,或证书保护机制下的访问可以进行。

  • 最近改进的Linux命名空间机制将可以实现使用非root用户来运行全功能的容器。

  • 目前,Docker滋生改进安全防护的目标是实现以下两个特性:

    • 将容器的root用户映射到本地主机上的非root用户。
    • 允许Docker服务端在非root权限下运行。
  • 参考:你不应该在容器中使用root用户

  • 如果你要创建一个镜像,那么你就应该在Dockerfile中创建一个默认的用户,而不是使用默认的root。这样更加容器控制权限。我们举一个root容器的例子,看一下他的危害:

  • 在宿主机器的root目录下创建一个隐私文件,我使用root用户创建,只有root权限的用户才能访问这个文件

    root@srv:~# cd /root
    root@srv:~# echo "top secret stuff" >> ./secrets.txt
    root@srv:~# chmod 0600 secrets.txt
    root@srv:/root# ls -l
    total 4
    -rw------- 1 root root 17 Sep 26 20:29 secrets.txt
    
    # 使用非root用户访问
    marc@srv:~$ cat /root/secrets.txt
    cat: /root/secrets.txt: Permission denied
  • 退出root,使用一个普通的用户来创建一个Dockerfile:

    FROM debian:stretch
    CMD ["cat", "/tmp/secrets.txt"]
  • 然后编译运行这个镜像,并且将我们的隐私文件挂载进去:

    marc@srv:~$ docker run -v /root/secrets.txt:/tmp/secrets.txt <img>
  • 即便我在宿主机器上的容器是marc,但是在容器中,我已经拥有root权限了,能够访问宿主机上root权限才能访问的资源文件。这也就是说任何人在DockerHub上下载这镜像,都会暴露自己的特权文件(当然,还取决于你怎么它)。

  • 建议在创建Dockerfile的时候创建一个普通用户,并且指定uid和gid。使用这个普通用户来启动容器。

    FROM debian:stretch
    RUN groupadd -g 999 appuser && \
        useradd -r -u 999 -g appuser appuser
        USER appuser
        CMD ["cat", "/tmp/secrets.txt"]
  • 再次上之前那样运行容器

    marc@srv:~$ docker run -v /root/secrets.txt:/tmp/secrets.txt <img>
    cat: /tmp/secrets.txt: Permission denied

# 基本概念

Docker 包括三个基本概念

  • 镜像Image
  • 容器Container
  • 仓库Repository

理解了这三个概念,就理解了 Docker 的整个生命周期。

# Docker镜像

我们都知道,操作系统分为 内核用户空间。对于 Linux 而言,内核启动后,会挂载 root 文件系统为其提供用户空间支持。而 Docker 镜像Image),就相当于是一个 root 文件系统。比如官方镜像 ubuntu:18.04 就包含了完整的一套 Ubuntu 18.04 最小系统的 root 文件系统。

Docker 镜像 是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像 不包含 任何动态数据,其内容在构建之后也不会被改变。

# 分层存储

因为镜像包含操作系统完整的 root 文件系统,其体积往往是庞大的,因此在 Docker 设计时,就充分利用 Union FS 的技术,将其设计为分层存储的架构。所以严格来说,镜像并非是像一个 ISO 那样的打包文件,镜像只是一个虚拟的概念,其实际体现并非由一个文件组成,而是由一组文件系统组成,或者说,由多层文件系统联合组成。

镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。比如,删除前一层文件的操作,实际不是真的删除前一层的文件,而是仅在当前层标记为该文件已删除。在最终容器运行的时候,虽然不会看到这个文件,但是实际上该文件会一直跟随镜像。因此,在构建镜像的时候,需要额外小心,每一层尽量只包含该层需要添加的东西,任何额外的东西应该在该层构建结束前清理掉。

分层存储的特征还使得镜像的复用、定制变的更为容易。甚至可以用之前构建好的镜像作为基础层,然后进一步添加新的层,以定制自己所需的内容,构建新的镜像。

关于镜像构建,将会在后续相关章节中做进一步的讲解。

Docker镜像类似于虚拟机镜像,可以将它理解为一个只读的模板。例如,一个镜像可以包含一个基本的操作系统环境,里面仅安装了Apache应用程序(或用户需要的其他软件)。可以把它称为Apache镜像。

# Docker容器

镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的 实例 一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。

容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的 命名空间。因此容器可以拥有自己的 root 文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。这种特性使得容器封装的应用比直接在宿主运行更加安全。也因为这种隔离的特性,很多人初学 Docker 时常常会混淆容器和虚拟机。

前面讲过镜像使用的是分层存储,容器也是如此。每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,我们可以称这个为容器运行时读写而准备的存储层为 容器存储层

容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。因此,任何保存于容器存储层的信息都会随容器删除而丢失。

按照 Docker 最佳实践的要求,容器不应该向其存储层内写入任何数据,容器存储层要保持无状态化。所有的文件写入操作,都应该使用 数据卷(Volume)、或者 绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。

数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。因此,使用数据卷后,容器删除或者重新运行之后,数据却不会丢失。

# Docker仓库

镜像构建完成后,可以很容易的在当前宿主机上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,Docker Registry就是这样的服务。

一个 Docker Registry 中可以包含多个 仓库Repository);每个仓库可以包含多个 标签Tag);每个标签对应一个镜像。

通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。

Ubuntu 镜像 为例,ubuntu 是仓库的名字,其内包含有不同的版本标签,如,16.04, 18.04。我们可以通过 ubuntu:16.04,或者 ubuntu:18.04 来具体指定所需哪个版本的镜像。如果忽略了标签,比如 ubuntu,那将视为 ubuntu:latest

仓库名经常以 两段式路径 形式出现,比如 jwilder/nginx-proxy,前者往往意味着 Docker Registry 多用户环境下的用户名,后者则往往是对应的软件名。但这并非绝对,取决于所使用的具体 Docker Registry 的软件或服务。

# Docker Registry 公开服务

Docker Registry 公开服务是开放给用户使用、允许用户管理镜像的 Registry 服务。一般这类公开服务允许用户免费上传、下载公开的镜像,并可能提供收费服务供用户管理私有镜像。

最常使用的 Registry 公开服务是官方的 Docker Hub,这也是默认的 Registry,并拥有大量的高质量的 官方镜像。除此以外,还有 Red Hat 的 Quay.io;Google 的 Google Container RegistryKubernetes 的镜像使用的就是这个服务;代码托管平台 GitHub 推出的 ghcr.io

由于某些原因,在国内访问这些服务可能会比较慢。国内的一些云服务商提供了针对 Docker Hub 的镜像服务(Registry Mirror),这些镜像服务被称为 加速器。常见的有 阿里云加速器DaoCloud 加速器 等。使用加速器会直接从国内的地址下载 Docker Hub 的镜像,比直接从 Docker Hub 下载速度会提高很多。在安装 Docker一节中有详细的配置方法。

国内也有一些云服务商提供类似于 Docker Hub 的公开服务。比如 网易云镜像服务DaoCloud 镜像市场阿里云镜像库 等。

# 私有 Docker Registry

除了使用公开服务外,用户还可以在本地搭建私有 Docker Registry。Docker 官方提供了 Docker Registry 镜像,可以直接使用做为私有 Registry 服务。在 私有仓库 一节中,会有进一步的搭建私有 Registry 服务的讲解。

开源的 Docker Registry 镜像只提供了 Docker Registry API 的服务端实现,足以支持 docker 命令,不影响使用。但不包含图形界面,以及镜像维护、用户管理、访问控制等高级功能。

除了官方的 Docker Registry 外,还有第三方软件实现了 Docker Registry API,甚至提供了用户界面以及一些高级功能。比如,HarborSonatype Nexus

  • Docker仓库类似于代码仓库,它是Docker集中存放镜像文件的场所。

  • Docker仓库可以分为公共仓库和私有仓库。Docker Hub是官方的、最大的公共仓库。

  • 从严格意义上来讲,应当区分仓库和仓库注册服务器(registry)。

    • 仓库注册服务器是存放仓库的服务器。一个服务器上会存放大量仓库。
    • 每个仓库存储某一类镜像,往往包含多个镜像文件,通过tag加以区分。例如存放Ubuntu操作系统的仓库称为Ubuntu仓库,其中包含不同版本的镜像。
更新于

请我喝[茶]~( ̄▽ ̄)~*

Fulsun 微信支付

微信支付

Fulsun 支付宝

支付宝