1.综述

一句话: 关注 CNCF 基金会 Cloud Native 云原生互动全景图

CNCF云原生互动全景图
打开网站,全景图是可以点击的,在图中找你关注的领域

2.找到你关注的分类领域

比如我关注“API Gateway API网关”,就点击他的图标就可以看到相关信息
APISIX

KrakenD

非常直观的一个概览
项目开发语言,代码提交柱状图,等开源代码维护情况信息

可以说CNCF的全景图就是一张开启云原始大门的大地图,地图在手开始遨游吧

3.CNCF分类大纲 (截止2020年02月08日)

CNCF云原生互动全景图

App Definition and Development 应用定义和开发

  • Database 数据库
  • Streaming & Messaging 流处理和消息系统
  • Application Definition & Image Build 应用程序定义和图像构建
  • Continuous Integration & Delivery 持续集成与交付

Orchestration & Management 编排和管理

  • Scheduling & Orchestration 计划与编排
  • Coordination & Service Discovery 协调与服务发现
  • Remote Procedure Call 远程过程调用
  • Service Proxy 服务代理
  • API Gateway API网关
  • Service Mesh 服务网格

Runtime 运行时

  • Cloud Native Storage 云原生存储
  • Container Runtime 容器运行时
  • Cloud Native Network 云原生网络

Provisioning 提供者

  • Automation & Configuration 自动化与配置
  • Container Registry 容器注册中心
  • Security & Compliance 安全与合规
  • Key Management 密钥管理

Platform 平台

  • Certified Kubernetes – Distribution k8s认证过的产品
  • Certified Kubernetes – Hosted k8s认证过的主机
  • Certified Kubernetes – Installer k8s认证过的安装工具
  • PaaS/Container Service PaaS平台/容器服务

Observability and Analysis 可观察性和分析

  • Monitoring 监控
  • Logging 日志
  • Tracing 跟踪
  • Chaos Engineering 混沌工程

Serverless 无服务器

Members 加入CNCF的会员

Special 特别的

  • Kubernetes Certified Service Provider k8s认证服务提供商
  • Kubernetes Training Partner k8s培训合作伙伴

api网关的本质

不用扯那么多,也不用画图,一句话说清楚
api网关:流量总入口,得以集中控制!
就这么简单

api网关协议上最基本要支持HTTP 和 WebSocket,功能强大点的更会支持tcp/udp的负载均衡接入
正因为支持的是http协议,所以api网关不仅仅可以作为 RESTful API 接入,接入带页面的web都可以的,完全可以当成一个web负载均衡器使用

api网关的作用

解决:认证、鉴权、安全、流量管控、缓存、服务路由,协议转换、服务编排、熔断、灰度发布、监控报警等问题
本质上,流量从我过,我就可以做想做的控制,上面列的就是我需要的控制
有了api网关才不至于裸奔,才不至于在业务层“重复建设”,才不至于在业务层去用redis+lua实现“亲,你访问过于频繁,请稍后再试”,这个事交给api网关就成

api网关比较

开源api网关大全

之前流水理鱼把市面上开源的api网关整理了个大全 “开源API网关大全20款+” https://www.iamle.com/archives/2591.html ,大部分都加入了CNCF

以下api网关3Scale、Ambassador、APISIX、Express Gateway、Gloo、Kong、KrakenD、Mia-Platform、MuleSoft、Reactive Interaction Gateway、Sentinel、Tyk、WSO2 API Microgateway
加入了CNCF

开源api网关技术栈情况

api网关技术栈,老一派的使用java,新派的使用golang、openresty+lua
小众Node.js、.net、C++ 技术栈虽然不一样,达到的目的却是一样的。
用静态语言编写api网关是有弊端的
使用静态语言编写的api网关都会有插件编写不方便的问题
使用java编写的老牌网关性能差,历史包袱重
openresty+lua也许是最佳的api网关、waf、web防火墙解决方案
依托于openresty平台具备超高性能,又依托于lua获得了动态性
CloudFlare也是春哥当年用openresty+lua技术栈做的引擎

我们从不同的技术栈来做个api网关分类
openresty+lua开源api网关
代表有Kong、APISIX、3scale、、API Umbrella

