published on

桂声前端部署踩坑之旅

这两天试着将华大桂声的前端代码部署到服务器上,短短几句代码居然历时两天,谨以此文记录两天以来踩的大大小小的坑。


本地构建镜像

在将node应用部署到服务器上之前,首先在本地尝试构建docker镜像,这主要是为了检查部署代码是否存在问题

1.1 安装docker

HomebrewCask 已经支持 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
登录registry的用户名是你的阿里云账号全名,密码是你开通namespace时设置的密码。

3.2 从registry中拉取镜像:

sudo docker pull registry.cn-shenzhen.aliyuncs.com/仓库名称:[镜像版本号]
这里的镜像版本号如果没有使用tag指明,一般就是latest,也可以在构建日志中查看得知。

3.3 查看镜像号

拉取镜像后,查看新拉取的镜像号

 docker images

3.4 运行镜像

然后运行镜像,根据需要选择映射的端口号,此处我仍映射在3000端口

docker run -p 3000:3000 -d 镜像号

成功后就可以在浏览器上通过http://[SERVER_IP]:3000访问你所部署的应用啦

ps: 可能遇到的坑:

有的时候会需要修改代码重新构建镜像,在将镜像pull下来之后,应先停掉原来运行的容器

① 查看容器号

docker ps

② 停止容器

docker stop 容器号

然后继续运行镜像就可以啦

总结

到这里桂生前端部署初尝试就结束啦,记录下来希望能对大家也有所裨益。

参考文献