k8s基本使用入门-了解Service

1、引入

现在准备了两个 pod 的 yaml 文件
pod_nginx.yml

[root@kube-node01 yaml]$ cat pod_nginx.yml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    app: nginx
spec:
  containers:
  - name: nginx-container
    image: nginx
    ports:
    - name: nginx-port
      containerPort: 80

pod_busybox.yml

[root@kube-node01 yaml]$ cat pod_busybox.yml
apiVersion: v1
kind: Pod
metadata:
  name: busybox-pod
  labels:
    app: busybox
spec:
  containers:
  - name: busybox-container
    image: busybox
    command:
      - sleep
      - "360000"

启动

kubectl create -f pod_nginx.yml
kubectl create -f pod_busybox.yml

然后看一下两个 pod 的 ip:

[root@kube-node01 yaml]$ kubectl get pod -o wide
NAME          READY     STATUS    RESTARTS   AGE       IP            NODE
busybox-pod   1/1       Running   0          15m       10.244.1.58   node
nginx-pod     1/1       Running   0          15m       10.244.1.59   node

此时,这两个生成的 ip,在集群当中任一节点里,都是可以畅通访问的。


image.png

详细的介绍,可以看官方的文档介绍:https://kubernetes.io/docs/concepts/cluster-administration/networking/

2、缘由

现在可以思考一个问题:为什么不直接通过 pod 来作为 k8s 的管理单位进行管理呢?

  • 当我们使用 ReplicaSet 或者 ReplicationController 做水平扩展 scale 的时候,Pod 会在这个过程中被 terminated,随着这个更替,Pod 的 ip 等的也都在变幻。

  • 当我们使用 Deployment 的时候,我们去更新 Docker Image Version,旧的 Pods 会被 terminated,然后新的 Pods 创建,这个过程中,同样会发生 Pod 的 ip 改变等问题。从而难于对其进行访问。

3、service 概念

之于如上所提问题,那么就引入了 service 这个概念。

k8s 分配给 Service 一个固定 IP,这是一个虚拟 IP(也称为 ClusterIP),并不是一个真实存在的 IP,而是由 k8s 虚拟出来的。虚拟 IP 的范围通过 k8s API Server 的启动参数 –service-cluster-ip-range=19.254.0.0/16 配置;

虚拟 IP 属于 k8s 内部的虚拟网络,外部是寻址不到的。在 k8s 系统中,实际上是由 k8s Proxy 组件负责实现虚拟 IP 路由和转发的,所以 k8s Node 中都必须运行了 k8s Proxy,从而在容器覆盖网络之上又实现了 k8s 层级的虚拟转发网络。

服务代理:

在逻辑层面上,Service 被认为是真实应用的抽象,每一个 Service 关联着一系列的 Pod。在物理层面上,Service 有事真实应用的代理服务器,对外表现为一个单一访问入口,通过 k8s Proxy 转发请求到 Service 关联的 Pod。

Service 同样是根据 Label Selector 来刷选 Pod 进行关联的,实际上 k8s 在 Service 和 Pod 之间通过 Endpoint 衔接,Endpoints 同 Service 关联的 Pod;相对应,可以认为是 Service 的服务代理后端,k8s 会根据 Service 关联到 Pod 的 PodIP 信息组合成一个 Endpoints。

4、service 几种类型。

1)ClusterIP 方式
kubernetes 默认就是这种方式,是集群内部访问的方式,外部的话,是无法访问的。

[root@kube-node01 yaml]$ cat XX.yaml
spec:
  clusterIP: 内网IP
  ports:
  - name: http

2)NodePort 方式

[root@kube-node01 yaml]$ cat XX.yaml
apiVersion: v1
kind: Service
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"creationTimestamp":"20XX-XX-XXTXX:XX:XXZ","labels":{"kubernetes.io/name":"heapster","plugin":"heapster"},"name":"heapster","namespace":"kube-system","resourceVersion":"173906247","selfLink":"/api/v1/namespaces/kube-system/services/heapster","uid":"91470fbb-404b-11e7-ba41-5254eec04736"},"spec":{"clusterIP":"节点 IP ","externalTrafficPolicy":"Cluster","ports":[{"nodePort":30003,"port":80,"protocol":"TCP","targetPort":8082}],"selector":{"k8s-app":"heapster"},"sessionAffinity":"None","type":"NodePort"},"status":{"loadBalancer":{}}}
  creationTimestamp: 20XX-XX-XXTXX:XX:XXZ
  labels:
    kubernetes.io/name: heapster
    plugin: heapster
  name: heapster
  namespace: kube-system
  resourceVersion: "789489505"
  selfLink: /api/v1/namespaces/kube-system/services/heapster
  uid: e56886a2-8fb9-11e8-acd2-5254171bf8db
