前言
省流:为了让编译这一步在本地机器上运行。
在使用 Goland 编写并部署 Go 代码时,有的项目我采用 docker-compose 的形式将代码打包进镜像编译运行。
Server 选择的是运行这个 docker-compose 脚本的机器,Build:Always 是为了每次都从代码编译一次镜像,这样做虽然可以一键编译部署到远程服务器,但顺序一般是 ①上传代码文件(上下文) -> ②运行 Dockerfile 编译镜像 -> ③运行 docker-compose 重建容器并运行。
这样做在理论上是没问题的,但平时总能遇到比如服务器性能较差编译时间长、编译时容器停止、网络断线导致编译中断等一系列问题。
思路
由于 IDEA 系 IDE 的配置都自带 “Before Launch” 功能,可以设置当前配置运行之前要运行的配置,形成一个工具链。
这样可以有一下两种思路:
-
将 docker-compose.yml 中的
build: .
改为image: some_image
,并在运行在本地编译镜像且 push 到某个 registry 上。 -
将 docker-compose.yml 中的
build: .
改为image: some_image
,在运行在本地编译镜像且直接将镜像复制到远程服务器上。
如何直接复制
第一种思路主要在于如何找到或部署一个符合自己保密要求的 registry,这里分享一下如何实现第二种。
其实在装了 Docker 插件的 Goland 中有直接将本地镜像复制到远程服务器的方法。
不过它没法整合到运行配置里,也就是不能自动化,但 bash 脚本可以,如下指令的效果是一样的。
docker save alpine | bzip2 | ssh root@your.server docker load
运行结束后,终端会提示"Loaded image alpine",这时就说明成功了,可以看看远程服务器上是否有这个最新镜像。
这个指令可以打包压缩上传并加载到远程服务器,但每次都要输入 ssh 密码,可以采用密钥登录或 sshpass 的方式。
docker save alpine | bzip2 | sshpass -p password ssh root@your.server docker load
这是 Linux 指令,那么在 Windows 平台如何运行呢?一般的指令在前面加 wsl
即可传递给 wsl 来执行,不过这里是带竖线的管道指令,需要将它作为一个整体传递给 wsl,否则会提示如“找不到bzip2”之类的报错。
在这个 ISSUE中有关于 wsl + 管道的讨论。
wsl bash -c "docker save alpine | bzip2 | sshpass -p password ssh root@your.server docker load"
将它保存为“docker_copy_image.ps1”文件,并创建一个 Powershell 配置来运行它。
运行该配置之前引用 Docker build 的配置,并将它引用给 docker-compose 的配置。
Goland 的小 Bug
由于工具链中有一个 Dockerfile 的编译打包步骤,但这个步骤在我目前使用的 Goland 2022.3 Beta2 中即使正确运行也无法自动退出并进行下一步,所以会终止整个工具链。
像这样卡在这里,即使“successfully”也不会进行下一步。
解决的方法很简单,和上一章一样自己写一个脚本并用 powershell 配置来运行。
补充
有些国外地址的 SSH 访问会出奇的慢,在用上述指令传输时往往只能有 100KB/S 的速度,略大的镜像就不知道传到猴年马月,经研究可以为管道中的第三段指令添加本地 Socks 代理。
要添加的就是在 ssh 后面的 -o
参数:
-o ProxyCommand='nc -X 5 -x 192.168.2.136:7890 %h %p'
注意事项:IP 地址不能填 127.0.0.1 或 localhost,因为上面说到是在 WSL2 中,需要填 Windows 的内网地址;这里由于外面有双引号,所以使用了单引号。
放在一起,最终的指令会很长:
wsl bash -c "docker save you/some_image | bzip2 | sshpass -p password ssh root@your.server -o ProxyCommand='nc -X 5 -x 192.168.2.136:7890 %h %p' docker load"
不过速度能上去也值得了。
可能还是使用 CI/CD 和本地测试服务器,或者自建镜像服务器更标准吧^-^