产品战略专家梁宁确认出席AICon北京站,分享AI时代下的商业逻辑与产品需求 了解详情
写点什么

Rego 不好用?用 Pipy 实现 OPA

作者: Addo Zhang

  • 2021-07-15
  • 本文字数:5099 字

    阅读完需:约 17 分钟

Rego 不好用?用 Pipy 实现 OPA

还不知道 Pipy 是什么的同学可以先看下简介:


Pipy 是一个轻量级、高性能、高稳定、可编程的网络代理。Pipy 核心框架使用 C++ 开发,网络 IO 采用 ASIO 库。 Pipy 的可执行文件仅有 5M 左右,运行期的内存占用 10M 左右,因此 Pipy 非常适合做 Sidecar proxy。


Pipy 内置了自研的 pjs 作为脚本扩展,使得 Pipy 可以用 JS 脚本根据特定需求快速定制逻辑与功能。

Pipy 采用了模块化、链式的处理架构,用顺序执行的模块来对网络数据块进行处理。这种简单的架构使得 Pipy 底层简单可靠,同时具备了动态编排流量的能力,兼顾了简单和灵活。通过使用 REUSE_PORT 的机制(主流 Linux 和 BSD 版本都支持该功能),Pipy 可以以多进程模式运行,使得 Pipy 不仅适用于 Sidecar 模式,也适用于大规模的流量处理场景。 在实践中,Pipy 独立部署的时候用作“软负载”,可以在低延迟的情况下,实现媲美硬件的负载均衡吞吐能力,同时具有灵活的扩展性。


在玩过几次 Pipy 并探究其工作原理后,又有了更多的想法。


初探可编程网关 Pipy可编程网关 Pipy 第二弹:编程实现 Metrics 及源码解读可编程网关 Pipy 第三弹:事件模型设计


在使用 OPA 的时候,一直觉得 Rego 不是那么顺手,使用 pipy js 来写规则的想法油然而生。今天就一起试试这个思路。果然,不试不知道,一试发现太多的惊喜~Pipy 不止于“代理”,更有很多可以适用的场景:


•极小的单一可执行文件(single binary)使得 pipy 可能是最好的 “云原生 sidecar”

•sidecar 不仅仅是代理,还可以做控制器,做运算单元

•proxy 的串路结构适合各种管控类的操作,比如访问控制

•Pipy js 的扩展能力和快速编程能力,很适合做 “规则引擎”,或者用最近流行的说法 “云原生的规则引擎”。对比 OPA 我认为它完全够格做一个 “羽量级规则执行引擎”。


现在我更倾向于定义 pipy 是一个 “云原生的流量编程框架”,代理只是其底层的核心能力,叠加了 pipy js 以后,上层可以做的事情很多,“流量滋养万物”。


在 使用 Open Policy Agent 实现可信镜像仓库检查 之后,就在想 Pipy 是否一样可以做到,将内核替换成 Pipy + 规则。所以今天大部分内容和上面这篇是相似的。


来,一起看看这个“不务正业”的 Pipy 如何实现 Kubernetes 的准入控制器 来做镜像的检查。


环境


继续使用 minikube


minikube start
复制代码


创建部署 Pipy 的命名空间


kubectl create namespace pipykubens pipykubectl label ns pipy pipy/webhook=ignore #后面解释
复制代码


规则


在 OPA 中,通过 kube-mgmt 容器监控 configmap 的改动,将 Policy 推送到同 pod 的 opa 容器中。


对于 Pipy 为了渐变,直接使用挂载的方式将保存了规则的 configmap 挂载到 Pipy 的容器中。


实际的使用中,Pipy 支持轮训的方式检查控制平面中规则的变更,并实时加载;也可以实现与 OPA 的 kube-mgmt 同样的逻辑。


实现了上一讲功能的 pipy 规则如下:


