前言
写了个React Hooks+Next.js+Nest.js+MongoDB作为依托的博客系统,包括前后台,数据开发,最后把三个项目使用docker部署在了阿里云ECS上。
部署的问题
Next.js由于是服务端渲染框架,部署起来不可能像静态页面那样,网上的做法大都是使用Next.js老家的zeit.now,或者直接整个拷到服务器上,这样的做法我不是很喜欢,虽然并不是做CICD,但是也得把整个步骤搞得井井有条不是。
于是还是捡起来Docker做配置,做个shell脚本,也不是一套下来也不会很麻烦.
同Next.js一样,Nest.js官网甚至都没有讲部署,而且看package.json文件,也不会一个node就能跑起来的,所以也是用Docker跑吧,既然都这样了,那直接用到底,CRA建立的后台也用Docker得了,万能.
整个流程就是这样,前后台和数据层分别使用三个Docker容器,跑在3000,4000,5000端口,最后用Nginx做分发,给后台和数据层加上
前台
Next.js的Docker部署我选择了基于Node做:
FROM node:12-alpine
RUN mkdir -p /var/publish/front
ADD . /var/publish/front
WORKDIR /var/publish/front
ENV HOST 0.0.0.0
ENV PORT 3000
EXPOSE 3000
CMD [ "npm","run","start" ]
方式也很简单,把整个目录都拷到Docker镜像,其实是只需要.next文件加上package.json文件即可,不过那样的话就要去用npm安装依赖,不如直接拷依赖快点,无论如何,镜像是肯定小不了.
shell脚本也是很简单:
yarn build
docker build -t registry.cn-shanghai.aliyuncs.com/first_ary/fblog:v2 .
docker run -d -p 3000:3000 --name blog registry.cn-shanghai.aliyuncs.com/first_ary/fblog:v2
docker push registry.cn-shanghai.aliyuncs.com/first_ary/fblog:v2
第二步我是习惯性的在本地跑一下,看看容器日志有没有问题,一般检验一次就行了,因此可以去掉.
这里使用到了阿里的容器镜像服务,感兴趣可以了解一下,个人感觉配合服务器上的portainer还是很方便的.
接口
由于接口是用Nest.js做的,官网都没介绍部署方式,我就类似于上面的办法做了个镜像跑在生产环境下:
FROM node:12-alpine
RUN mkdir -p /var/publish/mid
ADD . /var/publish/mid
WORKDIR /var/publish/mid
ENV HOST 0.0.0.0
ENV PORT 4000
EXPOSE 4000
CMD ["npm","run","start:prod"]
同样其实只需要dist文件夹和package.json即可,这里我们仍然是把所有的东西直接拷进去了.
shell脚本就不发了,类似与上面.
后台
关于后台,其实部署方式也有很多,本地推荐是安装serve,然后直接驱动打包生成的build文件夹.由于不需要node_modules,所以这个镜像要小得多,生产环境也没想太多,反正有docker兜着,干脆就直接上serve了,不过为了防止在项目目录下docker要检测上下文导致打包很慢,所以建立了一个docker文件夹,把build文件夹拷进来构建镜像.
FROM node:12-alpine
RUN mkdir -p /var/publish/back
RUN npm install serve -g
ADD . /var/publish/back
WORKDIR /var/publish/back
ENV HOST 0.0.0.0
ENV PORT 5000
EXPOSE 5000
CMD ["serve","-s","build"]
虽然仍是打包整个同级目录,但是其实只有个build文件夹,所以构建的相当快,同时因为基于node构建的,所以直接使用npm装了serve.
Portainer与Nginx
Portainer是很方便管理docker的服务,直接在上面连接到阿里的私人镜像仓库,然后创建stack在线写docker compose即可.
如:
version: '2'
services:
mblog:
image: registry.cn-shanghai.aliyuncs.com/first_ary/bblog:v3
restart: always
ports:
- 5000:5000
Nginx也很好配,在 /etc/nginx/sites-enabled下创建blog.conf,添加内容:
server {
listen 80;
server_name asenwang.top www.asenwang.top;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:3000;
}
}
server {
listen 80;
server_name api.asenwang.top;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:4000;
}
}
server {
listen 80;
server_name back.asenwang.top;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:5000;
}
}
这样就把3个服务分发到了三个分支上.
HTTPS
没有小锁看起来还是难受的,好在阿里云提供的个人CA认证,虽然因为有子域名的缘故,一共要申请三个…
搞好之后,下载到本地,把.pem和.key传到服务器位置如下:
/etc/nginx/ssl/blog/3402934_asenwang.top.key
没有的文件夹创建即可,然后在刚刚的Nginx配置中修改一下,注意433端口要打开:
server {
listen 443;
server_name asenwang.top www.asenwang.top;
ssl on;
ssl_certificate ssl/blog/3402934_asenwang.top.pem;
ssl_certificate_key ssl/blog/3402934_asenwang.top.key;
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:3000;
}
}
...
整个构建步骤不是很麻烦,注意Https中不能存在http请求的图片之类的,别问我怎么忽然提这个…
有了小锁,网站看起来就顺眼多了.
HTTP 2.0
这个就很简单了,我的是1.4的Nginx, 是支持http2.0的,使用:
/usr/sbin/nginx -V
查看有没有这个模块:
--with-http_v2_module
然后在刚刚的配置文件的443后面加上http2就成了:
server {
listen 443 http2;
server_name asenwang.top www.asenwang.top;
最后去Chrome检查一下,记得快捷键把protocol打开.