背景
Ingress 是对集群中服务的外部访问进行管理的 API 对象,典型的访问方式是 HTTP。提供负载均衡、SSL 终结和基于名称的虚拟托管。为了让 Ingress 资源工作,集群必须有一个正在运行的 Ingress 控制器。
Ingress 控制器 通过监控集群中的 Ingress 资源,对 HTTP 负载均衡器进行配置。
FSM 是 Flomesh 的另一款开源产品,用于 Kubernetes 南北向的流量管理。FSM 以可编程代理 Pipy 为核心,提供了 Ingress 管理器、Gateway API* 实现、负载均衡器以及跨集群的服务注册发现等功能。
从这篇开始,我们将通过多篇文章以演示的方式对 Flomesh Ingress 功能进行介绍。
演示
创建集群
export INSTALL_K3S_VERSION=v1.23.8+k3s2
curl -sfL https://get.k3s.io | sh -s - --disable traefik --disable servicelb --write-kubeconfig-mode 644 --write-kubeconfig ~/.kube/config
部署架构
安装 Flomesh Ingress
通过 Helm 安装 fsm。
helm repo add fsm https://flomesh-io.github.io/fsm
helm repo update
helm install \
--namespace fsm \
--create-namespace \
--set fsm.version=0.2.1-alpha.2 \
--set fsm.ingress.tls.enabled=true \
--set fsm.serviceLB.enabled=true \
fsm fsm/fsm
示例应用
这里使用的示例应用同时提供了 HTTP 8000
和 HTTPS 8443
访问,有下面几个 path
:
-
/
返回一个简单的 HTML 页面 -
/hi
返回200
Hi, there!
-
/api/private
返回401
Staff only
为了提供 HTTPS,需要为应用先签发 ca 和服务端证书。
openssl genrsa 2048 > ca-key.pem
openssl req -new -x509 -nodes -days 365000 \
-key ca-key.pem \
-out ca-cert.pem \
-subj '/CN=flomesh.io'
openssl genrsa -out server-key.pem 2048
openssl req -new -key server-key.pem -out server.csr -subj '/CN=example.com'
openssl x509 -req -in server.csr -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -days 365
部署示例应用,先创建 Secret 将证书和密钥保存在 secret 中并挂载到应用 pod 中。
kubectl create namespace httpbin
# mount self-signed cert to sample app pod via secret
kubectl create secret generic -n httpbin server-cert \
--from-file=./server-cert.pem \
--from-file=./server-key.pem
kubectl apply -n httpbin -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: httpbin
---
apiVersion: v1
kind: Service
metadata:
name: httpbin
labels:
app: httpbin
service: httpbin
spec:
ports:
- port: 8443
name: https
- port: 8000
name: http
selector:
app: httpbin
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpbin
labels:
app: httpbin
spec:
replicas: 1
selector:
matchLabels:
app: httpbin
template:
metadata:
labels:
app: httpbin
spec:
containers:
- name: pipy
image: addozhang/httpbin:latest
env:
- name: PIPY_CONFIG_FILE
value: /etc/pipy/tutorial/gateway/main.js
ports:
- containerPort: 8443
- containerPort: 8000
volumeMounts:
- name: cert
mountPath: "/etc/pipy/tutorial/gateway/secret"
readOnly: true
volumes:
- name: cert
secret:
secretName: server-cert
EOF
基础配置
HTTP 入口
下面的示例中,定义了 Ingress
资源,将 host
为 example.com
,path
为 /get
和 /
的请求路由到后端服务 httpbin
的 8000
端口。
注意这里 Ingress
资源与后端服务应属于同一命名空间。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: httpbin
spec:
ingressClassName: pipy
rules:
- host: example.com
http:
paths:
- path: /
pathType: Exact
backend:
service:
name: httpbin
port:
number: 8000
- path: /hi
pathType: Exact
backend:
service:
name: httpbin
port:
number: 8000
这里我们对部分字段进行说明:
-
metadata.name
字段定义了 Ingress 的资源名。 -
spec.ingressClassName
字段用于指定入口控制器的实现。ingressclass
是各个入口控制器实现定义的名字,这里我们用pipy
。通过kubectl get ingressclass
可以查看已安装的入口控制器。 -
spec.rules
字段用于定义路由资源。- 在
host
字段中定义了主机名example.com
-
paths
字段定义了两个路径规则:匹配路径为/
的请求,以及前缀为/hi
的请求 -
backend
字段定义了用于处理该路径规则的后端服务httpbin
以及端口8000
。
- 在
查看 Ingress Controller Service,可以看到其类型是 LoadBalancer
,且外部地址为 10.0.0.12
,正好就是节点的 IP 地址。
kubectl get svc -n fsm -l app.kubernetes.io/component=controller
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
fsm-ingress-pipy-controller LoadBalancer 10.43.144.20 10.0.0.12 80:30508/TCP,443:30607/TCP 10m
应用上面的 Ingress 配置。
在访问 httpbin
服务的 /hi
和 /
端点时,我们可以使用节点的 IP 地址以及端口 80
。
export HOST_IP=10.0.0.12
curl http://example.com/hi --connect-to example.com:80:$HOST_IP:80
Hi, there!
curl http://example.com/ --connect-to example.com:80:$HOST_IP:80
<!DOCTYPE html>
<html>
<head>
<title>Hi, Pipy!</title>
</head>
<body>
Hi, Pipy!
<p>This is a web page served from Pipy.</p>
</body>
</html>
HTTPS 入口
这个示例演示了如果配置入口控制器支持 HTTPS 访问。
FSM Ingress 默认是不启用 TLS 入口的,在安装时需要通过参数 --set fsm.ingress.tls.enabled=true
打开 TLS 入口功能。
下面的例子中的 Ingress 资源,配置了 https://example.com
访问入口。
- 字段
spec.tls
是 TLS 配置的专属字段,可以配置多个 HTTPS 入口。 -
hosts
字段用于配置 SNI,可以配置多个 SNI。这里使用example.com
,也可以支持通配符*.example.com
。 -
secretName
字段用于指定保存了证书和密钥的Secret
。注意 Ingress 资源和 Secret 应同属于一个命名空间。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: httpbin
spec:
ingressClassName: pipy
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: httpbin
port:
number: 8000
tls:
- hosts:
- example.com
secretName: ingress-cert
签发证书。
openssl req -x509 -newkey rsa:4096 -keyout ingress-key.pem -out ingress-cert.pem -sha256 -days 365 -nodes -subj '/CN=example.com'
使用证书和密钥创建 Secret。
kubectl create secret tls ingress-cert --cert=ingress-cert.pem --key=ingress-key.pem -n httpbin
使用服务 ingress-cert.pem
作为 ca 证书发起请求进行测试,注意目前是禁用 Ingress mTLS 功能。
curl --cacert ingress-cert.pem https://example.com/hi --connect-to example.com:443:$HOST_IP:443
Hi, there!
进阶配置
接下来,我们介绍下 FSM Ingress 的高阶配置。高阶配置是通过 Ingress
资源的 metadata.annotations
字段进行设置的。目前支持的功能有:
- 路径重写
- 指定负载均衡算法
- 会话保持
路径重写
这个例子演示如何使用路径重写的注解。
FSM 提供了 pipy.ingress.kubernetes.io/rewrite-target-from
和 pipy.ingress.kubernetes.io/rewrite-target-to
两个注解来配置路径重写,这两个注解需要同时使用。
比如在下面的示例中,在路由规则中定义了路径前缀为 /httpbin
的请求路由到服务 httpbin
的 14001
端口,然而服务 httpbin
本身是没有这个路径的。这时就需要用到路径重写功能了:
-
pipy.ingress.kubernetes.io/rewrite-target-from: ^/httpbin/?
,这里支持正则表达式,将路径起始的/httpbin/
进行重写 -
pipy.ingress.kubernetes.io/rewrite-target-to: /
,这里指定了重写的内容是/
综合起来就是将路径起始的 /httpbin/
替换 /
,比如 /httpbin/get
会被重写成 /get
。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: httpbin
annotations:
pipy.ingress.kubernetes.io/rewrite-target-from: ^/httpbin/?
pipy.ingress.kubernetes.io/rewrite-target-to: /
spec:
ingressClassName: pipy
rules:
- host: example.com
http:
paths:
- path: /httpbin
pathType: Prefix
backend:
service:
name: httpbin
port:
number: 8000
应用上面的 Ingress 配置。
现在我们要使用 /httpbin/hi
作为路径来访问 httpbin 的 /hi
端点。
curl http://example.com/httpbin/hi --connect-to example.com:80:$HOST_IP:80
Hi, there!
指定负载均衡算法
这个例子用于演示在后端存在多个实例时,指定路由的负载均衡算法。
默认情况下 FSM Ingress 使用 Round-Robin 负载均衡算法,可以通过注解 pipy.ingress.kubernetes.io/lb-type
指定其他的算法:
round-robin
hashing
least-work
在下面的示例中,通过注解指定使用 hashing
负载均衡算法。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: httpbin
annotations:
pipy.ingress.kubernetes.io/lb-type: 'hashing'
spec:
ingressClassName: pipy
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: httpbin
port:
number: 8000
为了直观展示演示效果,部署下面的示例应用,这个应用有 2 个实例,并在响应中携带主机名便于区分响应请求的示例。
kubectl create namespace httpbin
kubectl apply -n httpbin -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: httpbin
---
apiVersion: v1
kind: Service
metadata:
name: httpbin
labels:
app: httpbin
service: httpbin
spec:
ports:
- name: http
port: 8000
selector:
app: httpbin
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpbin
labels:
app: httpbin
spec:
replicas: 2
selector:
matchLabels:
app: httpbin
template:
metadata:
labels:
app: httpbin
spec:
containers:
- name: pipy
image: addozhang/httpbin:latest
ports:
- containerPort: 8000
command:
- pipy
- -e
- |
pipy()
.listen(8000)
.serveHTTP(new Message('Response from pod ' + os.env["HOSTNAME"]))
EOF
应用上面的 Ingress 配置,然后发送请求进行测试。
curl http://example.com/ --connect-to example.com:80:$HOST_IP:80
Response from pod httpbin-5f69c44674-t9cxc
curl http://example.com/ --connect-to example.com:80:$HOST_IP:80
Response from pod httpbin-5f69c44674-t9cxc
curl http://example.com/ --connect-to example.com:80:$HOST_IP:80
Response from pod httpbin-5f69c44674-t9cxc
会话保持
这个示例用于演示会话保持功能。
FSM Ingress 提供了注解 pipy.ingress.kubernetes.io/session-sticky
来配置会话保持,默认值为 false
(等同于 no
、0
、off
或者 ),即不保持会话。如若需要保持会话,则需要将值设置为
true
、yes
、1
或者 on
。
比如下面的例子中,将注解值设置为 true
,用于在后端服务的两个实例之间进行会话保持。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: httpbin
annotations:
pipy.ingress.kubernetes.io/session-sticky: 'true'
spec:
ingressClassName: pipy
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: httpbin
port:
number: 8000
为了直观展示演示效果,部署下面的示例应用,这个应用有 2 个实例,并在响应中携带主机名便于区分响应请求的示例。
kubectl create namespace httpbin
kubectl apply -n httpbin -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: httpbin
---
apiVersion: v1
kind: Service
metadata:
name: httpbin
labels:
app: httpbin
service: httpbin
spec:
ports:
- name: http
port: 8000
selector:
app: httpbin
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpbin
labels:
app: httpbin
spec:
replicas: 2
selector:
matchLabels:
app: httpbin
template:
metadata:
labels:
app: httpbin
spec:
containers:
- name: pipy
image: addozhang/httpbin:latest
ports:
- containerPort: 8000
command:
- pipy
- -e
- |
pipy()
.listen(8000)
.serveHTTP(new Message('Response from pod ' + os.env["HOSTNAME"]))
EOF
应用上面的 Ingress 配置,多次请求进行测试,可以发现都是同一个实例进行响应。
curl http://example.com/ --connect-to example.com:80:$HOST_IP:80
Response from pod httpbin-5f69c44674-hrvqp
curl http://example.com/ --connect-to example.com:80:$HOST_IP:80
Response from pod httpbin-5f69c44674-hrvqp
curl http://example.com/ --connect-to example.com:80:$HOST_IP:80
Response from pod httpbin-5f69c44674-hrvqp
总结
本篇我们主要介绍了 FSM Ingress 的基础功能,包括 HTTP、HTTPS 以及在 7 层上流量处理能力。
在下一篇,我们将会围绕 TLS 能力来介绍 FSM Ingress 的进阶功能。