Kong不用做太多介绍,应该是开源里面最热的一个api网关了,相对庞大复杂
APISIX,轻巧+极致性能+热插件,值得一提到是插件中有个serverless的支持,简单说就是写一段自定义lua脚本,挂载到openresty任意阶段执行!

golang开源api网关
代表有Tky、Manba、GOKU API Gateway、Ambassador(基于Envoy)、Gloo(基于Envoy)、KrakenD、BFE

java开源api网关
代表有Gravitee、Zuul、Sentinel、MuleSoft、WSO2、Soul

Erlang开源api网关
代表有RIG – Reactive Interaction Gateway

.net开源api网关
代表有Ocelot

Node.js开源api网关
代表有express-gateway

闭源商业api网关

从gartner(艾瑞咨询类似)的权威报告可以找到老牌的api网关玩家是谁
行业老大:Apigee、3Scale、Amazon等
各大云都是玩家,比如阿里云api网关、腾讯云api网关、Amazon API Gateway
国内还有几家也在做商业api网关,具体搜索下就能找到

总结下api网关选型建议

  • 前提满足功能需求
  • 不在乎商业闭源绑定,不想麻烦,选你最容易获取的商业api网关例如云平台卖的商业网关
  • 国内用户选 apisix 为代表的openresty+lua技术栈api网关,可以得到中文群组支持
  • 希望国际化的选 kong 为代表的openresty+lua技术栈api网关
  • 有大量的某语言开发人员,可以选基于这个技术栈的api网关,例如java选Gravitee,golang选tyk、Manba

采用多级拦截,后置拦截的方式体系化解决

1.分层拦截

1.1第一层 商业web应用防火墙(WAF)

直接用商业服务

传统的F5硬件,不过现在用的很少了
云时代就用云时代的产品,典型代表 阿里云 web应用防火墙

1.2第二层 API 网关(API Gateway)层

API 网关(API Gateway)

kong为代表的开源 API 网关 实现
openresty + lua 自实现
windows平台 安全狗、云锁 实现

1.3第三层 应用层

用Redis内置lua脚本

redis是块砖,哪里需要哪里搬
redis内置了lua引擎,2.6版本后你可以编写一段lua脚本,完成逻辑判断流程

常见的有对某维度计数器法 对某维度令牌桶法
维度的概念比如就是IP或者IP+模块等, 多个字段合并成一个维度

本方案满足绝大多数应用层的限流需求
当然也可以自己用应用层程序实现,前提是redis+lua满足不了你的需求

2.后置拦截

基本的套路其实很简单,从日志这里计算出恶意IP,恶意用户,再给其他系统用
分控的基本思想也是这样的

已经在用ELK日志系统:可以用ES中定时查询高频IP,送入WAF做拦截
已经在用流计算系统:flink和spark等流计算系统计算出高频恶意IP,用户等

然后就可以应用这些计算出的结果数据做限制,封禁等

3.一+二+三+后置协同工作

第一层Waf当然有拦截,但是对于新IP他不会马上生效, 会有几分钟的时间才会拦截
特别是恶意爬虫IP池一上,大量新IP就来了,第一层会放过来,如果只是一层,结果就是数据库慢查询告警叮叮叮

配合上二层 三层 一层一层拦截
如果没有精力搞二层,那么第一层用买的,第二层不做,搞第三层

后置拦截的结果可以作为长期封禁使用
这种多次拦截的策略和多级缓存的概念是不是很像
多层次的拦截保障源站监控告警静悄悄

面向C端的产品被爬虫,被恶意访问的概率会大很多
面向B端的网页也不是没有风险
面向B端的API也有限流的需求

1.场景

容器化+K8s编排已经是现在进行时
把网站的多个项目设计为云原生(Cloud Native)或老项改造为云原生可以获得诸多能力
例如无云绑定、弹性、部署环境一致性、微服务、DevOps、持续交付
同时下一代微服务框架 服务网格(ServiceMesh) 也能无痛接入

博主现有项目后端开发语言为 PHP、Golang
Golang做一些基础公共服务(短信、消息、搜索等)
这些公共服务化的项目已经容器化
PHP的项目做应用逻辑层,会调用Golang写的一些公共基础服务
PHP项目中直接通过服务名调用服务