spec:
  clusterIP: 节点 IP
  externalTrafficPolicy: Cluster
  ports:
  - nodePort: 30003
    port: 80
    protocol: TCP
    targetPort: 8082
  selector:
    k8s-app: heapster
  sessionAffinity: None
  type: NodePort
status:
  loadBalancer: {}

3)LoadBalancer 方式
这种方式主要是利用其他第三方的 LB 暴露服务的,谷歌或者亚马逊的 LB 等等

[root@kube-node01 yaml]$ cat XX.yaml
kind: Service
apiVersion: v1
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
  - protocol: TCP
    port: 80
    targetPort: 9376
  clusterIP: 10.0.171.239
  loadBalancerIP: 78.11.24.19
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
    - ip: 146.148.47.155

4)ExternalName 方式
这种方式主要是通过 CNAME 实现的,在 kubernetes 1.7.x 以及以上才支持这种方式,例如

[root@kube-node01 yaml]$ cat XX.yaml
kind: Service
apiVersion: v1
metadata:
  name: my-service
  namespace: prod
spec:
  type: ExternalName
  externalName: my.database.example.com

访问时,kube-dns 服务直接解析到指定的 Cnamemy.database.example.com 这个域名上

5、service 学习示例

1)cluster IP
首先准备一个 deployment 的 yaml 文件:

[root@kube-node01 yaml]$  cat deployment_python_http.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: service-test
spec:
  replicas: 2
  selector:
    matchLabels:
      app: service_test_pod
  template:
    metadata:
      labels:
        app: service_test_pod
    spec:
      containers:
      - name: simple-http
        image: python:2.7
        imagePullPolicy: IfNotPresent
        command: ["/bin/bash"]
        args: ["-c","echo \"

Hello from $(hostname)

\" > index.html; python -m SimpleHTTPServer 8080"] ports: - name: http containerPort: 8080

创建之前,可以先在 node 节点将镜像 pull 下来,以免等会儿创建的时候比较慢

[root@kube-node01 yaml]$ kubectl create -f deployment_python_http.yaml
deployment.extensions "service-test" created

[root@kube-node01 yaml]$ kubectl get deployment
NAME           DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
service-test   2         2         2            2           10m

[root@kube-node01 yaml]$ kubectl get pod
NAME                            READY     STATUS    RESTARTS   AGE
service-test-7bd7775475-ltbfc   1/1       Running   0          6m
service-test-7bd7775475-m4pbv   1/1       Running   0          6m

先在分别访问一下这两个 pod:

[root@kube-node01 yaml]$ kubectl describe pod service-test-7bd7775475-ltbfc|grep IP
IP:             172.30.64.2

[root@kube-node01 yaml]$ kubectl describe pod service-test-7bd7775475-m4pbv|grep IP
IP:             172.30.87.2

[root@kube-node01 yaml]$ curl 172.30.64.2:8080

Hello from service-test-7bd7775475-ltbfc

[root@kube-node01 yaml]$ curl 172.30.87.2:8080

Hello from service-test-7bd7775475-m4pbv

看到返回了两个不同的结果,之前有对这个名称做过分析,那么现在将请求的返回数据掐在 service 阶段,从而让访问统一,让返回值负载均衡。

实验快速更新部署:
现在同时开启两个窗口,一个窗口一直 curl 刚刚的 CLUSTER-IP


image.png

那么现在模拟应用升级,可以通过直接编译 yaml 文件来实现

[root@kube-node01 yaml]$ kubectl edit deployment service-test
在刚刚的echo处更改一下输出: 
添加一个new version然后保存退出:
- echo "

Hello from new version $(hostname)

" > index.html; python -m deployment.extensions "service-test" edited

不用动,可以看到下边的输出已经自动的变化了,基本上零停顿

