搜索
您的当前位置:首页正文

k8s 如何对外提供服务

来源:知库网

接下来的内容需要一些pod作为实际的服务处理者,你可以通过下面命令新建一个rs,这个rs会新建三个名为kubia-xxxx的 pod,其8080端口会开放一个服务,请求时会返回其所在节点名称:

kubectl create -f 

port-forward 映射服务到端口

首先来看一下最简单粗暴的方法,我们可以通过一条 k8s 命令来将指定的 pod 端口映射到本地的端口上,基本用法如下:

kubectl port-forward <资源类型>/<资源名> <本机端口>:<资源端口>

例如,我有个 pod 叫做kubia,它通过80端口对外提供服务,那么我就可以使用kubectl port-forward pod/kubia 8080:80将其映射到本机的8080端口上。你可以使用kubectl port-forward -h查看更多用法。

启用后会占用当前终端的标准输出,可以在后面添加&来指定后台运行:

root@master1:~# k port-forward kubia-5k2zr 8080:8080 &
[1] 13949
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080

root@master1:~# curl http://localhost:8080
Handling connection for 8080
You've hit kubia-5k2zr

port-forward可以将 pod 临时映射出来,一般用于测试资源是否可用,在生产环境并不会大规模应用。

NodePort 映射服务到节点端口

相对于上一种port-forward来说,这一种要正式的多,NodePort可以将其 转发到所有 k8s 节点的指定端口上,并且不会像port-forward一样在前台运行。我们先来新建一个NodePort,新建nodeport.yaml文件并填写如下内容,然后使用kubectl create -f nodeport.yaml新建。:

apiVersion: v1
kind: Service
metadata:
  name: kubia-nodeport
spec:
  type: NodePort
  ports:
  - port: 80
    targetPort: 8080
    nodePort: 30123
  selector:
    app: kubia

通过kind属性可以看到NodePort本质上是一个svc资源,他通过指定spec.ports.nodePort来讲服务映射到节点的端口上,接下来我们就可以访问下试试,直接curl访问节点ip + 端口号即可,你可以通过kubectl get nodes -o wide找到所有 k8s 节点的 ip:

root@master1:~# curl http://192.168.56.11:30123
You've hit kubia-m68bq

root@master1:~# curl http://192.168.56.11:30123
You've hit kubia-flg8w

root@master1:~# curl http://192.168.56.11:30123
You've hit kubia-flg8w

root@master1:~# curl http://192.168.56.11:30123
You've hit kubia-8r2cg

root@master1:~# curl http://192.168.56.11:30123
You've hit kubia-m68bq

可以看到,使用了nodePort之后,服务被正常的请求,并且也正常的被均衡到每一个 pod 上。

当然可以,这个就是接下来要说的Ingress

通过 Ingress 暴露服务

ingress 是啥?其实,ingress 就是一个nginx服务器。从本质上说,我们可以直接通过配置nginx服务器来实现刚才说的访问方式,但是这样每次svc发生变更了我们就要重新手动配置一遍,好麻烦的,于是就有聪明的人想出来了,为什么我们不把复杂的配置操作抽象成一个文件,这样有新的变更的话我们直接修改文件,不就可以避免直接操作nginx服务器了么?于是,ingress诞生了。记住,ingress本质上就是一个nginx和许多个配置文件

ingress 有两部分构成,负责转发服务的nginx-ingress-controller和每个服务的配置文件ingress资源,如下:

通过 ingress 配置 service 访问

每个想要对外暴露的svc都需要有一个对应的ingress资源(配置文件)才能对外提供服务,ingress资源并不负责实际的流量转发,它只是告诉nginx-ingress-controller应该把流量转发到哪个svc

接下来,我们实践一下,从头部署一个可用的ingress

安装 ingress

k8s 并不自带 ingress,所以我们需要重新安装,幸好安装比较简单,直接执行如下命令即可,k8s 会根据其内容安装所有需要的资源。

kubectl apply -f 

安装成功之后可以执行如下操作查看 ingress 是否安装完成,输入kubectl get namespaces,查看ingress-nginx(ingress相关的pod组) 的状态是否为Active。输入kubectl get pod -n ingress-nginx,查看nginx-ingress-controller(负责实际转发流量的nginx) 的状态是否为Running

root@master1:~# kubectl get namespaces 
NAME              STATUS   AGE
default           Active   34d
ingress-nginx     Active   27d
kube-node-lease   Active   34d
kube-public       Active   34d
kube-system       Active   34d

root@master1:~# kubectl get pod -n ingress-nginx 
NAME                                        READY   STATUS    RESTARTS   AGE
default-http-backend-7vg6q                  1/1     Running   1          26d
nginx-ingress-controller-5c4964c449-9ccbm   1/1     Running   2          26d

这两者正常基本可以断定ingress安装成功了,接下来我们来创建一个对外服务。