需求: PHP项目A 依赖 短信、消息、搜索这3个服务,开发人员无需在本机启动依赖的服务,通过服务直接名透明的调用开发环境dev下的服务,开发人员只需要关注PHP项目A的开发。

☆本文的方案完成了开发人员开发机透明的直接访问K8s服务,从而满足了本需求☆

需要开发机透明访的直接问Kubernetes群集内的服务本文讲的方案都适用

开发机直接访问Kubernetes群集内的服务 示意图

2.基本信息和完成的目标

2.1基本信息

开发办公内网 192.168.1.0/24
开发机2 192.168.1.2

运行K8s群集的Node网络 10.2.0.0/16
Node1 10.2.1.4
Node2 10.2.1.8
K8s 群集网络 10.3.0.0/16

部署deployment whoami服务用于测试
命名空间 default (这里可以用命名空间来区分环境例如dev为开发环境)
镜像 wwek/whoami
服务名 whoami

Pod ip
10.3.0.8在node1 10.2.1.4
10.3.0.70在node2 10.2.1.8

2.3完成的目标

开发机2 192.168.1.2 可以直接访问 whoami服务
也就是可以直接 curl http://whomai 就可以访问服务
本目标即完成需求

3.网络互通1 开发办公内网 <==> 公有云VPC(私有云内网)基础互通

开发办公内网 和 公有云VPC、私有云内网 网络互通

和公有云互通的方案
公有云VPN
专线(SDWAN)

私有云互通就不多讲了,很多公司内网的K8s开发测试群集和开发网络本身就是互通的

各家网络情况各有各的不同,相同的是这些有用的Tips
无论是在公有云VPC、私有云、K8s群集非常关键的一点,子网网段不要冲突不要冲突、子网网段不要冲突、子网网段不要冲突
做基础互通的时候善用公有云的VPC和路由配置功能
甚至你可以不用买公有云自带的VPN网关服务,直接配合VPC路由表用一台VM充当路由器网关、VPN网关
开发测试环境下用zerotier来打通各个内网性价比极高

最终要完成是 开发办公内网 和 公有云VPC(私有云内网) 基础互通

4.网络互通2 开发办公内网 <==> K8s群集内部Pod和Service网络

☆☆☆ K8s Node本身是直接可以访问K8s群集内部Pod网络的!☆☆☆
在Node1上用ping/curl测试 whoami服务 分布在2个Node的2个Pod

可以看到,whoami的2个pod ip都能ping通,用curl测试也能访问到

通过Edge Node互通K8s群集和开发办公之间的网络
那么用Node1作为 开发办公内网 和 K8s群集内部网络的“连接”点我们把这个Node1节点叫做 边缘节点(Edge Node)
边缘节点(Edge Node)可以在运行K8s群集中Node中随便选一个
这里选择Node1,他的网卡信息如下
eth0 vm网卡 ip 10.2.1.4
cbr0 K8s群集创建的网卡 ip 10.3.0.1

可以有2种方式
方式1 在 Edge Node eth0 上启用NAT 这样其他的子网的访问在K8s群集中看到的IP是 10.2.1.4
方式2 K8s群集子网和开发办公内网完全对等互通(公有云VPC路由表、开发办公网络路由表配合做)

完成后
开发办公网络中 在开发机2 192.168.1.2 ping/curl K8s群集中的pod ip

可ping/curl 属于whoami的2个Pod ip

㊗️网络搞通了,那么再解决DNS解析的问题就可以了

5.打通K8s群集中的DNS (开发办公内网的DNS,设置K8s中KubeDns为上游DNS)

在Edge Node1上可以直接访问到KubeDns

kubectl get svc -n kube-system
#kube-dns ip 10.3.254.107

那么在Edge Node1上面装一个DNS Server做个中间转发(使用CoreDNS)
开发网络中的电脑无法直接使用kube-dns,非Edge Node解析结果为空
所以需要在Edge Node1上转一个 DNS Server 做一个Proxy
CoreDNS的安装使用参考我的另外一篇文章
使用CoreDNS作为你的内网DNS服务器
可用CoreDNS配置文件参考
/etc/coredns/Corefile

