Docker 启蒙教程(2)
这部分提到了数据持久化、网络访问容器、Dockerfile 和 Docker Compose。
第六章 数据持久化
在前面的教程里,你学会了操作容器。然而,容器销毁后,数据也将消失。
为了保存容器运行时产生的数据,我们需要使用数据卷(Volume)。
创建数据卷
可以使用以下命令创建一个名为 MyVolume
的数据卷
1 | docker volume create MyVolume |
查看数据卷信息
如果想要查看 MyVolume
数据卷的信息,则使用
1 | docker volume inspect MyVolume |
docker volume inspect
是一个有用的命令,可以帮助我们迅速找到数据存储的路径。我们创建的 MyVolume
数据卷在主机上的实际存储路径是 /var/lib/docker/volumes/MyVolume/_data
,到这里就可以找到你的数据了。
列出数据卷
然而,要查看数据卷信息,首先要知道数据卷的名字。It is easy for you. 你只需要使用 docker volume ls
命令就可以列出所有数据卷,让它们乖乖立正站好。
1 | docker volume ls |
数据卷的特点
数据卷是特殊的。即使删除了依赖他的容器,数据卷也会保留在你的主机上;数据卷的数据是实时更新的;数据卷可以在容器之间重用,往返自然,可以让这个容器用,也可以让那个容器用。
数据卷具体使用
创建完数据卷,我们就需要在创建容器时使用 --mount
参数把它挂载到容器上。
下面的命令创建了名为 MyContainer
的容器,并挂载 MyVolume
数据卷到容器内部的 /home/yourdata
目录。该目录里的文件都会保存到这个数据卷里。
1 | docker run -d --name MyContainer --mount source=MyVolume,target=/home/yourdata mysql:latest |
第七章 网络访问容器
指定端口映射
容器内部与主机的端口是隔离的。我们可以通过 -p
参数进行端口映射。
下面的命令将容器内部的 3306 端口映射到主机的 12345 端口。
1 | docker run -p 12345:3306 mysql:latest |
冒号左边是主机的端口,冒号右边是容器内部端口。
除此之外,还有两种映射格式,在这里就不多讲了。
拿不定主意?
如果你拿不定主意,也可以使用 -P
参数,让 Docker 随机映射一个端口到内部容器开放的网络端口。
1 | docker run -P -d mysql:latest |
查看端口映射配置
你有可能会忘记你设置的端口映射,不过不用怕,你可以使用 docker port
命令查看端口映射的配置。
下面的命令查询 MyContainer
容器的 3306 端口映射情况。3306 是容器内部的端口。
1 | docker port MyContainer 3306 |
第八章 Dockerfile
Docker 通过读取 Dockerfile 中的指令来自动构建镜像,Dockerfile 是一个文本文件。Docker 会按照顺序执行此文件里的命令来构建镜像。
质疑 Dockerfile
如果你曾经浅浅了解过 Docker,你可能会在某个文件夹里看到 Dockerfile 文件。它没有任何后缀名,使用文本编辑器打开发现里面的指令 短小、全大写,有汇编内味了,对于一个习惯了 Windows 系统的人来说很难受。
人的天性就是这样,不喜欢未知的东西。
理解 Dockerfile
部分内容摘自阿里云开发者社区。
要理解 Dockerfile,我们首先要了解之前提过的「镜像分层」的概念。
Docker 的镜像是分层的,每执行一条 Dockerfile 指令,就会创建一个新的层。这些层是堆叠在一起的,每一层都是与前一层的变化的增量,堆叠到最后变成了你需要的镜像。
不分层就会导致拉取的镜像体积很大,让我们举个例子。
在不分层的情况下:假如我们拉取 6.2 版本的 Redis,文件大小是 100 MB ,下次要下载 6.3 版本,就要再次下载 100 MB 的文件,尽管两个版本之间只有几行配置文件的差异。这样做效率非常低,如果能只下载有差异的部分就好了。
这个痛点是镜像分层要解决的问题。如果版本 2 基于版本 1,那么拉取版本 2 只需要一份和版本 1 有差异的增量数据。是不是感觉在哪里见过?没错!你的手机系统更新的时候也是这样做的。
这样做的好处是:
- 拉取更快:分层了,只需要拉取本地不存在的层
- 存储更少:相同的层仅需存储一份
- 运行时存储更少:容器运行时可以共享相同的层
让我们看一段具体的例子:
1 | FROM ubuntu:22.04 |
就像上面我们讲的一样,在这个例子中,每执行一条命令,就会创建一个新的层。
FROM
从ubuntu:22.04
镜像中创建一个层COPY
从 Docker 客户端当前目录添加文件RUN
使用make
命令构建你的应用CMD
制定要在容器内运行的命令
当你运行镜像,生成容器时,你将在底层之上添加一个新的可写层,也称为「容器层」。对正在运行的容器做的所有更改,例如写入新文件、修改现有文件和删除文件,都会写入容器层。
当容器被销毁时,可写层也将随之销毁。如果你做了数据持久化,可写层的修改将被实时同步到数据卷中。
编写 Dockerfile
Dockerfile 有许多指令,作为启蒙教程,我们在这里仅介绍四个常用的命令,FROM
、COPY
、RUN
、CMD
。
FROM
FROM
指令初始化一个新的构建阶段,并为后续执行的命令设置基础镜像。前面我们讲过,在 Dockerfile 中,每执行一条命令,就会创建一个新的层。使用此命令意味着你创建了镜像中的第一个层,后续指令均以这层为基础。
这个指令有三种格式。
1 | FROM [--platform=<platform>] <image> [AS <name>] |
1 | FROM [--platform=<platform>] <image>[:<tag>] [AS <name>] |
1 | FROM [--platform=<platform>] <image>[@<digest>] [AS <name>] |
FROM
可以在单个 Dockerfile 内出现多次,以创建多个镜像或使用一个构建阶段作为另一构建阶段的依赖项。
image
填镜像名,去掉尖括号;tag
是标签,用来指定版本。用 []
括起来的均为可选项。
作为一个新手,其他参数大概率用不到,这里就不讲了。
1 | FROM ubuntu:latest |
通常情况下,我们只需要用到这个例子这样的指令。
COPY
1 | COPY <src> <dest> |
COPY
指令从主机的 <src>
处复制新文件或目录,并把他们粘贴到容器内的 <dest>
路径。
1 | COPY hom* /mydir/ |
这个命令展示了将主机当前目录所有以 hom
开头的文件粘贴到容器内 /mydir
目录中。
RUN
RUN
指令将执行你指定的命令,并在上一层的基础上创建新层,创建的新层将在 Dockerfile 的下一步中使用。一般用来安装软件包。
1 | RUN apt-get update |
直接在 RUN
后写命令即可。
CMD
CMD
指令设置容器新建时要在容器内执行的命令。和 RUN
指令的用法类似。
如果你需要再容器新建时默认执行一条命令,那就可以使用 CMD
语句。但如果在新建时指定了其他命令,该语句就会被省略。
在 Dockerfile 中,只能有一条 CMD
指令。如果有多个 CMD
指令,则只有最后一个生效。
Dockerfile 的介绍到此为止,后面也许会放一些例子,让大家更直观的感受。
第九章 Docker Compose
Docker Compose 类似于一个配置文件,我们称呼它为「模板文件」。你在里面写好了对新容器的要求,就可以执行一个非常简洁的指令启动,不必使用需要指定许多参数的 docker run
命令。
写好配置文件以后,只需要在配置文件目录执行下面的命令即可。
1 | docker-compose up |
是不是非常简洁?让我们现在就学习如何使用吧。
安装
如果你使用的是本教程的安装指令,那么 Docker Compose 已经安装到了你的主机。跳过本小节即可。
1 | sudo yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin |
亲自写一个模板文件吧
模板文件是 YAML 格式。先看一下官方给出的样例。
1 | services: |
web
和 redis
都是容器的名字,就相当于在用 docker run
命令时添加的 --name
参数,为容器指定名字。
你可能会疑惑:「为什么有多个容器名?是不是可以启动多个容器?」没错!Docker Compose 生来就是高山,用来批量启动容器。既然能同时启动多个容器,那就可以只启动单个容器。不管你通过它启动多少容器,都要比使用 docker run
方便得多。
我们首先看 web
下的内容:
build
指定的是 Dockerfile 的路径,用来构建容器,这里有一个.
是相对路径,表示的就是当前目录。ports
相当于-p
参数,用来配置端口映射。冒号左侧是主机端口,右侧是容器内部的端口。volumes
是使用数据卷存储数据。冒号左侧是主机的路径,冒号右侧是主机内部路径,这里的效果是将容器内部/code
路径下的文件存到主机的当前目录。
再看 redis
下的内容:
image
指定容器使用的镜像,这里不需要build
,只有没有指定镜像的时候才需要build
。
内容就是这些。此时你可以把文件命名为 compose.yaml
。
Docker Compose,启动!
在 compose.yaml
同级目录下,输入 docker-compose up
就可以启动了。你使用这条简单的命令分别启动了依赖同目录 Dockerfile 构建的镜像、容器内部 5000
端口映射到主机 5000
端口、在主机同目录存储容器内部 /code
路径内的数据、名为 web
的容器,依赖 redis
镜像、名为 redis
的容器。
如果想让它运行在后台,则使用 -d
参数,以守护态运行容器。
1 | docker-compose up -d |
Docker 启蒙教程(2)