一、Docker 安装与运行

这一小节我们介绍一下 Docker 安装与运行,在开始之后,我们需要明白的时候,Docker 有两个版本:

  • 一个是商业版收费的:Enterprice Edition,一般简称 Docker EE;
  • 另一个是社区版,也就是Community Edition,一般简称为 Docker CE。

这里安装我们会介绍在 Linux 平台、Mac 平台、Windows 平台的安装。重点会介绍一下在 Linux 平台的安装,Linux 平台又会细分两个:Centos 和 Ubuntu。

1、Linux 安装

Linux 下安装 Docker 我们将主要介绍 Centos 和 Ubuntu 系统

Centos

我们这里的示例 OS 版本是 Centos 7.4,使用命令 lsb_release -a 可以看到系统版本。

  1. LSB Version: :core-4.1-amd64:core-4.1-noarch
  2. Distributor ID: CentOS
  3. Description: CentOS Linux release 7.4.1708 (Core)
  4. Release: 7.4.1708
  5. Codename: Core

在 Centos 下面安装我们可以采用两种安装方式,一种是 yum 安装,一种是下载 rpm 包进行安装。

yum 安装

yum 安装需要确保 yum 源里面含有 Docker 软件包,国内的话推荐使用阿里云的 yum 源。如果要查看自己的系统的 yum 源,可以在目录 /etc/yum.repos.d/ 下查看,下面是我自己的阿里云的 ecs 虚拟机 yum 源文件,包含两个部分: CentOS-Base.repo 和 epel.repo 。内容分别如下

[base]
name=CentOS-$releasever
enabled=1
failovermethod=priority
baseurl=http://mirrors.cloud.aliyuncs.com/centos/$releasever/os/$basearch/
gpgcheck=1
gpgkey=http://mirrors.cloud.aliyuncs.com/centos/RPM-GPG-KEY-CentOS-7
[updates]
name=CentOS-$releasever
enabled=1
failovermethod=priority
baseurl=http://mirrors.cloud.aliyuncs.com/centos/$releasever/updates/$basearch/
gpgcheck=1
gpgkey=http://mirrors.cloud.aliyuncs.com/centos/RPM-GPG-KEY-CentOS-7
[extras]
name=CentOS-$releasever
enabled=1
failovermethod=priority
baseurl=http://mirrors.cloud.aliyuncs.com/centos/$releasever/extras/$basearch/gpgcheck=1
gpgkey=http://mirrors.cloud.aliyuncs.com/centos/RPM-GPG-KEY-CentOS-7
[epel]
name=Extra Packages for Enterprise Linux 7 - $basearch
enabled=1
failovermethod=priority
baseurl=http://mirrors.cloud.aliyuncs.com/epel/7/$basearch
gpgcheck=0
gpgkey=http://mirrors.cloud.aliyuncs.com/epel/RPM-GPG-KEY-EPEL-7

使用阿里云的 yum 源安装 Docker 非常简单,强烈建议各位同学配置阿里云的 yum 源。安装使用下面一条命令即可:
执行完之后,可以通过如下命令查看 Docker 的版本:

Client:
Version: 1.13.1
API version: 1.26
Package version:
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker
daemon running?

这个输出表示 Docker 的版本是 1.13.1。细心的同学会注意到最后一句提示,是因为 Docker Daemon进程还没有启动,启动命令如下:
或者:

systemctl start docker.service

启动完之后,我们就可以通过 docker 的命令来查看 Docker 是不是运行正常了,比如使用 docker images 查看本地所有的镜像。如下输出是正常的。

REPOSITORY TAG IMAGE ID CREATED  SIZE

下载 rpm 包安装

其中 containerd 和 docker-ce-cli 是 docker-ce 安装的前置条件,也就是要安装 docker-ce,需要先安装 containerd 和 docker-ce-cli。版本之间保证 docker-ce 和 docker-ce-cli 的版本一致,containerd 的版本尽可能新就 ok。下载到本地之后,使用 yum 安装。

yum install <pkg_name>.rpm

我这里选的版本是:

docker-ce-cli-19.03.5-3.el7.x86_64.rpm
containerd.io-1.2.6-3.3.el7.x86_64.rpm
docker-ce-19.03.5-3.el7.x86_64.rpm

按上面的顺序安装之后启动 docker

systemctl start docker.service

我们看一下 docker version:

Client: Docker Engine - Community
  Version: 19.03.5
  API version: 1.40
  Go version: go1.12.12
  Git commit: 633a0ea
  Built: Wed Nov 13 07:25:41 2019
  OS/Arch: linux/amd64
  Experimental: false
  Server: Docker Engine - Community
  Engine:
    Version: 19.03.5
    API version: 1.40 (minimum version 1.12)
    Go version: go1.12.12
    Git commit: 633a0ea
    Built: Wed Nov 13 07:24:18 2019
    OS/Arch: linux/amd64
    Experimental: false
  containerd:
    Version: 1.2.6
    GitCommit: 894b81a4b802e4eb2a91d1ce216b8817763c29fb
  runc:
    Version: 1.0.0-rc8
    GitCommit: 425e105d5a03fabd737a126ad93d62a9eeede87f
  docker-init:
    Version: 0.18.0
    GitCommit: fec3683

这个要比阿里云的 Yum 源中的 Docker 版本高很多,如果需要新的版本的 feature 的话,建议自己下载对应的 rpm 包进行安装

Ubuntu

我们知道 ubuntu 的包管理是通过 apt-get 来做的,但是默认的 apt-get 里面是没有包含 docker 的软件包的,我们需要将 Docker 的官方仓库加进来。

apt-get 安装

更新 ubuntu 的 apt 源索引,安装包允许 apt 通过 HTTPS 使用仓库

sudo apt-get install \
  apt-transport-https \
  ca-certificates \
  curl \
  software-properties-common

添加 Docker 官方 GPG key

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

设置 Docker 稳定版仓库

sudo add-apt-repository \
  "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) \
  stable"

添加仓库后,更新 apt 源索引,安装 Docker CE,不如过不输入 Version,则默认安装最新版本

sudo apt-get install docker-ce=<VERSION>

启动 Docker

systemctl start docker.service

使用这种方式安装的最大劣势就是 Docker 官方仓库和我们国内的机器网速捉急,相比之下将 deb 包下载到本地再进行安装往往是一种更好的安装方式。

deb 软件包安装

image.png
然后我们选择一个 docker-ce 版本,直接本地安装即可

sudo dpkg -i <deb pkg name>

2、Mac 安装

安装 Docker

  • stable: 稳定版
  • edge: 最新的 release,稳定性不保障

image.png
然后我们通过上图中 “Get Docker for Mac” 链接获取 dmg 安装文件。

启动 Docker

启动,找到你的 Application 中的下面这个 Docker 图标,点击运行即可。
image.png
启动之后,我们可以在导航栏上发现这么一个小图标,就表示 Docker 运行成功了。
image.png

3、Windows 安装

二、Docker 概览

这篇文章我们将来介绍一下 Docker 的基本情况,主要包括如下几个部分:
Docker 是什么;
Docker v.s. 虚拟机;
Docker 的应用场景;
Docker 架构浅析

1、Docker 是什么

相信有很多同学在平时的工作或者学习中应该都或多或少地使用过 Docker 了,那么 Docker 究竟是什么呢?有没有一个准确的定义来定义 Docker 呢?我们不妨先来看一下官方是如何来定义 Docker 的。

