下面的 yaml 文件内容,是使用 sts 创建两个 web 服务,并配置对应的 servcie。web 服务的首页内容使用 configmap 配置并挂载到各自的 POD 中。
apiVersion: v1
kind: Namespace
metadata:
name: shark-test
---
apiVersion: v1
kind: ConfigMap
metadata:
namespace: shark-test
name: index.html
data:
# 类属性键;每一个键都映射到一个简单的值
web1.index.html: |
web1 站点
web2.index.html: |
web2 站点
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
namespace: shark-test
name: web1
spec:
selector:
matchLabels:
app: web1 # 必须匹配 .spec.template.metadata.labels
serviceName: "web1"
replicas: 1
minReadySeconds: 10 # 默认值是 0
template:
metadata:
labels:
app: web1 # 必须匹配 .spec.selector.matchLabels
spec:
terminationGracePeriodSeconds: 10
containers:
- name: web1
image: nginx:1.21.6-alpine
ports:
- containerPort: 80
name: web1
volumeMounts:
- name: index-html
mountPath: /usr/share/nginx/html
volumes:
- name: index-html # 给 volumeMounts[].name使用
configMap:
name: index.html # configmap 的名称
items:
- key: web1.index.html # configmap 对象中 data 中的一个 key
path: index.html # 挂载到 pod 后,被创建的文件名称
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
namespace: shark-test
name: web2
spec:
selector:
matchLabels:
app: web2 # 必须匹配 .spec.template.metadata.labels
serviceName: "web2"
replicas: 1
minReadySeconds: 10 # 默认值是 0
template:
metadata:
labels:
app: web2 # 必须匹配 .spec.selector.matchLabels
spec:
terminationGracePeriodSeconds: 10
containers:
- name: web2
image: nginx:1.21.6-alpine
ports:
- containerPort: 80
name: web2
volumeMounts:
- name: index-html
mountPath: /usr/share/nginx/html
volumes:
- name: index-html # 给 volumeMounts[].name使用
configMap:
name: index.html # configmap 的名称
items:
- key: web2.index.html # configmap 对象中 data 中的一个 key
path: index.html # 挂载到 pod 后,被创建的文件名称
---
apiVersion: v1
kind: Service
metadata:
namespace: shark-test
name: web1
labels:
app: web1
spec:
type: ClusterIP
ports:
- port: 8080
name: web1-http
targetPort: 80
clusterIP: None
selector:
app: web1
---
apiVersion: v1
kind: Service
metadata:
namespace: shark-test
name: web2
labels:
app: web2
spec:
type: ClusterIP
ports:
- port: 8080
name: web2-http
targetPort: 80
clusterIP: None
selector:
app: web2
Ingress 是管理集群外部访问集群内部服务的流量的 API 对象,是 kubernetes 中对 service 的反向代理。 流量的去向由 Ingress 资源所定义的规则来控制。
可提供负载均衡、SSL 和基于名称的虚拟主机功能。
主要的访问方式是 HTTP/HTTPS,不支持四层协议。下一代替代 Ingress 的产品 Gateway API 可以实现 四层和七层协议流量管理。
Ingress 在 kubernentes v1.28 版本停止更新,并推出了可以实现更多功能的 Gateway API。
Ingress 资源的 YAML 文件,可以理解为是对 Nginx 子配置文件的抽象,因为它和 nginx 中关于虚拟机主机 server 配置块的功能一致 。
下面是 Nginx 子配置文件和Ingress 的 yaml 文件的对比图。
资源名称: Ingress 对象的命名必须是合法的 DNS 子域名名称。
rewrite-target
注解。 不同的 Ingress 控制器支持不同的注解。规则(rule): 其中包含对所有入站请求进行匹配的规则列表。
为了让 Ingress 对象有效的创建和工作,需要有一个 Ingress Controller 。
Ingress Controller 的角色是用一个反向代理实现的。反向代理可以是 nginx、haproxy 等其中的一个,因此 Ingress Controller 可以有很多种。
这里我用最常用的 Ingress-Nginx Controller 为例说明。
当一个 Ingress 对象被成功创建后,Ingress Controller 会把 Ingress 对象中的内容转换成 nginx 的子配置文件,并让 Ingress Controller 使用。
后续会详细介绍。
一个简单的 Ingress 资源示例。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: minimal-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx-example
rules:
- http:
paths:
- path: "/web1"
pathType: Prefix
backend:
service:
name: web1
port:
number: 8080
每个 HTTP 规则都包含以下信息:
host
,因此该规则适用于使用指定 IP 地址进行入站 HTTP 请求的情况。 如果提供了 host
(例如 foo.shark.com),则 rules 适用于所指定的主机( foo.shark.com)。path
路径列表(例如 /web1)。每个路径都有一个由 service.name
和 service.port.name
或 service.port.number
确定的关联后端。入站请求的内容都必须与 host
和 path
的值相匹配,负载均衡器才会将流量引导到所引用的 Service,backend
(后端)是 Service 中所定义的 名称和端口的组合, 或者是通过 CRD 方式来实现的自定义资源后端。通常会在 Ingress 控制器中配置 defaultBackend
(默认后端), 以便为无法与规约中任何路径匹配的所有请求提供服务,也就是通常会返回 404 页面。
Ingress 中的每个路径都需要有对应的路径类型(Path Type)。未明确设置 pathType 的路径无法通过合法性检查。当前支持的路径类型有三种:
ImplementationSpecific:对于这种路径类型,匹配方法取决于 IngressClass。 具体实现可以将其作为单独的 pathType 处理或者作与 Prefix 或 Exact 类型相同的处理。
Exact:精确匹配 URL 路径,且区分大小写。
Prefix:基于以 /
分隔的 URL 路径前缀匹配。匹配区分大小写, 并且对路径中各个元素逐个执行匹配操作。 路径元素指的是由 /
分隔符分隔的路径中的标签列表。
说明: 如果
path
值的最后一个元素是请求路径中最后一个元素的子字符串,则不会被视为匹配 (例如:/foo/bar 匹配 /foo/bar/baz, 但不匹配 /foo/barbaz)。
有的时候,一个请求会和一个 Ingress 中的多个 path
匹配,这时 path
最长者优先匹配。 如果仍然有两条同等的匹配路径,则精确路径类型优先于前缀路径类型。
Ingress 可以由不同的控制器实现,通常使用不同的配置。 每个 Ingress 应当指定一个类,也就是一个对 IngressClass 资源的引用。 IngressClass 资源包含额外的配置,其中包括应当实现该类的控制器名称。
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
labels:
app.kubernetes.io/component: controller
name: nginx-example
spec:
controller: k8s.io/ingress-nginx
设置默认的 Ingress 类,只需要在注解中添加:
ingressclass.kubernetes.io/is-default-class: "true"
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
labels:
app.kubernetes.io/component: controller
name: nginx-example
annotations:
ingressclass.kubernetes.io/is-default-class: "true"
spec:
controller: k8s.io/ingress-nginx
openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj “/C=CN/ST=BJ/L=BJ/O=nginx/CN=itheima.com”
可以通过设定包含 TLS 私钥和证书的Secret 来保护 Ingress。TLS Secret 的数据中必须包含键名为 tls.crt
的证书和键名为 tls.key
的私钥, 才能用于 TLS 目的。例如:
apiVersion: v1
kind: Secret
metadata:
name: testsecret-tls
namespace: default
data:
tls.crt: base64 编码的证书
tls.key: base64 编码的私钥
type: kubernetes.io/tls
也可以使用下面的方法创建
kubectl create secret tls tls-secret --key tls.key --cert tls.crt
注意,不能针对默认规则使用 TLS,因为这样做需要为所有可能的子域名签发证书。 因此,
tls
字段中的hosts
的取值需要与rules
字段中的host
完全匹配。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tls-example-ingress
spec:
tls:
- hosts:
- https-example.foo.com
secretName: testsecret-tls
rules:
- host: https-example.foo.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: service1
port:
number: 80