# kubernetes设置
cluster.local:53 {
  # kube-dns
  forward . 10.3.254.107:53
  log
  errors
  #debug
}

# 默认设置
.:53 {
  # 先走本机的hosts
  # https://coredns.io/plugins/hosts/
  hosts {
    # 自定义sms.service search.service 的解析
    # 因为解析的域名少我们这里直接用hosts插件即可完成需求
    # 如果有大量自定义域名解析那么建议用file插件使用 符合RFC 1035规范的DNS解析配置文件
    #10.6.6.2 servicename
    # ttl
    ttl 60
    # 重载hosts配置
    reload 1m
    # 继续执行
    fallthrough
  }

  # file enables serving zone data from an RFC 1035-style master file.
  # https://coredns.io/plugins/file/
  # file service.signed service
  # 最后所有的都转发到系统配置的上游dns服务器去解析
  forward . /etc/resolv.conf

  # 缓存时间ttl  s
  #cache 6
  # 自动重新加载配置文件的间隔时间
  reload 6s
  # 输出日志
  log
  # 输出错误
  errors
  #debug
}

启动CoreDNS

dig @10.2.1.4 whoami.default.svc.cluster.local
# 测试下确保可以解析

在 开发机2
配置DNS为 Edge Node1 IP 10.2.1.4
配置搜索域为 default.svc.cluster.local

这个2个配置可以在开发办公网络中的DHCP服务器上统一配置

-w564

来测试下DNS解析 curl访问

6.关键实现总结

  • 网络互通1 开发办公内网 <==> 公有云VPC(私有云内网)基础互通
  • 网络互通2 开发办公内网 <==> K8s群集内部Pod和Service网络(通过Edge Node)
  • 打通K8s群集中的DNS (开发办公内网的DNS,设置K8s中KubeDns为上游DNS)
  • 开发机DNS配置 Edge Node DNS 和 搜索域设置default.svc.cluster.local

7.QA

问1:这也太复杂了吧,有没有简单点的?
答:
解决的目标不同

如果只是单纯的能访问k8s中的服务有以下的方式
访问K8s中的服务还有这些方式
telepresence (快速,本地开发面向k8s的微服务)
K8s中装个openvpn 拨入群集内网络
K8s自带的服务暴露方式 NodePort Ingress

这些方法在一个应用有多个服务依赖的时候无法做到让所有开发人员透明的直接通过服务名调用

为了做到对多个开发人员透明,所有人都不需要安装项目依赖的服务,只需要运行项目本身,本项目透明的调用依赖的服务。
所以才有了本文的“复杂”方案

问2:这样直通了暴露K8s群集后岂不是不安全?
答:
是的,但是可以解决,我是这么解决的
K8s群集分为线上和线下实现了隔离
线上为准生产、生产,线下为开发、测试
k8s中可以用命名空间(namespace)来做环境的区分
dev、testing、staging、prod

问题3:开发机中DNS用K8s的DNS作为上游后网站的CDN乱解析了!
答:
开发办公网络和公有云的网络运营商和地理位置都不同,
也就是如果网络出口不一样这会导致CDN解析的IP是错的

需要在开发办公网络也部署一个DNS Server成为二级DNS
开发办公网络 开发机设置DNS为这个二级DNS
cluster.local转发到 Edge Node DNS上
其他的走本地默认的DNS
同样采用CoreDNS,配置文件参考

cluster.local:53 {
  # Edge Node DNS
  forward . 10.2.1.4:53
  log
  errors
  #debug
}
.:53 {
   ....
}

私有云或者自己在开发办公网络部署的K8s群集,因为是同一个网络出口那么网站的DNS解析应该不会有问题

Istio

Istio官网
Istio中文官网
Istio开源
无需太多介绍Service Mesh明日之星,扛把子,截止2019.11还有太多问题没解决
复杂性,性能让人望而却步,能上生产的是真要技术厉害,还得内心强大,项目允许

Linkerd

Linkerd官网
Linkerd中文官网

A service mesh for Kubernetes and beyond. Main repo for Linkerd 2.x.
Linkerd is a service mesh, designed to give platform-wide observability, reliability, and security without requiring configuration or code changes.

Linkerd is a Cloud Native Computing Foundation (CNCF) project.

Maesh