Docker is an open platform for developing, shipping, and running applications. Docker enables you to separate your applications from your infrastructure so you can deliver software quickly. With Docker, you can manage your infrastructure in the same ways you
manage your applications. By taking advantage of Docker’s methodologies for shipping, testing, and deploying code quickly, you can significantly reduce the delay between writing code and running it in production.

简单翻译下就是:
Docker 是一个开源的平台,我们可以用 Docker 来开发、部署和运行我们的应用程序。Docker 可以帮助我们将应用程序和底层基础设施进行分离,以帮助我们更快的实现交付。通过 Docker 技术,我们可以像管理我们的应用一样管理我们的基础设施(比如基础依赖等,这里的具体技术其实
就是镜像)。通过 Docker 技术,我们可以精简我们的整个开发和交互流程。
这里面的几个核心点包括:

  • 平台(platform):官方将 Docker 定义为一个平台,但是其实更准确的来说,Docker 其实是一个技术栈,包括 Docker 镜像,可以类比为程序,是磁盘上面的静态文件,可以通过 Docker 来启动运行;Docker 容器,也就是 Docker 镜像的运行时实例;Docker Daemon,用来管理机器上的
    镜像、容器等。
  • 应用程序和底层基础设施分离:传统的软件开发模式是我们先开发好我们的应用,然后在线上环境或者测试环境上先安装应用的基础依赖,比如像一些 C++ 的二进制文件会依赖一些操作系统的动态链接库。
    依赖安装完成之后,然后将应用程序部署上去。使用 Docker 的镜像技术我们可以将这些依赖和应用程序都打包到镜像中,然后测试或者正式上线的时候只需要将整个镜像部署上去就可以了,不需要关心目标服务器上面的基础环境,这也就是应用程序和基础设施分离。也是精简开发流程的核心的所在。

熟悉 Docker 的同学肯定会意识到这里对 Docker 的定义其实少了很多东西,确实是这样的,比如Docker 的隔离性和资源限制在定义里面都没有体现出来。定义还是从一种更加宏观的角度来介绍Docker,也没错。

2、Docker v.s. 虚拟机

很多人学习 Docker 的过程中都会看到有人把 Docker 拿来和虚拟机做对比,也就是下面这张图。左边是 Docker 的架构,右边是虚拟机的架构图。我们可以看到 Docker 和虚拟机的主要区别有:

  • 所有的 Docker 应用共享一个宿主机操作系统,每个虚拟机有自己的操作系统;
  • 每个 Docker 应用通过 Docker 层和宿主机的操作系统交互,而虚拟机应用直接和操作系统交互。

image.png
但是上图左边的图中的 Docker 的位置其实很不严谨,实际上 Docker 并不会像 Hypervisor 那样对应用进程的隔离环境负责,也不会创建任何实体的容器,真正对环境负责的是宿主机操作系统本身。所以上图中 Docker 的问题应该是处于靠边的位置,因为通过 Docker 启动的容器本质上和操作系统中运行的进程并没有本质的区别。

3、Docker 的应用场景

应用交付

Docker 技术为应用交付领域带来的最大的变化就是开发环境的一致性。传统的开发方式需要开发者自己在本地进行开发,但是本地的开发环境和远端的测试和正式环境还是存在差异,所以每次开发完成都需要反复比对环境的差异,包括操作系统以及操作系统里面的依赖软件包是否齐全,非常的麻烦。
但是使用 Docker 镜像,我们可以将所有的环境依赖都打包到镜像中,然后通过镜像来传输,这样会更加地高效。
试想下面几种场景:

  • 开发者在本地编写代码进行开发,然后通过 Docker 镜像和其他协作者共享;
  • 使用 Docker 技术将应用 push 到测试环境,自动触发自动化 test case;
  • 当开发者发现应用程序的 bug 时,可以在本地开发环境进行修复。修复完之后再将应用重新部署到测试环境进行测试验证;
  • 当测试完成之后,需要给客户的环境升级,只要把修复完的应用镜像推送到客户可以访问的镜像中心即可。

    多版本混合部署

    随着产品的不断更新换代,一台服务器上部署同一个应用的多个版本在企业内部非常常见。但一台服务器上部署同一个软件的多个版本,文件路径、端口等资源往往会发生冲突,造成多个版本无法共存的问题。
    如果用 docker,这个问题将非常简单。由于每个容器都有自己独立的文件系统,所以根本不存在文件路径冲突的问题;对于端口冲突问题,只需要在启动容器时指定不同的端口映射即可解决问题。

    内部开发测试环境

    传统的开发测试环境都是由运维人员进行专门的环境配置而搭建出来的,而且需要运维人员进行专门维护。环境一旦出现问题,恢复起来也很麻烦。
    借助于 Docker 技术,我们将应用程序需要的依赖都固化到 Docker 镜像中,然后在对应的 Docker 容器中进行开发测试。就算环境出现问题,我们只要将当前容器删除重新启动即可恢复。
    使用 Docker 镜像来维护内部开发测试环境还有另一个好处就是 DevOps,传统的应用开发部署要跨两个团队:开发团队负责开发,运维团队服务部署,一旦涉及到跨团队合作就要牵扯到沟通成本。而且开发作为应用的 owner,实际上对其依赖环境会更加的熟悉才对。
    通过 Docker 镜像技术,开发人员在开发应用的过程中就将这些依赖固化到镜像中。在环境部署环节,即使需要运维人员参与,也只是负责拉起 Docker。整个过程都会更加的高效。
    通过 Docker 镜像技术,开发人员在开发应用的过程中就将这些依赖固化到镜像中。在环境部署环节,即使需要运维人员参与,也只是负责拉起 Docker。整个过程都会更加的高效。

    4、Docker 架构浅析

    很多人说 Docker 是简单的 Server-Client 的架构,其实并不一定准确。Docker 的架构比较复杂,并不是纯粹的只有 Server 和 Client。下图是 Docker 架构的一个详细的图。几个主要的组成部分有:

  • Docker Client;

  • Docker Daemon;
  • Docker Registry。

image.png

Docker Client

我们安装完 Docker 包之后,直接使用敲命令: docker ,界面是有提示的,这个 docker 就是 docker client。docker client 都是用来和 docker daemon 交互的。

Docker Daemon

docker daemon 是一个 docker 后台运行的守护进程,我们的 docker client 的命令就是和 Docker Daemon 来进行交互的。
Docker daemon 启动可以使用 service 或者 systemctl 操作.

systemctl start docker.service

然后我们使用 ps 命令就能看到 docker daemon 进程了。

$ ps aux | grep dockerd
root 10214 1.2 0.0 1014252 23768 ? Ssl 00:58 0:00
/usr/bin/dockerd-current --add-runtime docker-runc=/usr/libexec/docker/dockerrunc-current --default-runtime=docker-runc --exec-opt native.cgroupdriver=systemd
--userland-proxy-path=/usr/libexec/docker/docker-proxy-current --initpath=/usr/libexec/docker/docker-init-current --seccompprofile=/etc/docker/seccomp.json --selinux-enabled --log-driver=journald --
signature-verification=false --storage-driver overlay2

然后我们查看和 client 交互的 socket 文件也存在了。

