簡介
Service是Kubernetes的核心概念,通過建立Service,可以為一組具有相同功能的容器應用提供一個統一的入口地址,並且將請求負載分發到後端的各個容器應用上。
Service從邏輯上代表了一組Pod,具體是哪組Pod則是由label來挑選的
在Kubernetes中Service的Cluster IP實現資料包文請求的轉發,都離不開node上部署的重要元件 kube-proxy
kube-proxy作用
- 實時監聽kube-api,獲取建立service的建立,升級資訊,增加或刪除pod資訊。來獲取Pod和VIP的對映關係
- 維護本地Netfileter iptables IPVS核心元件
- 通過修改和更新ipvs規則來實現資料包文的轉發規則
- 構建路由資訊,通過轉發規則轉發報文到對應的pod上
1. Service資源定義
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
labels:
app: nginx
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
selector:
app: nginx
1.1 Service Type
根據建立Service的type不同 可以分為以下幾種型別
-
ClusterIP
預設方式,根據是否生成ClusterIP又可以分為普通Service和Headless Service兩類此方式僅用於叢集內部之間實現通訊的
-
NodePort
NodePort模式除了使用cluster ip外,也將service的port對映到每個node的一個指定內部port上,對映的每個node的內部port都一樣。可以通過訪問Node節點的IP實現外部通訊
-
LoadBalancer
要配合支援公有云負載均衡使用比如GCE、AWS。其實也是NodePort,只不過會把: 自動新增到公有云的負載均衡當中 -
ExternalName
外部IP;如果叢集外部需要有一個服務需要我們進行訪問;那麼就需要在service中指定外部的IP讓service與外部的那個服務進行訪問;那麼接下的叢集內部到外部那個資料包走向便是:資料包先到service然後由service交給外部那個服務;回來的資料包是:交給node node交給service service交給Pod
下面說下生產常用的型別定義以及使用
ClusterIP
定義一個web應用
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-deploy
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: myappnginx
release: stable
template:
metadata:
labels:
app: myappnginx
release: stable
spec:
containers:
- name: nginxweb
image: nginx:1.14-alpine
imagePullPolicy: IfNotPresent
建立service資源基於ClusterIP型別
apiVersion: v1
kind: Service
metadata:
name: webservice #service名字;也就是後面驗證基於主機名訪問的名字
namespace: default #名稱空間要與剛才建立的Pod的名稱空間一致,service資源也是基於namespace隔離的
spec:
selector: #標籤選擇器很重要決定是要關聯某個符合標籤的Pod
app: myappnginx #標籤要與剛才定義Pod的標籤一致;因為service是通過標籤與Pod關聯的
release: stable
type: ClusterIP #型別是ClusterIP
ports: #暴露的埠設定
- port: 88 #service暴露的埠
targetPort: 80 #容器本身暴露的埠,和dockerfile中的expose意思一樣
檢視service狀態
[root@master replicaset]# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3d9h <none>
webservice ClusterIP 10.102.99.133 <none> 88/TCP 13s app=myappnginx,release=stable
[root@master replicaset]# kubectl describe svc webservice
Name: webservice
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"webservice","namespace":"default"},"spec":{"ports":[{"port":88,"t...
Selector: app=myappnginx,release=stable
Type: ClusterIP
IP: 10.102.99.133
Port: <unset> 88/TCP
TargetPort: 80/TCP
Endpoints: 10.244.1.27:80,10.244.2.27:80
Session Affinity: None
Events: <none>
連線一個客戶端Pod進行測試
[root@master replicaset]# kubectl exec -it web-deploy-75bfb496f9-fm29g -- /bin/sh
/ # wget -O - webservice:88 #基於coredns進行解析的
Connecting to webservice:88 (10.102.99.133:88)
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
無頭service
無頭IP只能使用CluserIP型別就是沒有clusterip 而是將解析的IP 解析到後端的Pod之上
該服務不會分配Cluster IP,也不通過kube-proxy做反向代理和負載均衡。而是通過DNS提供穩定的網路ID來訪問,DNS會將headless service的後端直接解析為podIP列表。主要供StatefulSet使用
[root@master replicaset]# cat svc.yaml
apiVersion: v1
kind: Service
metadata:
name: webservice
namespace: default
spec:
selector:
app: myappnginx
release: stable
clusterIP: None 定義cluserIP為空
ports:
- port: 88
targetPort: 80
[root@master replicaset]# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3d10h <none>
webservice ClusterIP None <none> 88/TCP 7s app=myappnginx,release=stable
[root@master replicaset]# kubectl exec -it web-deploy-75bfb496f9-fm29g -- /bin/sh
/ # cat /etc/resolv.conf
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
/ # nslookup webservice
nslookup: can't resolve '(null)': Name does not resolve
Name: webservice
Address 1: 10.244.2.27 10-244-2-27.webservice.default.svc.cluster.local
Address 2: 10.244.1.27 web-deploy-75bfb496f9-fm29g
/ #
NodePort
[root@k8s-master01 daem]# cat deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: default
name: nginxapp
labels:
app: nginx-deploy
spec:
replicas: 2
selector:
matchLabels:
app: mynginx
template:
metadata:
labels:
app: mynginx
spec:
containers:
- name: nginxweb1
image: nginx:1.15-alpine
您在 /var/spool/mail/root 中有新郵件
[root@k8s-master01 daem]# cat svc.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
labels:
app: nginx-svc
spec:
ports:
- name: http
port: 80 #service暴露的埠,可以基於內部叢集訪問
protocol: TCP
nodePort: 30001 #node節點的對映埠 可以通過外部訪問
targetPort: 80
selector:
app: mynginx
sessionAffinity: None
type: NodePort
可以基於內部叢集訪問
[root@k8s-master01 daem]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 8d
nginx-svc NodePort 10.99.184.91 <none> 80:30001/TCP 5s
您在 /var/spool/mail/root 中有新郵件
[root@k8s-master01 daem]# curl 10.99.184.91
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
[root@k8s-master01 daem]#
外部瀏覽器訪問
sessionAffinity實現源地址session繫結
apiVersion: v1
kind: Service
metadata:
name: webservice
namespace: default
spec:
selector:
app: myappnginx
release: stable
sessionAffinity: ClientIP 將來自同意客戶端的請求排程到後端的同一個Pod上
type: NodePort
ports:
- port: 88
nodePort: 30001
targetPort: 80
直接通過Pod的IP地址和埠號可以訪問到容器應用內的服務,但是Pod的IP地址是不可靠的,例如當Pod所在的Node發生故障時,Pod將被Kubernetes重新排程到另一個Node,Pod的IP地址將發生變化。更重要的是,如果容器應用本身是分散式的部署方式,通過多個例項共同提供服務,就需要在這些例項的前端設定一個負載均衡器來實現請求的分發。Kubernetes中的Service就是用於解決這些問題的核心元件。