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