$ll /var/run/docker.sock
srw-rw---- 1 root root 0 Dec 3 00:58 /var/run/docker.sock

Docker Registry

Registry 中文一般翻译为注册中心,是用来存储 Docker 镜像的地方。Docker Registry 有多种不同的表现,比如 Docker Hub 就是一个公开的注册中心,同时各大云厂商也提供了自己的注册中心,比如阿里云、腾讯云等,甚至你可以搭建自己的私有注册中心。
Docker 默认使用 Docker Hub,比如我们执行 docker pull 时,Docker 默认去 Docker Hub 中寻找名字为 image-name 的镜像。如果使用自己的 Registry 需要进行单独的配置。

Docker Images

Image 一般中文称之为镜像。官方对镜像的定义比较复杂,我一般使用类比的方式来理解镜像。镜像可以理解成计算机系统中的程序,也就是静态的位于磁盘上面可以通过特定方式执行的文件(程序是操作系统可以识别的特定的二进制文件,Docker 镜像是可以被 Docker Daemon 识别并执行的特定文件)。
镜像和普通的可执行文件的区别在于镜像是分层架构,每个镜像一般都依赖于一个基础镜像。最基本的镜像叫 scratch 镜像。当然我们也可以构建自己的镜像,然后发布到镜像中心别人就也可以使用了。
Docker 镜像的构建是通过一个 DSL 语言来编写的,叫 Dockerfile。后文我们会细说,这里就先不赘述了。

Docker Container

Container 也就是容器。Docker 官方对容器的定义非常的优雅。

A container is a runnable instance of an image.

翻译过来就是:
这个定义和进程的定义非常类似:进程是程序的运行实例。这样我们就可以将镜像类比为程序,容器类比为进程,这样就更好理解了。
我们可以使用 Docker 的 CLI 命令或者 API 来创建、启动、停止和删除容器等操作。同时对于运行状态的容器我们可以登录进去,类似 ssh 命令等操作。
容器默认是和其他容器以及其宿主机隔离开的。具体的隔离策略可以进行自定义设置。

三、Docker 镜像

1、镜像概述

Docker 技术正是凭借镜像这一个微小的创新一骑绝尘,所以说镜像是 Docker 技术的基石也不为过。

1.1、镜像是什么

为了保证文章的完备性,在开始之前还是要简单介绍一下 Docker 镜像是什么。
要理解 Docker 镜像,我们不妨先看另外一组概念:程序和进程。在《深入理解计算机系统》中对程序和进程的关系描述有一句话非常好:进程是程序的一个运行实例。程序是打包好的静态文件,而进程相当于把这些静态文件加载到计算机内存中运行起来。相应的,容器也可以说是镜像的一个运行实例。
不过这两组概念之间还有一个重大的区别就是:程序运行还依赖于一些操作系统的文件,但是镜像相当于把操作系统的文件也一起打包进了静态文件中。我们看一个简单的镜像,busybox,镜像界的 hello world。

docker pull busybox:latest

启动容器:

docker run -ti busybox:latest sh

image.png
通过 ls 可以看到镜像中确实包含了很多操作系统的文件,而且细心的同学会发现 busybox 镜像中包含的操作系统的文件只是一个精简版的,并不是全量的。值得注意的是,镜像中也只是包含了操作系统的必要的文件,在容器启动之后,容器进程还是去和宿主机的操作系统进行交互的。

1.2、基础镜像

虽然说镜像解决了容器所谓的一致性:无论在本地、云端,用户只需要解压打包好的容器镜像,那么这个容器的运行环境就被重现出来了。这里又出现了另外一个问题:如果我们每一个应用都自己打包我们的容器依赖的镜像,过程还是很繁琐的,那么这个过程能不能做到复用呢?
当然是可以的。首先官方镜像仓库中心提供了很多操作系统镜像,比如 ubuntu,centos 等。这样我们的应用就可以基于这些操作系统基础镜像来构建了。
其次,对于同一个公司内部,多个 Java 应用的开发人员对于环境的依赖都是一致的,比如 JDK,tomcat等等。我们可以每个人都基于 centos 基础镜像来构建我们的应用镜像,但是还有一种更好的方式是我们构建出一个 Java 应用基础镜像,然后大家复用这个基础镜像。
既然已经说到了基础镜像,这里顺便举几个例子。

alpine

尽管我在上面提到很多操作系统基础镜像,比如 Ubuntu 或者 CentOS,但是这些镜像实在是太大了,在实际使用的使用时候会导致镜像的传输效率不高。这里介绍一个精简版本的 Linux 系统镜像 : alpine。
下图是 alpine Linxu 官方网站 的截图。从图中我们可以看到 alpine Linux 的核心特点就是三个:small,simple,secure。也就是 alpine Linux 主打的特点:以安全为理念的轻量级的 Linux 发行版。很多情况下我们都可以使用 alpine Linux 来替代 Ubuntu 或者 CentOS,而且这样会使得我们最终的镜像的体积小很多。
image.png

busybox

很多 Docker 教程都使用 busybox 镜像来举例子,而且很多应用镜像都使用 busybox 镜像来作为基础镜像,那么 busybox 是什么呢?
简单来说 busybox 是一个集成了一百多个最常用的 Linux 命令和工具的软件工具箱,它在单一的可执行文件中提供了精简的 Unix 工具集。busybox 既包含了一些简单使用的工具,如 cat 和 echo,也包含了一些更大,更复杂的工具,如 grep,find,mount 以及 telnet 等。可以说 busybox 是 Linux 系统的瑞士军刀。另外 busyBox 可运行于多款 Posix 环境的操作系统中。

openjdk

Java 语言作为目前使用最广泛的编程语言,这里有必要介绍一下 Docker 的 Java 基础镜像:docker 官方提供的 openjdk。
image.png
我们要使用 openjdk 镜像和使用其他基础镜像没有区别。

FROM openjdk:7
COPY . /usr/src/myapp
WORKDIR /usr/src/myapp
RUN javac Main.java
CMD ["java", "Main"]

1.3、镜像构建

镜像构建是基于 Dockerfile 来构建的,具体来说我们只需要按照容器标准编写好 Dockerfile 文件,然后通过构建命令就可以构建出来我们需要的镜像了。

Web应用编写

下面是一个具体的例子。我们先通过 Go 语言编写一个 web 应用。

package main
import (
    "io"
    "log"
    "net/http"
) 
func main() {
    helloHandler := func(w http.ResponseWriter, req *http.Request) {
        io.WriteString(w, "Hello, world!\n")
    } 
    http.HandleFunc("/hello", helloHandler)
    log.Fatal(http.ListenAndServe(":8080", nil))
}

为了避免部分同学没有 Go 语言基础,这里简单解释一下这个程序的作用。这个是一个 web server,会在 8080 端口进行监听,对于路由 /hello 进行响应,返回 “Hello, world!”。我们可以在本地启动这个程序。
然后浏览器打开 localhost:8080/hello 或者直接 curl 访问。

-> ~ $ curl localhost:8080/hello
Hello, world!

下面我们就基于 centos 镜像来构建我们的应用镜像并启动。

应用程序 build

由于我的机器环境是 Mac OS,我本地编译的话需要使用交叉编译。如果读者对交叉编译不了解也没有关系,可以简单理解在某个平台编译另外一个平台的可执行应用程序。

-> $ GOOS=linux GOARCH=amd64 go build hello.go

