记录一下在项目中使用 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 制作镜像
先看示例:
1 | 使用官方 Python 运行时作为基础镜像 |
关键指令的解释:
FROM:指定基础镜像(在此示例中为 Python 镜像)。
WORKDIR:设置容器中的工作目录。
COPY:将文件从主机机器复制到容器中。
RUN:执行命令以安装依赖或执行设置任务。
EXPOSE:将容器的端口暴露给主机系统。
ENV:定义环境变量。
CMD:指定容器启动时要运行的默认命令。
定义了我们自己的 Dockerfile 文件后,在存在 dockerfile 文件的目录下就可以开始制作镜像了,方式为:
1 | docker build --network=host -t <image-name>:<tag> -f Dockerfile . |
这样就从 Dockerfile 中创建了我们自己的 docker 镜像了
打包镜像:
docker save 可以将一个或多个镜像归档打包为单个文件,如:
1 | 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
要发布前面制作好的镜像,需要先登录:
1 | docker login https://my.harbor.com |
然后将本地镜像打上特定的 tag:
1 | docker tag source_image[:tag] my.harbor.com/my-projects/repository[:tag] |
最后就可以推送了:
1 | docker push my.harbor.com/my-projects/repository[:tag] |
Docker container
创建新容器的命令有:docker create, docker run
通过 docker --help 查看他们的用法如下:
docker create: Create a new container
docker run: Run a command in a new container
可以看到 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 选项则是尝试删除容器,所以它们不能同时使用。
所以创建容器时会这样做:
1 | docker run -t -d --rm --name my-container <image-id> |
实际上要使用容器并不是这样简单,容器还需要网络,需要共享主机上的一些资源等等。比如要使用主机上的网络,需要加上 --network 选项(伴随着网络,往往还有端口映射问题,但这里先不管)。
Tips:
要想在容器内部访问主机上的文件,需要 --volume 选项将主机上的卷挂载到容器内部,这个能力在有些场景下非常重要。比如,当主机采用了 CST 时区(东八区时间),而容器采用了 UTC 时区(标准时间),它们相差 8 个小时,这在查看容器内服务产生的日志时不太方便,于是我想让容器内的时间与主机上的时间保持一致,这个时候只需要将主机上的 /etc/localtime 挂载到容器内即可。
再比如,如果主机上有多个容器,而我想在一个容器内去另一个容器内执行命令,那么只需要将主机上的 /var/run/docker.sock 挂载到这个容器内即可。
所以实际创建容器时可能是这样:
1 | 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
1 | docker exec <container-name> commands |
如果要进入容器内部,则需要加上 -t(--tty) 选项和 -i(--interactive) 选项
1 | docker exec -it <contaienr-name> /bin/bash |
Docker compose
Docker compose 是定义和运行多容器服务的工具,它通过 yaml 文件来编排容器服务,官方文档为:https://docs.docker.com/compose/
具体怎么用就不写了,看官方文档即可。但使用时有两点需要注意,一是 docker compose 文件(即 .yml 配置文件)的版本兼容性问题,这个也可以从官方文档了解;二是写配置文件时注意 yml 语法的缩进问题。