Kubernetes(五) - Service
Kubernetes解決的另外一個痛點就是服務發現,服務發現機制和容器開放訪問都是通過Service來實現的,把Deployment和Service關聯起來只需要Label標籤相同就可以關聯起來形成負載均衡,基於kuberneres的DNS服務我們只需要訪問Service的名字就能以負載的方式訪問到各個容器
Kubernetes官方文件: ofollow,noindex" target="_blank">https://kubernetes.io/docs/reference/
Kubernetes官方Git地址: https://github.com/kubernetes/kubernetes
PS:本系列中使用 KubernetesV1.8 RancherV1.6.14
1. Service的三種類型
Service有三種類型:
-
ClusterIP:預設型別,自動分配一個僅cluster內部可以訪問的虛擬IP 常用於內部程式互相的訪問,比如Gitlab需要訪問Redis的postgresql,但是是內部使用的不需要外部訪問,這個時候用ClusterIP就比較合適
-
NodePort:在ClusterIP基礎上為Service在每臺機器上繫結一個埠,這樣就可以通過<NodeIP>:NodePort來訪問改服務 當我們的Gitlab需要提供訪問,可以使用NodePort指定一個埠釋放服務,然後外層負載均衡對映就可以在外部訪問,或者直接訪問對應的埠
PS:NodePort方式暴露服務的埠的預設範圍(30000-32767)如果需要修改則在apiserver的啟動命令裡面新增如下引數 –service-node-port-range=1-65535
- LoadBalancer:在NodePort的基礎上,藉助cloud provider建立一個外部的負載均衡器,並將請求轉發到<NodeIP>:NodePort LoadBalancer是NodePort的升級版本,相當於和cloud provider結合不需要手動指定
我們經常使用的還是上面前兩種方式,我們先建立一個nginx-deployment映象2個Pod以便於接下來的使用
> vim nginx-deployment.yaml apiVersion: extensions/v1beta1 # K8S對應的API版本 kind: Deployment # 對應的型別 metadata: name: nginx-deployment labels: name: nginx-deployment spec: replicas: 2 # 映象副本數量 template: metadata: labels: # 容器的標籤 可和service關聯 app: nginx spec: containers: - name: nginx # 容器名和映象 image: nginx imagePullPolicy: Always > kubectl create -f nginx-deployment.yaml

我們分別修改一下對應的輸出
> echo nginx1 > /usr/share/nginx/html/index.html > echo nginx2 > /usr/share/nginx/html/index.html
安裝好ping 和 curl
> apt-get update > apt-get install curl iputils-ping
2. ClusterIP
> vim test-clusterip-service.yaml apiVersion: v1 kind: Service metadata: name: test-clusterip-service # 名稱 labels: name: test-clusterip-service spec: type: ClusterIP # 開發埠的型別 selector: # service負載的容器需要有同樣的labels app: nginx ports: - port: 80 # 通過service來訪問的埠 targetPort: 80 # 對應容器的埠 > kubectl create -f test-clusterip-service.yaml service "test-clusterip-service" created > kubectl get service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.43.0.1 <none> 443/TCP 12d test-clusterip-service ClusterIP 10.43.202.97 <none> 80/TCP 18s
應為selector關聯上了Deployment的Label所以直接訪問是可以訪問到的具體nginx映象內,而且應為是兩個Pod所以是負載均衡之前我們修改了輸出多次訪問可以看到不一樣的結果,基於Kube-DNS也可以使用Service名稱進行訪問
root@nginx-deployment-68fcbc9696-wbgxr:/usr/share/nginx/html# curl 10.43.202.97 nginx2 root@nginx-deployment-68fcbc9696-wbgxr:/usr/share/nginx/html# curl test-clusterip-service nginx1
3. NodePort
NodePort設計出來的主要目的就是對外部放出服務,也就是被外部能夠訪問到,
> vim test-nodeport-service.yaml apiVersion: v1 kind: Service metadata: name: test-nodeport-service # 名稱 labels: name: test-nodeport-service spec: type: NodePort # 開發埠的型別 selector: # service負載的容器需要有同樣的labels app: nginx ports: - port: 80 # 通過service來訪問的埠 targetPort: 80 # 對應容器的埠 nodePort: 30080 # 對應需要放到宿主機IP上的埠 > kubectl create -f test-nodeport-service.yaml service "test-nodeport-service" created > kubectl get service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.43.0.1 <none> 443/TCP 12d test-clusterip-service ClusterIP 10.43.202.97 <none> 80/TCP 14m test-nodeport-service NodePort 10.43.101.60 <none> 80:30080/TCP 5s
此時在宿主機上的30080埠就可以訪問到我們的兩個Nginx容器了,如果機器繫結的有IP的話就可以直接訪問或者在使用負載均衡對外放出服務
只有在KUbernetes中才會受到Kube-DNS的影響,在宿主機上無法使用test-nodeport-service訪問Service只能通過NodePort進行訪問
[root@k8s-m ~]# curl 127.0.0.1:30080 nginx2 [root@k8s-m ~]# curl 127.0.0.1:30080 nginx1
4. Ingress
Service主要是處理4層TCP負載,但是往往對外需要放出HTTP七層協議的服務,一般我們在一套叢集下如果有多個HTTP服務會使用Nginx來統一接受80埠的資料然後通過域名或者是訪問路徑來選擇不同的服務,Ingress就是解決這個問題誕生的,Ingress可以和Service結合對80埠的訪問更具域名的過濾和訪問路徑的過濾路由到對應的service,我們一起看幾個例子:
foo.bar.com -> 172.168.0.128 -> / foo nginx:80 / bar nginx:80
> vim ing.yaml apiVersion: extensions/v1beta1 kind: Ingress metadata: name: test annotations: nginx.ingress.kubernetes.io/rewrite-target: / spec: rules: - host: foo.bar.com http: paths: - path: /foo backend: serviceName: nginx servicePort: 80 - path: /bar backend: serviceName: nginx servicePort: 80 > kubectl create -f ing.yaml > kubectl get ing NAME RULE BACKEND ADDRESS test - foo.bar.com /foo nginx:80 /bar nginx:80
foo.bar.com --| |-> foo.bar.com nginx:80 | 172.168.0.128 | bar.foo.com --| |-> bar.foo.com nginx:80
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: test spec: rules: - host: foo.bar.com http: paths: - backend: serviceName: nginx servicePort: 80 - host: bar.foo.com http: paths: - backend: serviceName: nginx servicePort: 80
支援TLS需要使用Secret預先配置好對應的證書
apiVersion: v1 data: tls.crt: base64 encoded cert tls.key: base64 encoded key kind: Secret metadata: name: testsecret namespace: default type: Opaque
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: no-rules-map spec: tls: - secretName: testsecret backend: serviceName: nginx servicePort: 80
使用Ingress能實現部分功能,但是筆者推薦使用閘道器服務(比如kong)來進行處理會更具靈活功能更下強大可控
小技巧
- 跨namespace訪問Service 到這裡我們還沒有展開說NameSpace,NameSpace隔離了資源,比如你在A中不能建立兩個名字一樣的Service(Kubernetes其他資源同理),但是創建出一個NameSpace的是可以建立名字為Nginx的Service的 這個時候你在A空間中訪問nginx-service的是A空間的容器,在B空間訪問是B空間的nginx-service 但是如果需要在B空間訪問A空間的Nginx-service要怎麼辦呢?
Kube提供在訪問Service的時候末尾增加NameSpace名字進行訪問,在B空間訪問A的nginx-service可以使用nginx-service.A 進行訪問
本文轉自開源中國- Kubernetes(五) - Service