1. 项目概述从零到一的全栈部署之旅最近帮几个朋友处理了他们项目上线的问题发现一个挺普遍的现象很多开发者尤其是刚入行或者独立做项目的朋友对于如何把一个本地开发好的项目完整地部署到一台全新的服务器上并对外提供服务整个流程是模糊甚至有些畏惧的。大家可能对写代码、调Bug很熟悉但一提到“服务器”、“部署”、“上线”就觉得是运维的活儿门槛很高。其实只要理清思路借助现代工具这个过程完全可以变得清晰、可控甚至充满乐趣。今天我就以一个典型的Web应用为例带你走一遍“从零到一”的完整旅程从拿到一台裸机服务器开始到最终项目稳定运行在互联网上。这个“一”指的是一个可对外提供稳定服务的线上环境。整个过程的核心我会围绕两个关键词展开服务器环境搭建和Docker容器化部署。前者是基石决定了你的应用跑在什么样的“土地”上后者是利器它通过标准化的“集装箱”技术解决了环境一致性、依赖隔离和部署效率这三大痛点。无论你是想部署一个个人博客、一个小程序后端还是一个微服务架构的商业应用这套方法论都是相通的。接下来我会把每个环节掰开揉碎不仅告诉你“怎么做”更重点解释“为什么这么做”以及我在这个过程中踩过的坑和总结的经验。2. 服务器选型与基础系统准备2.1 服务器选择云服务商与配置考量部署的第一步是得有一台服务器。现在主流的选择无疑是各大云服务商提供的云服务器ECS。对于个人项目或初创公司我通常的建议是优先选择国内主流云厂商如阿里云、腾讯云、华为云。它们的稳定性、文档和社区支持相对更完善。选择时你需要关注几个核心参数CPU与内存这是决定服务器计算能力的关键。对于一个初期没有巨大流量的Web应用比如使用Spring Boot、Django、Express等框架1核2G或2核4G的配置通常足够起步。如果你的应用涉及AI推理、视频处理等计算密集型任务那就要优先考虑CPU性能甚至需要关注是否有GPU实例。带宽这决定了用户访问你网站的速度。按量计费的带宽如1Mbps、5Mbps对于展示型网站足够但如果预期有文件上传下载或视频流需要更高的带宽。一个技巧初期可以选择按量计费后付费的带宽模式用多少付多少避免闲置浪费。系统盘建议至少40GB。除了安装系统还需要存放你的应用代码、Docker镜像、日志等。选择SSD云盘I/O性能会好很多。地域选择离你的目标用户群体最近的地域节点可以显著降低网络延迟。例如用户主要在华东就选上海或杭州机房。注意购买时务必设置一个强密码并妥善保管密钥对如果选择密钥登录。安全组防火墙的配置先保持默认我们后续会详细调整初期可以先开放22端口SSH用于远程连接。2.2 操作系统安装与基础配置拿到服务器IP后我们通过SSH连接进行初始化。绝大多数云服务器在购买时就可以选择操作系统镜像。对于部署项目我强烈推荐使用Linux发行版其中Ubuntu Server LTS长期支持版或CentOS/Rocky Linux是首选。它们拥有庞大的社区和丰富的软件包教程也最多。这里以Ubuntu 22.04 LTS为例。连接服务器后第一件事不是急着装软件而是进行系统更新和安全加固# 1. 更新软件包列表 sudo apt update # 2. 升级所有已安装的包到最新版本 sudo apt upgrade -y # 3. 安装一些常用工具如vim、curl、wget、net-tools用于ifconfig等 sudo apt install -y vim curl wget net-tools接下来创建一个用于部署的专用用户而不是一直使用root这是一个重要的安全实践# 创建新用户例如叫 deployer sudo adduser deployer # 按照提示设置密码和其他信息可以按回车跳过非必填项 # 给新用户添加sudo权限以便在需要时执行管理员命令 sudo usermod -aG sudo deployer然后配置SSH密钥登录并禁用密码登录这能极大提升安全性# 在你的本地电脑生成SSH密钥对如果还没有的话 # 本地执行ssh-keygen -t rsa -b 4096 -C “your_emailexample.com” # 将本地公钥~/.ssh/id_rsa.pub内容上传到服务器的deployer用户 # 在服务器上切换到deployer用户并创建.ssh目录 sudo su - deployer mkdir -p ~/.ssh chmod 700 ~/.ssh # 将你的公钥内容写入authorized_keys文件 echo “你的公钥字符串” ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys # 退出deployer用户回到root或你自己的登录用户 exit # 编辑SSH服务配置文件禁用密码登录谨慎操作确保密钥登录已成功 sudo vim /etc/ssh/sshd_config # 找到以下行并修改 # PasswordAuthentication yes 改为 PasswordAuthentication no # PubkeyAuthentication yes 确保为yes # 重启SSH服务使配置生效 sudo systemctl restart sshd实操心得在禁用密码登录前务必在另一个终端窗口用密钥测试新用户deployer能否成功登录。否则一旦配置错误你可能被锁在服务器外面。另外建议修改SSH默认端口22可以减少自动化攻击脚本的扫描但这属于进阶安全配置初期可以不做。3. 核心环境搭建Docker与依赖安装基础系统准备好后我们开始安装核心工具。现代应用部署Docker几乎是必需品它带来的环境一致性是无可替代的。3.1 Docker引擎安装与配置Docker的安装其实非常简单但需要注意版本和源的选择。我们使用Docker官方提供的安装脚本这是最可靠的方式# 1. 卸载旧版本如果是全新系统可跳过 sudo apt-get remove docker docker-engine docker.io containerd runc # 2. 安装依赖包允许apt通过HTTPS使用仓库 sudo apt-get update sudo apt-get install -y \ ca-certificates \ curl \ gnupg \ lsb-release # 3. 添加Docker官方GPG密钥 sudo mkdir -p /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg # 4. 设置Docker稳定版仓库 echo \ “deb [arch$(dpkg --print-architecture) signed-by/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable” | sudo tee /etc/apt/sources.list.d/docker.list /dev/null # 5. 安装Docker引擎、命令行工具和容器运行时 sudo apt-get update sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin安装完成后验证Docker是否运行sudo systemctl status docker # 应该看到 active (running) 状态 # 运行一个测试容器 sudo docker run hello-world默认情况下运行Docker命令需要sudo权限。为了方便我们可以将当前用户deployer加入docker用户组这样就不用每次都加sudo了sudo usermod -aG docker $USER # 注意执行此命令后你需要完全退出当前SSH会话并重新登录用户组变更才会生效。 # 重新登录后运行 docker ps 测试应该可以正常执行而不需要sudo。常见问题与排查如果你在安装后遇到类似“Cannot connect to the Docker daemon”的错误通常是因为Docker服务没有启动或者当前用户不在docker组。请使用sudo systemctl start docker启动服务并确认用户组已正确添加且已重新登录。3.2 Docker Compose的安装与使用场景虽然Docker可以单独运行容器但在管理多容器应用比如一个Web应用需要数据库、缓存、前端等多个服务时docker-compose或Docker Compose Plugin是更优雅的工具。它通过一个YAML文件来定义和运行多个容器。从Docker v20.10.0开始Compose已经作为插件docker-compose-plugin集成我们在上一步安装docker-compose-plugin时已经装好了。可以通过以下命令使用# 使用集成插件的方式 docker compose version # 或者使用独立的二进制文件如果安装了旧版 docker-compose --version我推荐使用新的插件方式docker compose因为它与Docker CLI集成更好版本管理也更简单。在后续的部署中我们将使用它来编排我们的应用服务栈。3.3 其他可能需要的依赖根据你的项目类型可能还需要在宿主机安装一些基础工具Git用于拉取代码。sudo apt install -y gitNode.js / Python / Java原则上如果你的应用完全容器化了这些运行时环境都应该封装在Docker镜像里宿主机可以不装。但有时为了执行一些构建脚本或管理任务安装一个也无妨。建议使用版本管理工具如nvmNode、pyenvPython来安装避免污染系统环境。Nginx作为反向代理服务器。它通常直接安装在宿主机上负责将外部HTTP/HTTPS请求转发到内部Docker容器中的应用。sudo apt install -y nginx。我们会在部署环节详细配置它。4. 项目容器化编写Dockerfile与Compose文件环境就绪现在进入核心环节让你的项目能在Docker中运行。这需要为你的应用创建一个“蓝图”——Dockerfile以及一个“编排手册”——docker-compose.yml。4.1 Dockerfile深度解析以Python Flask应用为例假设我们有一个简单的Python Flask应用项目结构如下myapp/ ├── app.py # Flask主程序 ├── requirements.txt # Python依赖列表 ├── Dockerfile # Docker镜像构建文件 └── docker-compose.yml # 服务编排文件app.py内容from flask import Flask app Flask(__name__) app.route(‘/’) def hello(): return ‘Hello, Docker World!’ if __name__ ‘__main__’: app.run(host‘0.0.0.0’, port5000)requirements.txt内容Flask2.3.3现在我们来编写Dockerfile它定义了如何从零开始构建一个包含我们应用的镜像# 第一阶段构建阶段可选用于多阶段构建减小最终镜像体积 # 使用官方Python轻量级镜像作为构建环境 FROM python:3.11-slim as builder WORKDIR /app # 将依赖文件复制到工作目录 COPY requirements.txt . # 安装依赖到虚拟环境或特定目录这里我们安装到 /usr/local RUN pip install --no-cache-dir --user -r requirements.txt # 第二阶段运行阶段 # 使用更小的基础镜像只包含运行环境 FROM python:3.11-slim WORKDIR /app # 从构建阶段拷贝已安装的Python包 COPY --frombuilder /root/.local /root/.local # 确保脚本能找到这些包 ENV PATH/root/.local/bin:$PATH # 复制应用代码 COPY . . # 声明容器运行时暴露的端口Flask默认5000 EXPOSE 5000 # 定义容器启动时执行的命令 CMD [“python”, “app.py”]关键点解析多阶段构建FROM ... as builder和COPY --frombuilder是多阶段构建的语法。目的是在第一个“构建”镜像中安装依赖、编译代码等然后将仅需要的运行产物复制到第二个更小的“运行”镜像中。这能显著减少最终镜像的体积从约300MB的构建镜像减少到约100MB的运行镜像提升拉取和部署速度。基础镜像选择python:3.11-slim比python:3.11体积小因为它移除了许多非必要的通用工具。对于生产环境-alpine版本基于Alpine Linux更小但可能遇到某些依赖的兼容性问题需测试。稳妥起见-slim是很好的平衡点。WORKDIR设置工作目录后续的COPY、RUN、CMD命令都会在这个目录下执行。COPY将宿主机文件复制到镜像内。COPY . .把当前目录所有文件复制到镜像的/app目录。注意通常我们会通过.dockerignore文件排除node_modules、.git、__pycache__等不需要的文件避免它们增大镜像。RUN在构建镜像时执行的命令比如安装软件包。EXPOSE声明容器打算使用的端口这是一个文档性质的元数据实际端口映射在运行容器时通过-p参数指定。CMD容器启动时执行的默认命令。一个Dockerfile中只能有一个CMD。它有两种格式shell格式CMD python app.py和exec格式CMD [“python”, “app.py”]。推荐使用exec格式它能正确处理信号如SIGTERM使容器能优雅停止。4.2 Docker Compose编排整合数据库与网络一个完整的应用往往不止一个服务。假设我们的Flask应用需要使用PostgreSQL数据库。使用Docker Compose可以轻松定义和管理这两个服务。docker-compose.yml文件version: ‘3.8’ # 指定Compose文件格式版本 services: # Web应用服务 web: build: . # 使用当前目录的Dockerfile构建镜像 container_name: myapp-web ports: - “5000:5000” # 宿主机端口:容器端口 environment: - DATABASE_URLpostgresql://user:passworddb:5432/mydb depends_on: - db # 声明依赖确保db服务先启动 networks: - app-network # 健康检查确保应用真正就绪 healthcheck: test: [“CMD”, “curl”, “-f”, “http://localhost:5000”] interval: 30s timeout: 10s retries: 3 start_period: 40s # 重启策略除非手动停止否则总是重启 restart: unless-stopped # 数据库服务 db: image: postgres:15-alpine # 直接使用官方镜像无需构建 container_name: myapp-db environment: POSTGRES_USER: user POSTGRES_PASSWORD: password POSTGRES_DB: mydb volumes: # 将数据库数据持久化到宿主机避免容器删除后数据丢失 - postgres_data:/var/lib/postgresql/data networks: - app-network restart: unless-stopped # 定义命名数据卷用于持久化数据 volumes: postgres_data: # 定义自定义网络使服务间可以通过服务名通信如web服务中使用的‘db’ networks: app-network: driver: bridge编排逻辑详解服务定义services下每个键如webdb代表一个容器服务。网络自定义的app-network让web和db容器处于同一网络web容器可以直接用db这个服务名访问数据库容器无需知道其IP地址。这是Docker Compose提供的服务发现机制。数据卷volumes定义了命名卷postgres_data并挂载到数据库容器的数据目录。这样即使db容器被销毁重建数据依然保留在宿主机上实现了数据持久化。环境变量通过environment传递配置如数据库连接字符串。注意将密码明文写在Compose文件中不安全对于生产环境应使用Docker secrets或外部配置文件如.env文件来管理敏感信息。依赖与健康检查depends_on确保启动顺序但注意它只控制启动顺序不保证服务已就绪。结合healthcheck可以更好地实现“等待依赖服务就绪”的逻辑。重启策略restart: unless-stopped意味着容器退出时除非被手动停止会自动重启提高了服务的自愈能力。5. 部署上线配置、运行与反向代理5.1 在服务器上启动项目将你的项目代码包含Dockerfile和docker-compose.yml上传到服务器。可以通过Git克隆或者使用scp命令上传。# 在服务器上假设使用deployer用户 cd ~ git clone 你的项目仓库地址 myapp cd myapp现在使用Docker Compose一键构建和启动所有服务# 在项目目录下执行 docker compose up -d-d参数代表“detached”模式让容器在后台运行。执行后你会看到Docker拉取基础镜像如postgres:15-alpine、构建你的应用镜像并启动容器。使用以下命令查看状态# 查看所有运行中的容器 docker compose ps # 查看容器日志-f 可以持续跟踪 docker compose logs -f web如果一切顺利你的Flask应用现在已经在容器内运行并映射到了宿主机的5000端口。但此时外网还无法通过服务器的IP和5000端口访问因为云服务器的安全组默认只开放了少数端口如22 80 443。5.2 配置Nginx反向代理与HTTPS直接让应用监听公网端口如5000是不安全且不专业的。我们应该使用Nginx作为反向代理它负责接收80HTTP和443HTTPS端口的请求然后转发给内部容器的5000端口。此外Nginx还能处理静态文件、负载均衡、SSL终止等。首先安装Nginx如果之前没装sudo apt install -y nginx然后为我们的应用创建一个Nginx站点配置文件。通常放在/etc/nginx/sites-available/目录下然后创建一个符号链接到/etc/nginx/sites-enabled/。sudo vim /etc/nginx/sites-available/myapp写入以下配置假设你的域名是example.com服务器IP是your_server_ipserver { listen 80; server_name example.com www.example.com; # 你的域名 # 如果暂时没有域名也可以用服务器IP但建议尽快配置域名 # server_name your_server_ip; location / { # 将请求代理到Docker Compose中web服务的5000端口 # ‘web’是Compose中定义的服务名在Docker网络内可解析 proxy_pass http://web:5000; # 或者如果Nginx在宿主机容器映射了端口也可以用 localhost:5000 # proxy_pass http://127.0.0.1:5000; # 传递重要的请求头信息 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } # 可选静态文件由Nginx直接处理效率更高 # location /static/ { # alias /path/to/your/static/files; # expires 1y; # add_header Cache-Control “public, immutable”; # } }启用该配置并测试# 创建符号链接 sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/ # 测试Nginx配置语法是否正确 sudo nginx -t # 如果显示“syntax is ok”则重载Nginx使配置生效 sudo systemctl reload nginx现在你应该可以通过服务器的IP地址HTTP协议访问到你的应用了。但HTTP是不安全的我们需要配置HTTPS。5.3 使用Let‘s Encrypt获取免费SSL证书获取和部署SSL证书最方便免费的工具是Certbot。以下是使用Certbot为Nginx自动获取并配置证书的步骤# 安装Certbot和Nginx插件 sudo apt install -y certbot python3-certbot-nginx # 运行Certbot它会自动读取你的Nginx配置列出server_name并交互式地帮你获取和配置证书 sudo certbot --nginx按照提示操作输入邮箱用于接收安全通知、同意服务条款、选择要为哪个域名启用HTTPS它会自动检测server_name。Certbot会自动完成以下工作向Let‘s Encrypt申请证书。验证你对域名的所有权通过HTTP挑战Certbot会临时修改你的Nginx配置。下载证书并保存到/etc/letsencrypt/live/your_domain/目录。自动修改你的Nginx配置文件添加443端口监听和SSL相关配置并设置HTTP到HTTPS的301重定向。完成后你的Nginx配置会被Certbot更新现在通过https://your_domain就能安全地访问你的应用了。Certbot还会自动设置一个定时任务cron job来续期证书证书有效期90天续期是自动的。5.4 配置云服务器安全组最后别忘了在云服务商的控制台配置安全组防火墙规则开放80端口HTTP和443端口HTTPS的入站流量允许所有人访问源IP设为0.0.0.0/0。关闭5000端口的公网访问如果之前临时开放过。现在所有流量都应通过Nginx的80/443端口进入。确保22端口SSH的源IP最好限制为你自己的办公或家庭IP地址以增强安全性。6. 运维、监控与持续集成初探项目上线不是终点而是运维的起点。这里分享几个让线上服务更稳健的实用技巧。6.1 基础运维命令与日志查看掌握几个关键的Docker命令能让你在出现问题时快速定位# 查看容器状态 docker compose ps # 或 docker ps # 查看特定容器的实时日志 docker compose logs -f web # 查看最近100行日志 docker compose logs --tail100 web # 进入正在运行的容器内部用于调试 docker compose exec web bash # 或 docker exec -it myapp-web bash # 停止所有服务 docker compose down # 停止并删除所有容器、网络数据卷默认保留 docker compose down -v # 加上-v会删除在Compose文件中定义的匿名卷谨慎使用 # 重新构建镜像并启动代码更新后 docker compose up -d --build实操心得养成查看日志的习惯。将应用日志输出到标准输出stdout和标准错误stderrDocker就能捕获它们并通过docker logs查看。避免将日志只写在容器内的文件里那样查看起来很麻烦。6.2 简单的监控与健康检查除了Docker Compose中定义的healthcheck我们还可以添加一些简单的监控使用cAdvisor监控容器资源Google开源的容器监控工具可以提供一个Web界面查看所有容器的CPU、内存、网络、文件系统使用情况。# 快速启动一个cAdvisor容器 docker run \ --volume/:/rootfs:ro \ --volume/var/run:/var/run:ro \ --volume/sys:/sys:ro \ --volume/var/lib/docker/:/var/lib/docker:ro \ --volume/dev/disk/:/dev/disk:ro \ --publish8080:8080 \ --detachtrue \ --namecadvisor \ --privileged \ --device/dev/kmsg \ gcr.io/cadvisor/cadvisor:latest访问http://your_server_ip:8080即可查看监控面板。注意生产环境请为其配置访问权限不要直接暴露在公网。配置日志轮转Docker容器日志默认会一直增长可能占满磁盘。可以配置Docker守护进程的日志驱动和轮转策略。编辑/etc/docker/daemon.json如果不存在则创建{ “log-driver”: “json-file”, “log-opts”: { “max-size”: “10m”, “max-file”: “3” } }然后重启Docker服务sudo systemctl restart docker。这会将每个容器的日志文件大小限制在10MB最多保留3个文件。6.3 迈向自动化GitHub Actions持续集成/部署CI/CD思路手动登录服务器执行git pull和docker compose up --build虽然可行但效率低且易出错。一个简单的自动化部署流程可以通过GitHub Actions实现。其核心思想是当代码推送到GitHub仓库的特定分支如main时自动触发一个工作流这个工作流会在GitHub提供的虚拟机上测试你的代码。通过SSH连接到你的服务器。拉取最新代码。重新构建并启动Docker容器。你需要做的是在服务器上生成一个专用于部署的SSH密钥对并将公钥添加到服务器的~/.ssh/authorized_keys文件中。将私钥以加密Secret的形式存储到你的GitHub仓库设置中Settings - Secrets and variables - Actions。在项目根目录创建.github/workflows/deploy.yml文件编写工作流脚本。这是一个极简的示例工作流name: Deploy to Server on: push: branches: [ main ] jobs: deploy: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkoutv3 - name: Deploy via SSH uses: appleboy/ssh-actionv0.1.5 with: host: ${{ secrets.SERVER_HOST }} # 你的服务器IP username: ${{ secrets.SERVER_USER }} # 部署用户如deployer key: ${{ secrets.SSH_PRIVATE_KEY }} # 服务器私钥 script: | cd /home/deployer/myapp git pull origin main docker compose down docker compose up -d --build注意事项这只是一个起点。真实的CI/CD流水线应该包含测试阶段、多环境开发、测试、生产、更安全的密钥管理、回滚机制等。但对于个人项目或小团队这个简单的自动化已经能带来巨大的效率提升。7. 常见问题与排查技巧实录即使流程再清晰实际操作中总会遇到各种“坑”。下面是我总结的一些高频问题及解决方法。7.1 Docker相关错误问题1docker: Cannot connect to the Docker daemon. Is the docker daemon running on this host?原因Docker服务未启动或当前用户没有权限不在docker用户组。排查sudo systemctl status docker检查服务状态。sudo usermod -aG docker $USER确保用户已加入docker组并重新登录SSH会话。尝试用sudo docker ps如果成功则是权限问题。问题2ERROR: failed to solve: ... no matching manifest for linux/amd64 in the manifest list entries原因你正在一个ARM架构如苹果M系列芯片Mac的机器上构建镜像但基础镜像没有提供ARM版本或者你指定了错误的平台。解决如果是本地开发可以使用--platform参数docker build --platform linux/amd64 -t myapp .强制构建amd64镜像。检查你使用的基础镜像如node:18是否支持多平台。可以在Docker Hub上查看其标签详情。对于生产服务器确保服务器架构通常是x86_64/amd64与构建镜像的平台一致。问题3容器启动后立即退出Exited (0) 或 Exited (1)原因容器内主进程CMD或ENTRYPOINT指定的命令执行完毕或出错退出。排查docker compose logs service_name查看容器日志这是最快的方法。检查Dockerfile中的CMD命令是否正确特别是路径和参数。对于Web应用确保应用绑定到了0.0.0.0而不是127.0.0.1后者只在容器内可访问。可以尝试以交互模式运行容器来调试docker run -it --entrypoint/bin/bash your_image_name然后手动执行命令看报错。7.2 网络与连接问题问题4应用在容器内运行正常但通过宿主机IP:端口无法访问排查步骤检查端口映射docker compose ps或docker ps查看PORTS列确认映射关系如0.0.0.0:5000-5000/tcp。检查防火墙云服务器安全组确保已放行该端口如5000。宿主机防火墙如UFWsudo ufw status查看状态如果启用需放行端口sudo ufw allow 5000。检查应用监听地址确保应用监听的是0.0.0.0。在Flask中是app.run(host‘0.0.0.0’)在Node.js Express中是app.listen(port, ‘0.0.0.0’)。在宿主机内部测试在服务器上运行curl http://localhost:5000或curl http://127.0.0.1:5000。如果宿主机能通但外网不通问题大概率在安全组或网络ACL。问题5Nginx配置后出现502 Bad Gateway原因Nginx无法将请求正确代理到后端应用。排查检查Nginx错误日志sudo tail -f /var/log/nginx/error.log。确认proxy_pass地址是否正确。如果Nginx和Docker容器都在宿主机且容器端口映射到了宿主机可以用http://127.0.0.1:5000如果使用了Docker Compose的自定义网络并且Nginx也作为Compose中的一个服务则可以用服务名http://web:5000。但宿主机上的Nginx无法直接通过Docker Compose的服务名访问容器这是最常见的错误。解决方案是要么将后端应用的端口映射到宿主机如5000:5000然后Nginx代理到127.0.0.1:5000要么将Nginx也容器化并加入到同一个Docker Compose网络中。确认后端应用容器是否正在运行docker compose ps。在后端应用容器内检查应用是否真的在监听docker compose exec web netstat -tlnp或使用ss -tlnp。7.3 资源与性能问题问题6服务器磁盘空间不足原因Docker会占用大量空间包括未使用的镜像none、停止的容器、构建缓存和日志。清理命令# 删除所有已停止的容器 docker container prune # 删除所有未被使用的镜像谨慎会删除所有未被容器引用的镜像 docker image prune -a # 删除所有未被使用的数据卷非常谨慎会删除数据 # docker volume prune # 一键清理所有未使用的资源容器、镜像、网络、构建缓存 docker system prune -a定期执行docker system prune可以释放不少空间。对于日志如前所述配置日志轮转策略。问题7容器内应用性能不佳或出现内存不足OOM排查使用docker stats命令实时查看各容器的CPU、内存使用情况。如果某个容器内存持续增长可能是应用内存泄漏需要结合应用本身的监控和日志分析。可以为容器设置资源限制在docker-compose.yml中services: web: # ... deploy: resources: limits: cpus: ‘0.5’ # 限制使用0.5个CPU核心 memory: 512M # 限制内存为512MB reservations: memory: 256M # 启动时预留256MB内存注意deploy部分通常用于Docker Swarm模式在单机Compose中可以使用resources顶级键Compose v2格式支持。更直接的方式是使用cpus和mem_limit等旧参数取决于版本但建议查阅对应版本的Compose文档。走完这一整套流程从一台裸机到服务上线你应该对服务器部署有了一个立体而扎实的理解。这套以Docker为核心的部署模式其优势在于环境标准化和流程可重复。一旦你的Dockerfile和docker-compose.yml定型在任何一台安装了Docker的机器上都能以极小的代价复现出完全一致的环境。这不仅是运维的便利更是团队协作和持续交付的基石。下次当你需要部署新项目或者迁移服务器时你会发现大部分工作只是复制粘贴和微调配置那种一切尽在掌控的感觉才是工程师最大的乐趣所在。