为什么你该现在学Docker?
上周帮朋友排查一个“本地能跑,服务器报错”的bug——Node版本不一致、Redis没装、系统依赖缺失…折腾两小时后我直接甩了份Dockerf
ile过去。他跑完说了句:“这东西早该学了。”
如果你也经历过:
- “在我电脑上明明能跑”的玄学问题
- 部署新项目要装一堆依赖,环境配置写满三页文档
- 线上扩容每次都要手动配置新服务器
Docker就是你的解药。它把应用和依赖打包成一个标准化的容器,保证开发、测试、生产环境完全一致。我自己的项目从传统部
署切到Docker后,部署时间从15分钟降到3分钟,出错的概率直接归零。
(插一张Docker与传统虚拟机的架构对比图:左边是VM的Hypervisor+Guest OS,右边是Docker的Docker Engine+共享内核,突出容器更轻量的特点)
核心概念:3个词搞懂Docker
镜像 vs 容器 vs Dockerfile
很多教程喜欢讲一堆术语,我换个说法:
- 镜像:做饭的菜谱+食材包(包含运行应用的所有东西)
- 容器:按菜谱做出来的那盘菜(镜像运行后的实例)
- Dockerfile:写菜谱的步骤说明(如何构建镜像的脚本)
实际使用中,你写Dockerfile描述应用怎么跑,然后docker build生成镜像,最后docker run启动容器。就这么简单。
安装与验证
踩坑提醒:Windows用户别直接装Docker Desktop,Hyper-V容易和虚拟机软件冲突。建议先装WSL2,再装Docker Desktop选WSL2后端。
“bash
安装完成后验证
docker --version # 我用的版本是24.0.6
docker info # 看有没有出现Server Version
`
实战第一步:让一个Node应用集装箱化
写Dockerfile
假设你有一个Express应用,目录结构长这样:
``
my-app/
├── package.json
├── app.js
└── Dockerfile
新手最容易犯的错是把整个项目丢进去,结果node_modules也打包进去。正确的写法:
`dockerfile
多阶段构建,减小镜像体积
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production # 注意用ci不是install,保证锁定版本
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .
EXPOSE 3000
CMD ["node", "app.js"]
`
我用的发现:alpine版本镜像只有5MB,完整版node镜像超过200MB。生产环境必选alpine。
构建并运行
`bash
构建镜像,-t是打标签
docker build -t my-app:1.0 .
运行容器,-d后台运行,-p映射端口
docker run -d -p 3000:3000 --name app-instance my-app:1.0
查看运行状态
docker ps # 显示所有运行的容器
docker logs -f app-instance # 实时看日志
进入容器内部调试
docker exec -it app-instance sh
`
执行docker ps后应该看到类似输出:``
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a1b2c3d4e5f6 my-app:1.0 "node app.js" 5 seconds ago Up 4 seconds 0.0.0.0:3000->3000/tcp app-instance
(插入一个终端截图:docker build过程中分层构建的输出,突出每一层缓存使用的提示)
实战第二步:容器编排与数据库
单跑一个应用不够,实际项目通常需要数据库、缓存等。我踩过的坑是:手动启动多个容器,端口和网络配置经常搞混。
Docker Compose拯救你
在项目根目录创建docker-compose.yml:
`yaml
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
environment:
- DB_HOST=db
- DB_PORT=27017
depends_on:
db:
condition: service_healthy # 等数据库就绪才启动
volumes:
- .:/app # 开发模式挂载源码,热更新
- /app/node_modules # 排除node_modules覆盖
db:
image: mongo:6
volumes:
- mongodb_data:/data/db # 持久化数据
healthcheck:
test: echo 'db.runCommand("ping").ok' | mongosh --quiet
interval: 10s
volumes:
mongodb_data:
`
踩过的坑:depends_on默认只等容器启动,不等服务就绪。比如MongoDB要几秒才能接受连接,不加healthcheck的话app启动就会报连接拒绝。
一键启动
`bash
启动所有服务
docker compose up -d
查看服务状态
docker compose ps
查看所有日志
docker compose logs -f
停止并清理
docker compose down -v # -v会删掉volume,生产慎用
`
部署实战:从本地到服务器
搭建私有镜像仓库
直接把镜像推到Docker Hub?慢且不安全。我推荐用Harbor搭建私有仓库:
`bash
下载Harbor离线安装包(约2.3GB,建议先下好)
wget https://github.com/goharbor/harbor/releases/download/v2.10.0/harbor-offline-installer-v2.10.0.tgz
修改配置
tar xzf harbor-offline-installer-*.tgz
cd harbor
cp harbor.yml.tmpl harbor.yml
修改hostname为你服务器的域名或IP
生产环境务必启用HTTPS
安装(需要docker compose)
./install.sh
`
推送镜像到仓库
`bash
登录仓库
docker login your-registry.com -u admin
给镜像打标签
docker tag my-app:1.0 your-registry.com/library/my-app:1.0
推送
docker push your-registry.com/library/my-app:1.0
`
服务器上拉取并运行
建议先…再…:先写个docker-compose.prod.yml,区分开发和生产配置:
`yaml
version: '3.8'
services:
app:
image: your-registry.com/library/my-app:1.0
ports:
- "80:3000"
restart: always # 自动重启
logging:
driver: "json-file"
options:
max-size: "10m" # 限制日志大小,防磁盘爆满
`
然后在服务器上执行:
`bash
从仓库拉取最新镜像
docker compose -f docker-compose.prod.yml pull
重启服务,如果镜像没变不会重新创建
docker compose -f docker-compose.prod.yml up -d
`
(插入一张Harbor仓库管理界面的截图,显示镜像列表和标签,突出制品存储功能)
生产环境5个避坑指南
,防止容器逃逸。我见过生产环境被黑就是因为容器里装的root权限。,或者compose里配deploy.resources。不加限制的话,一个容器能把整台服务器搞崩。和max-file,或者用ELK统一收集。立刻动手
Docker的核心价值不是技术,而是“一次构建,到处运行”的确定性。浪费在环境问题上的时间,省下来写代码不香吗?
本文由AI辅助创作,仅供参考。