编译成功之后就会生成一个叫 hello 的可执行文件。

Dockerfile 编写

我们将上面 build 出来的可执行文件放到镜像中,下面我们开始编写 Dockerfile 文件,如下:

FROM busybox:glibc
COPY hello /bin/hello
EXPOSE 8080
ENTRYPOINT ["/bin/hello"]

简单解释一下上面的文件内容:

  • FROM: 表示我们镜像基于 busybox 镜像构建,这里的 busybox 是基础镜像中被广泛使用的一个镜像
  • COPY:拷贝文件,其中 hello 就是我们上面 go build 生成的可执行文件
  • EXPOSE:暴露端口
  • ENTRYPOINT:用来指定我们的镜像的默认启动脚本

目前先了解一下,后续会详细解释。

镜像 build

编写完 Dockerfile 文件,我们就可以基于 Dockerfile 文件来构建我们的镜像了。将上面的文件命名为 Dockerfile,然后执行如下的 docker build 命令。

docker build -t hello:v1 .

执行完之后如果没有出错就会生成一个镜像 hello:v1,可以通过 docker images 命令查看。

启动镜像

启动镜像我们通过如下的 docker run 命令来启动

$ docker run -p 8080:8080 hello:v1

其中参数 -p 是用来将容器的端口和宿主机的端口做映射。
运行完之后我们打开浏览器,或者直接通过curl 命令请求 localhost:8080/hello 都会得到返回的 Hello World!
image.png
至此,我们通过一个简单例子介绍了一个完整链路的镜像构建的例子,当然我们这里的例子比较简单,由于我们使用的是 Go 语言示例,直接是二进制文件,对环境没有依赖,所以镜像的构建非常简单。但是在日常环境中我们可以会遇到非常复杂的环境的构建,比如 Java 应用程序可能需要我们自己去安装JDK 或者 tomcat 环境等。

2、镜像仓库介绍

前面简单提到过 Docker 镜像仓库,这里我们再来详细介绍一下 Docker 的镜像仓库中心,也就是Docker Registry。本文涉及到的 Registry 主要有三个,由于云厂商的 Registry 大同小异,所以下文中我们将主要介绍官方的 Docker Hub 和使用最多的阿里云的 Docker Registry。

  • 官方 Docker Registry,Docker Hub;
  • 阿里云 Docker Registry;
  • 腾讯云 Docker Registry。

    Docker Hub

    Docker Hub 是 Docker 官方提供的 Registry,官网页面如下:
    image.png
    如果我们想要下载 ubuntu 镜像,那么在搜索框输入 ubuntu 进行搜索就得到下面的结果
    image.png
    其中右侧的黑框中的 docker pull ubuntu 就是镜像的拉取方式。
    Docker Hub 使用起来非常的简单,但是我们一般也只是使用 Docker Hub 来搜索并下载镜像,并不会用来上传存储我们的自定义镜像,这其中的一个主要原因就是网络原因。所以关于 Docker Hub 的镜像上传我们这里就不介绍了。推荐使用云厂商的镜像仓库中心,比如阿里云。

    阿里云 Docker Registry

    阿里云的 Docker Registry 可以在容器镜像服务 ACR 中找到。容器镜像服务(简称 ACR,下面都简称为ACR)提供云原生资产的安全托管和全生命周期管理,支持多场景下镜像的高效分发,与容器服务 ACK无缝集成,打造云原生应用一站式解决方案。
    ACR 简化了 Registry 的搭建运维工作,支持多地域的镜像托管,并联合容器服务等云产品,打造云上使用 Docker 的一体化体验。下面是官方网站上面介绍的 ACR 的优势。

    ACR 优势

    多架构镜像托管支持

  • 支持 Linux、Windows、ARM 等多架构容器镜像。

灵活的地域选择

  • 用户可以根据自己的业务需求,选择不同的地域创建和删除镜像仓库。
  • 每个镜像仓库都提供了公网、内网、VPC 网络下对应的网络地址。

镜像安全扫描

  • 支持便捷的镜像安全扫描功能,展示详细的镜像层信息。
  • 提供镜像漏洞报告,展示漏洞编号、漏洞等级、修复版本等多维度漏洞信息。

稳定构建服务

  • 支持阿里云 Code、GitHub、Bitbucket、自建 GitLab 的源代码构建源。
  • 支持自动构建,实现源代码变更后自动构建成新 Docker 镜像。
  • 支持海外构建,实现源代码在海外构建成新 Docker 镜像。

云产品间无缝集成

  • 整合阿里云 Code 及 CodePipeline,实现源代码到应用编译测试后,自动构建成新镜像。
  • 整合容器服务,实现新镜像构建完成后便捷部署至容器服务集群。

由上面的介绍我们可以看出如果我们最终的容器要运行在阿里云上面,那么阿里云的 Docker Registry 绝对是我们的最佳选择。下面我们就来看一下如何使用。

基本介绍

image.png
我们首先看到右侧的一个 tab:
image.png
访问凭证:我们知道对于私有的 Docker Registry 有一个 docker login 命令需要输入用户名密码,而这个访问凭证就是用来设置 docker login 的密码相关的。可以设置固定密码和临时密码。固定密码相对来说更加方便,但是没有临时密码安全。大家可以根据实际情况使用。
image.png

基本设置

所以要真正使用这个 Docker Registry,我们需要先创建命名空间和镜像仓库。我们先创建一个命名空间叫 mooc-demo。
image.png
再创建一个镜像仓库叫 imooc-demo。
image.png
下一步选择本地仓库
image.png
创建完成之后我们可以看到镜像仓库的详细信息如下。我们可以看到镜像有多个地址:

  • 公网地址:很容易理解,就是暴露在公网中。
  • 专有网络:VPC 网络,VPC 可以简单理解一个特定的私有网络。
  • 经典网络:经典网络是在 VPC 网络出来之前的内网,现在已经很少用了。

内网的好处是不需要上传下载镜像不需要走公网流量,毕竟网络流量收费还挺贵的。
image.png

镜像上传下载

作为一个 Registry,它的最基本功能肯定是镜像的上传和下载,下面演示一下如何操作。
login
首先我们需要在本地先 login。

$ docker login --username=xxx registry.cn-hangzhou.aliyuncs.com
Password:
Login Succeeded

tag

要把本地的镜像上传到 Registry,需要将本地镜像重命名成远端镜像的形式,也就是上面截图中的第 3 步的操作。我们将本地的 busybox 镜像上传。

$ docker tag busybox registry.cn-hangzhou.aliyuncs.com/mooc-demo/imooc-demo:v1

push

$ docker push registry.cn-hangzhou.aliyuncs.com/mooc-demo/imooc-demo:v1
The push refers to repository [registry.cn-hangzhou.aliyuncs.com/mooc-demo/imoocdemo]
50761fe126b6: Pushed
v1: digest:
sha256:2131f09e4044327fd101ca1fd4043e6f3ad921ae7ee901e9142e6e36b354a907 size:
527

这就表示上传上去了,我们从页面上面访问看一下。点击左侧的镜像版本可以看到最近的 v1 版本就是我们刚才上传的。
image.png

3、热门 Docker 镜像介绍