使用 ingress 创建对外服务

在"通过 ingress 配置 service 访问"图里我们可以看出,使用 ingress 暴露服务需要先新建一个svc,所以我们先使用如下内容创建一个,它会把 pod kubia端口8080上的服务转发到自己的8080上,他控制的 pod 就是我们文章开头时新建的那些

kubia-svc.yaml

apiVersion: v1
kind: Service
metadata:
  name: kubia
spec:
  ports:
  - port: 8080
    targetPort: 8080
  selector:
    app: kubia

然后使用kubectl create -f kubia-svc.yaml创建该svc,接下来我们创建一个ingress。ingress 支持创建HTTPHTTPS的服务,接下来我们先来创建一个HTTP的:

创建 HTTP 协议的访问

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: kubia
spec:
  rules:
    # 将服务映射到该域名
  - host: 
    http:
      paths:
        # 通过 / 路径就可以访问该服务
      - path: /
        # 该服务后端 svc 的名称及端口号
        backend:
          serviceName: kubia
          servicePort: 8080
root@master1:~# k describe ingress kubia
Name:             kubia
Namespace:        default
Address:          
Default backend:  default-http-backend:80 (<none>)
Rules:
  Host               Path  Backends
  ----               ----  --------
    /     kubia:8080 (10.244.1.59:8080,10.244.2.31:8080,10.244.3.30:8080)
Annotations:
Events:  <none>

配置域名到 ip 地址

首先获取nginx-ingress-controller的 ip 地址,执行如下命令后按Tab补全名称,然后在IP列就可以找到对应的 ip 了。

kubectl describe pod -n ingress-nginx nginx-ingress-controller-

我的 ip 地址为192.168.56.22,执行vi /etc/hosts,输入以下内容即可:

 192.168.56.22
root@master1:~# curl 
You've hit kubia-m68bq

root@master1:~# curl 
You've hit kubia-8r2cg

root@master1:~# curl 
You've hit kubia-flg8w

创建 HTTPS 协议的访问

https 请求链路
openssl genrsa -out tls.key 2048

openssl req -new -x509 \
  -key tls.key \
  -out tls.cert \
  -days 360 \
  -subj 

执行完之后你就可以在当前文件夹下发现两个文件,分别为tls.certtls.key。因为这种秘钥比较敏感,不适合直接挂载到 pod 上,所以可以使用 k8s 提供的专门用于提供敏感数据的资源secret来存放它,我们先来新建一个名为tls-secretsecret资源:

kubectl create secret tls tls-secret --cert=tls.cert --key=tls.key

什么是secret资源?

secret用于存放一些敏感的配置信息,如密码、密钥等,你可以把他理解成一个更安全的ConfigMap资源,k8s 提供了很多类型的secret,例如上文的kubectl create secret tls就是一个常用的secret

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: kubia
spec:
  # 添加 tls 字段来启用 https
  tls:
  - hosts: 
      # 启用 https 的域名
    - 
    # 给其分配的证书及密钥,要求 tls 类型的 k8s secret 资源
    secretName: tls-secret
  rules:
  - host: 
    http:
      paths:
      - path: /
        backend:
          serviceName: kubia
          servicePort: 8080
kubectl apply -f kubia-https-ingress.yaml
root@master1:~# curl -k -v 
...
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
...
* Server certificate:
*  subject: 
...
You've hit kubia-flg8w

使用 ingress 暴露多个服务

kubia-ingress.yaml文件中可以看到,rulespaths都是数组,所以我们可以通过其暴露多个服务,如下:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: kubia
spec:
  rules:
  - host: 
    http:
      paths:
        # 通过指定不同的路径来访问不同的服务
      - path: /foo
        backend:
          serviceName: foo-svc
          servicePort: 8080
      - path: /bar
        backend:
          serviceName: bar-svc
          servicePort: 8080
  # 也可以通过指定多个 host 来配置不同的主机
  - host: 
    http:
      paths:
      - path: /kubia
        backend:
          serviceName: kubia
          servicePort: 8080

但是哪怕在一个文件中可以配置多个规则,但是依旧推荐为每一个svc都创建一个自己专属的ingress,这样条理会比较清晰,也方便日后的管理。

总结

本文介绍了如何将服务暴露出去,最简单的是port-forward命令,他可以将指定资源的端口转发到本机,但是一般都用于测试。

其次是NodePort模式,NodePort本质上也是个svc,只不过他在完成svc本质工作的同时还将服务开放到了集群中所有节点的指定端口上。

但是用户更倾向于通过子路径访问服务,而不是端口。为了实现这个目标,我们可以使用ingress资源,通过发布ingress配置文件,nginx-ingress-controller就可以将指定的服务发布到指定域名的指定路径上,ingress支持发布HTTPHTTPS连接。

参考

Top