之前用 Rails 做小项目就直接 Rails (puma) + Nginx 扔到服务器上
(是的,安装依赖花了 10-20 分钟)
没有用 Docker/Heroku 或任何其他方便部署的东西。
(非广告)
没怎么写测试(RSpec/单元测试)。
而 0 downtime 要么靠 puma 的 phashed_restart 要么 nginx 的 load balancer。
日志和监控什么的也没有太在意。
这一段的重点是:现有的流程不但原始(只适合小项目),而且也不够方便。这个流程需要改进。
最近在忙的项目,用户逐渐变多,不再是小项目了,在往中小型项目发展。
技术栈:Ruby on Rails 做 JSON API 后端,微信小程序作为前端。(不方便给具体信息,不贴小程序码了,见谅)
一方面希望方便 scale
另一方面希望工作流能方便一些。git push 之后自动部署,或者,在最后一步手动点按钮触发部署。
这一段的重点是:改进流程迫在眉睫,不能再推了
Gitlab -> Drone.io -> Docker swarm
Gitlab CI 纯粹做测试。测完了发个 http 请求触发 bash 脚本进行部署? vm 虚拟机啥意思?就是云服务商提供的裸机是吧?没用 docker。 感谢回复
我们用的 CI 工具是 GitLab 和它的 CI, 部署用的是 Docker Swarm.
选用 GitLab CI 的想法是和 GitLab 紧密整合:把最终部署的步骤写成一个 CI job, 在项目的 Pipeline 界面手动触发这个 job 就可以部署。不用开发者学用一个新的软件界面。
部署耗时:目前我们放宽了 CI 的流程限制,合并进主干的代码不用等测试跑通,就会先构建 Docker Image. 构建好了之后就可以部署。
docker service update
. 因为要滚动更新,还要下载镜像,这个时间稍微长一点。最近一次要 66 秒。未来应该还有提升空间。赞,我也是打算这样做。Gitlab + Swarm。
Drone.io 我在发帖之后又继续试了。觉得构建镜像和推送镜像到 Docker hub 的部分挺简单的。
但是复制 docker-compose.yml 到服务器以及 ssh 进行 Swarm 的更新非常麻烦。 Drone.io 的官方文档又非常精简,没啥有用的内容。
appleboy/scp 和 applyboy/ssh 的文档试了又不行。Drone 插件不算多。 基本每一个插件点进去的顶部都是一个红框说这是 0.8 版本的语法。blahblah。
简言之就是因为文档劝退我了。 说这一堆希望对以后查阅到这篇帖子的人有用。
所以更新一次最快速度是:16 秒构建 + push image20 秒 -40 秒 + docker service update
1 分钟左右。
大概 2 分钟就可以全自动更新一版了。
话说有 rollback 的应急方案吗?还是说干脆代码回滚再 push。而不是用什么回滚机制。
感谢详尽的回复
push image 没有那么慢。因为我们用的私有 Docker Registry 和 CI / 生产环境服务器都在同一个内网网络 (某公有云平台), 再加上合适的 Docker 分层缓存,如果没有依赖更新,每次 push 的量也就只有仓库里的几 MB 的代码量。16 秒的时间已经包含 push 在内了。
不过如果你真的要计量精确的部署时间,还得把 GitLab CI Job 的运行前的延迟加上。Job 在触发运行之后,会有几秒钟的时间停在"job 正在等待被某个 runner 认领执行"的状态。
rollback 我们没有专门的方案。如果需要部署到旧版本,可以 SSH 到 Docker Swarm Manager 上手动执行 docker service rollback
. 也可以直接在 GitLab 的界面上找一个旧版本,再点一次部署。因为应用服务器上的旧版本镜像还在,不需要重新下载,这样部署的时间会更短一些。而且这样做,不需要担心引入了回滚操作而制造更多的语义。比如:不用担心"回滚的回滚"应该是什么意义。就不会造成误解 / 记错。
嗯原来这样。感谢。 过阵子等我学习(发音:踩坑)完 Docker, Docker Swarm, 实践用在项目里了, 写几篇博客分享一下~ 等 Swarm 稳了说不定再弄 k8s
Gitlab -> Gitlab-runner -> Swarm
不过我觉得 Rails 项目少量更新代码没必要 redeploy,于是直接找了个小工具 docker_swarm_helpers 去做热重启,我只能说——灰快。需要重新打镜像的时候,通过打 tag 去触发重新部署的流程
另外关于 Swarm 的管理,推荐 Portainer,至少不用再纠结 docker-compose.yml 文件放哪儿了
贴一下我的 GitHub Actions workflow。
workflow "Build Docker for master branch" {
on = "push"
resolves = [
"Push Frontend Image to Tencent Cloud",
"Push Backend Image to Tencent Cloud",
]
}
action "Filters for GitHub Actions" {
uses = "actions/bin/filter@b2bea0749eed6beb495a8fa194c071847af60ea1"
args = "branch master"
}
action "Docker Registry" {
uses = "actions/docker/login@c08a5fc9e0286844156fefff2c141072048141f6"
needs = ["Filters for GitHub Actions"]
secrets = [
"DOCKER_USERNAME",
"DOCKER_PASSWORD",
]
env = {
DOCKER_REGISTRY_URL = "ccr.ccs.tencentyun.com"
}
}
action "Build Frontend Image" {
uses = "actions/docker/cli@c08a5fc9e0286844156fefff2c141072048141f6"
needs = ["Docker Registry"]
args = "build -t frontend frontend"
}
action "Build Backend Image" {
uses = "actions/docker/cli@c08a5fc9e0286844156fefff2c141072048141f6"
needs = ["Docker Registry"]
args = "build -t backend backend"
}
action "Tag Frontend Image" {
uses = "actions/docker/tag@c08a5fc9e0286844156fefff2c141072048141f6"
args = "frontend ccr.ccs.tencentyun.com/xxx/xxx-frontend"
needs = [
"Build Frontend Image",
"Build Backend Image",
]
}
action "Tag Backend Image" {
uses = "actions/docker/tag@c08a5fc9e0286844156fefff2c141072048141f6"
args = "backend ccr.ccs.tencentyun.com/xxx/xxx-backend"
needs = ["Tag Frontend Image"]
}
action "Push Frontend Image to Tencent Cloud" {
uses = "actions/docker/cli@c08a5fc9e0286844156fefff2c141072048141f6"
args = "push ccr.ccs.tencentyun.com/xxx/xxx-frontend"
needs = ["Tag Backend Image"]
}
action "Push Backend Image to Tencent Cloud" {
uses = "actions/docker/cli@c08a5fc9e0286844156fefff2c141072048141f6"
args = "push ccr.ccs.tencentyun.com/xxx/xxx-backend"
needs = ["Tag Backend Image"]
}
可以参考我写的这篇文章: