携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第10天。
使用 Ingress 统一访问入口
k8s 有三种访问外部的方式:
-
NodePort
NodePort 服务是引导外部流量到你的服务的最原始方式。在所有节点(虚拟机)上开放一个特定端口,任何发送到该端口的流量都被转发到对应服务。
-
LoadBalancer
LoadBalancer 服务是暴露服务到 Internet 的标准方式。所有通往你指定的端口的流量都会被转发到对应的服务。它没有过滤条件,没有路由等。这意味着你几乎可以发送任何种类的流量到该服务,像 HTTP,TCP,UDP,WebSocket,gRPC 或其它任意种类。
-
Ingress
Ingress 事实上不是一种服务类型。相反,它处于多个服务的前端,扮演着 “智能路由” 或者集群入口的角色。你可以用 Ingress 来做许多不同的事情,各种不同类型的 Ingress 控制器也有不同的能力。它允许你基于路径或者子域名来路由流量到后端服务。
Ingress 可能是暴露服务的最强大方式,但同时也是最复杂的。
Ingress 简单的理解就是你原来需要对集群进行 Nginx 配置,然后配置各种域名对应哪个 Service,现在把这个动作抽象出来,变成一个 Ingress 对象,你可以用 yaml 创建,每次需要对集群节点进行变更时不要去改 Nginx 了,直接改 yaml 然后创建/更新就行了。
Ingress Controoler 通过与 Kubernetes API 交互,动态的去感知集群中 Ingress 规则变化,然后读取他,按照他自己模板生成一段 Nginx 配置,再写到 Nginx Pod 里,最后 reload 一下,工作流程如下图:
实际上Ingress也是Kubernetes API的标准资源类型之一,它其实就是一组基于DNS名称(host)或URL路径把请求转发到指定的Service资源的规则。用于将集群外部的请求流量转发到集群内部完成的服务发布。我们需要明白的是,Ingress资源自身不能进行“流量穿透”,仅仅是一组规则的集合,这些集合规则还需要其他功能的辅助,比如监听某套接字,然后根据这些规则的匹配进行路由转发,这些能够为Ingress资源监听套接字并将流量转发的组件就是Ingress Controller。
PS:Ingress 控制器不同于Deployment 控制器的是,Ingress控制器不直接运行为kube-controller-manager的一部分,它仅仅是Kubernetes集群的一个附件,类似于CoreDNS,需要在集群上单独部署。
如何创建Ingress资源
Ingress 资源是基于 HTTP 虚拟主机或 URL 的转发规则,需要强调的是,这是一条转发规则。它在资源配置清单中的 spec 字段中嵌套了 rules、backend 和 tls 等字段进行定义。如下示例中定义了一个 Ingress 资源,其包含了一个转发规则:将发往 myapp.magedu.com 的请求,代理给一个名字为 myapp 的 Service 资源。
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-myapp
namespace: default
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: myapp.magedu.com
http:
paths:
- path:
backend:
serviceName: myapp
servicePort: 80
Ingress 中的spec字段是Ingress资源的核心组成部分,主要包含以下3个字段:
-
rules:用于定义当前 Ingress 资源的转发规则列表;由 rules 定义规则,或没有匹配到规则时,所有的流量会转发到由 backend 定义的默认后端。
-
backend:默认的后端用于服务那些没有匹配到任何规则的请求;定义Ingress资源时,必须要定义backend或rules两者之一,该字段用于让负载均衡器指定一个全局默认的后端。
-
tls:TLS配置,目前仅支持通过默认端口443提供服务,如果要配置指定的列表成员指向不同的主机,则需要通过SNI TLS扩展机制来支持该功能。backend对象的定义由2个必要的字段组成:serviceName和servicePort,分别用于指定流量转发的后端目标Service资源名称和端口。rules对象由一系列的配置的Ingress资源的host规则组成,这些host规则用于将一个主机上的某个URL映射到相关后端Service对象,其定义格式如下:
spec:
rules:
- hosts: <string>
http:
paths:
- path:
backend:
serviceName: <string>
servicePort: <string>
需要注意的是,.spec.rules.host属性值,目前暂不支持使用IP地址定义,也不支持IP:Port的格式,该字段留空,代表着通配所有主机名。tls对象由2个内嵌的字段组成,仅在定义TLS主机的转发规则上使用。
-
hosts:包含 于 使用 的 TLS 证书 之内 的 主机 名称 字符串 列表, 因此, 此处 使用 的 主机 名 必须 匹配 tlsSecret 中的 名称。
-
secretName:用于 引用 SSL 会话 的 secret 对象 名称, 在 基于 SNI 实现 多 主机 路 由 的 场景 中, 此 字段 为 可选。
Ingress Nginx部署
使用Ingress功能步骤:1、安装部署ingress controller Pod2、部署后端服务3、部署ingress-nginx service4、部署ingress
1、部署Ingress controller
ingress-nginx在github上的地址(1)下载ingress相关的yaml
[root@k8s-master ~]# mkdir ingress-nginx
[root@k8s-master ~]# cd ingress-nginx/
[root@k8s-master ingress-nginx]# for file in namespace.yaml configmap.yaml rbac.yaml tcp-services-configmap.yaml with-rbac.yaml udp-services-configmap.yaml default-backend.yaml;do wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/$file;done
[root@k8s-master ingress-nginx]# ll
total 28
-rw-r--r-- 1 root root 199 Sep 29 22:45 configmap.yaml#configmap用于为nginx从外部注入配置的
-rw-r--r-- 1 root root 1583 Sep 29 22:45 default-backend.yaml#配置默认后端服务
-rw-r--r-- 1 root root 69 Sep 29 22:45 namespace.yaml#创建独立的名称空间
-rw-r--r-- 1 root root 2866 Sep 29 22:45 rbac.yaml#rbac用于集群角色授权
-rw-r--r-- 1 root root 192 Sep 29 22:45 tcp-services-configmap.yaml
-rw-r--r-- 1 root root 192 Sep 29 22:45 udp-services-configmap.yaml
-rw-r--r-- 1 root root 2409 Sep 29 22:45 with-rbac.yaml
(2)创建ingress-nginx名称空间
[root@k8s-master ingress-nginx]# cat namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: ingress-nginx
---
[root@k8s-master ingress-nginx]# kubectl apply -f namespace.yaml
namespace/ingress-nginx created
(3)创建ingress controller的pod
[root@k8s-master ingress-nginx]# kubectl apply -f ./
...
[root@k8s-master ingress-nginx]# kubectl get pod -n ingress-nginx -w
NAME READY STATUS RESTARTS AGE
default-http-backend-7db7c45b69-gjrnl 0/1 ContainerCreating 0 35s
nginx-ingress-controller-6bd7c597cb-6pchv 0/1 ContainerCreating 0 34s
此处遇到一个问题,新版本的Kubernetes在安装部署中,需要从k8s.grc.io仓库中拉取所需镜像文件,但由于国内网络防火墙问题导致无法正常拉取。docker.io仓库对google的容器做了镜像,可以通过下列命令下拉取相关镜像:
[root@k8s-node01 ~]# docker pull mirrorgooglecontainers/defaultbackend-amd64:1.5
1.5: Pulling from mirrorgooglecontainers/defaultbackend-amd64
9ecb1e82bb4a: Pull complete
Digest: sha256:d08e129315e2dd093abfc16283cee19eabc18ae6b7cb8c2e26cc26888c6fc56a
Status: Downloaded newer image for mirrorgooglecontainers/defaultbackend-amd64:1.5
[root@k8s-node01 ~]# docker tag mirrorgooglecontainers/defaultbackend-amd64:1.5 k8s.gcr.io/defaultbackend-amd64:1.5
[root@k8s-node01 ~]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
mirrorgooglecontainers/defaultbackend-amd64 1.5 b5af743e5984 34 hours ago 5.13MB
k8s.gcr.io/defaultbackend-amd64 1.5 b5af743e5984 34 hours ago 5.13MB
2、部署后端服务
[root@k8s-master ingress-nginx]# cd ../mainfests/
[root@k8s-master mainfests]# mkdir ingress && cd ingress
[root@k8s-master ingress]# cp ../deploy-demo.yaml .
[root@k8s-master ingress]# vim deploy-demo.yaml
#创建service为myapp
apiVersion: v1
kind: Service
metadata:
name: myapp
namespace: default
spec:
selector:
app: myapp
release: canary
ports:
- name: http
targetPort: 80
port: 80
---
#创建后端服务的pod
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-backend-pod
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: myapp
release: canary
template:
metadata:
labels:
app: myapp
release: canary
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v2
ports:
- name: http
containerPort: 80
[root@k8s-master ingress]# kubectl apply -f deploy-demo.yaml
service/myapp created
deployment.apps/myapp-backend-pod unchanged
查看新建的后端服务pod
[root@k8s-master ingress]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-backend-pod-67f6f6b4dc-9jl9q 1/1 Running 0 7m
myapp-backend-pod-67f6f6b4dc-x5jsb 1/1 Running 0 7m
myapp-backend-pod-67f6f6b4dc-xzxbj 1/1 Running 0 7m
3、部署ingress-nginx service
通过ingress-controller对外提供服务,现在还需要手动给ingress-controller建立一个service,接收集群外部流量。方法如下:(1)下载ingress-controller的yaml文件
[root@k8s-master ingress]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/baremetal/service-nodeport.yaml
[root@k8s-master ingress]# vim 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: 30080
- name: https
port: 443
targetPort: 443
protocol: TCP
nodePort: 30443
selector:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
---
(2)创建ingress-controller的service,并测试访问
[root@k8s-master ingress]# kubectl apply -f service-nodeport.yaml
service/ingress-nginx created
[root@k8s-master ingress]# kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default-http-backend ClusterIP 10.104.41.201 <none> 80/TCP 45m
ingress-nginx NodePort 10.96.135.79 <none> 80:30080/TCP,443:30443/TCP 11s
此时访问:【IP】:30080此时应该是404 ,调度器是正常工作的,但是后端服务没有关联
4、部署ingress
(1)编写ingress的配置清单
[root@k8s-master ingress]# vim ingress-myapp.yaml
apiVersion: extensions/v1beta1 #api版本
kind: Ingress #清单类型
metadata: #元数据
name: ingress-myapp #ingress的名称
namespace: default #所属名称空间
annotations: #注解信息
kubernetes.io/ingress.class: "nginx"
spec: #规格
rules: #定义后端转发的规则
- host: myapp.magedu.com #通过域名进行转发
http:
paths:
- path: #配置访问路径,如果通过url进行转发,需要修改;空默认为访问的路径为"/"
backend: #配置后端服务
serviceName: myapp
servicePort: 80
[root@k8s-master ingress]# kubectl apply -f ingress-myapp.yaml
[root@k8s-master ingress]# kubectl get ingress
NAME HOSTS ADDRESS PORTS AGE
ingress-myapp myapp.magedu.com 80 46s
(2)查看ingress-myapp的详细信息
[root@k8s-master ingress]# kubectl describe ingress ingress-myapp
Name: ingress-myapp
Namespace: default
Address:
Default backend: default-http-backend:80 (<none>)
Rules:
Host Path Backends
---- ---- --------
myapp.magedu.com
myapp:80 (<none>)
Annotations:
kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"extensions/v1beta1","kind":"Ingress","metadata":{"annotations":{"kubernetes.io/ingress.class":"nginx"},"name":"ingress-myapp","namespace":"default"},"spec":{"rules":[{"host":"myapp.magedu.com","http":{"paths":[{"backend":{"serviceName":"myapp","servicePort":80},"path":null}]}}]}}
kubernetes.io/ingress.class: nginx
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal CREATE 1m nginx-ingress-controller Ingress default/ingress-myapp
[root@k8s-master ingress]# kubectl get pods -n ingress-nginx
NAME READY STATUS RESTARTS AGE
default-http-backend-7db7c45b69-fndwp 1/1 Running 0 31m
nginx-ingress-controller-6bd7c597cb-6pchv 1/1 Running 0 55m
(3)进入nginx-ingress-controller进行查看是否注入了nginx的配置
[root@k8s-master ingress]# kubectl exec -n ingress-nginx -it nginx-ingress-controller-6bd7c597cb-6pchv -- /bin/bash
www-data@nginx-ingress-controller-6bd7c597cb-6pchv:/etc/nginx$ cat nginx.conf
......
## start server myapp.magedu.com
server {
server_name myapp.magedu.com ;
listen 80;
set $proxy_upstream_name "-";
location / {
set $namespace "default";
set $ingress_name "ingress-myapp";
set $service_name "myapp";
set $service_port "80";
set $location_path "/";
rewrite_by_lua_block {
balancer.rewrite()
}
log_by_lua_block {
balancer.log()
monitor.call()
}
......
(4)修改本地host文件,进行访问
192.168.56.12 myapp.magedu.com
192.168.56.13 myapp.magedu.com
5、总结
从前面的部署过程中,可以再次进行总结部署的流程如下:
①下载Ingress-controller相关的YAML文件,并给Ingress-controller创建独立的名称空间;
②部署后端的服务,如myapp,并通过service进行暴露;
③部署Ingress-controller的service,以实现接入集群外部流量;
④部署Ingress,进行定义规则,使Ingress-controller和后端服务的Pod组进行关联。
本次部署后的说明图如下: