Docker的镜像与容器
- 获取镜像
- 构建python镜像
- Dockerfile制作镜像
- FROM 指定基础镜像
- RUN 执行命令
- Docker容器
获取镜像
镜像和容器的相关内容在后续的文章中会讲述。
电脑环境采用的是Ubuntu20.04,配置最新的Docker版本。
从Docker镜像仓库获取镜像的命令是docker pull
。其命令格式为:
$ docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]
具体的选项可以通过 docker pull --help 命令看到,这里我们说一下镜像名称的格式。
- Docker 镜像仓库地址:地址的格式一般是 <域名/IP>[:端口号]。默认地址是 Docker Hub(docker.io)。
- 仓库名:如之前所说,这里的仓库名是两段式名称,即 <用户名>/<软件名>。对于 Docker Hub,如果不给出用户名,则默认为
library,也就是官方镜像。
举例:获取一个python镜像
使用Docker,可以从Docker的官方registry或者其他仓库,获取一个可以移植的python运行环境镜像,无需安装。然后,你可以基于这个镜像开发应用程序,这样可以确保应用程序、依赖和运行时都一起运行。
构建python镜像
- 搜索python镜像
docker search python
- 拉取python镜像(tensorflow的docker环境)
docker pull python:3.8.3-buster
# 运行并进入镜像
docker run -it --name=py-3.8.3 python:3.8.3-buster bash
# 查看镜像
docker images
# 列出镜像
docker images ls
- 上面的命令中没有给出 Docker 镜像仓库地址,因此将会从 Docker Hub (docker.io)获取镜像。而镜像名称是 python3.8.3,因此将会获取官方镜像 library/python 仓库中标签为 3.8.3 的镜像。docker pull 命令的输出结果最后一行给出了镜像的完整名称,即: docker.io/library/python3.8.3。
从下载过程中可以看到我们之前提及的分层存储的概念,镜像是由多层存储所构成。下载也是一层层的去下载,并非单一文件。下载过程中给出了每一层的 ID 的前 12 位。并且下载结束后,给出该镜像完整的 sha256 的摘要,以确保下载一致性。
在使用上面命令的时候,你可能会发现,你所看到的层 ID 以及 sha256 的摘要和这里的不一样。这是因为官方镜像是一直在维护的,有任何新的 bug,或者版本更新,都会进行修复再以原来的标签发布,这样可以确保任何使用这个标签的用户可以获得更安全、更稳定的镜像。
- 保存镜像
#退处容器,保存容器为镜像
docker commit py-3.8.3 python:3.8.3
- 删除本地镜像
$ docker image rm [选项] <镜像1> [<镜像2> ...]
用 ID、镜像名、摘要删除镜像<镜像>
可以是 镜像短 ID
、镜像长 ID
、镜像名
或者 镜像摘要
。
Dockerfile制作镜像
Dockerfile 是一个文本文件,其内包含了一条条的 指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。
还以之前定制 nginx 镜像为例,这次我们使用 Dockerfile 来定制。
在一个空白目录中,建立一个文本文件,并命名为 Dockerfile
:
$ mkdir mynginx
$ cd mynginx
$ touch Dockerfile
其内容为:
FROM nginx
RUN echo<h1>Hello, Docker!</h1>
> /usr/share/nginx/html/index.html
这个 Dockerfile 很简单,一共就两行。涉及到了两条指令,FROM 和 RUN。
FROM 指定基础镜像
所谓定制镜像,那一定是以一个镜像为基础,在其上进行定制。就像我们之前运行了一个 nginx
镜像的容器,再进行修改一样,基础镜像是必须指定的。而 FROM
就是指定 基础镜像,因此一个 Dockerfile
中 FROM 是必备的指令,并且必须是第一条指令。
Docker 还存在一个特殊的镜像,名为 scratch。这个镜像是虚拟的概念,并不实际存在,它表示一个空白的镜像。
FROM scratch
…
如果你以 scratch 为基础镜像的话,意味着你不以任何镜像为基础,接下来所写的指令将作为镜像第一层开始存在。
不以任何系统为基础,直接将可执行文件复制进镜像的做法并不罕见,对于 Linux 下静态编译的程序来说,并不需要有操作系统提供运行时支持,所需的一切库都已经在可执行文件里了,因此直接 FROM scratch 会让镜像体积更加小巧。使用 Go 语言 开发的应用很多会使用这种方式来制作镜像,这也是为什么有人认为 Go 是特别适合容器微服务架构的语言的原因之一。
RUN 执行命令
RUN
指令是用来执行命令行命令的。由于命令行的强大能力,RUN 指令在定制镜像时是最常用的指令之一。其格式有两种:
- shell 格式:RUN <命令>,就像直接在命令行中输入的命令一样。刚才写的 Dockerfile 中的 RUN 指令就是这种格式。
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
- exec 格式:RUN [“可执行文件”, “参数1”, “参数2”],这更像是函数调用中的格式。
镜像是多层存储,每一层的东西并不会在下一层被删除,会一直跟随着镜像。因此镜像构建时,一定要确保每一层只添加真正需要添加的东西,任何无关的东西都应该清理掉。每一层构建的最后一定要清理掉无关文件。
Docker容器
容器是 Docker 又一核心概念。简单的说,容器是独立运行的一个或一组应用,以及它们的运行态环境。
本节将具体介绍如何来管理一个容器,包括创建、启动和停止等。
启动容器有两种方式,一种是基于镜像新建一个容器并启动,另外一个是将在终止状态(exited)的容器重新启动。
因为 Docker 的容器实在太轻量级了,很多时候用户都是随时删除和新创建容器。
$ docker run ubuntu:18.04 /bin/echo 'Hello world'