编写一个Dockerfile不引入Nginx进行跑前后端服务
前言
最近网易对neteast-colud-music-api这个开源项目发起了律师函,作者已经不再更新和维护这个项目了,我这才想起来三年前自己写过的一个毕设项目,一款使用该服务的高仿网易云的播放器,播放界面是模仿qq音乐,纯纯一个缝合怪播放器,但是好歹让三个人毕业了,所以这个项目意义非凡。随着网易云音乐的下一次更新,这个开源项目能使用的接口就越来越少了,到最后这个项目的所有接口都会不能使用,所以我要把这个项目迁移到docker上面,把它作为一款nas专属的web播放器。
前端代码编译
这个就不需要多说了
git clone https://git.icoding.fun/yigencong/wangyiyun.git
cd wangyiyun
npm install 或者 pnpm install
npm run build 或者 pnpm build
DockerFile编写
思路: 首先neteast-colud-music-api是有docker镜像的,我们只要把它作为基础镜像,再在这个镜像上面做其他操作,熟悉neteast-colud-music的朋友应该都会知道,这个项目是一个nodejs项目,这个项目是基于express开发的,所以我们只
要在这个镜像的基础上再运行一个express的服务给前端静态文件提供静态文件的访问服务就可以实现前端界面的访问了,可是只提供前端镜像的访问还不够,因为数据都是neteast-colud-music这个镜像提供的,前端浏览器不可能直接访问容器里面的内容,所以我们让前端浏览器访问自己静态服务器上面的/api接口,只要静态服务器接收到这个接口的数据,就转发给neteast-colud-music-api,这样就实现了前后端项目的容器化,之后部署直接一条命令就行了,那些pm2什么的都不需要了。
# 使用 netease_cloud_music_api 镜像作为基础镜像
FROM binaryify/netease_cloud_music_api
# 设置工作目录
WORKDIR /wangyiyun
# 复制静态文件到工作目录
COPY ./src /wangyiyun/src
COPY ./wangyiyun.js /wangyiyun/app.js
COPY ./wangyiyun.sh /
# 安装 Express.js
RUN npm install express http-proxy-middleware --registry=https://registry.npmjs.org/
WORKDIR /
# 暴露容器的端口
EXPOSE 3001
# 运行 Express.js HTTP 服务器来提供静态文件并转发 API 请求
CMD ["/bin/sh", "/wangyiyun.sh"]
解释:
COPY ./src /wangyiyun/src 会把前端文件放置到镜像的/wangyiyun/src 文件下面
COPY ./wangyiyun.js /wangyiyun/app.js 为使用express编写的静态服务
const express = require('express'); // 使用express作为web服务
const { createProxyMiddleware } = require('http-proxy-middleware'); // 反向代理的中间件
const path = require('path'); // 拼接路径使用,因为默认路径会是工作路径
// 配置静态目录,使用自带的express.static()中间件
const app = express(); app.use(express.static(path.join(__dirname, 'src')));
// 使用代理中间件将/api的所有请求代理到neteast-could-music-api
app.use('/api', createProxyMiddleware({ target: 'http://localhost:3000', changeOrigin: true }));
// 将服务跑在容器的3001端口
app.listen(3001, () => { console.log('Server running at http://localhost:3001/'); }
COPY ./wangyiyun.sh / 把shell文件上传到镜像里面,因为一个docker容器只能跑一个进程
#!/bin/bash
start_api_server() { // api的服务
node app/app.js &
}
start_static_server() { // 静态文件的服务
node wangyiyun/app.js &
}
## start services
start_api_server // 启动这个服务(主进程会开启这个进程)
start_static_server // 启动这个服务(主进程会开启这个进程)
tail -f /dev/null // 防止主进程结束
tail -f /dev/null 这是一个无限运行而不会使用任何cpu的命令,用于保持主进程不被退出,因为docker CMD运行的进程被执行完毕就会结束容器,如果主进程结束,由这个主进程开启的两个node进程也会结束,所以我们只要保持主进程不结束,那么子进程就不会结束。那么我们就可以在一个容器里面跑两个服务,其实这种操作docker是不推荐的,docker的目的就是要让容器功能单一,然后使用docker-compose编排技术来管理多容器,但是对于这个项目太麻烦了,没有这个必要。
构建镜像
cd到我们编写Dockerfile的目录里面,运行下面这个命令
docker build -t wangyiyun:v1.0 .
如果你比较有个性Dockerfile的文件名不是"Dockerfile",那么要指定一下文件
docker build -t wangyiyun:v1.0 -f Dockerfile文件名 .
⚠️注意: 最后面那个点不是我手误,这个点代表Dockerfile所在的目录
上传镜像
docker login # 按要求输入dockerhub的用户名和密码
docker tag 本地镜像名 新添加的镜像名 # 新添加的镜像名一般使用"用户名/本地镜像名"防止冲突
docker push 新添加的镜像名 # 把这个镜像推到dockerhub
使用镜像
现在我们可以在任何地方使用这个镜像了,只需要执行下面这个两条命令
docker pull yigencong/wangyiyun:v1.0
docker run -d -p 3001:3001 --name wangyiyun yigencong/wangyiyun:v1.0
总结
我们在没有使用nginx的情况下,只靠一个带有node服务的镜像完成了一个前后端分离项目的部署,重点就是docker只会执行一个CMD 所创建的服务,我们不可以写多个服务来启动多个node服务,这样创建出来的镜像只会执行最后一个CMD,所以我们让镜像跑一个shell,让shell去启动两个服务,之后只要不让这个shell结束运行就行了。
评论区