开发者Docker指南:镜像、容器与Compose
你听说过Docker和容器,但当你尝试使用时,却被镜像、容器、卷和Compose这些术语搞得不知所措。或者你可能已经在使用Docker,但你的镜像巨大,构建缓慢,管理多个服务感觉像是一件苦差事。本指南将拨开迷雾。我们将介绍开发者使用Docker的要点,专注于你真正需要知道的内容,以高效地构建、运行和管理容器化应用。
为什么选择Docker?它解决的问题
在Docker出现之前,部署应用意味着要匹配完全相同的环境:特定的操作系统版本、库和配置。“在我的机器上能运行”成为陈词滥调,因为它确实如此。Docker通过将你的应用程序及其依赖项打包成一个可移植的单元——容器来解决这个问题。容器轻量、隔离,并且可以在任何安装了Docker的地方一致地运行。
镜像与容器:核心区别
镜像是一个只读模板,包含你的应用代码、运行时、库和设置。容器是镜像的运行实例。可以把镜像看作类,容器看作对象。你可以从同一个镜像运行多个容器,每个容器相互隔离。
镜像如何构建
镜像是通过Dockerfile构建的,这是一个包含指令的文本文件。以下是一个Node.js应用的最小示例:
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
每条指令都会创建一个层。层会被缓存,所以如果你只更改源代码,Docker会重用依赖项的缓存层,从而使重新构建变得快速。
构建和运行
构建镜像并运行容器:
docker build -t my-app .
docker run -p 3000:3000 my-app
-p标志将主机上的端口3000映射到容器内的端口3000。
高效Docker镜像的最佳实践
大型镜像会减慢构建、推送和部署速度。遵循以下实践以保持镜像精简:
- 尽可能使用官方的slim或alpine基础镜像。例如,
node:18-alpine比node:18小得多。 - 利用多阶段构建将构建时依赖项与运行时分离。这可以保持最终镜像最小化。
- 合并RUN命令以减少层数,并在同一层中清理包管理器缓存。
- 使用.dockerignore文件从构建上下文中排除不必要的文件(例如node_modules、.git)。
以下是一个Go应用的多阶段Dockerfile:
# 构建阶段
FROM golang:1.21-alpine AS builder
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /app/main .
# 最终阶段
FROM alpine:latest
COPY --from=builder /app/main /main
CMD ["/main"]
最终镜像只包含编译后的二进制文件和Alpine,不包含Go工具链。
使用卷管理数据
容器是短暂的;当它们被删除时,数据也会丢失。卷将数据持久化在容器生命周期之外。将它们用于数据库、上传或任何必须在重启后保留的状态。
docker run -v my-data:/var/lib/postgresql/data postgres
这会创建一个由Docker管理的命名卷my-data。对于开发,你还可以将源代码绑定挂载到容器中,以实现实时重新加载:
docker run -v $(pwd):/app -p 3000:3000 my-app
Docker Compose:编排多个容器
实际应用通常需要多个服务:Web服务器、数据库、缓存。使用docker run逐个启动既繁琐又容易出错。Docker Compose允许你通过一个YAML文件定义和运行多容器应用。
一个实用的docker-compose.yml
以下是一个包含PostgreSQL和Redis的Node.js应用的Compose文件:
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-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: mydb
volumes:
- postgres_data:/var/lib/postgresql/data
cache:
image: redis:7-alpine
volumes:
postgres_data:
运行docker compose up启动所有服务。Compose会创建一个默认网络,以便容器可以通过服务名(例如db、cache)相互访问。
常用Compose命令
docker compose up -d– 以分离模式(后台)启动。docker compose logs -f web– 跟踪服务的日志。docker compose exec web sh– 在运行中的容器中打开shell。docker compose down– 停止并删除容器、网络和卷(除非卷是外部的)。
何时使用Docker Compose与Kubernetes
Docker Compose非常适合本地开发、测试和小型部署。Kubernetes擅长在集群中大规模编排容器以用于生产环境。对于许多开发者来说,Compose足以满足日常工作,当你需要自动扩展、自愈和高级网络时,可以过渡到Kubernetes。
| 特性 | Docker Compose | Kubernetes |
|---|---|---|
| 使用场景 | 本地开发、小型部署 | 生产集群 |
| 复杂性 | 低 | 高 |
| 扩展性 | 手动 | 自动 |
| 学习曲线 | 平缓 | 陡峭 |
常见问题
镜像和容器有什么区别?
镜像是一个只读模板,包含你的应用和依赖项。容器是镜像的运行实例。你可以从一个镜像运行多个容器。
如何减小Docker镜像大小?
使用更小的基础镜像(如Alpine)、多阶段构建、合并RUN命令,并使用.dockerignore文件排除不必要的文件。
我可以在生产环境中使用Docker Compose吗?
可以,适用于小规模部署。对于更大、动态的环境,Kubernetes或Docker Swarm更合适。
准备好优化你的Docker工作流程了吗?查看我们的Nginx日志分析器来调试和监控你的容器化Web服务器。