首先我们来思考用传统的web服务器,比如Nginx,如何处理这种场景?
比如使用Nginx充当一个反向代理服务器拦截外部请求,读取路由规则配置,转发相应的请求到后端服务。
kubernetes处理这种场景时,涉及到三个组件:
负责拦截外部请求,比如Nginx、Apache、traefik等等。我一般以Deployment方式部署到kubernetes集群中,当然也可以用DeamonSet方式部署;这两种部署方式个人觉得有利有弊,感兴趣的请参考这篇文章。
k8s中的controller有很多,比如CronJob、DeamonSet、Deployment、ReplicationSet、StatefulSet等等,大家最熟悉的应该是Deployment,它的作用就是监控集群的变化,使集群始终保持我们期望的最终状态(yml文件)。同理,Ingress controller的作用就是实时感知Ingress路由规则集合的变化,再与Api Server交互,获取Service、Pod在集群中的 IP等信息,然后发送给反向代理web服务器(比如Nginx),刷新其路由配置信息,这就是它的服务发现机制。
Ingress资源时基于HTTP虚拟主机或URL的转发规则,需要强调的是,这是一条转发规则。它在资源配置清单中的spec字段中嵌套了rules、backend和tls等字段进行定义。
如下示例中定义了一个Ingress资源,其包含了一个转发规则:将发往myapp.test.com的请求,代理给一个名字为myapp的Service资源。
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-myapp
namespace: default
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: myapp.test.com
http:
paths:
- path:
backend:
serviceName: myapp
servicePort: 80
Ingress 中的spec字段是Ingress资源的核心组成部分,主要包含以下3个字段:
spec:
rules:
- hosts: >
http:
paths:
- path:
backend:
serviceName: >
servicePort: >
Ingress资源类型
Ingress的资源类型有以下4种:
1、单Service资源型Ingress
2、基于URL路径进行流量转发
3、基于主机名称的虚拟主机
4、TLS类型的Ingress资源
1 .部署文件介绍、准备
默认下载最新的yaml:
wget https://github.com/kubernetes/ingress-nginx/blob/nginx-0.20.0/deploy/mandatory.yaml
准备镜像,从这里mandatory.yaml查看需要哪些镜像
镜像名称 | 版本 | 下载地址 |
---|---|---|
k8s.gcr.io/defaultbackend-amd64 | 1.5 | registry.cn-qingdao.aliyuncs.com/kubernetes_xingej/defaultbackend-amd64 |
kquay.io/kubernetes-ingress-controller/nginx-ingress-controller | 0.20.0 | registry.cn-qingdao.aliyuncs.com/kubernetes_xingej/nginx-ingress-controller |
在每一个节点(Node)上下载镜像:
[root@k8s-node2 ~]# docker pull registry.cn-qingdao.aliyuncs.com/kubernetes_xingej/defaultbackend-amd64:1.5
1.5: Pulling from kubernetes_xingej/defaultbackend-amd64
26de8f6c1f4b: Pull complete
Digest: sha256:2cdff48ab9b20ca5f9b0ee48bf3c139c51d6fb1a15245966583bc371c121c238
Status: Downloaded newer image for registry.cn-qingdao.aliyuncs.com/kubernetes_xingej/defaultbackend-amd64:1.5
registry.cn-qingdao.aliyuncs.com/kubernetes_xingej/defaultbackend-amd64:1.5
[root@k8s-node2 ~]# docker pull registry.cn-qingdao.aliyuncs.com/kubernetes_xingej/nginx-ingress-controller:0.20.0
0.20.0: Pulling from kubernetes_xingej/nginx-ingress-controller
8e41b996a802: Pull complete
f8e7d603ef88: Pull complete
610da4f3123f: Pull complete
62702a85e6c9: Pull complete
7cedf5b2083f: Pull complete
755f7fa719b6: Pull complete
6adbdd0c8aaf: Pull complete
2389d8b0d2a2: Pull complete
1ea794448393: Pull complete
bb0c388ee432: Pull complete
9626641c5a97: Pull complete
bd0bebb5ba38: Pull complete
Digest: sha256:3f06079f7727b2fb7ad5c97d8152eb622ae504674395dfa71fda7ce315aaaf30
Status: Downloaded newer image for registry.cn-qingdao.aliyuncs.com/kubernetes_xingej/nginx-ingress-controller:0.20.0
registry.cn-qingdao.aliyuncs.com/kubernetes_xingej/nginx-ingress-controller:0.20.0
下载yaml文件并更新mandatory.yaml中的镜像地址(master上)
[root@k8s-master ~]# mkdir ingress-nginx
[root@k8s-master ingress-nginx]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.20.0/deploy/mandatory.yaml
[root@k8s-master ingress-nginx]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.20.0/deploy/provider/baremetal/service-nodeport.yaml #对外提供服务,如果不需要可以不下载
[root@k8s-master ingress-nginx]# sed -i 's#k8s.gcr.io/defaultbackend-amd64#registry.cn-qingdao.aliyuncs.com/kubernetes_xingej/defaultbackend-amd64#g' mandatory.yaml #替换defaultbackend-amd64镜像地址
sed -i 's#quay.io/kubernetes-ingress-controller/nginx-ingress-controller#registry.cn-qingdao.aliyuncs.com/kubernetes_xingej/nginx-ingress-controller#g' mandatory.yaml #替换nginx-ingress-controller镜像地址
[root@k8s-master ingress-nginx]# grep image mandatory.yaml #检查替换结果
# Any image is permissible as long as:
image: registry.cn-qingdao.aliyuncs.com/kubernetes_xingej/defaultbackend-amd64:1.5
image: registry.cn-qingdao.aliyuncs.com/kubernetes_xingej/nginx-ingress-controller:0.20.0
如果无法下载可以手动下然后上传。地址
修改service-nodeport.yaml文件,添加NodePort端口,默认为随机端口
[root@k8s-master ingress-nginx]# cat service-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
name: ingress-nginx
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
spec:
type: NodePort
ports:
- name: http
port: 80
targetPort: 80
protocol: TCP
nodePort: 32080 #http
- name: https
port: 443
targetPort: 443
protocol: TCP
nodePort: 32443 #https
selector:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
部署nginx-ingress-controller
[root@k8s-master ingress-nginx]# kubectl apply -f mandatory.yaml
namespace/ingress-nginx created
deployment.apps/default-http-backend created
service/default-http-backend created
configmap/nginx-configuration created
configmap/tcp-services created
configmap/udp-services created
serviceaccount/nginx-ingress-serviceaccount created
clusterrole.rbac.authorization.k8s.io/nginx-ingress-clusterrole created
role.rbac.authorization.k8s.io/nginx-ingress-role created
rolebinding.rbac.authorization.k8s.io/nginx-ingress-role-nisa-binding created
clusterrolebinding.rbac.authorization.k8s.io/nginx-ingress-clusterrole-nisa-binding created
deployment.apps/nginx-ingress-controller created
[root@k8s-master ingress-nginx]# kubectl apply -f service-nodeport.yaml
service/ingress-nginx created
查看ingress-nginx组件状态
[root@k8s-master ingress-nginx]# kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default-http-backend ClusterIP 10.1.103.71 <none> 80/TCP 8m48s
ingress-nginx NodePort 10.1.243.42 <none> 80:32080/TCP,443:32443/TCP 6s
访问ingress-nginx服务,查看是否配置成功
http://192.168.200.130:32080/
default backend - 404
可以看到,提示404,这个因为当前ingress-nginx服务现在还没有后端服务,这是正常的
创建一个Service及后端Deployment(以nginx为例)
apiVersion: v1
kind: Service
metadata:
name: myapp
namespace: default
spec:
selector:
app: myapp
release: canary
ports:
- name: http
port: 80
targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deploy
spec:
replicas: 5
selector:
matchLabels:
app: myapp
release: canary
template:
metadata:
labels:
app: myapp
release: canary
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v2
ports:
- name: httpd
containerPort: 80
创建相关服务及检查状态是否就绪
[root@k8s-master ingress-nginx]# kubectl get pods
NAME READY STATUS RESTARTS AGE
busvbox 1/1 Running 0 3h38m
busybox-7c84546778-9jzpx 1/1 Running 15 17d
busybox-7c84546778-rs5d9 1/1 Running 15 17d
httpd-595dc58589-c4hcv 1/1 Running 5 2d6h
httpd-595dc58589-lxj9w 1/1 Running 6 2d6h
httpd-595dc58589-v6wzw 1/1 Running 11 5d
kindly-robin-mychart-fb68878c8-g4cfx 1/1 Running 0 5h10m
myapp-deploy-77c5c86fdb-52bnt 1/1 Running 0 11m
myapp-deploy-77c5c86fdb-9xjdm 1/1 Running 0 11m
myapp-deploy-77c5c86fdb-kznvk 1/1 Running 0 11m
myapp-deploy-77c5c86fdb-sp22l 1/1 Running 0 11m
myapp-deploy-77c5c86fdb-zp2tj 1/1 Running 0 11m
将myapp添加至ingress-nginx中
apiVersion: apps/v1
kind: Ingress
metadata:
name: ingress-myapp
namespace: default
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: myapp.soft.com #生产中该域名应当可以被公网解析
http:
paths:
- path:
backend:
serviceName: myapp
servicePort: 80
将myapp添加至ingress-nginx中
vi ingress-myapp.yaml
apiVersion: apps/v1
kind: Ingress
metadata:
name: ingress-myapp
namespace: default
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: myapp.soft.com #生产中该域名应当可以被公网解析
http:
paths:
- path:
backend:
serviceName: myapp
servicePort: 80
[root@k8s-master ingress-nginx]# kubectl apply -f ingress-myapp.yaml ingress.extensions "ingress-myapp" created
配置域名解析,当前测试环境我们使用hosts文件进行解析,修改本机的host
C:\Windows\System32\drivers\etc
192.168.200.130 myapp.soft.com
浏览器访问域名
http://myapp.soft.com:32080/
Hello MyApp | Version: v2 | Pod Name
再创建一个Service及后端Deployment(以tomcat为例)
vi tomcat-deploy.yaml
apiVersion: v1
kind: Service
metadata:
name: tomcat
namespace: default
spec:
selector:
app: tomcat
release: canary
ports:
- name: http
port: 8080
targetPort: 8080
- name: ajp
port: 8009
targetPort: 8009
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: tomcat-deploy
spec:
replicas: 3
selector:
matchLabels:
app: tomcat
release: canary
template:
metadata:
labels:
app: tomcat
release: canary
spec:
containers:
- name: tomcat
image: tomcat:7-alpine
ports:
- name: httpd
containerPort: 8080
- name: ajp
containerPort: 8009
通过kubectl将其部署到K8S集群:
kubectl apply -f tomcat-deploy.yaml```
```bash
[root@k8s-master ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
tomcat-deploy-f59fd664-47rbp 0/1 ContainerCreating 0 23s > k8s-node2 > >
tomcat-deploy-f59fd664-8h9s6 0/1 ContainerCreating 0 23s > k8s-node1 > >
tomcat-deploy-f59fd664-fwxwc 0/1 ContainerCreating 0 23s > k8s-node2 > >
将tomcat添加至ingress-nginx中
vi ingress-tomcat.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-tomcat
namespace: default
annotations:
kubernets.io/ingress.class: "nginx"
spec:
rules:
- host: tomcat.soft.com
http:
paths:
- path:
backend:
serviceName: tomcat
servicePort: 8080
通过kubectl将其部署到K8S集群:
kubectl apply -f ingress-tomcat.yaml
添加域名解析及访问服务
C:\Windows\System32\drivers\etc
192.168.200.130 myapp.soft.com
192.168.200.130 tomcat.soft.com
浏览器访问域名
http://tomcat.soft.com:32080/
Apache Tomcat/7.0.94 界面,就不放图了
创建私钥和证书
[root@k8s-master ingress-nginx]# openssl genrsa -out tls.key 2048
Generating RSA private key, 2048 bit long modulus
...........+++
..................................+++
e is 65537 (0x10001)
创建自签证书
openssl req -new -x509 -key tls.key -out tls.crt -subj /C=CN/ST=Beijing/L=Beijing/O=DevOps/CN=tomcat.soft.com #注意域名要和服务的域名一致
注意生成的证书是不能直接贴到nginx的pod中去的,我们需要把它先转成特殊格式,这个特殊格式叫secret,它也是标准的k8s集群对象,它可以直接注入到pod中被pod所引用。因此接下来我们需要把它做成secret
kubectl create secret tls tomcat-ingress-secret --cert=tls.crt --key=tls.key
查看secret
[root@k8s-master ingress-nginx]# kubectl get secret
NAME TYPE DATA AGE
default-token-pj9g7 kubernetes.io/service-account-token 3 17d
kindly-robin-mychart-token-54rjt kubernetes.io/service-account-token 3 20h
mysecret Opaque 2 3d17h
tomcat-ingress-secret kubernetes.io/tls 2 53s
[root@k8s-master ingress-nginx]# kubectl describe secret tomcat-ingress-secret
Name: tomcat-ingress-secret
Namespace: default
Labels: <none>
Annotations: <none>
Type: kubernetes.io/tls
Data
====
tls.key: 1679 bytes
tls.crt: 1289 bytes
将证书应用至tomcat服务中
vi ingress-tomcat-tls.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-tomcat-tls
namespace: default
annotations:
kubernets.io/ingress.class: "nginx"
spec:
tls:
- hosts:
- tomcat.soft.com #与secret证书的域名需要保持一致
secretName: tomcat-ingress-secret #secret证书的名称
rules:
- host: tomcat.soft.com
http:
paths:
- path:
backend:
serviceName: tomcat
servicePort: 8080
通过kubectl将其部署到K8S集群:
kubectl apply -f ingress-tomcat-tls.yaml
查看ingress
[root@k8s-master ingress-nginx]# kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress-myapp <none> myapp.soft.com 80 46m
ingress-tomcat <none> tomcat.soft.com 80 13m
ingress-tomcat-tls <none> tomcat.soft.com 80, 443 4m4s
浏览器访问域名
https://tomcat.soft.com:32443/
Apache Tomcat/7.0.94 界面,就不放图了