image.png

2)NodePort
了解之前,先将之前所有的环境都清理一波,还原成一个干净的环境。

2.1)通过指令创建 NodePort
准备有 nginx 的一个 yaml 文件:

[root@kube-node01 yaml]$ cat pod_nginx.yml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    app: nginx
spec:
  containers:
  - name: nginx-container
    image: nginx
    ports:
    - name: nginx-port
      containerPort: 80

启动这个常规的 pod:

[root@kube-node01 yaml]$ kubectl create -f pod_nginx.yml
pod "nginx-pod" created

[root@kube-node01 yaml]$ kubectl get pod
NAME                            READY     STATUS    RESTARTS   AGE
nginx-pod                       1/1       Running   0          7s
service-test-7ddddbdd69-b7s2x   1/1       Running   0          27m
service-test-7ddddbdd69-hqgxb   1/1       Running   0          29m


[root@kube-node01 yaml]$ kubectl get pod -o wide
NAME                            READY     STATUS    RESTARTS   AGE       IP            NODE
nginx-pod                       1/1       Running   0          15s       172.30.87.2   kube-node02
service-test-7ddddbdd69-b7s2x   1/1       Running   0          27m       172.30.87.3   kube-node02
service-test-7ddddbdd69-hqgxb   1/1       Running   0          29m       172.30.84.2   kube-node01

现在将其配置为 NodePort 的形式,使用如下指令:

[root@kube-node01 yaml]$ kubectl expose pod nginx-pod --type=NodePort
service "nginx-pod" exposed

[root@kube-node01 yaml]$ kubectl get svc
NAME               TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)       AGE
kubernetes         ClusterIP   10.254.0.1               443/TCP       3d
nginx-pod          NodePort    10.254.202.150           80:8675/TCP   19s

这个时候可以看到类型变成 NodePort 了,而且后边也详细标出了端口的映射关系,是将 pod 的 80 端口映射到 node 的 8675 上。

那么现在就可以通过这种方式就可以访问了:
master


image.png

node1~2


image.png

2.2)通过 yaml 形式创建 NodePort。
现在介绍另外一种情况,介绍之前,先将刚刚的 service 删除。

[root@kube-node01 yaml]$ kubectl get svc
NAME               TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)       AGE
kubernetes         ClusterIP   10.254.0.1               443/TCP       3d
nginx-pod          NodePort    10.254.202.150           80:8675/TCP   8m

[root@kube-node01 yaml]$ kubectl delete svc nginx-pod
service "nginx-pod" deleted

[root@kube-node01 yaml]$ kubectl get svc
NAME               TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)       AGE
kubernetes         ClusterIP   10.254.0.1              443/TCP       3d

然后添加一个文件:

[root@kube-node01 yaml]$ more service_nginx.yml
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  ports:
  - port: 8999
    nodePort: 8999
    targetPort: nginx-port
    protocol: TCP
  selector:
    app: nginx
  type: NodePort

此文件内容是基于刚刚还存在的 pod 而成立的,selector,就是检索刚刚创建的 nginx 的 pod,然后直接将端口类型设置为 NodePort,端口为 8999。

然后创建之:

[root@kube-node01 yaml]$ kubectl create -f service_nginx.yml
service "nginx-service" created

[root@kube-node01 ~]$ kubectl get svc
NAME               TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)         AGE
kubernetes         ClusterIP   10.254.0.1               443/TCP         3d
nginx-service      NodePort    10.254.184.147           8999:8999/TCP   1m

访问之:


image.png

kubeadm 更改NodePort端口范围

提示:The Service "nginx-service" is invalid: spec.ports[0].nodePort: Invalid value: 8999: provided port is not in the valid range. The range of valid ports is 30000-32767

1)配置文件里,一般的在这个文件夹下: /etc/kubernetes/manifests/
2)找到文件名为kube-apiserver.yaml的文件,也可能是json格式
3)编辑添加配置 service-node-port-range=1000-9999

[root@master01 manifests]# sed -n "12,43p" /etc/kubernetes/manifests/kube-apiserver.yaml
spec:
  containers:
  - command:
    - kube-apiserver
    ..........
    - --service-node-port-range=1000-9999   # 添加配置

你可能感兴趣的:(k8s基本使用入门-了解Service)