k8s 如何对外提供服务


本文将介绍在 k8s 中向外界提供服务的几种方法port-forwardNodePort,以及 更加常用的提供服务的资源ingress。本文要求对service资源有一定的了解,如果你还不清楚的话,可以点击 k8s 中的服务如何沟通 简单学习一下。

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

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

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

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

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:

kubectl apply -f https://raw.githubusercontent.com/StudyXX/google-containers/v1.10.2/install/ingress-nginx/ingress-nginx-controller.yaml

如果出现了镜像拉取失败的情况可以先手动将命令中的配置文件下载下来,然后将其的镜像地址从quay.io/替换成quay-mirror.qiniu.com/,重新kubectl apply即可。文件地址为 github - StudyXX/ingress-nginx-controller.yaml 。

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

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 协议的访问

http协议的访问比较简单,直接创建如下配置文件即可,通过这个ingress配置文件,nginx-ingress-controller就知道如何对外开发服务了。

kubia-http-ingress.yaml

root@master1:~# k describe ingress kubia
Name:             kubia
Namespace:        default
Address:          
Default backend:  default-http-backend:80 (<none>)
Rules:
  Host               Path  Backends
  ----               ----  --------
  kubia.example.com  /     kubia:8080 (10.244.1.59:8080,10.244.2.31:8080,10.244.3.30:8080)
Annotations:
Events:  <none>

ok,现在我们就可以通过http://kubia.example.com/来访问目标svc啦,这时你可能会疑惑,我没这个域名啊?没关系,在系统的hosts文件里配置一下,将这个域名映射到nginx-ingress-controller的 ip 地址就可以了,详情见下方:

配置域名到 ip 地址

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

192.168.56.22 kubia.example.com

修改完了之后,我们就可以进行访问了,执行curl http://kubia.example.com/,就可以看到来自 svc kubia的响应了。

openssl genrsa -out tls.key 2048

openssl req -new -x509 \
  -key tls.key \
  -out tls.cert \
  -days 360 \
  -subj /CN=kubia.example.com

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

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: kubia
spec:
  # 添加 tls 字段来启用 https
  tls:
  - hosts: 
      # 启用 https 的域名
    - kubia.example.com
    # 给其分配的证书及密钥,要求 tls 类型的 k8s secret 资源
    secretName: tls-secret
  rules:
  - host: kubia.example.com
    http:
      paths:
      - path: /
        backend:
          serviceName: kubia
          servicePort: 8080

然后我们就可以通过以下命令来讲刚才创建的http服务提升至httpskubectl apply依靠kindmetadata字段中的数据来寻找要修改的资源,所以改名字并不会造成什么影响

root@master1:~# curl -k -v https://kubia.example.com
...
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
...
* Server certificate:
*  subject: CN=kubia.example.com
...
You've hit kubia-flg8w

使用 ingress 暴露多个服务

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

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

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

总结

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

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

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



作者:HoPGoldy
链接:https://www.jianshu.com/p/58976bf0a8a4
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。