目录

如何快速开发&部署前后端

前言

随着云计算、开源社区、AI的兴起,能够简单复制的工作价值已经开始下降,组织的核心价值是具有独创性的工作。未来的人才也必须时具有多维度视角,又有独特专长的人。未来的组织也一定是朝着富有创造力的人+机器协同成为主流的工作形态。是一个紧耦合的特种兵小团队+松耦合的内部合作+开放的网络协同。 以前互联网相关创业时,没有百十来号人根本玩不转。但是现在十几号人的团队也能做出非常大、非常成功的产品。就像是Midjourney一样。 那么话说回来,如何快速开发&部署前后端分离的一个产品呢?

主要工作

主要的工作有:

后端

语言选择

如果是一个简单的后端项目,golang一定是首选。语法简单,占用资源也少,最关键的是golang本就是开源的语言,围绕golang的开源社区也非常丰富。一些通用的能力都无需自己再造轮子。最近比较火的Rust语言也比较适合,但是使用起来比较复杂。 如果是一个复杂的后端项目,需要各种复杂的抽象,分层,封装。那么Java还是当之无愧。现在大型的复杂后端项目,用Java的还是比较多。当然如果更熟悉C++也是可以的。

架构选择

  • 数据库:对于后端,很多都是需要数据库的,那么首选gorm来完成数据库的增删改查。在测试阶段可以直接使用sqlite,如果要发布到线上,最好要切到mysql。因为sqlite不具备备份能力,性能也跟不上。因为有云计算,所以你不必自己搭建mysql的服务,可以直接在云上申请数据库,既保证安全,又有监控,方便运维。当然如果你想自己搭建一个mysql服务,可以直接找一个已经封装好的,可以直接部署到k8s的mysql,提交到集群即可。
  • 缓存:对于一些常用的数据,需要经常访问,此时需要一个缓存来减轻数据库的压力,并提高响应效率。本地测试的时候可能并不需要。如果要发布到线上,最好配上redis。当然也可以自己部署,但是最好的是直接在云上申请。
  • Rest服务:使用golang开发后端,gin无疑是最好的rest框架
  • 鉴权:前后端在通信的时候,一般都需要带上token,特别是微信小程序/App等前端,很容易能被第三方来请求到他人的数据。此时可以使用DES加密,使用密码将每个用户的id进行加密后组成token,后端将token解密后再与用户id进行比较,能够匹配上才可以访问。
  • 对象存储:当有图片/文件需要存储时,首选一定是云服务的OSS,这样前端访问时可以直接通过OSS来访问,也可以减轻后端压力。本地测试的时候可以存到本地。图片存到OSS,也可以用到云厂商的图片审核能力来做安全审核。

部署

不要认为代码开发完工作就完成了,很多时候,当你完成一个项目的90%,你还需要用另一个90%细化。

K8S

当前要部署一个应用,最好的选择一定是部署到K8S上,这已经是事实标准。如果测试可以自己部署一套K3S,需要的只是一条命令就能拉起一个集群 参考 K3S Doc 。如果是线上环境则最好直接在云厂商申请一套K8S。 如果使用k3s,在集群外使用kube-config时,需要将中的server: https://127.0.0.1:6443 改为 server: https://{公网IP}:6443 并在集群内执行 curl -vk --resolve 1{公网IP}:6443:127.0.0.1 https://{公网IP}:6443/ping 这里需要补充一下在国内一般使用 curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn sh - 来安装,以免拉不到包的问题。但是仍然存在像是github无法访问,包拉不到等等网络问题。此时可以通过离线安装,官方文档有介绍。

  • 或者在环境里直接配置一个正向代理,比如使用gost gost -L socks5://:1080 -F 'http2://xxx:xxx@xxx:443' 详细方法可以参考本blog优雅上网的那篇文章。
  • 在执行k3s-install.sh 是 在脚本前面加上
    1
    2
    
    export http_proxy="socks5://127.0.0.1:1080"
    export https_proxy="socks5://127.0.0.1:1080"
    
  • 部署完成后 如果要删除代理。需要
    • 修改文件 /etc/systemd/system/k3s.service.env 去掉代理
    • sudo systemctl daemon-reload 重新加载配置文件
    • sudo systemctl restart k3s 重启k3s服务

