那是19年,正在上大三的柏成用一堆屎山代码从零搭建了一款个人博客,对于一个刚刚入门的前端崽来说,想要部署在云服务器上,需要安装mysql,redis,配置环境变量 ....... 过五关斩六将,每一步都踩了好多好多坑
服务器到期后,柏成也没再续费.......
21年,柏成又想重启个人博客,哐哐哐一顿操作,顺利上线,还精挑细选了域名 burc.com.cn
服务器到期后,柏成也没再续费.......
25年初,柏成又想重启个人博客,问题来了,那么能不能一行命令,自动安装所有依赖,完成部署操作呢?
答案是:可以!docker 闪亮登场
docker 核心概念
我们先了解下 docker的几个核心概念:镜像、容器、仓库、Dockerfile
- 镜像(Image): 镜像是容器的"模板",是将软件环境打包好的模板,用来创建容器的,一个镜像可以创建多个容器
- 容器(Container): 应用程序及其依赖环境的运行实例,启动一个镜像就是一个容器,容器与容器之间相互隔离,并且互不影响, 可以简单理解为一个"轻量级、可移植的微型操作系统"
- 仓库(Registry) : 类似于代码托管平台(如 GitHub),我们可以制作镜像然后 push 推送到云端的仓库,也可以从仓库 pull 拉取镜像
- Dockerfile: 包含了一系列指令和配置,用于描述如何组装一个 docker镜像,相当于列出了镜像所需的原材料。通过 Dockerfile,你可以自动化地构建镜像,确保在不同的环境中都可以复现相同的容器
下面这张图展示了他们之间的关系

docker 基础操作
这里就不做过多介绍
docker-compose
通过一个单独的 YAML 文件定义和管理多个 Docker 容器的配置
统一配置 :通过一个 docker-compose.yml
文件,可以同时定义多个服务及其依赖关系(例如数据库、缓存、反向代理等)
一键管理:只需一条命令即可启动、停止所有服务
- 启动:
docker-compose up -d
- 停止:
docker-compose down
我们先对docker-compose.yml
有个大体认知,至于YAML文件里的内容是什么,最后附上源码
容器化部署实战
柏成通过 Docker 和 Docker Compose 实现了多容器化部署,包含后端服务、前端服务、数据库服务、redis服务以及 Nginx 服务,目录结构如下