Maesh官网
Maesh开源

Containous(Traefik 团队)推出了全新设计的轻量级 service mesh(服务网格)工具:Maesh,Maesh 允许对 Kubernetes 集群内流动的流量进行管理,这与入流量和出流量同样很重要。
Maesh 构建在 Traefk 之上,是一个简单但功能齐全的服务网格,支持最新的服务网格接口规范 SMI,有助于与现有的一些解决方案进行集成。此外,Maesh 默认是需要开启使用的,这意味着在你决定将它们添加到网格之前,你的现有服务不会受到影响。

比较喜欢用go语言编写的东西,毕竟CNCF中绝大多数项目都是go语言编写的,看后续走向

Consul

Consul官网
Consul开源

Secure Service Networking
Consul is a service networking solution to connect and secure services across any runtime platform and public or private cloud

consul原本是个分布式kv,可以用来做配置中心,注册中心,现在官方默认的宣传语都改成了连接和保护服务

定位服务发现(Service discovery)和 服务网格(Service Mesh)

Envoy

Envoy官网
Envoy开源
ENVOY IS AN OPEN SOURCE EDGE AND SERVICE PROXY, DESIGNED FOR CLOUD-NATIVE APPLICATIONS
ENVOY是开放源代码边缘和服务代理,专为云应用程序而设计

envoy作为服务网格中的通用数据平面, xDS API 已经成为数据平面API接口的实施标准
就好像AWS的OSS对象存储中的S3一样,成了事实标准

SOFAMson

SOFAMson官网
SOFAMson开源

SOFAMson 是一款使用 Go 语言开发的 Service Mesh 数据平面代理,旨在为服务提供分布式、模块化、可观察和智能化的代理能力。SOFAMosn 是 SOFAStack 中的一个项目,其中 MOSN 是 Modular Observable Smart Network 的简称。SOFAMosn 可以与任何支持 xDS API 的 Service Mesh 集成,亦可以作为独立的四、七层负载均衡使用。未来 SOFAMosn 将支持更多云原生场景,并支持 Nginx 的核心转发功能。

目前蚂蚁金服有大规模落地,2019年的双十一已经做了生产实践
API接口方面也是兼容Envoy的 xDS API 标准

1. 单机运行的Docker

容器化部署是现在进行时,开源应用大多数支持容器化部署
在少量机器的场景下往往采用docker cli 和 docker-compose管理,进行“单机式管理”
机器稍多点会采用Docker Swarm群集的方式,毕竟k8s稍重
如果有更多的机器情况下一般会采用k8s的方式
在个人、创业公司、小团队的场景下我们往往在多个云、家里、vps上拥有少量虚拟机服务器,这些服务器上都运行了docker实例
虽然我们也可以用公网vpn、zerotier等方式打通各个地域的机器形成一个内网,从而构建“群集”,但实际情况是没那么多带宽,从而无法“负载均衡”,所以实际的实际还是独立使用
受限制于公网带宽很小,只能独立使用
我们也拥有一些4G移动流量接入这种EDGE边缘场景的情况,这些IoT上也运行着Docker实例
那么这些NAT内网环境下的Docker实例,公网IP环境下的Docker实例,是否能集中管理?
当然可以,用Portainer就挺方便

2. 用Portainer作为Docker实例管理平台实战步骤

2.1 主节点-Portainer server主控安装

选一个7×24小时且有公网IP的节点运行Portainer server主控

docker run -d -p 8000:8000 -p 9000:9000 --name portainer --restart always -v /var/run/docker.sock:/var/run/docker.sock -v /data/appdata/portainer:/data portainer/portainer

9000端口为web管理界面端口
8000端口为Agent接入端口
这2个端口公网IP防火墙都必须放行

浏览器打开web管理界面
http://Portainer server主控公网IP:9000

初次访问设置一个密码,设置密码后需要选择连接docker的方式
选第一个Local 然后点击Connect
默认进入Home菜单,点击这个Local本地docker实例进入其他管理

Portainer官方安装手册参考

2.2 配置https nginx代理(可选)

如果不配置https可跳过本节
http://你的公网IP:9000 默认没有https不安全
规划一个域名用于https访问例如https://portainer.iamle.com
用nginx作为接入反向代理到 http://portainerip:9000
下面为示例nginx portainer配置(其中包含需要的websocket proxy)