前面我们介绍过可以通过一个基础镜像,比如 CentOS 镜像,来构建我们自己的应用的镜像。但是很多情况下,操作系统镜像都会比较大,比如官方的 Docker Hub 的 CentOS 镜像就有几百兆。使用这些镜像作基础镜像毫无疑问会导致我们最终的应用镜像会非常大。
但是更多时候,我们并不需要一个完整的操作系统镜像。换句话说,更多情况下我们只需要操作系统中部分文件,比如 /usr/bin 目录下的很多二进制文件我们可能都使用不到。针对这种情况,有没有裁剪版或者说精简版的操作系统镜像可以提供给我们使用呢?下面我们就来看看两个精简版的操作系统镜像:busybox 和 alpine。
很多时候我们构建应用镜像的使用都没有必要使用 ubuntu 或者 centos 镜像作为基础镜像,因为完整的操作系统镜像体积非常的大。当我们在分布式环境下涉及到镜像分发的话,如果镜像太大会严重影响分发的速度。

1、BusyBox

BusyBox 是一个精简的工具集合,集成了很多 Unix 应用工具,下面是 BusyBox 的官方定义。
BusyBox combines tiny versions of many common UNIX utilities into a single small executable. It provides replacements for most of the utilities you usually find in GNU fileutils, shellutils, etc. The utilities in BusyBox generally have fewer options than their full-featured GNU cousins; however, the options that are included provide the expected functionality and behave very much like their GNU counterparts. BusyBox provides a fairly complete environment for any small or embedded system.
BusyBox has been written with size-optimization and limited resources in mind. It is also extremely modular so you can easily include or exclude commands (or features) at compile time. This makes it easy to customize your embedded systems. To create a working system, just add some device nodes in /dev, a few configuration files in /etc, and a Linux kernel.
简单翻译一下:
BusyBox 将许多常用的 UNIX 应用工具精简版集成到一个小的可执行文件中。使用 BusyBox 中的应用通常情况下可用替换我们在 Linux 系统中使用的 GNU 应用工具,比如文件应用工具(比如cp, rm),shell 应用工具(比如 xargs)。BusyBox 中的工具比 GNU 完整版要少一些命令选项,通常是一些不太常用。BusyBox 提供的命令选项是和 GNU 完整命令一致的。同时 BusyBox提供了一个相对完整和轻巧的操作系统环境。
BusyBox 的设计实现考虑对自身大小的优化和资源的物尽其用。同时 BusyBox 也是模块化的,这也就意味者你可以通过编译选择去掉一些特性。这也意味可以更好的支持定制化系统。
相应地,在镜像领域中有一个镜像就叫 busybox,可以理解为是上面 busybox 对应的 docker 镜像,也被称为容器界的 helloworld。busybox 有很多版本,我们可以通过 docker search busybox 来搜索。
image.png
其中带有 OFFICIAL 标志的是官方镜像,我们通过 docker pull 命令下载

[root@docker ~]
Using default tag: latest
latest: Pulling from library/busybox
Digest: sha256:6915be4043561d64e0ab0f8f098dc2ac48e077fe23f488ac24b665166898115a
Status: Image is up to date for busybox:latest

然后我们通过 docker images 命令查看,可以看到镜像非常的小,只有 1.22MB。

[root@docker ~]
busybox latest 6d5fcfe5ff17 5 weeks ago 1.22MB

下面我们通过 docker run 命令启动 busybox 镜像。出现了 / # 提示符则说明现在我们位于 busybox 镜像启动的容器内部。我们可以通过 ls 命令查看包含了哪些文件。

/ b
in dev etc home proc root sys tmp usr var

细心的同学会发现这个相比完整的操作系统,少了很多目录,下面是一个完整的 centos 系统的根目录文件,相比 busybox 多了很多文件目录,也就是说 busybox 相当于是一个裁剪版的操作系统。

[root@docker ~]
bin boot dev etc home lib lib64 lost+found media mnt opt proc root
run sbin srv sys tmp usr var

我们再看一下 busybox 内部包含了操作系统命令,在 /bin 目录下。常用的操作系统命令都包含了,比如 df、du、awk、sed,所以 busybox 又被称为瑞士军刀。
不光如此我们还可以把 BusyBox 作为我们的基础镜像来构建我们的应用镜像,只需要像下面那样在首行通过 FROM 引用即可。

2、Alphine

Alpine 操作系统是一个面向安全的轻型 Linux 发行版。它不同于通常 Linux 发行版,Alpine 采用了 musl libc 和 busybox 以减小系统的体积和运行时资源消耗,但功能上比 busybox 又完善的多,因此得到开源社区越来越多的青睐。在保持瘦身的同时,Alpine 还提供了自己的包管理工具 apk,可以通过 https://pkgs.alpinelinux.org/packages 网站上查询包信息,也可以直接通过 apk 命令直接查询和安装各种软件。
Alpine 由非商业组织维护的,支持广泛场景的 Linux 发行版,它特别为资深 / 重度 Linux 用户而优化,关注安全,性能和资源效能。Alpine 镜像可以适用于更多常用场景,并且是一个优秀的可以适用于生产的基础系统 / 环境。
Alpine Docker 镜像也继承了 Alpine Linux 发行版的这些优势。相比于其他 Docker 镜像,它的容量非常小,仅仅只有 5 MB 左右(对比 Ubuntu 系列镜像接近 200 MB),且拥有非常友好的包管理机制。官方镜像来自 docker-alpine 项目。
目前 Docker 官方已开始推荐使用 Alpine 替代之前的 Ubuntu 做为基础镜像环境。这样会带来多个好处。包括镜像下载速度加快、镜像安全性提高、主机之间的切换更方便、占用更少磁盘空间等。
同样的我们可以通过 docker search 来搜索 alpine 镜像。
image.png
启动第一个带有 alpine 标志的为官方镜像,我们下面通过 docker pull 进行下载.

[root@docker ~]
Using default tag: latest
latest: Pulling from library/alpine
Digest: sha256:ab00606a42621fb68f2ed6ad3c88be54397f981a7b70a79db3d1172b11c4367d
Status: Image is up to date for alpine:latest
[root@docker ~]
alpine latest e7d92cdc71fe 2 weeks ago 5.59MB

我们可以看到镜像大小只有 5.59MB,可以说是非常的小。下面我们通过 docker run 启动。

[root@docker ~]
/ 
bin dev etc home lib media mnt opt proc root run sbin
srv sys tmp usr var

上一篇文章介绍了基础的热门 Docker 操作系统镜像,这篇文章我们来介绍一些应用镜像,也是我们可以直接拿来使用的。
很多时候我们要学习一门新的技术,比如 MySQL (这里举个例子,MySQL 当然不能算是新技术),如果不使用 Docker 的情况下,我们第一步是配置开发环境。但是很多软件的环境配置起来非常复杂,这一步就吓退了很多初学者。借助于 Docker 镜像,我们将不再受到这些困扰,因为镜像中包含了运行该软件需要的所有软件依赖,这样我们就可以将主要精力用来学习核心技术,而不是环境配置上。下面我们就来介绍几个热门的 Docker 镜像:Nginx、MySQL、Redis。其他镜像使用各位读者可以举一反三。

3、Nginx

