嘿,朋友!想知道如何用 Docker 部署一整套 Web 应用吗?别担心,这篇教程就是为你准备的。咱们会用大白话,一步步带你从零开始,把一个完整的 Web 应用栈(前端、后端、数据库)装进 Docker 容器里,并让它们愉快地协同工作。
为什么选择 Docker?
想象一下,你精心开发了一个网站,在你的电脑上跑得飞快。但一部署到服务器,就各种报错,什么环境不一致、依赖缺失……是不是很头大?
Docker 就是解决这个问题的神器。它能把你的应用以及它需要的所有东西(比如代码、运行时、库、环境变量)都打包到一个叫做“容器”的小盒子里。这个小盒子可以随处运行,无论是在你的笔记本、测试服务器还是云端,都能保证环境的一致性。 这样一来,“在我电脑上明明是好的”这种话,就可以彻底成为历史了。
我们要搭建什么样的 Web 应用栈?
为了让教程更具代表性,我们选择一个非常流行的技术栈:PERN。
- PostgreSQL:一个功能强大、稳定可靠的开源关系型数据库。
- Express.js:一个简洁、灵活的 Node.js Web 应用框架,用来搭建我们的后端 API。
- React:一个用于构建用户界面的 JavaScript 库,是目前最火的前端框架之一。
- Node.js:一个让 JavaScript 可以在服务器端运行的环境。
这个组合非常经典,能够应对各种复杂的 Web 应用场景。
实战开始:一步步 Docker 化你的 PERN 应用
好了,理论说得差不多了,咱们卷起袖子开始干活吧!
准备工作
在开始之前,请确保你的电脑上已经安装了 Docker 和 Docker Compose。你可以从 Docker 官网轻松获取它们。
项目结构
为了让项目清晰明了,我们先规划一下目录结构:
pern-docker-app/
├── backend/
│ ├── Dockerfile
│ ├── package.json
│ └── server.js
├── frontend/
│ ├── Dockerfile
│ ├── package.json
│ └── src/
│ └── App.js
└── docker-compose.yml
-
backend
目录存放我们的 Express 后端代码。 -
frontend
目录存放我们的 React 前端代码。 -
docker-compose.yml
是一个非常重要的文件,它用来定义和编排我们的多个 Docker 容器。
第一步:后端服务 Docker 化
我们的后端服务是一个简单的 Express 应用,它会提供一个 API 接口。
backend/server.js
const express = require('express');
const { Pool } = require('pg');
const app = express();
const port = 3001;
const pool = new Pool({
user: 'myuser',
host: 'db', // 这里我们直接使用 service 的名字
database: 'mydatabase',
password: 'mypassword',
port: 5432,
});
app.get('/api/users', async (req, res) => {
try {
const result = await pool.query('SELECT * FROM users');
res.json(result.rows);
} catch (err) {
console.error(err);
res.status(500).send("Error connecting to database");
}
});
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});
backend/package.json
{
"name": "backend",
"version": "1.0.0",
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"dependencies": {
"express": "^4.17.1",
"pg": "^8.7.1"
}
}
接下来,我们为后端服务编写一个 Dockerfile
。Dockerfile
就像一个菜谱,告诉 Docker 如何一步步构建我们的应用镜像。
backend/Dockerfile
# 选择一个官方的 Node.js 镜像作为基础
FROM node:16
# 设置工作目录
WORKDIR /app
# 拷贝 package.json 和 package-lock.json
COPY package*.json ./
# 安装依赖
RUN npm install
# 拷贝所有应用代码
COPY . .
# 暴露端口
EXPOSE 3001
# 启动应用的命令
CMD ["npm", "start"]
第二步:前端服务 Docker 化
前端是一个简单的 React 应用,它会从后端获取数据显示出来。
frontend/src/App.js
import React, { useState, useEffect } from 'react';
function App() {
const [users, setUsers] = useState([]);
useEffect(() => {
fetch('/api/users')
.then(res => res.json())
.then(data => setUsers(data));
}, []);
return (
<div>
<h1>Users</h1>
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
</div>
);
}
export default App;
frontend/package.json
(这是一个简化的 package.json
,你可以使用 create-react-app
来生成一个完整的项目)
{
"name": "frontend",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "4.0.3"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build"
}
}
现在,为前端应用编写 Dockerfile
。这里我们使用一个“多阶段构建”的技巧,这样可以大大减小最终镜像的体积。
frontend/Dockerfile
# --- 构建阶段 ---
FROM node:16 as build
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# --- 生产阶段 ---
FROM nginx:alpine
# 从构建阶段拷贝构建好的静态文件
COPY /app/build /usr/share/nginx/html
# 暴露端口
EXPOSE 80
# 启动 Nginx
CMD ["nginx", "-g", "daemon off;"]
第三步:使用 Docker Compose 编排服务
单个的容器是孤立的,我们需要一种方式让它们互相通信。Docker Compose 就是为此而生的。 它可以让我们在一个 YAML 文件中定义和管理多个容器的应用。
docker-compose.yml
version: '3.8'
services:
# 后端服务
backend:
build: ./backend
ports:
- "3001:3001"
depends_on:
- db
environment:
- DATABASE_URL=postgres://myuser:mypassword@db:5432/mydatabase
# 前端服务
frontend:
build: ./frontend
ports:
- "3000:80"
depends_on:
- backend
# 数据库服务
db:
image: postgres:14-alpine
restart: always
environment:
- POSTGRES_USER=myuser
- POSTG-RES_PASSWORD=mypassword
- POSTGRES_DB=mydatabase
volumes:
- db-data:/var/lib/postgresql/data
volumes:
db-data:
在这个 docker-compose.yml
文件中,我们定义了三个服务:backend
、frontend
和 db
。
-
build
指令告诉 Docker Compose 去哪里找Dockerfile
来构建镜像。 -
ports
指令将容器的端口映射到主机的端口。 -
depends_on
确保服务按正确的顺序启动(比如,后端服务依赖于数据库服务)。 -
environment
用来设置环境变量。 -
volumes
用来持久化数据库的数据,这样即使容器被删除了,数据也不会丢失。
第四步:启动整个应用栈
现在,万事俱备,只欠东风!在项目的根目录下,打开终端,运行以下命令:
docker-compose up --build
--build
参数会强制 Docker Compose 重新构建镜像。第一次启动时,Docker 会下载所有需要的基础镜像并构建你的应用镜像,所以可能会需要一些时间。
当所有的服务都成功启动后,你就可以在浏览器中访问 http://localhost:3000
,看到你的 React 应用了!它会向后端发起请求,后端再从 PostgreSQL 数据库中查询数据,最后将数据返回给前端展示。
总结
恭喜你!你已经成功地使用 Docker 部署了一个完整的 Web 应用栈。通过这个过程,你应该已经体会到了 Docker 的强大之处:
- 环境一致性:告别“在我电脑上明明是好的”的烦恼。
- 简化部署:一条命令就能启动整个应用栈。
- 服务隔离:每个服务都在自己的容器中运行,互不干扰。
- 易于扩展:可以轻松地为每个服务增加更多的容器实例。
希望这篇教程能帮助你打开 Docker 的大门。Docker 的世界还有很多有趣的东西等着你去探索,比如 Docker Swarm 和 Kubernetes,它们可以帮助你管理更大规模的容器集群。 祝你在容器化的世界里玩得开心!