开发者 Docker 指南:镜像、容器与 Compose
你在本地构建了一个能正常运行的应用,但部署时却出了问题:依赖缺失、版本不一致、配置混乱。Docker 通过将应用及其运行环境打包成一个可移植的单元来解决这些问题。本文通过实用示例解释 Docker 镜像、容器和 Docker Compose,帮助你简化开发工作流。
什么是 Docker 镜像?
Docker 镜像是一个只读模板,包含应用代码、运行时、库、环境变量和配置文件。可以把它看作应用环境的快照。镜像通过 Dockerfile 构建,这是一个包含指令的文本文件。
以下是一个 Node.js 应用的简单 Dockerfile:
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
每条指令都会创建一个层。层会被缓存,因此代码更改后重新构建时,只会重新运行从更改层开始的步骤。这使构建变得快速。
什么是 Docker 容器?
容器是镜像的运行实例。它是一个隔离的进程,拥有自己的文件系统、网络和进程空间,但与宿主机共享操作系统内核。与虚拟机相比,容器更轻量,启动更快。
从镜像运行容器:
docker run -d -p 3000:3000 --name myapp my-node-app
这会在分离模式(-d)下启动容器,将宿主机的 3000 端口映射到容器的 3000 端口(-p 3000:3000),并将其命名为 myapp。
默认情况下容器是临时的。容器停止时,写入其中的任何数据都会丢失。要持久化数据,请使用卷:
docker run -v /host/data:/app/data my-node-app
为什么使用 Docker Compose?
实际应用通常需要多个服务:Web 服务器、数据库、缓存等。用 docker run 逐个运行并手动连接它们很繁琐。Docker Compose 让你通过一个 YAML 文件定义并运行多容器应用。
以下是一个包含 PostgreSQL 和 Redis 的 Node.js 应用的 docker-compose.yml:
version: '3.8'
services:
web:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgres://user:pass@db:5432/mydb
- REDIS_URL=redis://cache:6379
depends_on:
- db
- cache
db:
image: postgres:15
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: mydb
volumes:
- pgdata:/var/lib/postgresql/data
cache:
image: redis:7
volumes:
pgdata:
使用以下命令运行所有内容:
docker compose up -d
Compose 会创建一个网络,使服务可以通过名称相互访问(例如 db、cache)。它还处理卷的创建和依赖顺序。
开发者常用的 Docker 命令
docker build -t myapp .– 从当前目录的 Dockerfile 构建镜像。docker images– 列出本地镜像。docker ps– 列出运行中的容器(添加-a查看所有容器)。docker exec -it myapp sh– 在运行中的容器内打开 shell。docker logs myapp– 查看容器日志。docker compose down– 停止并删除 Compose 中定义的容器、网络和卷。
开发中使用 Docker 的最佳实践
- 使用 .dockerignore 将 node_modules、.git 和其他不必要的文件排除在构建上下文之外。
- 利用多阶段构建 保持生产镜像小巧。例如,在一个阶段构建应用,只将产物复制到最小运行时镜像中。
- 固定版本 在 Dockerfile 中(例如使用
node:18-alpine而非node:latest)以实现可重现的构建。 - 开发时使用卷挂载代码 以实现热重载:在 Compose 中设置
volumes: - .:/app。 - 不要以 root 身份运行 生产环境。在 Dockerfile 中创建非 root 用户。
常见陷阱及避免方法
陷阱 1:镜像臃肿。 使用完整的操作系统基础镜像如 ubuntu 可能导致镜像超过 1GB。使用 slim 或 alpine 变体。
陷阱 2:构建缓慢。 将 Dockerfile 指令按从最不常变到最常变的顺序排列。在复制源代码之前先复制包文件并安装依赖。
陷阱 3:数据丢失。 数据库始终使用卷。否则,容器删除时数据会消失。
陷阱 4:网络混淆。 在 Compose 中,服务通过默认网络以服务名作为主机名进行通信。不要使用 localhost 访问另一个服务。
常见问题
镜像和容器有什么区别?
镜像是一个只读模板;容器是该镜像的运行实例。你可以从同一个镜像运行多个容器。
我可以在生产环境使用 Docker Compose 吗?
Compose 主要用于开发和测试。对于生产环境,考虑使用 Kubernetes 或 Docker Swarm 等编排工具,不过 Compose 也可以用于简单部署。
如何用新代码更新容器?
使用 docker build 重新构建镜像,然后重新创建容器:docker compose up -d --build。
准备好简化你的开发工作流了吗?试试我们的 Nginx 日志分析器,快速调试容器化 Web 服务器的日志。