Nginx 是一个高性能的 HTTP 和反向代理 web 服务器,支持 HTTP、HTTPS、SMTP、POP3、IMAP 等协议。我们可以通过 docker search 命令搜索官方镜像中心有哪些版本的 nginx,如下图。
image.png
其中第一个 OFFICIAL 标志显示 OK 的为官方镜像。同时我们也可以通过官方的 Docker Hub 网站搜索,结果如下图:
image.png
其中第一个即为官方 Nginx 镜像,点进去我们可以看到镜像描述、评价、tag 等。image.png
下面我们来简单演示一下镜像的使用,首先通过 docker pull 命令下载镜像。

[root@docker ~]
Using default tag: latest
latest: Pulling from library/nginx
bc51dd8edc1b: Pull complete
66ba67045f57: Pull complete
bf317aa10aa5: Pull complete
Digest: sha256:ad5552c786f128e389a0263104ae39f3d3c7895579d45ae716f528185b36bc6f
Status: Downloaded newer image for nginx:latest
[root@docker ~]
nginx latest 2073e0bcb60e 4 days ago 127MB

要使用 nginx 我们需要准备一个 index.html 也就是网站初始页,使用 nginx 镜像的时候,我们可以在启动的时候通过 volume 的方式将 index.html 映射进去:
其中 -p 是将宿主机的 8080 端口映射到容器,-v 是数据卷的意思,我们后面会详述,将宿主机的/root/nginx 目录映射到容器中的 /usr/share/nginx/html 目录。细心一点的同学会发现不管是端口映射还是数据卷映射,都是宿主机在前,容器在后。在宿主机的 /root/nginx 目录存放在 index.html,也就是网站的初始页,内容很简单,如下:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Docke技术原理与实践(imooc.com)</title>
  </head>
  <body>
    <h1>站在巨人的肩膀上:热门 Docker 镜像介绍(二)</h1>
    <p>Nginx 首页</p>
  </body>
</html>

然后我们使用宿主机的浏览器打开 0.0.0.0:8080 端口就能看到 index.html 的内容显示在浏览器上,如下图。
image.png

4、MySQL

MySQL 是一个关系型数据库管理系统,由瑞典 MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL 是最好的 RDBMS (Relational Database Management System,关系数据库管理系统) 应用软件之一。
关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。MySQL 所使用的 SQL 语言是用于访问数据库的最常用标准化语言。MySQL 软件采用了双授权政策,分为社区版和商业版,由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,一般中小型网站的开发都选择 MySQL 作为网站数据库。
下面我们像介绍 Nginx 镜像一样,直接通过 docker search 搜索 mysql 相关的镜像,结果如下图。
image.png
我们可以看到最上面两个 MySQL 和 MariaDB 就是官方提供的镜像。MariaDB 源于 MySQL 的一个分支,主要由开源社区进行维护,采用 GPL 授权许可。MariaDB 完全兼容 MySQL,包括 API 和命令行,我们完全可以将 MariaDB 作为 MySQL 的替代品使用,实际上确实有很多公司是这么使用的。所以这里我们通过 docker search mysql 的时候,MariaDB 的结果也出来了。 我们下面演示一下 MySQL 的镜像使用。首先通过 docker pull 下载镜像。

[root@docker ~]
...
[root@docker1 ~]
mysql latest 791b6e40940c 4 days ago
465MB

需要注意的是,我们这里没有加 tag,下载的是 latest 版本,也就是 8.x 版本。如果要使用 5.7 版本,可以指定 mysql:5.7。下面启动 MySQL 容器。

[root@emr-header-1 ~]
6cb8b944810bd318cab711b8cb15596f4b5514470dcfa06401131335043b66ae
[root@emr-header-1 ~]
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6cb8b944810b mysql:latest "docker-entrypoint.s…" 5 seconds ago Up 4 seconds 33060/tcp, 0.0.0.0:3307->3306/tcp wonderful_neumann

其中通过环境变量 MYSQL_ROOT_PASSWORD 指定了 root 用户的密码。由于我们这里直接使用了 latest 版本的,如果我们直接通过 MySQL Client 连接的话会报如下的错。原因是 mysql8 之前的版本中加密规则是 mysql_native_password, 而在 mysql8 之后, 加密规则是 caching_sha2_password。

[root@docker1 ~]
Enter password:
ERROR 2059 (HY000): Authentication plugin 'caching_sha2_password' cannot be loaded: /usr/lib64/mysql/plugin/caching_sha2_password.so: cannot open shared object file: No such file or directory

对于上面出现的问题我们可以通过迂回的方式进行解决,首先通过 docker exec 登录到 MySQL 容器中解决。

[root@docker1 ~]
root@945fb3c4fc2f:/
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 11
Server version: 8.0.19 MySQL Community Server - GPL
Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
Query OK, 0 rows affected (0.01 sec)

这时候我们再通过 MySQL 客户端进行登录就可以了。

