概要
目标
使用 Git 提交代码后,自动编译,并自动上线.
支持 HTTPS
单服务器可以承载多个后端服务
访问每个后端服务时,只有域名不同
可以很方便的区分测试环境和生产环境
前后端完全分离,前端部署在高速的OSS上享受CDN加速,且可由前端人员自己完成前端文件的更新.
使用的技术/产品
Git
Github
Docker
Docker Hub
Nginx
OSS
跨域
示例
域名为 Domain.com 的服务器上,运行 后端服务A 8000,后端服务B 8001.
显然,此时,通过 http://backend.Domain.com:8000 和 http://backend.Domain.com:8001 即可通过不安全的 HTTP 访问后端服务.
通过 Nginx ,我们可以做到 https://a.backend.Domain.com 和 https://b.backend.Domain.com 分别通过安全的 HTTPS 访问后端服务.对于用户访问网站的时候,显然要访问前端文件.给用户的网站地址是 a.Domain.com,然后前端通过 ajax 等方法与 https://a.backend.Domain.com 通信.
持续集成
目标
这一部分,我们要做到的是以持续集成的方式,在 http://backend.Domain.com:8000 上运行起 服务.
概要
程序员将代码推送到 Github 上 -> Docker Hub 检测到 Github 仓库发生了改变,使用它的服务器 Clone 代码,并且执行 Docker build 构建镜像,完成构建后发送到 Docker Hub 上 -> 服务器定时检测 Docker Hub 是否有更加新的镜像.如果有,就运行新的镜像.
Git / Github
为了便于后续的 Docker 化,项目名称最好不要使用大写字母,多使用小写字母+下划线
采用 commit 规范
https://blog.csdn.net/y491887095/article/details/80594043
Commit message格式
<type>: <subject>
注意冒号后面有空格。
type
用于说明 commit 的类别,只允许使用下面7个标识。
- feat: 新功能(feature)
- fix: 修补bug
- docs: 文档(documentation)
- style: 格式(不影响代码运行的变动)
- refactor: 重构(即不是新增功能,也不是修改bug的代码变动)
- test: 增加测试
- chore: 构建过程或辅助工具的变动
如果type为feat和fix,则该 commit 将肯定出现在 Change log 之中。
subject
subject 是 commit 目的的简短描述,不超过50个字符,且结尾不加句号 ‘.’
Docker 化项目
编写 dockerfile 文件
比较棘手的一点是私密的环境变量不能随意存放.任何时候都要确保 Git 中没有私密配置文件.另一方面,镜像也是公开的,所以私密配置不能在镜像构建 docker build 的时候加入,只能在最后镜像运行 docker run 的时候加入.
对于编译型语言,要使用docker的分层构建功能,确保最后生成的镜像中,只有最简单的二进制文件以及运行环境,没有代码和各种JDK.
对于 Java 的 Spring Boot ,Go 的 Gin, 我都已经编写了docker化的示例代码,详情见
https://github.com/117503445/spring_boot_docker
https://github.com/117503445/go_docker
对于 Python 的 Flask ,没有专门的示例代码,可以参考
https://github.com/117503445/XduCheckInLog
Docker Hub 自动构建
每次代码发生更新,就需要有机器去拉取代码,执行 docker build.幸运的是,docker hub提供了这些功能
可以参考 https://blog.csdn.net/xichenguan/article/details/79083630 进行操作
本地自动拉取
docker hub 完成了镜像的构建以后,还需要服务器定时去主动的拉取镜像,更新正在运行的后端服务,完成项目上线.
watchtower 就可以很给力的完成这个任务.watchtower本身也可以使用docker镜像的方式运行.
运行
1 | docker run -d --restart=always \ |
就可以启用 watchtower 镜像,此后每 5 min,服务器都会去查看docker hub 是否有版本更加新的镜像,如果有,就删除当前镜像,拉取新镜像,并使用相同的运行参数完成新的镜像.上述的代码会检查所有镜像的更新,如果只想对特定的镜像进行检查,可以去查 watchtower 的文档,修改参数.
美观的域名
示例
域名为 Domain.com 的服务器上,运行 后端服务A 8000,后端服务B 8001.
显然,此时,通过 http://backend.Domain.com:8000 和 http://backend.Domain.com:8001 即可通过不安全的 HTTP 访问后端服务.
通过 Nginx ,我们可以做到 https://a.backend.Domain.com 和 https://b.backend.Domain.com 分别通过安全的 HTTPS 访问后端服务.对于用户访问网站的时候,显然要访问前端文件.给用户的网站地址是 a.Domain.com,然后前端通过 ajax 等方法与 https://a.backend.Domain.com 通信.
证书准备
先将 a.backend.Domain.com 和 b.backend.Domain.com 都采用 CNAME 的方式解析到 https://a.Domain.com 上.
比较方便的是使用阿里云的免费证书,如果域名也是阿里云的就更加方便了.
切换到阿里云的 SSL证书 功能页面,购买证书,选中免费的,然后 申请 a.backend.Domain.com 和 b.backend.Domain.com 并启动验证,就可以获得证书了,下载 nginx 的,进行重命名,pem结尾的是公钥,key结尾的是密钥
这时候我们分析一下,用户访问 https://a.backend.Domain.com 和 https://b.backend.Domain.com 的时候,实际都会访问 https://a.Domain.com 的443端口.但是从 HTTP 的角度来看,这2个请求中的 host 是不一样的,所以可以根据 host 字段转发到不同的后端服务上去.同时,在转发过程中,也可以加上 TLS 层.
具体来说,就需要使用 Nginx 了.
创建相关文件结构如下
1 | nginx - crt - a.backend.Domain.com.key |
DockerFile 内容
1 | FROM nginx1 |
nginx.conf 内容
1 | user nginx; |
主要看 Server 部分
ssl_certificate 定义了公钥路径
ssl_certificate_key 定义了密钥路径
访问 https://a.backend.Domain.com 时,Nginx 就会发现 HTTP 包里的 Host 和第一个 server 块中 的 server_name 相同,所以会转发到本机的 http://127.0.0.1:8000 上,并提供了 SSL 服务.
同理,访问 https://b.backend.Domain.com 时,会转发到 本机的 http://127.0.0.1:8001 上,并提供了 SSL 服务.
最后使用 docker 运行 Nginx
1 | docker rm mynginx -f |
前端 OSS
一般来说,会把前端文件也放在服务端里.但是这样有2个不好的地方.第一是服务器的网络带宽不够,阿里云服务器只有5m,就算只给一个用户传递网页文件也会卡,更别说更大的并发量了.第二就是前后端分离不彻底,每次前端更新,都必须依靠后端才能部署.
所以,可以借助 ali oss ,把前端文件放在OSS上,就能解决上述的2个问题了
把前端文件放进 oss 并绑定上 a.Domain.com
用户访问 a.Domain.com 时就可以访问到 静态前端文件了
然后前端文件再访问 a.backend.Domain.com 与 服务器交互
可以参考 https://help.aliyun.com/document_detail/67323.html?spm=a2c4g.11186623.6.723.7104300eVXRz4Z
记录一个坑
记得把 基础设置 -> 默认首页 和 默认 404 页 都改成 index.html.当然,具体操作要看前端文件是怎么样的.
然后创建一个子账号,授予权限,然后就可以把子账号交给前端,前端下载 oss-browser,就可以由前端自行控制文件上传了.
a.Domain.com 访问到 a.backend.Domain.com 的内容,会触发跨域问题.记得前后端一起协同处理.