前言
互联网发展到今天,已经完全不是10年前那种刀耕火种的状态。渐渐地,无论是大公司,还是小作坊团队,由于云技术的发展,他们都开始对基础设施的建设进行投入,这背后的原因很多,我这里提出几个关键的:
- 程序员工资太高,要降低成本,必须要用机器来取代人
- 行业人员流动大,程序员跳槽至竞对,会携带大量信息
- 1 + 1 < 2,当公司到了一定规模,堆人的边际效应递减,甚至还会带来管理成本的急剧增长
所以,降本提效,是下一个十年互联网公司之间竞争的关键,谁能最大化组织效能,而不是依靠996和堆人,谁就能占据生产力优势,这在变化无常的互联网,是十分关键的。
祛魅
DevOps、Serverless、CI,这些词听起来高大上,很多设施只停留在大公司层面,小的个体还有团队很难去打破信息壁障去构建自己的开发基础设施。
下面我从一个前端出发,分享一下我基于Github,是如何构建一套属于自己的自动化部署流程,希望让上述那些词不再高大上,让它们更加接地气,让前端工程师也能轻松构建自动化流程,享受到遍历。
说明:非最佳实践,只是最适合业务的实践,如果有更好地实践,可以在评论里交流一下。
部署流程
业务背景
写了一个小程序组件库(独立仓库),为此做了一个小程序官网(基于Nextjs,独立仓库),同时为了省事儿,要实现如下功能:
- 组件库仓库更新readme或是package.json时,官网的markdown以及组件相关信息需要同步更新
- 需要提供组件下载的功能,下载下来的是单个组件zip格式的压缩包
- 需要提供ts、less|js、wxss这两种类型的组件压缩包
基于以上需求,所以我把小程序组件库这个独立仓库作为server的子仓库,通过node的文件读写能力,把组件库当作“数据库”,编写接口来获取组件readme.md、package.json以及zip压缩包。
server基于Nestjs + fastify构建,通过json5、fast-json-stringify来优化json相关性能。
Server部署脚本
Dockerfile.prod
FROM node:lts-alpine AS compile
WORKDIR /app
COPY . /app
RUN npm install -g cnpm --registry https://registry.npm.taobao.org && cnpm install && npm run build
RUN cd light-design && cnpm install && npm run build:es5
FROM node:lts-alpine AS deploy
WORKDIR /app
RUN apk add --no-cache zip
COPY --from=compile /app/dist /app/dist
COPY --from=compile /app/node_modules /app/node_modules
COPY --from=compile /app/package.json /app/package.json
COPY --from=compile /app/light-design/miniprogram/data /app/light-design/miniprogram/data
COPY --from=compile /app/light-design/miniprogram/components /app/light-design/miniprogram/components
COPY --from=compile /app/light-design/miniprogram/components_es5 /app/light-design/miniprogram/components_es5
- 部署在国内的话就用cnpm,快很多
- 不要把项目源文件打包到镜像中
Dockerfile.dev
FROM node:lts-alpine
WORKDIR /app/
COPY package*.json ./ \
yarn.lock ./
RUN yarn --registry=https://registry.npm.taobao.org
RUN cd light-design && yarn --registry=https://registry.npm.taobao.org && npm run build:es5
RUN apk add --no-cache zip
COPY . .
本地调试的话,就随意了,以好用为主。
docker-compose.yml
version: '3.8'
services:
main:
container_name: main
build:
context: .
ports:
- ${DG_PT}:${DG_PT}
- ${SV_PT}:${SV_PT}
env_file:
- .env
networks:
- webnet
depends_on:
- postgres
postgres:
container_name: ${DB_C_NM}
image: postgres:13
networks:
- webnet
environment:
POSTGRES_PASSWORD: ${DB_PD}
POSTGRES_USER: ${DB_US}
POSTGRES_DB: ${DB_NM}
PG_DATA: /var/lib/postgresql/data
ports:
- ${DB_PT}:${DB_PT}
volumes:
- pgdata:/var/lib/postgresql/data
networks:
webnet:
volumes:
pgdata:
- 注意docker-compose版本,有些服务器安装的docker-compose版本较低,需要yml文件的version符合
- 对于容器之间通信,不能用localhost + port,得用容器名称 + port
开发环境和生产环境使用各自的yml配置文件:
docker-compose.prod.yml
services:
main:
build:
dockerfile: Dockerfile.prod
command: npm run deploy
docker-compose.dev.yml
services:
main:
build:
dockerfile: Dockerfile.dev
volumes:
- .:/app
command: npm run debug
上述yml配置文件中用到的变量在env中定义,其中涉及到数据库相关的信息,所以就展示了。
package.json
"init:submodule": "git submodule update --init --recursive",
"update:submodule": "git submodule sync && git submodule update --recursive --remote --merge",
"d:dev": "docker-compose -f docker-compose.yml -f docker-compose.dev.yml up",
"d:prod": "docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d --build --force-recreate"
.github/workflows/ci.yml
name: Deploy Actions
on:
push:
branches:
- master
paths-ignore:
- test
- README.md
- LICENSE
jobs:
Deploy:
runs-on: ubuntu-20.04
steps:
- name: Checkout Repo
uses: actions/checkout@v2
- name: Checkout Submodules
uses: textbook/git-checkout-submodule-action@master
with:
remote: true
- name: Upload To Server
uses: burnett01/rsync-deployments@4.1
with:
switches: -avzr --delete
path: ./
remote_path: /app/
remote_port: '22'
remote_host: ${{ secrets.SSH_HOST }}
remote_user: ${{ secrets.SSH_USERNAME }}
remote_key: ${{ secrets.DEPLOY_KEY }}
- name: Start Service
uses: appleboy/ssh-action@master
with:
port: '22'
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USERNAME }}
key: ${{ secrets.DEPLOY_KEY }}
script: cd /app/ && npm run d:prod
源代码在这,由于最近在面试,所以限时public,后续会转回private。
组件库相关脚本
package.json
"build:es5": "webpack --mode production --config ./webpack/es5/webpack.config.js && cd webpack/es5 && node build",
"dev": "cross-env NODE_ENV=development webpack --mode development --watch --config ./webpack/webpack.config.common.js",
"build": "cross-env NODE_ENV=production webpack --mode production --config ./webpack/webpack.config.common.js",
执行npm run build:es5 会将miniprogram/components文件夹下面的组件打包成miniprogram/components_es5
.github/workflows/ci.yml
name: Deploy Actions
on:
push:
branches:
- master
paths-ignore:
- test
- README.md
- LICENSE
jobs:
Deploy:
runs-on: ubuntu-20.04
steps:
- name: Checkout Repo
uses: actions/checkout@v2
- name: Start Service
uses: appleboy/ssh-action@master
with:
port: '22'
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USERNAME }}
key: ${{ secrets.DEPLOY_KEY }}
script: cd /app/ && npm run update:submodule && npm run d:prod
源代码在这,限时public。
结语
这样当你server或者组件库提交了新的代码,github actions会替你做好部署相关工作,你只需要,通过远程连接docker引擎查看部署状态即可。
基本上能做到如Vercel自动化部署版流程,后续基础设施在我建设完成之后会分享出来的。