这两天试着将华大桂声的前端代码部署到服务器上,短短几句代码居然历时两天,谨以此文记录两天以来踩的大大小小的坑。
本地构建镜像
在将node应用部署到服务器上之前,首先在本地尝试构建docker镜像,这主要是为了检查部署代码是否存在问题
1.1 安装docker
Homebrew 的 Cask 已经支持 Docker for Mac,因此可以很方便的使用 Homebrew Cask 来进行安装:
brew cask install docker
1.2 创建node应用
1.2.1 package.json
在项目根目录下创建server
文件夹,接着在server
目录下创建package.json
,以定义node应用中所需要的各种模块以及相关的配置信息,可用npm init
进行交互式问答生成,这里给出其中部分信息
{
"name": "guisheng",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index.js",
"test": "echo \"Error: no test specified\" && exit 1",
"build": "rm -rf dist/* && webpack --config webpack.build.config.js"
},
...
"dependencies": {
"koa": "^2.2.0",
"koa-router": "^7.2.0",
"koa-send": "^4.1.0",
"koa-useragent": "^1.0.0",
"swig": "^1.4.2"
}
}
1.2.2 node.js
然后在node.js文件中实现View层(传统后端MVC中的View),主要负责渲染同步路由的模板。此处选用koa2作为Web框架,部分代码如下:
const send = require('koa-send');
const Koa = require('koa');
const Router = require('koa-router');
const userAgent = require('koa-useragent');
const path = require('path')
const swig = require('swig');
const router = new Router();
const app = new Koa();
//HTML文件位于../dist/template中
const templateRoot = path.join(__dirname, "../dist/template")
app.use(userAgent);
router.get('/', function(ctx, next){
console.log(ctx.userAgent)
let template = swig.compileFile(path.resolve(templateRoot, "index.html"));
ctx.body = template({})
});
router.get('/profile/:id', function(ctx, next){
console.log(ctx.userAgent)
let template = swig.compileFile(path.resolve(templateRoot, "profile.html"));
ctx.body = template({})
});
//将../dist下的文件放到/static/中
router.get(/^\/static(?:\/|$)/, async (ctx) => {
let filePath = ctx.path.replace(/static\//, "")
await send(ctx, filePath, {
root: path.join(__dirname, "../dist")
});
})
app
.use(router.routes())
.use(router.allowedMethods());
app.listen(3000);
console.log('listening on port 3000');
1.2.3 Dockerfile
一份Dockerfile文件可以帮助我们构建部署镜像,因此我们需要在项目根目录下创建一个Dockerfile文件
FROM node:latest
# Create app directory
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY . /usr/src/app
# Build static file
RUN npm install --registry=https://registry.npm.taobao.org
RUN npm run build
WORKDIR /usr/src/app/server
# Build server file
RUN npm install --registry=https://registry.npm.taobao.org
# Bundle app source
EXPOSE 3000
CMD [ "npm", "start" ]
Dockerfile的具体的写法可以参考官方文档。此处的Dockerfile的作用主要是,构建了静态文件,然后启动了node服务进程。
1.3 创建镜像
通过运行下面👇这条指令,创建一个名为name/application
的镜像,可以根据需要修改name/application
,但是不要忘记后面的.
,它表明根据当前目录下的Dockerfile构建镜像
docker build -t name/application .
successful
的提示,那就代表镜像构建成功,可以进行下一步啦
ps:可能失败原因如下:
- 网络故障,那么可以等网好一点再试一次
- 代码错误,此时则注意看报错信息,根据报错信息修改
- Docker版本太低,先使用
docker -v
查看版本,根据需要升级Docker版本
1.4 部署测试应用
现在一切就绪,在本地运行镜像试试看,此处我继续选择将镜像映射到3000端口
docker run -p 3000:3000 -d name/application
curl
输出页面上的数据,本地测试成功后我们就可以将应用部署到服务器上了。
在阿里云镜像仓库Build镜像
在直接登录服务器使用Docker Build镜像时,在因为网络问题失败N次之后,高人指点我去阿里云镜像仓库Build镜像。
为了方便ECS用户使用Docker官方镜像,阿里云同步Docker官方镜像库的最新版本到国内服务器,使得ECS用户可以通过内网连接该服务器。
在登录阿里云账号后,进入管理控制台,找到容器仓库中的镜像,进入镜像仓库控制台,创建镜像仓库,根据提示一步一步创建namespace等,配置的时候选择关联github,这样以后每次我们推送代码至github,阿里云就会自动帮我们构建镜像了。然后开始管理自己刚刚创建的镜像,进入构建页面立即构建,接着就可以在构建日志中查看构建状态了。
ps:可能存在的坑
如果一次构建失败了,查看日志寻找错误,然后重推一次代码到github,重新构建一般就能成功。
进入服务器部署
然后就可以登录服务器部署了。
3.1 clone仓库
在登录服务器后,从github上将项目clone至服务器上,接下来可以按照镜像仓库里的操作指南进行
在服务器上登录阿里云docker registry
sudo docker login --username=你的账号名 registry.cn-shenzhen.aliyuncs.com
3.2 从registry中拉取镜像:
sudo docker pull registry.cn-shenzhen.aliyuncs.com/仓库名称:[镜像版本号]
latest
,也可以在构建日志中查看得知。
3.3 查看镜像号
拉取镜像后,查看新拉取的镜像号
docker images
3.4 运行镜像
然后运行镜像,根据需要选择映射的端口号,此处我仍映射在3000端口
docker run -p 3000:3000 -d 镜像号
成功后就可以在浏览器上通过http://[SERVER_IP]:3000
访问你所部署的应用啦
ps: 可能遇到的坑:
有的时候会需要修改代码重新构建镜像,在将镜像pull下来之后,应先停掉原来运行的容器
① 查看容器号
docker ps
② 停止容器
docker stop 容器号
然后继续运行镜像就可以啦
总结
到这里桂生前端部署初尝试就结束啦,记录下来希望能对大家也有所裨益。