前端服务(frontend)
react 文件夹下是前端 build打包的产物
Dockerfile 定义了如何构建前端镜像
powershell
# 使用官方 Nginx 镜像作为基础镜像
FROM nginx:latest
# 将当前目录的内容拷贝到 Nginx 默认的静态文件目录
COPY ./react/ /usr/share/nginx/html/
# 暴露 Nginx 默认端口
EXPOSE 80
后端服务(backend)
node 文件夹下是整个后端项目
Dockerfile 定义了如何构建后端镜像
powershell
# 使用 Node.js 构建阶段
FROM node:18
# 设置工作目录
WORKDIR /app
# 复制宿主机 ./node/目录中的文件 到容器的 /app/node/
COPY ./node/ ./
# 更换 npm 镜像源为淘宝镜像
RUN npm config set registry https://registry.npm.taobao.org/
# 禁用 SSL 证书验证(可选,只有在其他解决方法无效时使用)
RUN npm config set strict-ssl false
# 安装依赖
RUN npm install
# 暴露后端端口,这里其实没用。我们在node后端服务中暴露了5000端口,以node进程暴露的为准
# EXPOSE 5000
# 启动后端服务
CMD ["npm", "run", "prd"]
数据库服务
初始化脚本
blog.sql
是数据库初始化脚本,用于创建表和初始数据
我们在docker-compose.yml
中通过 volumes 将其映射到了 mysql容器内部 /docker-entrypoint-initdb.d/blog.sql
/docker-entrypoint-initdb.d/
是一个特殊目录,在 mysql容器初始化时,会自动执行放置在该目录下的 .sql
文件
powershell
volumes:
- ./mysql/blog.sql:/docker-entrypoint-initdb.d/blog.sql
数据持久化
mysql_data
是用于 MySQL 数据库的持久化存储挂载点
默认情况下,所有数据存储在容器的文件系统中。如果容器被删除或重新创建,数据会丢失
我们将主机上的mysql_data
目录挂载到容器内,用来持久化存储数据
当我们新增、更新 mysql数据时,mysql数据会映射到本地目录;反之当容器重启后,也会自动加载 ./mysql/mysql_data
中的文件,自动恢复数据
powershell
volumes:
- ./mysql/mysql_data:/var/lib/mysql
Nginx服务
nginx.conf
文件是 Nginx 的配置文件,用于反向代理前端和后端服务,以及提供静态资源服务
powershell
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
client_max_body_size 8M; # (设置客户端请求体最大值)
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
location / {
root html;
proxy_pass http://frontend:80; # 800 是 frontend 容器内部端口
index index.html index.htm;
}
# 配置后端 API 代理
location /api/ {
proxy_pass http://backend:5000; # 替换为你的后端服务地址,5000 是 backend 容器内部端口
# 超时设置
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# 禁用缓存
proxy_buffering off;
# 保持连接
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
docker-compose.yml
docker-compose.yml
全部源码如下
powershell
services:
nginx:
image: nginx:latest
container_name: nginx
ports:
- "80:80" # 将主机的 80 端口映射到容器的 80 端口
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf # 挂载自定义的 Nginx 配置文件
depends_on:
- frontend
- backend
networks:
- app_network
frontend:
build:
context: ./frontend # 指定前端项目 ./fronten文件夹作为构建上下文
dockerfile: Dockerfile # 指定构建镜像时使用的 Dockerfile
ports:
- "3001:80" # 将容器内的 80 端口映射到主机的 3001 端口,3001端口供外部访问
depends_on:
- backend # 指定该服务依赖 backend,确保 backend 服务先启动
networks:
- app_network
backend:
build:
context: ./backend
dockerfile: Dockerfile
ports:
- "8001:5000" # 将容器内的 5000 端口映射到主机的 8001 端口,8001端口供外部访问
depends_on:
# 后端服务依赖 mysql 和 redis 服务,确保它们先启动
mysql: # backend 服务会等待 mysql 服务的健康检查(healthcheck)通过后再启动
condition: service_healthy
redis: # backend 服务会等待 redis 服务容器启动
condition: service_started
networks:
- app_network
mysql:
image: mysql:8.0
container_name: mysql
restart: always
command: --default-authentication-plugin=mysql_native_password # 身份验证协议兼容
ports:
- "3307:3306" # 将容器内的 3306 端口(MySQL 默认端口)映射到主机的 3307 端口
environment:
MYSQL_ROOT_PASSWORD: 123456 # 设置 root用户密码
MYSQL_DATABASE: blog # 初始化时会自动创建一个名为 blog 的数据库
volumes:
# 将主机上的 ./mysql/blog.sql 文件(一个 SQL 脚本文件)挂载到容器内的 /docker-entrypoint-initdb.d/blog.sql 目录
# 特殊目录 /docker-entrypoint-initdb.d/ : 在容器初始化时,会自动执行放置在 /docker-entrypoint-initdb.d/ 目录中的 .sql 文件
# 因此,当容器第一次启动时, 执行 blog.sql 来初始化数据库表结构
- ./mysql/blog.sql:/docker-entrypoint-initdb.d/blog.sql
# 默认情况下,所有数据存储在容器的文件系统中。如果容器被删除或重新创建,数据会丢失
# 我们将主机上的./mysql/mysql_data目录 挂载到容器内,用来持久化存储数据
# 当我们通过项目向 MySQL新增、更新数据时,MySQL 数据目录会地映射到本地目录;反之当容器重启后,会自动加载 ./mysql/mysql_data中的文件,自动恢复数据
- ./mysql/mysql_data:/var/lib/mysql
healthcheck: # 定义健康检查,确保 mysql 服务在正常运行后标记为健康
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p666666"]
interval: 10s
timeout: 5s
retries: 3
networks:
- app_network
redis:
image: redis:alpine
container_name: redis
ports:
- "6379:6379"
networks:
- app_network
# 显式声明一个网络,并将服务连接到该网络(默认创建的网络好像不太行。。。)
networks:
app_network:
driver: bridge
结语
这样我们就实现了 docker容器化部署,通过一行命令即可启动所有服务并将其运行在后台,以后,柏成个人博客再次迁移服务器时,就不用一个一个安装服务了,爽歪歪啊!
powershell
docker-compose up -d