[root@docker1 ~]
Enter password:
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MySQL connection id is 16
Server version: 8.0.19 MySQL Community Server - GPL
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MySQL [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
4 rows in set (0.01 sec)

5、Redis

Redis 是使用 C 语言编写的高性能 key-value 数据库系统,遵守开源 BSD 协议。在日常开发中,Redis经常被用来当做缓存使用,后端在加一层持久化存储,比如 MySQL 等。我们也可以通过 docker search来搜索一下 docker hub 中包含的 Redis 镜像,下图是搜索结果。
image.png
我们先通过 docker pull 命令下载上图中第一个,也就是官方的 Redis 镜像。

[root@docker ~]
Using default tag: latest
latest: Pulling from library/redis
bc51dd8edc1b: Already exists
37d80eb324ee: Pull complete
392b7748dfaf: Pull complete
48df82c3534d: Pull complete
2ec2bb0b4b0e: Pull complete
1302bce0b2cb: Pull complete
Digest: sha256:7b84b346c01e5a8d204a5bb30d4521bcc3a8535bbf90c660b8595fad248eae82
Status: Downloaded newer image for redis:latest
[root@docker ~]
redis latest 44d36d2c2374 4 days ago 98.2MB

通过 docker run 启动容器,我们这里使用默认配置。如果需要指定配置,可以先将配置文件通过数据卷的方式映射到容器内部,然后将配置文件作为启动参数加进去。

docker run --name redis-test -p 6379:6379 -d redis:latest

Part III

四、Docker 操作参数详解

1、容器操作

Docker 和容器相关的常用的操作命令如下:

run

docker run 用来通过镜像启动一个容器。这个可以算是操作 docker 容器的核心命令了,参数及其丰富,多达 91 个参数,使用手册如下:

[root@emr-header-1 ~]
Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
Run a command in a new container

比如我们启动一个 centos 的镜像

[root@xxx ~]
[root@b16716790a3f /]

其中 centos:latest 就是 Usage 中的 IMAGE,COMMAND 就是 /bin/bash,然后 -ti 分配一个终端用于交互式输入。
我们下面主要介绍几个重要的参数。

--interactive 等同于 -i ,接受 stdin 的输入;
--tty 等同于 -t,分配一个 tty,一般和 i 一起使用;
--name 给容器设置一个名字;
--add-host 给容器设置 hosts 文件,格式 host:ip;
--env 环境变量设置;
--expose 暴露端口;
--hostname 设置容器的主机名;
--link 容器网络相关,和其他的 container 连接;
--cpu-quota 设置 CPU 限制;
--memory 设置容器可以使用的内存限制。

attach

docker attach 让我们可以进入到一个运行着的容器的内部,这个命令的原理是给一个正在运行的容器分
配一个 stdin、stdout 和 stderr。

[root@xxx ~]
Usage: docker attach [OPTIONS] CONTAINER
Attach local standard input, output, and error streams to a running container
Options:
  --detach-keys string Override the key sequence for detaching a container
  --no-stdin Do not attach STDIN
  --sig-proxy Proxy all received signals to the process (default true)

需要注意的是,如果 docker attach 之后要退出的话,不能使用 exit,使用 exit 原容器也会退出。我们可以使用 Ctrl + C 的方式退出。

exec

docker exec 命令也可以达到 attach 的目的。exec 命令的用处是在一个运行着的容器里面执行一个命令。关于这个命令的原理其实很简单,在 Linux 内核层面,相当于 fork 了一个进程,然后这个进程设置和容器相同的 NameSpace。如果我们 OPTIONS 指定 -ti ,那么我们就可以进入到一个运行着的容器里面执行命令了。因为这个是一个 fork 出来的进程,所以可以 exit。

[root@emr-header-1 ~]
Usage: docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
Run a command in a running container
Options:
  -d, --detach Detached mode: run command in the background
      --detach-keys string Override the key sequence for detaching a container
  -e, --env list Set environment variables
  -i, --interactive Keep STDIN open even if not attached
      --privileged Give extended privileges to the command
  -t, --tty Allocate a pseudo-TTY
  -u, --user string Username or UID (format: <name|uid>[:<group|gid>])
  -w, --workdir string Working directory inside the container

ps

docker ps 可以用来列出所有在运行的容器的信息,同时支持一些类似 filter 的参数。

[root@xxx ~]
Usage: docker ps [OPTIONS]
List containers
Options:
  -a, --all Show all containers (default shows just running)
  -f, --filter filter Filter output based on conditions provided
      --format string Pretty-print containers using a Go template
  -n, --last int Show n last created containers (includes all states) (default -1)
  -l, --latest Show the latest created container (includes all states)
      --no-trunc Don't truncate output
  -q, --quiet Only display numeric IDs
  -s, --size Display total file sizes

kill

docker kill 用来 kill 一个或者一组 container。

[root@xxx ~]
Usage: docker kill [OPTIONS] CONTAINER [CONTAINER...]
Kill one or more running containers
Options:
  -s, --signal string Signal to send to the container (default "KILL")

logs

docker logs 用来获取 docker 的 log。

[root@xxx ~]
Usage: docker logs [OPTIONS] CONTAINER
Fetch the logs of a container
  Options:
      --details Show extra details provided to logs
  -f, --follow Follow log output
      --since string Show logs since timestamp (e.g. 2013-01-02T13:23:37) or relative (e.g. 42m for 42 minutes)
      --tail string Number of lines to show from the end of the logs (default "all")
  -t, --timestamps Show timestamps
      --until string Show logs before a timestamp (e.g. 2013-01-02T13:23:37) or relative (e.g. 42m for 42 minutes)

top

docker top 这个命令有时候比较有用,我们想看一下运行这个容器在宿主机上面是那个进程就可以使用这个命令,毕竟 container 的本质就是一个进程,这个我们后面会细说。

[root@xxx ~]
Usage: docker top CONTAINER [ps OPTIONS]
Display the running processes of a container

2、镜像操作

和镜像相关的常用的操作命令如下:

  • images:列出本地所有的镜像;
  • build:通过 Dockerfile build 出镜像;
  • commit:将容器中的所有改动生成新的镜像;
  • history:查看镜像的历史;
  • save:将镜像保存成 tar 包;
  • import:通过 tar 包导入新的镜像;
  • load:通过 tar 包或者标志输入导入镜像;
  • rmi:删除本地镜像;
  • tag:给镜像打 tag。

    images

    docker images 会显示本地所有的非隐藏镜像,默认会将中间依赖镜像进行隐藏。

    [root@xxx ~]
    REPOSITORY TAG IMAGE ID CREATED SIZE
    busybox 1-musl ff04c2bddacb 3 days ago 1.44MB
    busybox 1-glibc ad06ec8ab37b 3 days ago 5.2MB
    busybox 1-uclibc b534869c81f0 3 days ago 1.22MB
    busybox latest b534869c81f0 3 days ago 1.22MB
    busybox 1.24-glibc 54df49495ae4 3 years ago 4.18MB
    busybox 1-ubuntu d34ea343a882 3 years ago 4.35MB
    busybox 1.21-ubuntu d34ea343a882 3 years ago 4.35MB
    busybox 1.21.0-ubuntu d34ea343a882 3 years ago 4.35MB
    busybox 1.23 a84c36ecc374 4 years ago 1.1MB
    busybox 1.23.2 a84c36ecc374 4 years ago 1.1MB
    

    这是 docker images 的默认显示,但是有时候我们需要显示更多的信息比如 Digest,或者过滤掉一些镜像,那么我们可以通过添加参数来实现。我们看一下 docker images 的完整的功能。

    [root@xxx ~]
    Usage: docker images [OPTIONS] [REPOSITORY[:TAG]]
    List images
    Options:
    -a, --all Show all images (default hides intermediate images)
        --digests Show digests
    -f, --filter filter Filter output based on conditions provided
        --format string Pretty-print images using a Go template
        --no-trunc Don't truncate output
    -q, --quiet Only show numeric IDs
    
  • all 参数显示所有镜像,包括中间依赖镜像;

  • digest 显示 digest;
  • filter 对镜像进行过滤;
  • no-trunc 默认会对某些输出列进行截断展示,该参数将全量展示。
  • quiet 只展示镜像的数字 ID。
  • format 参数使用一种 Go 模板的形式输出,简单来说就是指定输出的列。这么描述不太直观,我们可以看一个简单的例子如下,其中的 ID 和 Repository 就是指定的输出的列。
    [root@xxx ~]
    ff04c2bddacb: busybox
    ad06ec8ab37b: busybox
    b534869c81f0: busybox
    b534869c81f0: busybox
    
    除了 ID 和 Repository,Docker 支持的全部的列如下:
Placeholder Description
.ID 镜像 ID
.Repository 镜像 repo,其实就是镜像名称
.Tag 镜像 tag
.Digest 镜像 digest
.CreatedSince 镜像创建之后多长时间
.CreatedAt 镜像的创建时间
.Size 镜像的磁盘大小

build

在 Docker 中我们可以通过一个 Dockerfile,使用 docker build 构建出镜像。这一块我们后面将会有专门的小节来展开,这里暂时先略过。

commit

上面说到我们可以通过一个 Dockerfile 构建出镜像,但是有时候我们在使用过程中对容器(container)做了一些改动,比如安装了一些依赖包。我们想把这些改动保存下来形成新的镜像,同时不想再去编写 Dockerfile,或者之前的 Dockerfile 我们没有。那么这时候我们就可以通过 docker commit 将一个 container 的环境持久成镜像。我们首先看一下 docker commit 的使用规范说明。

[root@xxx ~]
Usage: docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
Create a new image from a container's changes
Options:
  -a, --author string Author (e.g., "John Hannibal Smith <hannibal@ateam.com>")
  -c, --change list Apply Dockerfile instruction to the created image
  -m, --message string Commit message
  -p, --pause Pause container during commit (default true)

如果要对现在的一个 container 进行 commit 操作,我们首先可以通过 docker ps 找到我们要执行commit 操作的 container 的 id。

[root@xxx ~]
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d7bb841d9811 legendtkl:v2.1 "/bin/bash" About a minute ago Up About a minute 22/tcp vigorous_chaplygin

然后执行 commit 。
然后再执行 docker images 就可以看到我们新 commit 出来的镜像了。

history

使用 docker history 可以查看镜像的历史,举个例子。后面的命令我们在 Dockerfile 那一节在详细说。

[root@emr-header-1 ~]
IMAGE CREATED CREATED BY SIZE COMMENT
a84c36ecc374 4 years ago /bin/sh -c
<missing> 4 years ago /bin/sh -c
[root@emr-header-1 ~]
IMAGE CREATED CREATED BY SIZE COMMENT
243b193cdf70 3 hours ago 0B
e104690ec93c 2 weeks ago /bin/sh -c
<missing> 2 weeks ago /bin/sh -c
<missing> 2 weeks ago /bin/sh -c
<missing> 2 weeks ago /bin/sh -c
<missing> 2 weeks ago /bin/sh -c
<missing> 5 weeks ago /bin/sh -c mkdir -p /app 0B
<missing> 4 years ago /bin/sh -c
<missing> 4 years ago /bin/sh -c
<missing> 4 years ago /bin/sh -c sh /tmp/install/run.sh 260MB
<missing> 4 years ago /bin/sh -c
<missing> 4 years ago 2.31GB Imported from http://10.137.67.190/download/os/AliOS5U7-x86-64.tgz

save

有这么一种场景,有时候我们要将一台机器的本地镜像导入到另外一台机器,当然你可以将镜像先 push到镜像仓库中心,然后另外一个机器再进行 pull。但是有的时候由于镜像的安全性或者镜像比较大,不是很适合这种先 push 再 pull 的场景,那么我们就可以将镜像先导出成压缩文件,然后再将压缩文件导入到另外一个机器。其中镜像导出成压缩文件,就是 docker save 做的事情。

[root@xxx ~]
Usage: docker save [OPTIONS] IMAGE [IMAGE...]
Save one or more images to a tar archive (streamed to STDOUT by default)
Options:
  -o, --output string Write to a file, instead of STDOUT

默认是输出到 stdout,当然也可以通过 -o 参数指定输出的文件。那么我们可以通过如下两个方式进行导出。

docker save busybox:latest > busybox-latest.tar

或者

docker save busybox:latest -o busybox-latest.tar

import

docker import 以及下面的 load 都是用来从压缩中导入镜像。使用方式也比较简单。

[root@emr-header-1 ~]
Usage: docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]]
Import the contents from a tarball to create a filesystem image
Options:
  -c, --change list Apply Dockerfile instruction to the created image
  -m, --message string Set commit message for imported image

