Docker容器化部署教程实战项目开发教程
在现代软件开发与运维领域,容器化技术已成为提升效率、保证环境一致性的核心工具。Docker作为容器技术的代表,极大地简化了应用的打包、分发和部署流程。本教程将通过一个实战项目,手把手带你完成从零开始的容器化部署。我们将以一个典型的Vue.js前端应用结合后端API服务的项目为例,涵盖Vue.js组件开发、数据库优化以及最终的Docker化部署全流程。无论你是开发人员还是运维工程师,都能从中获得实用的知识和技能。
项目概述与技术栈
我们的实战项目是一个简单的“任务管理”应用。它包含以下核心部分:
- 前端:使用Vue.js 3构建,包含任务列表、新增、编辑、删除等组件。
- 后端API:使用Node.js (Express框架) 编写,提供RESTful接口。
- 数据库:使用PostgreSQL存储任务数据。
- 部署目标:将所有服务(前端、后端、数据库)通过Docker Compose进行编排和部署。
本教程将重点串联三个关键技术点:Vue.js的组件化开发、数据库表设计与查询优化,以及最终的Docker容器化。
一、Vue.js组件开发与项目搭建
前端是用户交互的入口,良好的组件设计是项目可维护性的基础。我们使用Vue CLI快速搭建项目。
1.1 创建项目与基础组件
首先,使用Vue CLI创建项目,并安装必要依赖(如Vue Router、Axios)。
vue create task-manager-frontend
cd task-manager-frontend
npm install axios
我们创建两个核心组件:TaskList.vue和TaskForm.vue。
1.2 TaskList.vue 组件示例
这个组件负责展示任务列表,并处理任务的完成状态切换。我们使用composition API。
任务列表
-
{{ task.title }}
这个组件展示了Vue.js的核心特性:响应式数据(ref)、生命周期钩子(onMounted)以及与后端API的交互。组件职责单一,逻辑清晰。
二、后端API与数据库优化实践
后端服务使用Node.js和Express,数据库选用PostgreSQL。我们将关注API设计和数据库层面的优化。
2.1 数据库设计与初始化
首先,设计一个简单的tasks表。创建SQL文件init.sql:
CREATE TABLE IF NOT EXISTS tasks (
id SERIAL PRIMARY KEY,
title VARCHAR(255) NOT NULL,
description TEXT,
completed BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
-- 为经常查询的字段创建索引以优化查询速度
CREATE INDEX IF NOT EXISTS idx_tasks_completed ON tasks(completed);
CREATE INDEX IF NOT EXISTS idx_tasks_created_at ON tasks(created_at);
数据库优化要点:
- 使用
SERIAL自增主键。 - 为布尔字段
completed和时间字段created_at创建索引。当应用数据量增大时,根据completed状态或创建时间进行筛选的查询速度将得到显著提升。 - 添加
updated_at字段便于追踪。
2.2 实现优化后的API服务
使用Express和node-postgres(pg)库连接数据库。关键代码片段如下:
const express = require('express');
const { Pool } = require('pg');
const app = express();
app.use(express.json());
// 数据库连接配置(后续会移到环境变量中)
const pool = new Pool({
user: 'postgres',
host: 'localhost',
database: 'taskdb',
password: 'yourpassword',
port: 5432,
});
// 获取所有任务 - 使用索引优化的查询
app.get('/api/tasks', async (req, res) => {
try {
// 示例:按创建时间倒序排列,充分利用索引
const result = await pool.query('SELECT * FROM tasks ORDER BY created_at DESC');
res.json(result.rows);
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Internal server error' });
}
});
// 创建新任务
app.post('/api/tasks', async (req, res) => {
const { title, description } = req.body;
try {
const result = await pool.query(
'INSERT INTO tasks (title, description) VALUES ($1, $2) RETURNING *',
[title, description]
);
res.status(201).json(result.rows[0]);
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Internal server error' });
}
});
// 其他API:GET by ID, PUT, DELETE 略...
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
优化点:在GET /api/tasks接口中,我们使用ORDER BY created_at DESC,这能有效利用之前创建的idx_tasks_created_at索引,避免全表扫描。
三、Docker容器化部署实战
这是本教程的核心。我们将为前端、后端和数据库分别创建Docker镜像,并使用Docker Compose编排它们。
3.1 为每个服务编写Dockerfile
后端Dockerfile (backend/Dockerfile):
# 使用官方Node.js运行时作为父镜像
FROM node:18-alpine
# 设置工作目录
WORKDIR /usr/src/app
# 复制package文件并安装依赖
COPY package*.json ./
RUN npm ci --only=production
# 复制应用源代码
COPY . .
# 暴露端口
EXPOSE 3000
# 定义环境变量(数据库连接信息将由Docker Compose覆盖)
ENV PGUSER=postgres
ENV PGHOST=db
ENV PGDATABASE=taskdb
ENV PGPASSWORD=changeme
# 启动命令
CMD ["node", "server.js"]
前端Dockerfile (frontend/Dockerfile):
# 构建阶段
FROM node:18-alpine as build-stage
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# 生产阶段 - 使用Nginx提供静态文件
FROM nginx:stable-alpine as production-stage
COPY --from=build-stage /app/dist /usr/share/nginx/html
# 可以复制自定义的nginx配置(如果需要处理Vue Router的history模式)
# COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
这里我们使用了多阶段构建,最终镜像只包含Nginx和构建好的静态文件,非常轻量。
3.2 使用Docker Compose编排服务
创建docker-compose.yml文件,这是整个应用部署的蓝图。
version: '3.8'
services:
# PostgreSQL数据库服务
db:
image: postgres:15-alpine
container_name: task_db
restart: always
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: securepassword123
POSTGRES_DB: taskdb
volumes:
- postgres_data:/var/lib/postgresql/data
- ./backend/init.sql:/docker-entrypoint-initdb.d/init.sql # 初始化SQL
ports:
- "5432:5432"
networks:
- app-network
# 后端API服务
backend:
build: ./backend
container_name: task_backend
restart: always
depends_on:
- db
environment:
PGUSER: postgres
PGHOST: db # 使用服务名作为主机名,这是Docker Compose的网络特性
PGDATABASE: taskdb
PGPASSWORD: securepassword123
PORT: 3000
ports:
- "3000:3000"
networks:
- app-network
# 前端Nginx服务
frontend:
build: ./frontend
container_name: task_frontend
restart: always
depends_on:
- backend
ports:
- "8080:80"
networks:
- app-network
# 定义卷和网络
volumes:
postgres_data:
networks:
app-network:
driver: bridge
关键配置解析:
- 网络:所有服务加入自定义的
app-network,使得容器间可以通过服务名(如db,backend)直接通信。 - 数据持久化:数据库数据通过命名卷
postgres_data持久化,即使容器删除数据也不会丢失。 - 初始化:通过挂载
init.sql到/docker-entrypoint-initdb.d/目录,PostgreSQL容器在首次启动时会自动执行该SQL文件来创建表和索引。 - 依赖:使用
depends_on控制启动顺序,确保数据库先于后端启动,后端先于前端启动。
3.3 构建与启动
在包含docker-compose.yml的目录下,执行一条命令即可启动整个应用栈:
docker-compose up -d --build
命令解释:
up:创建并启动所有服务。-d:在后台运行(守护进程模式)。--build:在启动前重新构建镜像。
启动后,你可以通过以下方式访问:
- 前端应用:
http://localhost:8080 - 后端API:
http://localhost:3000/api/tasks
使用docker-compose logs -f可以查看所有容器的实时日志,便于调试。
总结
通过本实战教程,我们完整地走通了一个现代Web应用的开发与部署流程:
- 我们使用Vue.js开发了结构清晰、可复用的前端组件,实现了与后端的数据交互。
- 在数据库优化层面,我们通过合理的表设计和为高频查询字段创建索引,为应用性能打下了坚实基础。
- 最后,我们利用Docker和Docker Compose,将前端、后端和数据库三个独立服务完美地容器化。通过编写
Dockerfile和docker-compose.yml,我们定义了可重复、环境一致的部署方案,实现了“一次构建,处处运行”的目标。
这种容器化的部署方式,不仅简化了本地开发环境的搭建,更使得应用能够轻松迁移到任何支持Docker的云服务器或CI/CD流水线中,极大地提升了开发和运维效率。你可以以此项目为模板,将其扩展到更复杂的微服务架构中。




