保姆级教程:用Docker Compose一键部署你的第一个Web应用(附常见错误排查)

当你第一次听说Docker时,可能觉得它像某种魔法——把应用和它的运行环境打包在一起,无论在哪都能一键运行。但真正动手部署时,那些晦涩的命令行参数和突如其来的报错信息,往往让初学者望而却步。本文将带你用最直观的方式,从零开始部署一个真实的Web应用,过程中遇到的每个坑我都替你踩过一遍了。

1. 环境准备:从零搭建Docker游乐场

在开始之前,确保你的开发机已经安装好以下工具。如果是Windows/macOS用户,建议直接安装Docker Desktop,它会自动包含我们需要的所有组件:

# 检查Docker和Compose版本
docker --version
docker-compose --version

常见安装问题解决方案

  • 如果遇到权限问题,记得将当前用户加入docker组:
    sudo usermod -aG docker $USER
    
  • 国内用户推荐配置镜像加速器,在/etc/docker/daemon.json中添加:
    {
      "registry-mirrors": ["https://registry.docker-cn.com"]
    }
    

提示:所有命令行操作建议在项目根目录下进行,本文示例代码都假设你已创建专用项目文件夹。

2. 构建第一个容器化的Web应用

我们从最简单的Python Flask应用开始,这个微型应用只包含一个显示欢迎页面的路由。创建app.py文件:

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello():
    return "<h1>我的第一个Docker应用正在运行!</h1>"

if __name__ == '__main__':
    app.run(host="0.0.0.0", port=5000)

接着编写Dockerfile,这是构建容器镜像的配方文件:

# 使用官方Python轻量级镜像
FROM python:3.9-slim

# 设置工作目录
WORKDIR /app

# 先复制依赖声明文件(利用Docker缓存层)
COPY requirements.txt .
RUN pip install -r requirements.txt

# 再复制应用代码
COPY . .

# 声明暴露端口
EXPOSE 5000

# 启动命令
CMD ["python", "app.py"]

创建requirements.txt文件只需一行内容:

Flask==2.0.1

现在可以构建镜像了:

docker build -t my-webapp .

3. 使用Compose编排多容器服务

真实的Web应用通常需要多个服务协同工作。我们通过docker-compose.yml文件定义整个应用栈:

version: '3.8'

services:
  web:
    build: .
    ports:
      - "5000:5000"
    environment:
      - FLASK_ENV=development
    volumes:
      - .:/app
    depends_on:
      - redis

  redis:
    image: "redis:alpine"
    ports:
      - "6379:6379"

这个配置定义了两个服务:

  1. web服务:基于我们刚构建的Flask应用
  2. redis服务:使用官方Redis镜像作为缓存层

关键参数解析

参数作用典型值示例
build指定构建上下文. (当前目录)
ports端口映射主机端口:容器端口
volumes目录挂载主机路径:容器路径
depends_on服务依赖依赖的服务名

启动整个应用栈只需一行命令:

docker-compose up -d

4. 实战问题排查手册

即使按照教程操作,仍可能遇到各种环境问题。以下是经过验证的解决方案:

问题1:端口已被占用

ERROR: for web Cannot start service web: driver failed programming external connectivity on endpoint web (...): Error starting userland proxy: listen tcp4 0.0.0.0:5000: bind: address already in use

解决方案

  • 查找占用端口的进程:sudo lsof -i :5000
  • 终止该进程或修改compose文件中的端口映射

问题2:镜像拉取失败

ERROR: Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)

解决方案

  • 检查DNS设置:nslookup registry-1.docker.io
  • 临时使用国内镜像源:docker pull registry.docker-cn.com/library/redis:alpine

问题3:容器权限问题

redis: Can't open the append-only file: Permission denied

解决方案

  • 在compose文件中添加用户声明:
    redis:
      user: "1000:1000"
      volumes:
        - redis_data:/data
    

问题4:修改代码后变化未生效 解决方案

  • 确保compose中配置了volume挂载
  • 重启服务:docker-compose restart web
  • 或者完全重建:docker-compose up -d --build

5. 进阶技巧:提升开发体验

热重载配置: 修改compose文件中web服务的配置:

web:
  environment:
    - FLASK_ENV=development
  volumes:
    - .:/app
  command: ["flask", "run", "--host=0.0.0.0", "--port=5000", "--reload"]

日志查看技巧

  • 跟踪实时日志:docker-compose logs -f web
  • 过滤错误日志:docker-compose logs web | grep -i error
  • 查看特定时间段的日志:
    docker-compose logs --since 10m web
    

资源监控

# 查看容器资源占用
docker stats

# 进入容器内部
docker-compose exec web bash

清理命令备忘

# 停止并删除所有容器
docker-compose down

# 删除未使用的镜像
docker image prune

# 彻底清理所有缓存
docker system prune -a

在实际项目中使用这套配置几个月后,我发现最实用的功能是docker-compose up -d --build这条命令——它能在保持服务运行的同时重建更新的镜像。当需要调试时,docker-compose exec web bash让我能像操作普通服务器一样进入容器内部检查运行状态。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