比如我们导入上面导出的镜像 tar 包,可以使用下面的命令。

[root@emr-header-1 ~]
sha256:1278080eee0524c6ca5c1de63ea439deb0e6d62035549cca9dbd4d9129e38655

load

通过 tar 包导入镜像,使用方式。

[root@xxx ~]
Usage: docker load [OPTIONS]
Load an image from a tar archive or STDIN
Options:
  -i, --input string Read from tar archive file, instead of STDIN
  -q, --quiet Suppress the load output

比如我要将上面导出的镜像压缩包导入,可以通过下面的命令完成。

$ [root@xxx ~]
Loaded image: busybox:latest

rmi

docker rmi 可以用来删除镜像。使用方式如下:

[root@xxx ~]
Usage: docker rmi [OPTIONS] IMAGE [IMAGE...]
Remove one or more images
Options:
-f, --force Force removal of the image
    --no-prune Do not delete untagged parents

其中 IMAGE 我们可以直接使用镜像名称 + tag 或者镜像 ID 的方式来知道,上面的说明文档我们看到还支持两个参数:

  • force:强制删除;
  • no-prune:不要删除未带标签的父镜像。

    tag

    docker tag 可以用来给镜像打 tag,目标镜像可以使用镜像名称 + tag 或者镜像 ID 的方式,如下:

    docker tag busybox:v1 busybox:v2
    

    或者

    docker tag <image_id> busybox:v2
    

    3、镜像仓库操作

    和镜像仓库(registry)相关的操作重要有 4 个操作命令:

  • login: 登录镜像仓库;

  • logout: 登出镜像仓库;
  • pull: 从镜像仓库拉取镜像 ;
  • push: 向镜像仓库 push 镜像,需要先 login。

    login

    login 的使用比较简单,我们可以直接通过 help 看一下使用说明,如下:
    root@xxx
    Usage: docker login [OPTIONS] [SERVER]
    Log in to a Docker registry
    Options:
    -p, --password string Password
        --password-stdin Take the password from stdin
    -u, --username string Username
    
    如上所示 docker login [OPTION] [SERVER] ,其中 SERVER 就是仓库地址,OPTION 是用户名密码,比如我要登入阿里云杭州的镜像仓库,可以像如下操作:
    $ docker login -u legendtkl -p <password> registry.cn-hangzhou.aliyuncs.com
    
    但是一般我们不太建议将密码直接展示在命令行中,这样别的用户可以通过 history 直接看到,所以我们一般都是省略 -p 参数,由键盘输入密码,如下:
    $ docker login -u legendtkl registry.cn-hangzhou.aliyuncs.com
    Password:
    

    logout

    logout 就比较简单了,不需要任何参数,直接接仓库地址即可,如下。
    root@xxx
    Usage: docker logout [SERVER]
    Log out from a Docker registry
    

    pull

    拉取镜像也比较简单,如下
    root@xxx
    Usage: docker pull [OPTIONS] NAME[:TAG|@DIGEST]
    Pull an image or a repository from a registry
    Options:
    -a, --all-tags Download all tagged images in the repository
        --disable-content-trust Skip image verification (default true)
    
    我们可以通过镜像名称后面加 Tag 或者 Digest 来拉取指定版本的镜像,如果不指定则拉取 latest 这个标签的。那么什么是 Tag 和 Digest 呢?
    我们可以这样理解,Tag 和 Digest 都是镜像版本的一种唯一性标识。Tag 可以理解成 Git 里面的 Tag,Digest 是镜像文件的摘要,一般是 sha256 散列计算出来的值。当然我们正常 pull 的时候都是指定Tag,很少会指定 Digest,举个例子:
    docker pull busybox:1.23
    docker pull busybox@sha256:2824fe048727a69da66cf1be00cebd3bb9cfe1f238473693aa9358b411208527
    
    有一种情况需要注意的是,尽量不要使用 latest 这个 Tag。顾名思义,latest 这个标签表示最新的镜像,换言之,也就是会进行变化的,这种情况是万万不能用于生产环境的。
    我们看到拉取的镜像的时候还有两个参数: all-tags 和 disable-content-trust。第一个参数会下载镜像的全部标签,一般不会这么用。第二个参数是用来跳过镜像的校验。

    push

    向仓库 push 镜像,参数和 pull 类似。有一点需要注意的是,如果 push 的镜像在仓库中已经存在,则会覆盖已经存在的镜像。
    root@xxx
    Usage: docker push [OPTIONS] NAME[:TAG]
    Push an image or a repository to a registry
    Options:
      --disable-content-trust Skip image signing (default true)
    

    五、Docker实践

    从 0 到 1 构建自己的 Docker 应用