Skip to content

Docker 的使用笔记

· 8 min
TL;DR

记录一下在项目中使用 Docker 时的一些笔记

本文分享 Docker 在实际项目中的应用经验,涵盖从镜像管理到容器操作的完整流程。详细讲解了如何从 Docker Hub 获取镜像、使用 Dockerfile 创建自定义镜像以及发布镜像到私有仓库的步骤。同时提供了创建和管理容器的实用技巧,包括网络配置、卷挂载和时区同步等常见问题的解决方案,并简要介绍了 Docker Compose 多容器编排工具的应用注意事项。

从 Docker image 开始

Docker image#

1. 从 Docker Hub 拉取镜像#

关于 Docker 镜像,可以从 https://hub.docker.com/ 中查找我们需要的镜像。 然后再使用 docker 命令 docker pull 拉取目标镜像到本地,当然我们可以使用 docker search [name] 直接查找需要的镜像。 虽然 docker search 有 —filter 选项对结果进行过滤,但是直接在网页上进行筛选更方便一些。

另外一种方式是我们自己定制自己需要的镜像,因为直接拉取别人制作好的镜像可能不满足我们自己的实际需要,比如别人的镜像中安装了一些我们不需要的依赖。

2. 使用 Dockerfile 制作镜像#

先看示例:

Terminal window
使用官方 Python 运行时作为基础镜像
FROM python:3.8-slim
# 在容器中设置工作目录
WORKDIR /app
# 将当前目录的内容复制到容器中的 /app
COPY . /app
# 指定 pip 源
COPY pip.conf /root/.pip/pip.conf
# 安装 requirements.txt 中指定的必需包
RUN pip install -r requirements.txt
# 对外暴露端口
EXPOSE 80
# 定义环境变量
ENV NAME World
# 在容器启动时运行应用程序
CMD ["python", "app.py"]

关键指令的解释:

定义了我们自己的 Dockerfile 文件后,在存在 dockerfile 文件的目录下就可以开始制作镜像了,方式为:

Terminal window
docker build --network=host -t <image-name>:<tag> -f Dockerfile .

这样就从 Dockerfile 中创建了我们自己的 docker 镜像了

打包镜像: docker save 可以将一个或多个镜像归档打包为单个文件,如:

Terminal window
docker save <image-name>:<tag> -o v1-x86_64.docker

3. 发布镜像#

前面提到了 Docker Hub,这是存放 docker 镜像的公共仓库。实现存放,分发 docker 镜像的地方称作 Docker Register

我们在运行 docker pull、docker search 时,实际上是通过 docker daemon 与 docker registry 通信。而 Docker Hub 实际是 Docker Register 的一种实现。

有了公共仓库的概念,那么就有私有仓,但如何创建私有仓库不是现在的主题。 在企业内部可以使用 Harbor 来实现 Docker Register,它在 Docker Registry 上进行了相应的企业级扩展,因此特别适合来搭建企业内部的 docker 镜像仓,提供公司内部使用。

假设企业内部的的 Harbor 服务的地址为:https://my.harbor.com

要发布前面制作好的镜像,需要先登录:

Terminal window
docker login https://my.harbor.com

然后将本地镜像打上特定的 tag:

Terminal window
docker tag source_image[:tag] my.harbor.com/my-projects/repository[:tag]

最后就可以推送了:

Terminal window
docker push my.harbor.com/my-projects/repository[:tag]

Docker container#

创建新容器的命令有:docker create,docker run

通过 docker —help 查看他们的用法如下:

可以看到 docker run 与 docker create 的区别是它除了创建新容器,还可以运行命令。

使用 docker create 创建容器成功后,容器状态为 Created,正常运行的容器状态为 Up,所以创建容器后,还需要 docker start 来拉起容器。所以一般我们没有使用 docker create 命令创建容器。

Tips:

一般使用 docker run 命令来创建容器,并加上 -d(--detach) 选项让新创建的容器在后台(background)运行,而 docker create 命令则没有这个选项。另外要让容器一直保持运行,还可以加上 -t(--tty) 选项,否则容器会在后台一直是 Exited 状态,当然如果加上了 --rm 选项,则会自动将 Exited 状态的容器删除掉, —— rm 选项会与 —— restart 选项冲突,因为当 —— restart 打开时意味着当容器进入 Exited 状态后会尝试拉起,而 --rm 选项则是尝试删除容器,所以它们不能同时使用。

所以创建容器时会这样做:

Terminal window
docker run -t -d --rm --name my-container <image-id>

实际上要使用容器并不是这样简单,容器还需要网络,需要共享主机上的一些资源等等。 比如要使用主机上的网络,需要加上 --network 选项(伴随着网络,往往还有端口映射问题,但这里先不管)。

Tips:

要想在容器内部访问主机上的文件,需要 --volume 选项将主机上的卷挂载到容器内部,这个能力在有些场景下非常重要。 比如,当主机采用了 CST 时区(东八区时间),而容器采用了 UTC 时区(标准时间),它们相差 8 个小时,这在查看容器内服务产生的日志时不太方便,于是我想让容器内的时间与主机上的时间保持一致,这个时候只需要将主机上的 /etc/localtime 挂载到容器内即可。

再比如,如果主机上有多个容器,而我想在一个容器内去另一个容器内执行命令,那么只需要将主机上的 /var/run/docker.sock 挂载到这个容器内即可。

所以实际创建容器时可能是这样:

Terminal window
docker run -t -d --rm --net=host -v /etc/localtime:/etc/localtime -v var/run/docker.sock:var/run/docker.sock --name my-container <image-id>

当容器运行起来之后,要在容器内执行命令或脚本,可以不进入容器,直接在主机上执行 docker exec

Terminal window
docker exec <container-name> commands
# or
docker exec <container-name> bash -c "commands"

如果要进入容器内部,则需要加上 -t(--tty) 选项和 -i(--interactive) 选项

Terminal window
docker exec -it <contaienr-name> /bin/bash

Docker compose#

Docker compose 是定义和运行多容器服务的工具,它通过 yaml 文件来编排容器服务,官方文档为:https://docs.docker.com/compose/

具体怎么用就不写了,看官方文档即可。但使用时有两点需要注意,一是 docker compose 文件(即 .yml 配置文件)的版本兼容性问题,这个也可以从官方文档了解;二是写配置文件时注意 yml 语法的缩进问题。