Docker使用入门
# 引言
Docker 是一个开源的应用容器引擎,可以让开发者打包他们的应用及依赖到一个可移植的容器中,并且可以在任何流行的 Linux 机器上运行。
# 简单理解
docker 容器与虚拟机的最大区别是轻量级和快速启动。容器共享宿主机的内核,而虚拟机则需要完整的操作系统,因此容器启动更快,占用资源更少。
# 概念介绍
- 镜像(Image): Docker 镜像是一个只读的模板,用于创建 Docker 容器。可以将其视为应用程序的快照。
- 容器(Container): 容器是镜像的运行实例。它包含了应用程序及其所有依赖项,并且可以在任何支持 Docker 的环境中运行。
- 仓库(Repository): 仓库是存储 Docker 镜像的地方。可以是公共的 Docker Hub,也可以是私有的仓库,docker 的官方仓库是 Docker Hub。
- Dockerfile: Dockerfile 是一个文本文件,包含了构建 Docker 镜像的所有命令。它定义了镜像的内容和配置。
- Docker Compose: Docker Compose 是一个工具,用于定义和运行多容器 Docker 应用。通过一个 YAML 文件,可以配置应用的服务、网络和卷等。
# 技术原理
Docker 使用 Linux 内核的 cgroups 和 namespaces 技术来实现容器化。cgroups 用于限制和隔离资源(如 CPU、内存、磁盘等),而 namespaces 用于隔离进程、网络、文件系统等。这样,Docker 可以在同一操作系统上运行多个独立的容器,而不会相互干扰。
# 安装 Docker
在 Debian 系统中安装 Docker 非常简单。
首先打开 https://get.docker.com/,选择 Debian 系统的安装脚本。可以使用以下命令直接安装 Docker:
1 | # 下载并执行Docker安装脚本 |
也可以通过以下命令进行安装:
1 | sudo apt update |
安装完成后,可以通过以下命令启动 Docker 服务:
1 | sudo systemctl start docker |
检查 Docker 是否安装成功,可以运行以下命令:
1 | docker --version |
当然你也可以通过 wsl 安装 Docker,具体步骤可以参考 Docker 官方文档.
# Docker 镜像
我们首先看一下基础的拉取镜像命令:
1 | docker pull --platform=linux/amd64 docker.io/library/ubuntu:latest |
docker.io
是 Docker Hub 的域名,当这一部分省略时,默认使用 Docker Hub 官方镜像。library
是官方镜像的命名空间,ubuntu
是镜像的名称,:latest
是标签(tag),表示最新版本。当然你也可以自行指定版本,例如ubuntu:20.04
。--platform
参数可以指定平台,例如--platform=linux/amd64
。大多数情况下,Docker 会自动选择合适的架构,但在某些情况下(例如在 raspberry pi 上运行),你可能需要手动指定。或者检查是否有linux/arm64
版本。
# registry 与 repository 的区别
在 Docker 中,registry 是一个存储和分发 Docker 镜像的服务,而 repository 是一个特定的镜像集合。每个 repository 可以包含多个版本的镜像(通过标签区分)。简单来说,registry 是镜像的仓库,而 repository 是仓库中的一个具体项目。
# 镜像站点
在国内访问 Docker Hub 可能会比较慢,可以使用国内的镜像站点来加速下载。
配置 Docker 使用国内镜像站点非常简单。只需在 Docker 的配置文件中添加镜像站点地址即可。
1 | sudo mkdir -p /etc/docker |
# 镜像命令
# 列出所有镜像
1 | docker images |
# 删除镜像
1 | docker rmi <image_id> |
# 运行容器
运行容器是 Docker 的核心功能之一。可以使用以下命令来运行一个容器:
1 | docker run -it -d --rm --name my_container ubuntu:latest |
-it
选项表示以交互模式运行容器,并分配一个伪终端。--name
选项用于指定容器的名称,并且这个名称在同一时间内必须是唯一的。ubuntu:latest
是要运行的镜像名称。-d
选项可以让容器在后台运行。--rm
选项表示容器停止后自动删除容器。
如果需要查看正在运行的容器,可以使用以下命令:
1 | docker ps |
执行后会显示当前正在运行的容器列表。其中 CONTAINER ID
是容器的唯一标识符, IMAGE
是容器使用的镜像, COMMAND
是容器启动时执行的命令, STATUS
显示容器的运行状态。 NAMES
是容器的名称,如果没有手动设置,系统会分配一个随机的名称。 PORTS
显示容器的端口映射。
# 端口映射
容器中的端口和宿主机的端口是隔离的,默认情况下并不能直接从宿主机访问到 docker 的内部网络。如果容器需要与外部通信,可以使用端口映射。可以在运行容器时指定端口映射,例如:
1 | docker run -d -p 8080:80 --name my_web_container nginx:latest |
其中:
-p
选项用于指定端口映射。格式为<host_port>:<container_port>
,表示将宿主机的host_port
端口映射到容器的container_port
端口。- 在这个例子中,宿主机的 8080 端口映射到容器的 80 端口。
这个时候访问http://localhost:8080
就可以访问到容器中的 Nginx 服务。
# 挂载卷
容器中的数据是临时的,当容器停止或删除时,数据也会丢失。为了持久化数据,可以使用卷(Volume)来挂载宿主机的目录到容器中。
1 | docker run -d -v /path/on/host:/path/in/container --name my_data_container ubuntu:latest |
-v
选项用于挂载卷。格式为<host_path>:<container_path>
,表示将宿主机的host_path
目录挂载到容器的container_path
目录。
# 命名卷
如果需要使用命名卷,可以使用以下命令创建一个命名卷:
1 | docker volume create my_volume |
然后在运行容器时使用命名卷:
1 | docker run -d -v my_volume:/path/in/container --name my_named_volume_container ubuntu:latest |
查看命名卷目录
1 | docker volume inspect my_volume |
删除命名卷
1 | docker volume rm my_volume |
清理所有未使用的卷
1 | docker volume prune -a |
# 环境变量
环境变量是容器中运行的应用程序可以使用的配置参数。
在运行容器时,可以通过 -e
选项设置环境变量,例如:
1 | docker run -d -e MY_ENV_VAR=value --name my_env_container ubuntu:latest |
我们可以打开镜像的介绍页面查看环境变量的配置方法。
# 重启策略
在 Docker 中,可以设置容器的重启策略,以便在容器停止或崩溃时自动重启。可以使用 --restart
选项来设置重启策略,例如:
1 | docker run -d --restart unless-stopped --name my_restart_container ubuntu:latest |
--restart
选项可以设置以下几种重启策略:
no
: 不自动重启容器(默认)。always
: 无论容器退出状态如何,都会自动重启。unless-stopped
: 除非容器被手动停止,否则会自动重启。on-failure
: 当容器以非零状态退出时自动重启,可以指定最大重启次数。
# 调试容器
# 执行命令
如果需要进入正在运行的容器,可以使用以下命令:
1 | docker exec -it my_container /bin/sh |
这将打开一个交互式的 bash shell,允许你在容器内执行命令。
如果你不需要进入容器只需要在容器内运行命令,可以使用以下命令:
1 | docker exec my_container <command> |
容器的运行和停止命令
1 | docker start my_container |
如果我们忘记了容器启动时的命令,可以使用以下命令查看容器的详细信息:
1 | docker inspect my_container |
把所有的内容扔给 ai 就可以查看了。
# 创建容器
这里的创建是指创建一个新的容器实例,而不是运行它。可以使用以下命令创建一个容器:
1 | docker create --name my_container ubuntu:latest |
# 查看日志
要查看容器的日志,可以使用以下命令:
1 | docker logs my_container -f |
其中 -f
选项表示实时跟踪日志输出。
# 制作镜像
# dockerfile
Dockerfile 是一个文本文件,包含了构建 Docker 镜像的所有命令。里面详细的描述了如何从基础镜像开始,安装软件包,复制文件,设置环境变量等。编写 dockerfile 的流程和正常运行项目时的流程类似。首先需要选择一个基础镜像,然后安装所需的软件包,复制项目文件,设置环境变量等。
# 编写 Dockerfile
在项目根目录下创建一个名为 Dockerfile
的文件,然后开始编写。
所有的 dockerfile 的命令都是大写的,其中第一行通常是 FROM
命令,用于指定基础镜像。也就是我们的镜像是从哪个镜像开始构建的。
接下来是 WORKDIR
命令,用于设置工作目录。这个有点类似于 cd 命令,表示进入到指定的目录下。所有后续的命令都会在这个目录下执行。
然后是 COPY
命令,用于将本地文件复制到容器中。可以指定源路径和目标路径。命令后面写两个路径,第一个是本地路径,第二个是容器内的路径。一般用两个点: COPY . .
然后是 RUN
命令,用于在容器内执行命令。可以用来安装软件包,运行脚本等。例如我们可以用以下命令安装 Python 依赖: RUN pip install -r requirements.txt
.
EXPOSE
命令用于指定容器的端口。这个命令只是告诉 Docker 容器会监听哪个端口,并不会实际映射到宿主机的端口。
最后是 CMD
命令,用于指定容器启动时执行的命令。这个命令会在容器启动时自动执行。命令最好写成数组的形式,例如: CMD ["python", "app.py"]
。
最终写好的 Dockerfile 可能如下所示:
1 | FROM python:3.9-slim |
# 构建镜像
在项目根目录下,使用以下命令构建镜像:
1 | docker build -t my_image:latest . |
-t
选项用于指定镜像的名称和标签。my_image:latest
是镜像的名称和版本号。.
表示当前目录是 Dockerfile 所在的目录。
# 运行镜像
构建完成后,可以使用以下命令运行镜像:
1 | docker run -d -p 5000:5000 --name my_app_container my_image:latest |
-p
选项用于端口映射,将宿主机的 5000 端口映射到容器的 5000 端口。--name
选项用于指定容器的名称。
# 推送镜像到仓库
如果需要将镜像推送到 Docker Hub 或其他仓库,可以使用以下命令:
1 | docker push my_image:latest |
在执行这个命令之前,需要先登录到 Docker Hub:
1 | docker login |
然后使用以下命令推送镜像:
1 | docker tag my_image:latest <your_dockerhub_username>/my_image:latest |
# docker 网络
Docker 容器之间可以通过网络进行通信。Docker 提供了多种网络模式,包括桥接网络、主机网络和无网络等。
# 桥接模式
在默认情况下 docker 的网络模式都是桥接模式,所有容器都默认连接到这个网络上。每个容器都分配了一个内部的 IP 地址,通常是以 172.17.x.x
开头的。容器之间可以通过这个 IP 地址进行通信。但容器内部的服务默认是无法被外部访问的。
# 创建自定义网络
创建自定义网络的目的是为了让容器之间可以通过名称进行通信,而不需要使用 IP 地址。
我们可以使用以下命令创建一个自定义网络:
1 | docker network create my_network |
执行完这个命令后,创建容器时可以使用 --network my_network
选项将容器连接到自定义网络。
# 主机网络
这种模式下容器直接使用宿主机的网络栈,容器内的服务可以直接访问宿主机的网络接口,就像你直接在宿主机上运行应用程序一样。这种模式下容器的 IP 地址和宿主机的 IP 地址是相同的。可以使用 --network host
选项来指定主机网络模式。
# 无网络模式
最后一种网络模式是无网络模式,这种模式下容器没有网络连接。可以使用 --network none
选项来指定无网络模式。
# Docker Compose
有些时候一个完整的应用可能是由很多个应用程序组成的,比如一个 Web 应用可能需要一个数据库,一个缓存服务等。最容易想到的方法是将所有的服务都部署到一个容器里,但这样会导致容器变得非常庞大,而且只要有一个模块出现了故障整个容器都有可能崩溃。而且不易于管理和维护。Docker Compose 可以帮助我们解决这个问题。
Docker Compose 是一个工具,用于定义和运行多容器 Docker 应用。通过一个 YAML 文件,可以配置应用的服务、网络和卷等。使用 Docker Compose 可以更方便地管理多个容器,简化部署流程。
# 使用 docker run
命令部署
这是我在前几天创建的一个项目,按照往常的方法那我们就需要手动创建容器和网络了。以下是使用 docker run
命令部署的示例:
1 | # 创建自定义网络 |
但是这样往往需要手动管理容器和网络,配置起来比较繁琐。
# 使用 docker-compose
部署
使用 Docker Compose 可以将上述配置简化为一个 docker-compose.yml
文件,内容如下:
1 | version: '3.8' |
编写完 docker-compose.yml
文件后,可以使用以下命令启动所有服务:
1 | docker-compose up -d |
这将根据 docker-compose.yml
文件中的配置自动创建和启动所有服务。
要停止并删除所有服务,可以使用以下命令:
1 | docker-compose down |
# 使用 Docker Compose 的优势
- 用一个 YAML 文件统一管理多个服务,配置更清晰,支持服务依赖(
depends_on
)、网络、卷等自动创建。 - 一条命令即可启动 / 停止所有服务(
docker-compose up/down
),适合多容器应用和开发环境。 - 支持环境变量文件、扩展性强。
# 总结
Docker 是一个强大的容器化平台,可以帮助我们更高效地部署和管理应用程序。通过使用 Docker Compose,我们可以轻松地管理多容器应用,简化部署流程。本文介绍了 Docker 的基本概念、安装方法、镜像和容器的使用,以及如何使用 Docker Compose 来管理多容器应用。