cat > pipy-rule.js <<EOFpipy({  _repoPrefix: '192.168.64.1', //192.168.64.1:5000 是笔者本地容器运行的一个私有仓库。  _tagSuffix: ':latest',}).listen(6443, {  tls: {    cert: os.readFile('/certs/tls.crt').toString(),    key: os.readFile('/certs/tls.key').toString(),  },})  .decodeHttpRequest()  .replaceMessage(    msg => (        ((req, result, invalids, reason) => (            req = JSON.decode(msg.body),            invalids = req.request.object.spec.containers.find(container => (              (!container.image.startsWith(_repoPrefix) ? (                reason = `${container.image} repo not start with ${_repoPrefix}`,                console.log(reason),                true              ) : (false))              ||              (container.image.endsWith(_tagSuffix) ? (                reason = `${container.image} tag end with ${_tagSuffix}`,                console.log(reason),                true              ) : (false)            ))),            invalids != undefined ? (              result = {                "apiVersion": "admission.k8s.io/v1beta1",                "kind": "AdmissionReview",                "response": {                    "allowed": false,                    "uid": req.request.uid,                    "status": {                        "reason": reason,                    },                },              }            ) : (              result = {                "apiVersion": "admission.k8s.io/v1beta1",                "kind": "AdmissionReview",                "response": {                    "allowed": true,                    "uid": req.request.uid                },              }            ),            console.log(JSON.encode(result)),            new Message({              'status' : 200,              'headers': {                'Content-Type': 'application/json'              }              }, JSON.encode(result))        ))()    )  )  .encodeHttpResponse()  EOF
复制代码


将规则保存在 configmap 中:


kubectl create configmap pipy-rule --from-file=pipy-rule.js
复制代码


在 Kubernetes 上部署 Pipy


Kubernetes 与准入控制器(Admission Controller[3])的通信需要使用 TLS。配置 TLS,使用 openssl 创建证书颁发机构(certificate authority CA)和 OPA 的证书/秘钥对。


genrsa -out ca.key 2048req -x509 -new -nodes -key ca.key -days 100000 -out ca.crt -subj "/CN=admission_ca"
复制代码


为 OPA 创建 TLS 秘钥和证书:


cat >server.conf <<EOF[req]req_extensions = v3_reqdistinguished_name = req_distinguished_nameprompt = no[req_distinguished_name]CN = pipy.pipy.svc[ v3_req ]basicConstraints = CA:FALSEkeyUsage = nonRepudiation, digitalSignature, keyEnciphermentextendedKeyUsage = clientAuth, serverAuthsubjectAltName = @alt_names[alt_names]DNS.1 = pipy.pipy.svcEOF
复制代码


注意 CN 和 alt_names 必须与后面创建 Pipy service 的匹配。


openssl genrsa -out server.key 2048openssl req -new -key server.key -out server.csr -config server.confopenssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 100000 -extensions v3_req -extfile server.conf
复制代码


为 OPA 创建保存 TLS 凭证的 Secret:


kubectl create secret tls pipy-server --cert=server.crt --key=server.key
复制代码


将 Pipy 部署为准入控制器(admission controller)。为了方便调试,我们使用启动 Pipy 的时候打开了控制台。


kind: ServiceapiVersion: v1metadata:  name: pipy  namespace: pipyspec:  selector:    app: pipy  ports:  - name: https    protocol: TCP    port: 443    targetPort: 6443  - name: gui # 方便调试    protocol: TCP    port: 6060    targetPort: 6060  - name: http    protocol: TCP    port: 6080    targetPort: 6080---apiVersion: apps/v1kind: Deploymentmetadata:  labels:    app: pipy  namespace: pipy  name: pipyspec:  replicas: 1  selector:    matchLabels:      app: pipy  template:    metadata:      labels:        app: pipy      name: pipy    spec:      containers:         - name: pipy          image: pipy:latest          imagePullPolicy: IfNotPresent          args:            - "pipy"            - "/opt/data/pipy-rule.js"            - "--gui-port=6060" # 方便调试            # - "--log-level=debug"          ports:          - name: gui            containerPort: 6060            protocol: TCP          - name: http            containerPort: 6080            protocol: TCP            - name: https            containerPort: 6443            protocol: TCP          volumeMounts:            - readOnly: true              mountPath: /certs              name: pipy-server            - readOnly: false              mountPath: /opt/data              name: pipy-rule      volumes:        - name: pipy-server          secret:            secretName: pipy-server        - name: pipy-rule          configMap:            name: pipy-rule
复制代码


暴露控制台的访问:

kubectl expose deploy pipy --name pipy-node --type NodePortkubectl get svc pipy-portminikube service --url pipy-node -n pipy# 找到控制台端口
复制代码


接下来,生成将用于将 Pipy 注册为准入控制器的 manifest。


cat > webhook-configuration.yaml <<EOFkind: ValidatingWebhookConfigurationapiVersion: admissionregistration.k8s.io/v1beta1metadata:  name: pipy-validating-webhookwebhooks:  - name: validating-webhook.pipy.flomesh-io.cn    namespaceSelector:      matchExpressions:      - key: pipy/webhook        operator: NotIn        values:        - ignore    rules:      - operations: ["CREATE", "UPDATE"]        apiGroups: ["*"]        apiVersions: ["*"]        resources: ["pods"]    clientConfig:      caBundle: $(cat ca.crt | base64 | tr -d '\n')      service:        namespace: pipy        name: pipyEOF
复制代码


生成的配置文件包含 CA 证书的 base64 编码,以便可以在 Kubernetes API 服务器和 OPA 之间建立 TLS 连接。


kubectl apply -f webhook-configuration.yaml
复制代码


测试


pod-bad-repo.yaml:


apiVersion: v1kind: Podmetadata:  creationTimestamp: null  labels:    run: web-server  name: web-server  namespace: defaultspec:  containers:  - image: nginx:1.21.1    name: web-server    resources: {}  dnsPolicy: ClusterFirst  restartPolicy: Alwaysstatus: {}
复制代码


kubectl apply -f pod-bad-repo.yamlError from server (nginx:1.21.1 repo not start with 192.168.64.1): error when creating "pod-bad-repo.yaml": admission webhook "validating-webhook.pipy.flomesh-io.cn" denied the request: nginx:1.21.1 repo not start with 192.168.64.1
复制代码


pod-bad-tag.yaml:


apiVersion: v1kind: Podmetadata:  creationTimestamp: null  labels:    run: web-server  name: web-server  namespace: defaultspec:  containers:  - image: 192.168.64.1:5000/nginx:latest    name: web-server    resources: {}  dnsPolicy: ClusterFirst  restartPolicy: Alwaysstatus: {}
复制代码


kubectl apply -f pod-bad-tag.yamlError from server (192.168.64.1:5000/nginx:latest tag end with :latest): error when creating "pod-bad-tag.yaml": admission webhook "validating-webhook.pipy.flomesh-io.cn" denied the request: 192.168.64.1:5000/nginx:latest tag end with :latest
复制代码


pod-ok.yaml


apiVersion: v1kind: Podmetadata:  creationTimestamp: null  labels:    run: web-server  name: web-server  namespace: defaultspec:  containers:  - image: 192.168.64.1:5000/nginx:1.21.1    name: web-server    resources: {}  dnsPolicy: ClusterFirst  restartPolicy: Alwaysstatus: {}
复制代码


kubectl apply -f pod-ok.yamlpod/web-server created
复制代码


总结


OPA 哪哪都好,唯一缺点就是其引进的 Rego 语言抬高了使用的门槛。而 Pipy 的规则是通过 JavaScrip 来编写的,前端的同学一样可以完成规则的编写。完全替代可能夸张了一些,但确实在部分场景下可以替代 OPA。


玩到这里,你会发现有了规则,加上功能强大的过滤器(现在我喜欢叫他们 Hook 了),Pipy 的可玩性非常强。


比如OPA: Kubernetes 准入控制策略 Top 5,比如...。大胆的想象吧。

想写一个系列,就叫“如何把 Pipy 玩坏”?


引用链接


[1] GitHub: https://github.com/flomesh-io/pipy

[2] 上一讲功能: https://atbug.com/image-trusted-repository-with-open-policy-agent/

[3] Admission Controller: https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/

2021-07-15 17:582224

评论

发布
暂无评论
发现更多内容

【TUG 话题探讨004】对 TiDB 的爱恨之情!

TiDB 社区干货传送门

同城双中心自适应同步方案 —— DR Auto-Sync 详解

TiDB 社区干货传送门

涂鸦智能选型 TiKV 的心路历程

TiDB 社区干货传送门

数据库架构选型

Zetta:HBase 用户的新选择 —— 当知乎遇上 TiDB 生态

TiDB 社区干货传送门

实践案例

做出让人爱不释手的基础软件:可观测性和可交互性

TiDB 社区干货传送门

TiDB HTAP 上手指南丨添加 TiFlash 副本的工作原理

TiDB 社区干货传送门

数据引擎助力车娱融合新业态 让秒杀狂欢更从容

TiDB 社区干货传送门

TiDB 4.0 基于 Binlog 的跨机房集群部署

TiDB 社区干货传送门

安装 & 部署

TiDB5.0.3-ARM平台性能测试

TiDB 社区干货传送门

安装 & 部署

58同城大规模TiDB运维漫谈

TiDB 社区干货传送门

安装 & 部署

技术升级&行业升级 TiDB 助力易车打造超级汽车狂欢节

TiDB 社区干货传送门

TiDB 如何做到无限扩展和保证节点 id 唯一

TiDB 社区干货传送门

TiDB 底层架构

带你重走 TiDB TPS 提升 1000 倍的性能优化之旅

TiDB 社区干货传送门

性能调优

基于TiCDC 实现的双云架构实践

TiDB 社区干货传送门

实践案例

tidb中的key和MVCC value解析

TiDB 社区干货传送门

管理与运维

云集财务业务 TiDB 实践

TiDB 社区干货传送门

实践案例 数据库架构选型

数据总量 40 亿+,报表分析数据 10 亿+,TiDB 在中通的落地与进化

TiDB 社区干货传送门

实践案例

TIDB监控报警对接企业微信的简便工具推荐

TiDB 社区干货传送门

监控

PD 如何调度 Region

TiDB 社区干货传送门

TiDB 底层架构

通过 ProxySQL 在 TiDB 上实现 SQL 的规则化路由

TiDB 社区干货传送门

管理与运维

通过label调度副本测试

TiDB 社区干货传送门

TiDB 4.0 生产环境扩容 TiKV 节点详细步骤

TiDB 社区干货传送门

内存泄漏的定位与排查:Heap Profiling 原理解析

TiDB 社区干货传送门

故障排查/诊断

Chaos Mesh® 在腾讯——腾讯互娱混沌工程实践

TiDB 社区干货传送门

实践案例

我们为什么放弃 MongoDB 和 MySQL,选择 TiDB

TiDB 社区干货传送门

数据库架构选型

事务前沿研究丨事务测试体系解析

TiDB 社区干货传送门

TiDB 底层架构

【TUG 话题探讨 005】TiDB 生态工具(DM、TiCDC等)使用场景及常见问题

TiDB 社区干货传送门

TiDB 性能测试最佳实践

TiDB 社区干货传送门

数据库架构选型

TiDB 5.0 两阶段提交

TiDB 社区干货传送门

TiDB 底层架构

TiDB 监控整合方案

TiDB 社区干货传送门

实践案例

地产TiDB使用初探索

TiDB 社区干货传送门

安装 & 部署

Rego 不好用?用 Pipy 实现 OPA_大数据_InfoQ精选文章