# portainer.iamle.com.conf
map $http_upgrade $connection_upgrade {
    default Upgrade;
    ''      close;
}
upstream portainer {
    server 127.0.0.1:9000;
}
server {
        listen       80;
        server_name portainer.iamle.com;
        return      301 https://$server_name$request_uri;
}
server {

                listen 443 ssl http2;
        server_name portainer.iamle.com;

                ssl_certificate         ssl/iamle.com.cer;
                ssl_certificate_key     ssl/iamle.com.key;
                #ssl_session_cache           shared:SSL:10m;
                #ssl_session_timeout         10m;
                #ssl_session_tickets         off;

                ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
                ssl_ciphers         HIGH:!aNULL:!MD5:!EXPORT56:!EXP;
                ssl_prefer_server_ciphers on;

        location / {
                    proxy_set_header Host              $host;
                    proxy_set_header X-Forwarded-Proto $scheme;
                    proxy_set_header X-Forwarded-Port  $server_port;
                    proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
                    proxy_set_header X-Real-IP         $remote_addr;
                    proxy_set_header X-Request-Id $request_id;
                    proxy_set_header Upgrade           $http_upgrade;
                    proxy_set_header Connection        $connection_upgrade;
                    proxy_read_timeout 60m;
                    proxy_send_timeout 60m;
                    proxy_http_version 1.1;
                    proxy_pass http://portainer;
                    break;
        }


        error_log   /data/logs/portainer.iamle.com-error.log;
        access_log  /data/logs/portainer.iamle.com.log access;

}

2.3 主节点-配置一个在NAT内网Agent客户端

前面我们已经配置好一个具有公网IP的Portainer管理控制节点
那么现在把内网(NAT、IoT)、公有云、vps等运行的Docker实例来接入控制节点管理

一图胜千言,官方介绍图

图中这个Portainer管理了2个内网的Agent
其中一个是个Swarm群集,另外一个是个单机

Portainer server上增加一个Edge Agent
Endpoints菜单 》 Add endpoint 》 Edge Agent

Name:为自定义
Portainer server URL:默认为当前Portainer server ip (如果用nginx配置了https可以使用https不加端口号)
》 Add endpoint

增加端点后出现

部署客户端agent 有2种选择 Standalone 和 Swarm
如果已经组过Swarm那么选Swarm,默认就是Standalone
先点击 “Copy command” 复制命令,在Agent客户端去执行
Public IP: 如果有可以设置,这样在以后部署了docker容器暴露的端口可以自动生成url

2.4 被管理节点-需要被管理的Docker实例客户端机

在被管理的客户端终端上执行(内网(NAT、IOT)、公网环境都可以,只要能连接上我们的Portainer server)
本例内网1台ip为 192.168.0.8的机器

docker run -d -v /var/run/docker.sock:/var/run/docker.sock -v /var/lib/docker/volumes:/var/lib/docker/volumes -v /:/host --restart always -e EDGE=1 -e EDGE_ID=6ad0f1ff-6fea-4710-97e2-513ef1066fd8 -e CAP_HOST_MANAGEMENT=1 -p 8000:80 -v portainer_agent_data:/data --name portainer_edge_agent portainer/agent:1.5.1

访问 http://192.168.0.8:8000(如果有公网ip用公网ip)
打开后会有个输入框
输入上一步获得的Join token
点击Submit 出现 Agent setup OK. You can close this page. 代表完成agent接入

回到 Portainer server管理界面等待上线

点击 iamle-lan-01 等待几秒钟

这样我们就可以管理多个docker实例了

3. 贴士

  • 如果agent运行不起来,无限重启
    需要根据docker logs portainer_edge_agent 获取到的错误信息排查, 官方github issue是个好去处
    另外发现2019年10月19日16:55:01 pull 下来的portainer/agent:latest 也运行不起来 改为 portainer/agent:1.5.1正常

  • Stacks粘贴docker-compose.yml进来后一直报version版本不对
    目前只支持version 2 改为2即可

4. 参考

Portainer Edge Agent 官方发布
Portainer内网边缘节点配置说明书PDF