文章目录
- 需求描述
- 开始操作
- 准备阶段:准备 server.js 文件并安装依赖,将 vue 项目包装成单独的服务器
- 制作 server.js
- 安装 server.js 需要的依赖
- 构建 Dockerfile
- heroku container 链接和部署
- 其他细节
需求描述
- 你想用 vue 构建前端,用 django 构建后端,并且你不想用一个服务器来运行整个项目,而是想分开两个服务器部署
- 通过 heroku 来部署有三种方式
- 本地项目文件夹直接关联 heroku 远程仓库,push 上去自动开展部署
- 本地项目文件夹关联 github 远程仓库,github 远程仓库关联 heroku,每次 github push 自动部署
- 本地项目文件夹直接构建 dockerfile,然后关联 heroku container,通过 heroku container 进行部署
- 只有前端页面的话是无法部署的,所以准备阶段我们需要再 vue 中加一个 server.js 来将前端项目打包成一个服务器,然后整体部署
开始操作
准备阶段:准备 server.js 文件并安装依赖,将 vue 项目包装成单独的服务器
制作 server.js
.
├── README.md
├── babel.config.js
├── img.png
├── jsconfig.json
├── package-lock.json
├── package.json
├── public
│ ├── favicon.ico
│ └── index.html
├── server.js
├── src
│ ├── App.vue
│ ├── assets
│ ├── components
│ ├── http.js
│ ├── main.js
│ ├── pages
│ └── router
├── todo.md
├── vue.config.js
- 路径方面需要注意,
server.js
是直接放在你的 vue 的根目录底下,也就是最外层
const express = require('express');
const serveStatic = require('serve-static');
const path = require('path');
const app = express();
app.use('/', serveStatic(path.join(__dirname, '/dist')));
// 处理 SPA 的路由回退,确保重定向到 index.html
app.get('*', function (req, res) {
res.sendFile(path.join(__dirname, '/dist', 'index.html'));
});
const port = process.env.PORT || 16000;
app.listen(port);
console.log('Listening on port: ' + port);
安装 server.js 需要的依赖
- 这一步是为了将这两个构建服务器需要的 package 写入 package.json,部署的时候方便
npm install express --save
npm install serve-static
构建 Dockerfile
- 也是在 vue 项目目录的最外层(与 server.js同级),写入如下
Dockerfile
# 第一阶段:构建 =========================================
# 1. 指定平台,因为我本机是 mac 芯片的,而 docker 默认环境是 linux 所以我转换一下平台
# 2. 使用 Node.js 官方镜像作为构建环境, node:14 表示 node 的版本是 14
FROM --platform=linux/amd64 node:14 as build-stage
# 设置工作目录,设置了之后就可以直接使用 . 来表示 docker 中的 /app
WORKDIR /app
# 拷贝 package.json 和 package-lock.json (如果存在)
# COPY A B 是将 A文件夹或者文件拷贝到 B 文件夹或文件,下面命令中第二个位置是 ./ 代表将当前本地目录下 package.json 拷贝到 docker 的工作目录下,相当于 COPY package*.json /app
COPY package*.json ./
# 安装项目依赖
RUN npm install
# 拷贝项目文件和文件夹到工作目录
COPY . .
# 构建应用
RUN npm run build
# ======================================================
# 第二阶段:运行
# 再次使用 Node.js 镜像
FROM --platform=linux/amd64 node:14
# 设置工作目录
WORKDIR /app
# 将构建产物从构建阶段拷贝过来,因为docker 构建是层级结构, 所以相当于从上一层的缓存中 copy 过来
COPY --from=build-stage /app/dist /app/dist
COPY --from=build-stage /app/node_modules /app/node_modules
# 拷贝 server.js
COPY server.js ./
# 暴露 80 端口
EXPOSE 80
# 启动应用
CMD ["node", "server.js"]
问题:这个项目里面为什么先 COPY package*.json ./ 再 COPY . ., 这两部分似乎可以合并
在 Dockerfile 中,将 COPY package*.json ./
和 COPY . .
分开的原因是为了更有效地利用 Docker 的层级缓存机制。这种做法可以在某些情况下显著提高构建速度,尤其是在进行频繁的构建时。下面是详细解释:
层级缓存机制:
- 当 Docker 构建镜像时,它会按照
Dockerfile
中的指令逐层构建,并为每一层生成一个缓存。
如果某一层没有发生变化,Docker 就会重用这一层的缓存,而不是重新构建它。
优化依赖项安装:
- 通过首先只复制
package.json
和package-lock.json
文件,然后运行npm install
,可以确保只有当这些文件发生变化时(即依赖项发生变化),Docker 才会重新安装依赖项。 - 如果直接复制整个项目目录,那么任何文件的变化都会导致 Docker 无法使用缓存的依赖项层,因此即使只是源代码的一个小改动,也会导致 Docker 需要重新运行
npm install
。
提高构建效率:
在开发过程中,源代码的变化比依赖项的变化要频繁得多。因此,分开复制可以在大多数构建中避免不必要地重新安装依赖项,从而加快构建速度。
综上所述,尽管从技术上讲,将 COPY package*.json ./
和 COPY . .
合并为一个步骤是可行的,但分开这两个步骤可以更好地利用 Docker 的层级缓存,从而提高构建效率,特别是在频繁的开发和构建过程中。
heroku container 链接和部署
-
打开 heroku 并登录,create 一个 new app,这一步可以在 heroku 网站或者通过命令行完成
-
找到 deploy,并选择 container registry
-
接下来就是按照步骤执行,需要注意的是,你在
terminal
进行倒数两条命令的时候,一般需要再后面指定你的具体的 heroku app 名称,比如我在 heroku 上创建的 app 叫alpha
那么我的命令就需要对应的改成heroku container:push web -a alpha heroku container:release web -a alpha
其他细节
- 如果你需要和后端部署的服务器进行关联,那么请注意你的 vue 项目中链接后端项目的地址一定要对应的改好,注意点包括但不限于下面几点:
http -> https
如果后端部署到了服务器上,访问后端 api 的时候,就要使用 https 前缀ws -> wss
对应的,如果建立 websocket 链接,就使用 wss 前缀