文本先说一下背景,再谈一下组件关系,然后看看怎么实施配置部署。
在上篇 K8S HelloWord 一文中,我们已经实现了对 web 服务的部署和正常外部访问,但是你可能发现了,我们使用的端口是30001,采用了NodePort方式映射并固定了30001端口,使其可以固定对外提供服务。
但是,该端口默认范围是30000~32767,并且我们的web服务一般都是80、443端口对外,因此我们产生了如下几点需求和疑问:
1、如果想暴露80、443端口,你可以修改k8s apiserver的参数将端口设置为80~xxxx,但是不推荐这样做,因为k8s在一些场景需求的时候会自动在端口范围内生成一个端口使用,如果我们的端口访问包含了常用端口,可能会给其他本地服务带来麻烦。
2、如果你的系统服务增多,需要暴露更多的web服务的时候,那么也同样需要设置固定更多的NodePort端口,为了避免端口冲突你还要对使用的端口进行整理维护。
3、一个系统对外暴露的端口增多,就好比我们的园区开了更多的门一样,任何一个门有安全问题,都会导致整个园区产生安全风险,我们的系统同样如此。当这个问题在实现了下面第4点后就不是问题了。
4、还有一个最重要的是,我们是web服务,怎么能少了https证书呢。所以依然需要在增加一个独立的nginx、traefik等组件来配置证书。
针对如上问题,我们总是需要一个方向代理服务的。既然需要单独管理维护一个,不如用 k8s 为了提供了的ingress控制器方案,完美解决问题。
Service: 后端真实服务的抽象,一个 Service 可以代表多个相同的后端服务,向下对应多个 Pod。
Ingress: 反向代理规则,用来规定 HTTP/S 请求应该被转发到哪个 Service 上,根据根据请求中不同的 Host 和 url 路径让请求落到不同的 Service 上。
Ingress Controller: 它是一个反向代理程序,也是一个具体的 Pod,它负责解析 Ingress 的反向代理规则,如果 Ingress 有增删改的变动,所有的 Ingress Controller 都会及时更新自己相应的转发规则,当 Ingress Controller 收到请求后就会根据这些规则将请求转发到对应的 Service。
Kubernetes 并没有自带 Ingress Controller,它只是一种标准,具体实现有多种,需要自己单独安装,常用的是 Nginx Ingress Controller 和 Traefik Ingress Controller。 所以 Ingress 是一种转发规则的抽象,Ingress Controller 的实现需要根据这些 Ingress 规则来将请求转发到对应的 Service,我画了一张图来描述它们之间的关系,然后本文也实现一个该图的实例:
本例使用的 traefik-controller 版本为 traefik:1.7.20,现在官方最新版是 2.x 了,因为时间问题就直接拿本地 1.7.20 版本的配置来写文了,注意本文在上篇文章 K8S HelloWorld 的基础上配置。
1、文件 traefik.yml
---
apiVersion: v1
kind: Namespace
metadata:
name: traefik-ingress-controller
---
# Source: traefik/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: traefik-ingress
labels:
app: traefik
namespace: traefik-ingress-controller
data:
traefik.toml: |
logLevel = "info"
defaultEntryPoints = ["http", "https"]
[entryPoints]
[entryPoints.http]
address = ":80"
compress = true
[entryPoints.https]
address = ":443"
compress = true
[entryPoints.https.tls]
[ping]
entryPoint = "http"
[kubernetes]
[traefikLog]
format = "json"
---
# Source: traefik/templates/rbac.yaml
kind: ServiceAccount
apiVersion: v1
metadata:
name: traefik-ingress
namespace: traefik-ingress-controller
---
# Source: traefik/templates/rbac.yaml
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: traefik-ingress
rules:
- apiGroups:
- ""
resources:
- pods
- services
- endpoints
- secrets
verbs:
- get
- list
- watch
- apiGroups:
- extensions
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- extensions
resources:
- ingresses/status
verbs:
- update
---
# Source: traefik/templates/rbac.yaml
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: traefik-ingress
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: traefik-ingress
subjects:
- kind: ServiceAccount
name: traefik-ingress
namespace: traefik-ingress-controller
---
# Source: traefik/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: traefik-ingress
labels:
app: traefik
namespace: traefik-ingress-controller
spec:
replicas: 1
selector:
matchLabels:
app: traefik
template:
metadata:
labels:
app: traefik
spec:
hostNetwork: true
serviceAccountName: traefik-ingress
terminationGracePeriodSeconds: 60
containers:
- image: traefik:1.7.20
name: traefik-ingress
readinessProbe:
httpGet:
path: /ping
port: "http"
failureThreshold: 1
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 2
livenessProbe:
httpGet:
path: /ping
port: "http"
failureThreshold: 3
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 2
volumeMounts:
- mountPath: /config
name: config
ports:
- name: http
containerPort: 80
protocol: TCP
- name: https
containerPort: 443
protocol: TCP
args:
- --configfile=/config/traefik.toml
volumes:
- name: config
configMap:
name: traefik-ingress
2、文件 ingress-traefik.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: traefik-ingress
namespace: default
annotations:
kubernetes.io/ingress.class: traefik
spec:
tls:
- hosts:
- shanhy-k8s.com
- "*.shanhy-k8s.com"
secretName: ingress-secret
rules:
- host: www.shanhy-k8s.com
http:
paths:
- path: /
backend:
serviceName: helloworld-nodejs
servicePort: 20001
3、https 证书的生成
# 生成证书key
openssl genrsa -out ingress-key.pem 2048
# 生成证书
openssl req -new -x509 -key ingress-key.pem -out ingress.pem -subj /C=CN/ST=BeiJing/L=BeiJing/O=Shanhy/OU=Shanhy/CN=www.shanhy-k8s.com -days 3650
# 查看证书信息
openssl x509 -in ingress.pem -text -noout
4、k8s 创建 secret
kubectl create secret tls ingress-secret --key cert/ingress-key.pem --cert cert/ingress.pem
5、运行
kubectl apply -f traefik.yml
kubectl apply -f ingress-traefik.yaml
# 查看运行结果
[root@server1 k8s]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
helloworld-nodejs ClusterIP 10.96.0.246 20001/TCP 45h
kubernetes ClusterIP 10.96.0.1 443/TCP 3d2h
[root@server1 k8s]# kubectl get ingress
NAME HOSTS ADDRESS PORTS AGE
traefik-ingress www.shanhy-k8s.com 80, 443 108m
[root@server1 k8s]# kubectl get pod -A
NAMESPACE NAME READY STATUS RESTARTS AGE
default helloworld-nodejs-5dfb48565d-4snbs 1/1 Running 0 2d15h
default helloworld-nodejs-5dfb48565d-rxbcv 1/1 Running 0 2d15h
default helloworld-nodejs-5dfb48565d-tp2qw 1/1 Running 0 2d15h
traefik-ingress-controller traefik-ingress-558868f4db-swkr6 1/1 Running 0 4h12m
[root@server1 k8s]# kubectl get secret
NAME TYPE DATA AGE
default-token-wlmkn kubernetes.io/service-account-token 3 23h
ingress-secret kubernetes.io/tls
6、访问验证
在你电脑的C:\Windows\System32\drivers\etc\hosts
中添加192.168.1.65 www.shanhy-k8s.com
然后打开浏览器访问 http(s)://www.shanhy-k8s.com
可以看到输出结果 HelloWorld。
本文实例还有一个小结论:ingress
、service
、pod
、secret
都必须要在同一个 namespace
中,对 ingress-controller
的 namespace
没有要求。
相关资料:
https://github.com/containous/traefik
https://traefik.cn/
https://docs.traefik.io/user-guides/crd-acme/
(END)