Cloud Build不像Github Action那样支持node缓存。谷歌提供了几种编译加速的方法,这篇使用了Cloud Storage来储存node_modules文件夹来实现编译加速。
Cloud Build在俺写的简单评价下几家云服务平台和准备博客搬家有介绍。
实现
Cloud Build不支持一个环境跑多个命令,解决的方法有几种:
- 利用Bash进行命令组合,在简单评价下几家云服务平台中有例子。
- 利用Dockerfile的多阶段编译,在准备博客搬家中演示过。
- 多加几个编译步骤(steps)。代码仓库会被挂载到/workspace文件夹中,而这个文件夹在编译的各个阶段是持久的。
之前编译用的是方法2,但在实现缓存node_modules文件夹遇到了麻烦,那就是Dockerfile的COPY是单向的,只能从主机拷贝到容器,而不能从容器拷贝到主机。为了顺利实现缓存,抛弃Docker的多阶段编译而改为增加Cloud Build的编译步骤。
cloudbuild.yaml
下面是一个React项目的Cloudbuild.yaml。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
|
substitutions: _VERSION: '1.0.0' _NAME: 'artifact_name' _BUILD_DIR: 'project_location' steps:
- id: 'get cache' name: gcr.io/cloud-builders/gsutil dir: ${_BUILD_DIR} entrypoint: 'bash' args: - -c - | gsutil cp gs://your_back_name/some_location/node_modules.tar.gz . \ ; tar zxf node_modules.tar.gz || true
- id: "build react" name: 'node:16' dir: ${_BUILD_DIR} entrypoint: 'bash' args: - -c - | ls && npm install && npm run build \ && mkdir docker && cp -r build docker && cp Dockerfile default.conf docker \ && tar zcf node_modules.tar.gz node_modules/
- id: 'put cache' name: gcr.io/cloud-builders/gsutil dir: ${_BUILD_DIR} entrypoint: 'bash' args: - -c - | gsutil cp node_modules.tar.gz gs://your_bucket_name/some_location/
- id: 'build docker image' name: 'gcr.io/cloud-builders/docker' dir: ${_BUILD_DIR}/docker entrypoint: 'bash' args: - -c - | ls \ && docker build -t us-docker.pkg.dev/your_project/some_location/${_NAME}:${_VERSION} .
- id: 'push docker image' name: 'gcr.io/cloud-builders/docker' args: ['push', 'us-docker.pkg.dev/your_project/some_location/${_NAME}:${_VERSION}']
- id: 'deploy image to cloud run' name: 'gcr.io/google.com/cloudsdktool/cloud-sdk' entrypoint: gcloud args: ['run', 'deploy', '${_NAME}', '--image', 'us-docker.pkg.dev/your_project/some_location/${_NAME}:${_VERSION}', '--region', 'us-central1'] images: - us-docker.pkg.dev/your_project/some_location/${_NAME}:${_VERSION}
|
Dockerfile和Nginx conf
Dockerfile就很简单了,就把build文件夹下的文件拷贝到html文件夹下就好了。
如果用80端口则可以注释掉第二个COPY。我用的8080端口,用其他端口要把下面4个8080都要改掉。
1 2 3 4 5 6 7
| # Dockerfile FROM nginx:stable-alpine ENV PORT=8080 COPY build /usr/share/nginx/html COPY default.conf /etc/nginx/conf.d/default.conf EXPOSE 8080 CMD ["nginx", "-g", "daemon off;"]
|
Nginx的配置文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| # default.conf # 这里用的8080端口,要用其他改掉下面的两个8080,一个V4一个V6。 server { listen 8080; listen [::]:8080; server_name localhost;
#access_log /var/log/nginx/host.access.log main;
location / { root /usr/share/nginx/html; index index.html index.htm; }
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; }
# proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \.php$ { # proxy_pass http://127.0.0.1; #}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ \.php$ { # root html; # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # include fastcgi_params; #}
# deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\.ht { # deny all; #} }
|
额外提醒
Cloud Build, Cloud Run和Cloud Storage最好全部放一个地区,避免产生跨区域的流量费用。
我放的us-central-1,Cloud Storage有5G的免费储存额度。我的两个小项目的node_module.tar.gz的大小在100M左右,不会产生储存费用。
加速效果
测试了两个很小的React项目,只展示npm编译步骤的时间变化。
是否缓存 |
项目一 |
项目二 |
否 |
2分16秒 |
2分34秒 |
是 |
1分11秒 |
1分29秒 |
编译步骤大概能节省1分钟,但Cloud Run部署大概需要1-2分钟左右,最后总时间3分多钟。
小结
Cloud Build一天提供120分钟的免费构建,其实不优化也够用了,但优化后还是可以节省一点点时间。