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,在集群当中任一节点里,都是可以畅通访问的。
详细的介绍,可以看官方的文档介绍: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 \"<p>Hello from $(hostname)<p>\" > 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
<p>Hello from service-test-7bd7775475-ltbfc<p>
[root@kube-node01 yaml]$ curl 172.30.87.2:8080
<p>Hello from service-test-7bd7775475-m4pbv<p>
看到返回了两个不同的结果,之前有对这个名称做过分析,那么现在将请求的返回数据掐在 service 阶段,从而让访问统一,让返回值负载均衡。
实验快速更新部署:
现在同时开启两个窗口,一个窗口一直 curl 刚刚的 CLUSTER-IP
那么现在模拟应用升级,可以通过直接编译 yaml 文件来实现
[root@kube-node01 yaml]$ kubectl edit deployment service-test
在刚刚的echo处更改一下输出:
添加一个new version然后保存退出:
- echo "<p>Hello from new version $(hostname)<p>" > index.html; python -m
deployment.extensions "service-test" edited
不用动,可以看到下边的输出已经自动的变化了,基本上零停顿
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 <none> 443/TCP 3d
nginx-pod NodePort 10.254.202.150 <none> 80:8675/TCP 19s
这个时候可以看到类型变成 NodePort 了,而且后边也详细标出了端口的映射关系,是将 pod 的 80 端口映射到 node 的 8675 上。
那么现在就可以通过这种方式就可以访问了:
master
node1~2
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 <none> 443/TCP 3d
nginx-pod NodePort 10.254.202.150 <none> 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 <none> 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 <none> 443/TCP 3d
nginx-service NodePort 10.254.184.147 <none> 8999:8999/TCP 1m
访问之:
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 # 添加配置