部署 请问大家的 CI/CD 方案 (测试 / 部署方案) 使用的是什么流程?Docker+Drone+Swarm?

1c7 · 2019年01月24日 · 最后由 huobazi 回复于 2020年08月04日 · 8787 次阅读

之前的经历

之前用 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 之后自动部署,或者,在最后一步手动点按钮触发部署。

这一段的重点是:改进流程迫在眉睫,不能再推了

调查后的结果

  • 为了解决环境不一致,以及部署很麻烦需要手动安装软件的问题:Docker
  • 为了方便 Scale:Docker Swarm / Kubenetes
  • 为了 CI/CD:Gitlab CI / Travis CI / Circle CI / Drone.io / 等等

目前在尝试的流程(Workflow)

Gitlab -> Drone.io -> Docker swarm

  • Gitlab 纯粹代码托管,不用它的 CI 功能
  • Drone.io 负责 CI/CD。(说明:Drone.io 需要部署到自己的服务器上。在和 Gitlab 配置之后,Gitlab 会有 web hook 即时告知 Drone.io)
  • Docker swarm 负责部署。看了一些资料说 Kubenetes 学习曲线较为陡峭,实际试过了也发现的确是的,时间不够,不能折腾 Kubenetes 了,先 Swarm 也够了。

问题

大家都是用什么 CI/CD 流程?

从 git push 到代码 live,总共要多久?1/3/5 分钟?

发这个帖之前,在社区里搜了一下。 相关讨论不是很多,就几篇帖子

Gitlab CI + bash 脚本 + vm 虚拟机

Jenkins 现在也支持脚本配置和 docker

WoolenWang 回复

Gitlab CI 纯粹做测试。测完了发个 http 请求触发 bash 脚本进行部署? vm 虚拟机啥意思?就是云服务商提供的裸机是吧?没用 docker。 感谢回复

nouse 回复

嗯这样,谢谢

我们用的 CI 工具是 GitLab 和它的 CI, 部署用的是 Docker Swarm.

选用 GitLab CI 的想法是和 GitLab 紧密整合:把最终部署的步骤写成一个 CI job, 在项目的 Pipeline 界面手动触发这个 job 就可以部署。不用开发者学用一个新的软件界面。

部署耗时:目前我们放宽了 CI 的流程限制,合并进主干的代码不用等测试跑通,就会先构建 Docker Image. 构建好了之后就可以部署。

  • 构建 Docker Image 的过程是有 Docker 的分层缓存的。最近一次构建的时间是 16 秒.
    • 一个可以更好地利用 Docker 分层缓存的技巧是:在社区里搜了一下发现已经有人写好帖子了:https://ruby-china.org/topics/30078
    • 初次构建没有缓存,还是会慢一些。这可以通过从国内镜像安装依赖来解决。
  • 部署新版本:SSH 到一个 Docker Swarm Manager 节点,在上面运行 docker service update. 因为要滚动更新,还要下载镜像,这个时间稍微长一点。最近一次要 66 秒。未来应该还有提升空间。
5long 回复

赞,我也是打算这样做。Gitlab + Swarm。

Drone.io 我在发帖之后又继续试了。觉得构建镜像和推送镜像到 Docker hub 的部分挺简单的。

但是复制 docker-compose.yml 到服务器以及 ssh 进行 Swarm 的更新非常麻烦。 Drone.io 的官方文档又非常精简,没啥有用的内容。

appleboy/scp 和 applyboy/ssh 的文档试了又不行。Drone 插件不算多。 基本每一个插件点进去的顶部都是一个红框说这是 0.8 版本的语法。blahblah。

简言之就是因为文档劝退我了。 说这一堆希望对以后查阅到这篇帖子的人有用。

5long 回复

所以更新一次最快速度是:16 秒构建 + push image20 秒 -40 秒 + docker service update 1 分钟左右。
大概 2 分钟就可以全自动更新一版了。
话说有 rollback 的应急方案吗?还是说干脆代码回滚再 push。而不是用什么回滚机制。
感谢详尽的回复

1c7 回复

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 的界面上找一个旧版本,再点一次部署。因为应用服务器上的旧版本镜像还在,不需要重新下载,这样部署的时间会更短一些。而且这样做,不需要担心引入了回滚操作而制造更多的语义。比如:不用担心"回滚的回滚"应该是什么意义。就不会造成误解 / 记错。

5long 回复

嗯原来这样。感谢。 过阵子等我学习(发音:踩坑)完 Docker, Docker Swarm, 实践用在项目里了, 写几篇博客分享一下~ 等 Swarm 稳了说不定再弄 k8s

Gitlab -> Gitlab-runner -> Swarm

不过我觉得 Rails 项目少量更新代码没必要 redeploy,于是直接找了个小工具 docker_swarm_helpers 去做热重启,我只能说——灰快。需要重新打镜像的时候,通过打 tag 去触发重新部署的流程

另外关于 Swarm 的管理,推荐 Portainer,至少不用再纠结 docker-compose.yml 文件放哪儿了 😂

IChou 回复

学习了~

我现在用 GitHub Actions 来构建 docker 镜像😂

chunlea 回复

没听过这种操作…… 我得去查查

rancher, rancher , rancher

ForrestDouble 回复

听过但是还没接触。谢重要的事情说 3 遍。

lidashuang 回复

求 example .gitlab-ci.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"]
}

可以参考我写的这篇文章:

https://mp.weixin.qq.com/s?__biz=Mzg4MzAzMDE5Nw==&mid=2247483692&idx=1&sn=73b776c3c7f41838ad6fa0d35c36b7ca&chksm=cf4ce0f6f83b69e012439ee61a0145ed6a8e890443daed51236dc9e7c3ea4942606041b28a40&token=1885576722&lang=zh_CN#rd

好赞的讨论帖 👍

需要 登录 后方可回复, 如果你还没有账号请 注册新账号