这段时间完成了一个繁体 - 简体线上转换的小项目,采用 react+express 前后端分离开发。顺便学习了一下 google cloud build 和 docker 的相关应用。踩了些坑,在这里记录下。
前端代码
前端使用 create-react-app 开发,采用 axios 请求后端的接口。
前端请求后端需要制定一个 BASE_URL,由于最后是封装进 docker 镜像中,而一般来讲 create-react-app 由于使用 webpack 打包,BASE_URL 需要在编译时就指定,不适合 docker 这种模式。所以这里需要一个能取到运行时环境变量的方法。
我采用的方法是前端加入一个config.json
放在 public 目录下,里面放置 BASE_URL 的值。前端程序每次启动先请求 config 得到后端真实地址再进行后续请求。然后在 docker 容器运行时覆写这个 config,就能动态制定 BASE_URL。
后来发现一个 npm 包能做到类似功能:runtime-env-cra
后端代码
后端唯一需要动态指定的是服务运行的端口,这里用到dotenv这个 npm 包,这样环境变量可以在 docker 运行时指定,然后后端程序直接读取process.env.PORT
即可。
Docker 镜像
前后端代码安装依赖的时候发现会从package-lock.json
(yarn.lock
)里读取我本地开发时候用的淘宝源安装,但这样在国外机器上构建镜像的时候就很慢。暂时的解决方法是在 Dockerfile 中删掉 lock 文件。
前端 Dockerfile
前端镜像用分步构建,先用node:lts-alpine
这个镜像编译 react app,然后把编译好的文件复制出来,用nginx:stable-alpine
作为 http server。
记录一点,COPY 指令如果前面那个参数是目录,会把目录里面的具体内容复制走,而不是把整个目录复制走。这点跟 mv 和 cp 都不一样。
还有一点,如果 RUN 里面有多个命令用&&
之类的符号连接,在最前面加个set -x ;
可以查看如果有报错到底是哪个命令出错了,方便调试。
文件:https://github.com/juzeon/tw-cn/blob/master/frontend/Dockerfile
前面说到的运行时写入config.json
的代码放在 CMD 指令里面。
后端 Dockerfile
由于用到 opencc 库作为繁体 - 简体转换,而这个库里面核心代码是 C 写的,安装依赖时遇到 node-gyp 报错。刚开始还以为是 alpine 或者 python 的问题,换了几个镜像问题依旧。最后在构建中加入一行RUN apk add python make gcc g++
增加编译环境就解决了。
文件:https://github.com/juzeon/tw-cn/blob/master/backend/Dockerfile
Google Cloud Build
有几个坑:
- 如果在步骤中用到环境变量(或者 SECRET),需要采用
entrypoint: 'bash'
格式。 - Secret Manager 权限设置比较复杂,具体可以看这个文档:https://cloud.google.com/build/docs/interacting-with-dockerhub-images?hl=zh-cn。注意 Secret Manager 是收费的,$0.06/个/月。
- 构建触发器可以选择 github 上的项目。如果你用自建私有 git 仓库,需要在自己的服务器上安装谷歌提供的
gcloud
命令行工具,配置一下钩子。
另可参考文档:https://cloud.google.com/build/docs/configuring-builds/create-basic-configuration?hl=zh-cn
文件:https://github.com/juzeon/tw-cn/blob/master/cloudbuild.yaml
Cloud Build 每天免费 120 分钟,还是很不错的。
docker-compose
docker 容器编排,同一个网络中的容器和容器间交互是不需要用ports
做端口映射的,只有暴露给宿主机/公网的端口才需要。
这里的配置是前后端分别在容器中运行,另外再运行一个 nginx 镜像,将前后端组合起来,前端挂在/
下,后端挂在/backend
下,然后暴露 18080 端口(映射为 nginx 容器的 80 端口)给公网。
在 volumes 中挂载了一个 nginx 配置文件,覆写容器中默认的 vhost。
文件:https://github.com/juzeon/tw-cn/blob/master/docker-compose.yml
nginx 配置文件
其中把后端挂载/backend
目录的时候遇到 URI 方面的问题。查阅以下资料:
Nginx reverse proxy + URL rewrite
一文理清 nginx 中的 location 配置(系列一)
可以写成下面几种形式之一:
|
|
|
|
|
|
上面配置中的^~
都是可以去掉的,加上是为了保证优先级。
具体是什么原理,可以参考上面的链接的资料。
本来自己 nginx 都是乱配,通过这次把 location、proxy 相关的东西理解的更深刻了一点。
文件:https://github.com/juzeon/tw-cn/blob/master/nginx.conf
总结
这次进行一次全栈开发 + 部署,还是有学到很多运维相关的知识。