域名

申请

  • 域名申请可以在多个平台上申请,如果服务部署在国内,且主要是给国内使用,则可以在云厂商申请。可以申请时直接在云厂商进行备案。
  • 如果服务部署在国外,且主要是给国外访问,可以在GoDaddy上申请,GoDaddy上比较便宜,第一年3刀;

DNS绑定

DNS配置,(DNS)域名系统,的主要任务就是将域名映射到为IP地址。一个域名可以申请多个子域名,每个子域名都要进行DNS绑定。需要在域名申请机构来做DNS绑定,DNS配置A记录。其中name为申请的域名,例如example.com, value为公网IP。

  • 国外使用, 可以直接在cloudflare进行DNS绑定解析,cloudflare, cloudflare可以在全球进行CDN加速,关键还有很高的免费额度。非常良心。
  • 如果在国内使用,需要在域名申请的云厂商进行绑定。一般会有一两个免费的CDN节点,如果要更多CDN节点,或者网络请求分析之类的就要花钱了。

服务部署

通过一个deployment部署,并配合上service

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: "10"
  name: xxx-server
  namespace: default
spec:
  ...
---
apiVersion: v1
kind: Service
metadata:
  name: xxx-server
spec:
  selector:
    app: xxx-server
  type: NodePort
  ports:
    - name: xxx-port
      port: 8081
      protocol: TCP
      targetPort: 8081

服务域名

我们将域名绑定到公网IP之后,要如何与我们的服务绑定呢?因为我们的服务都是部署在K8S上的,K8S南北流量都是通过Ingress来绑定的。

  • 如果是通过云厂商申请的K8S,一般会提供external-vip,此时我们将ingress的service external ip绑定到云厂商提供的external-vip即可。
  • 如果是自己部署的K8S/K3S,我们能够拿到的只有服务器的公网IP,还需要将服务器的公网IP的请求转发到Ingress上。Ingress就是一个反向代理,来代理部署到服务器的服务。如果使用traefik, 会自动在节点上配置iptables 将节点的80/443 的请求转发的traefik controller上,别忘了还需要将服务器的防火墙的80/443端口打开。
1
2
-A CNI-DN-7eb9831515660be4ab481 -p tcp -m tcp --dport 80 -j DNAT --to-destination 10.42.0.7:80
-A CNI-DN-7eb9831515660be4ab481 -p tcp -m tcp --dport 443 -j DNAT --to-destination 10.42.0.7:443

Https证书

现在的服务,很少还有http的了,https是标配。具体原因就不细说了。我们可以通过 let’s encrypt来申请https证书。因为我们的服务是部署在K8S上的。直接提交一个yaml就可以进行证书自动申请。免费的证书有限期为90天,过期后会自动续签。 当拥有https证书后, 80端口也依然需要打开,后续certmanager做续签时需要使用80端口

 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
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  labels:
    app: test-server
  name: test-server
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  rules:
  - host: test-server.com
    http:
      paths:
      - backend:
          service:
            name: test-server
            port:
              number: 8081
        path: /
        pathType: Prefix
  tls:
  - hosts:
    - test-server.com
    secretName: letsencrypt-prod

---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer # I'm using ClusterIssuer here
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: xxx@xxx.com
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
    - http01:
        ingress:
          class: traefik

自动化

上面的工作做完之后就可以拉起一个服务务了,并且有https的能力。但是我们希望每次提交代码的时候都能自动发布。此时就需要使用github的action功能了。

仓库配置action secret

因为要自动构建,发布,所以需要将镜像仓库的username/token存到github上,每次可以自动推送镜像到docker hub。 通过k8s发布,还需要将kubeconfig配置上,一般需要做base64 编码,以防止乱序问题。 参考 https://www.ruanyifeng.com/blog/2019/09/getting-started-with-github-actions.html