前言
在談kubernetes的service之前,小編向帶大家複習一下負載均衡的概念,那麼何爲負載均衡呢,小編舉一個簡單的例子,能力相同的兩個人同時進入一家公司,一個人天天加班到深夜,另一個人則天天優哉遊哉到點下班,但兩個人的工資一樣,此時那個埋頭苦幹的人就會抱怨了,憑什麼我天天累死累活,這不公平!相對於機器而言也是一樣的,一臺機器一直幹活,另一臺機器一直空閒,總有一臺幹活的機器會罷工的!那麼如何解決這個問題呢?小編這裏舉一個web集羣的例子:
客戶端訪問一個虛擬的IP,通過這個虛擬的IP將請求發送給nginx的負載(主),此時主負載將接受的請求拋給後端的web服務做真正的處理,這裏的負載可以是輪詢也可以是根據集羣的資源,指定發送到某臺web服務器上。那有些讀者就想問了,如何設置這個虛擬的IP,又怎麼知道負載什麼時候會宕機,負載又如何發現後端的web服務器的,如何獲取集羣資源,精確計算出哪一臺web服務比較空閒等等,這一些列的問題,不要着急,小編接下來根據kubernetes的service將這其中的原理一一道來。
希望一篇文章就能寫完,此時絕不說廢話了,拜託拜託。
(1) service的定義和基本使用
service是kubernetes最核心的概念,通過創建service,可以爲一組具有相同功能的容器應用提供一個統一的入口地址,並且將請求負載發送到後端的各個容器應用上。
1) service的定義
apiVersion: v1
kind: Service
metadata: #元數據
name: string #service的名稱
namespace: string #service所屬的命名空間
labels: #service的標籤
- name: string
annotations: #service的註解
- name: string
spec:
selector: [] #label選擇器,將選擇具有指定label標籤的pod作爲管理範圍
type: string #Service的類型 [clusterIP|NodePort|LoadBalancer]
clusterIP: string #虛擬服務IP地址
sessionAffinity: string #是否支持session [ClientIP|None] 表示將同一個客戶端的訪問請求都轉發到同一個後端
ports: #service需要暴露的端口
- name: string #端口名稱,區分不同的應用的端口
protocol: string #使用的協議
prot: int #service監聽的端口
targetPort: int #發送到後端的應用的端口
nodePort: int #當spec.type=NodePort時,指定映射到物理機的端口
status: #當spec.type=LoadBalancer時,設置外部負載均衡器的地址
loadBalancer:
ingress:
ip: string #外部負載的IP
hostname: string #外部負載均衡的主機名
2) service的基本使用
這小編以三個案例介紹:
- 入門案例(RC+service)
- 多端口service
- 外部服務service
① 簡單案例(RC+service)
#webapp-rc.yaml
apiVersion: v1
kind: ReplicationController
metadata:
name: webapp
spec:
replicas: 2
template:
metadata:
name: webapp
labels:
app: webapp
spec:
containers:
- name: webapp
image: docker.io/tomcat
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
[root@zy yaml_file]# kubectl create -f webapp-rc.yaml #創建
[root@zy yaml_file]# kubectl get pods -l app=webapp -o yaml|grep podIP #查看pod的IP
[root@zy yaml_file]# curl 172.17.0.5:8080 #訪問
#創建service管理pod
[root@zy yaml_file]# kubectl expose rc webapp
或者 yaml文件
#webapp-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: webapp
spec:
ports:
- port: 8081
targetPort: 8080
selector:
app: webapp
[root@zy yaml_file]# kubectl get svc #查看創建的service的IP
[root@zy yaml_file]# curl 10.254.90.131:8081 #通過serviceIP訪問pod中的應用
② 多端口service
有時候一個容器應用也可能提供多個端口的服務,那麼在service的定義中也可以相應地設置爲將多個端口對應到多個應用中,有點類似於Apache的虛擬主機中的基於端口配置。
apiVersion: v1
kind: Service
metadata:
name: webapp
spec:
ports:
- port: 8081
targetPort: 8080
name: web
- port: 8005
targetPort: 8005
name: management
selector:
app: webapp
③ 外部服務service
在某些環境中,應用系統需要將一個外部數據庫作爲後端服務進行連接,或將另一個集羣或者namespace中的服務作爲服務的後端,這時可以通過創建一個無label selector的service來實現:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
ports:
- protocol: TCP
port: 33060
targetPort: 3306
因爲定義一個沒有selector的service,系統不會自動創建endpoint,需要手動定義,創建一個與service同名的endpoint,用於指向實際後端訪問地址。
#endpoint
kind: EndPoints
apiVersion: v1
metadata:
name: my-service #與service相同
subsets:
- addresses:
- IP: xxx.xxx.xxx.xxx
ports:
- port: 3306
此時:
這個service綁定的EndPoint就會連接外部的172.0.1.16:3306的服務,內部訪問這個service時,路由就會轉發到cluster B 的相應的服務中。
通過上面的三個案例是不是對service有了初步的瞭解呢,小編在這裏給大家總結一下,service的好處:
由於pod被RC或者deploy管理,pod重啓之後,pod的IP地址是改變的,如果使用podIP去訪問後端的應用,每次都要查IP,但是有了service,service的虛擬IP是固定的,我們只要訪問service的IP,至於service如何發現後端的重啓的Pod,我們不需要關係
Service的負載作用,如果一個service管理多個pod,而這多個pod提供的是相同的服務,那麼service自身也實現了負載:
RoundRobin(輪詢):將請求發送到後端的各個pod上
SessionAffinity:基於客戶端IP地址進行會話,如果SessionAffinity=ClientIP時,同一個客戶端發送請求,會被轉發到後端相同的pod中。
(2) Headless Service
在某些場景中,我們希望自己控制負載均衡的策略,不使用service提供的默認的負載,或者應用程序希望知道屬於同組服務的其他實例。Kubernetes提供了Headless Service來實現這個功能,即不爲service設置clusterIP,僅通過label selector將後端的pod列表返回給調用的客戶端:
apiVersion: v1
kind: Service
metadata:
labels:
name: cassandra
name: cassandra
spec:
ports:
- port: 9042
ClusterIP: None
selector:
name: cassandra
這樣service就不在具有一個特定的clusterIP,對其進行訪問將獲得包含label“name: cassandra”的全部pod列表,然後客戶端程序自行決定如何處理這個pod列表。
對於去中心化類的應用集羣,headless Service將非常有用。接下來我們通過搭建一個Cassandra集羣來看看headless Service巧妙的使用,自動實現應用集羣的創建。
通過對headless Service的使用,實現了Cassandra各節點之間的相互查找和集羣的自動搭建。
開始搭建:
#單個pod Cassandra節點: Cassandra-pod.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
name: cassandra
name: cassandra
spec:
containers:
- args:
- /run.sh
resources:
limits:
cpu: "0.5"
image: docker.io/shenshouer/cassandra:v5
imagePullPolicy: IfNotPresent
name: cassandra
ports:
- name: cql
containerPort: 9042
- name: thrift
containerPort: 9160
volumeMounts:
- name: data
mountPath: /cassandra_data
env:
- name: MAX_HEAP_SIZE
value: 512M
- name: HEAP_NEWSIZE
value: 100M
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
volumes:
- name: data
#cassandra-svc.yaml
apiVersion: v1
kind: Service
metadata:
labels:
name: cassandra
name: cassandra
spec:
ports:
- port: 9042
selector:
name: cassandra
#cassandra-rc.yaml
apiVersion: v1
kind: ReplicationController
metadata:
labels:
name: cassandra
name: cassandra
spec:
replicas: 1
selector:
name: cassandra
template:
metadata:
labels:
name: cassandra
spec:
containers:
- command:
- /run.sh
resources:
limits:
cpu: 0.5
env:
- name: MAX_HEAP_SIZE
value: 512M
- name: HEAP_NEWSIZE
value: 100M
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: docker.io/shenshouer/cassandra:v5
imagePullPolicy: IfNotPresent
name: cassandra
ports:
- containerPort: 9042
name: cql
- containerPort: 9160
name: thrift
volumeMounts:
- mountPath: /cassandra_data
name: data
volumes:
- name: data
emptyDir: {}
#依次執行一下命令
[root@zy yaml_file]# kubectl create -f cassandra-pod.yaml
[root@zy yaml_file]# kubectl create -f cassandra-svc.yaml
[root@zy yaml_file]# kubectl create -f cassandra-rc.yaml
#此時我們查看pod
[root@zy yaml_file]# kubectl get rc #查看RC
[root@zy yaml_file]# kubectl scale rc cassandra --replicas=2 #副本擴容到2個
[root@zy yaml_file]# kubectl exec -ti cassandra -- nodetool status #查看Cassandra Pod中運行nodetool
看見以上的頁面,表示擴容的pod已經成功加入到Cassandra集羣中。
原理解釋:因爲service是headless Service,他會返回selector中的所有的pod,一開始集羣中只有一個pod,所以返回一個,讓集羣中的pod變成多個時,他會將所有的pod都返回,那麼Cassandra是如何處理這新的pod呢?Cassandra鏡像它還給Cassandra添加一個定製的SeedProvider,在Cassandra中, SeedProvider設置一個gossip協議用來發現其它Cassandra節點。KubernetesSeedProvider使用內置的Kubernetes發現服務找到KubernetesAPI服務器,然後利用Kubernetes API發現新的節點。就這樣headless Service將selector選擇中的所有的endpoint,都發送給Cassandra集羣,Cassandra集羣根據SeedProvider,利用內置的Kubernetes發現服務找到KubernetesAPI服務器,然後利用Kubernetes API發現新的節點,並加入到集羣。
參考文檔:https://www.kubernetes.org.cn/doc-36
(3) 集羣外部訪問pod或者service
由於pod和service是kubernetes集羣範圍內的虛擬的概念,所有集羣外部的客戶端無法訪通過Pod的IP或者service的IP去訪問到它們。爲了讓外部的客戶端可以訪問這些服務,kubernetes提供了將Pod或者service的端口號映射到物理機上,以使得客戶端訪問宿主機的端口從而訪問到其容器中的服務。
案例1(①通過設置容器基本的hostPort,將容器應用的端口映射到物理機上)
#pod-hostport.yaml
apiVersion: v1
kind: Pod
metadata:
name: webapp
labels:
app: webapp
spec:
containers:
- name: webapp
image: docker.io/tomcat
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
hostPort: 8070
#創建之後,訪問宿主機的8070端口
[root@zy yaml_file]# curl 192.168.130.130:8070
訪問瀏覽器:http://192.168.130.130:8070/
案例2:(使用spec.hostNetWork參數定義)
通過設置pod級別的hostNetWork=true,該Pod中所有容器的端口號都將被直接映射到物理機上,但是需要注意的是,在容器的ports定義中,如果不指定hostPort,則默認爲containerPort,如果指定了hostPort,則hostPort必須等於containerPort的值。
apiVersion: v1
kind: Pod
metadata:
name: webapp
labels:
app: webapp
spec:
hostNetwork: true
containers:
- name: webapp
image: docker.io/tomcat
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
案例3(將service的端口號映射到物理機中)
#webapp-nodePort-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: webapp
spec:
type: NodePort
ports:
- port: 8080
targetPort: 8080
nodePort: 30000
selector:
app: webapp
該service將監聽8080端口,併發送到後端selector選擇的endpoint的8080端口,對宿主機暴露的端口爲30000
[root@zy yaml_file]# curl 192.168.130.130:30000 #訪問
案例4
通過設置LoadBalancer映射到雲服務商提供的LoadBalancer地址,LoadBalancer在NodePort基礎上,K8S可以請求底層雲平臺創建一個負載均衡器,將每個Node作爲後端,進行服務分發。該模式需要底層雲平臺(例如GCE)支持。
小編這裏以一個yaml爲例:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
nodePort: 30061
clusterIP: 10.0.171.12
loadBalancerIP: 78.11.42.19
type: loadBalancer
status:
loadBalancer:
ingress:
- ip: 146.147.12.155 #這個是雲服務商提供的負載IP
(4) DNS服務搭建
這裏大家要注意了,這一節非常的重要,希望大家一定細細閱讀,以後在分析kubernetes核心時這一節是重中之重的基礎。
Kubernetes的服務發現一共有兩種方式,1.通過環境變量的方式,2.通過集羣範圍內的DNS來完成服務名到clusterIP的解析。這裏小編帶大家瞭解一下如何搭建DNS服務。
1) kubernetes DNS服務的總體架構介紹
Kubernetes提供的虛擬DNS服務名爲ksydns,由4個組件組成:
etcd:DNS存儲
kube2sky:將kubernetes master中的service註冊到etcd
skyDNS:提供DNS域名解析服務
healthz:提供skydns服務的健康檢查功能
2) DNS服務搭建
① 編寫配置文件
② 修改每臺node上的kubelet啓動參數
③ 創建相應的資源對象
④ 測試
這裏小編就不一一介紹了,給出搭建的地址:https://www.cnblogs.com/yujinyu/p/6112233.html
3) DNS服務的工作原理
Kube2sky容器因供應用通過kubernetes master的API獲取集羣所有的service信息,並持續監控新service的生成,然後寫入etcd中:
通過命令查看etcd中存儲的service信息:
[root@zy ~]#kubectl exec kube-dns-v2-dc1s -c etcd --namespace=kube-system etcdctl ls /skydns/local/cluster/
此時看見目錄結果如下:
/skydns/local/cluster/default
/skydns/local/cluster/kube-system
/skydns/local/cluster/svc
可以看見在skydns下是我們配置的cluster.local(域名後綴),之後是命名空間,svc下也通過命名空間生成子目錄。
然後查看具體的內容:
[root@zy ~]# kubectl exec kube-dns-v2-dc1s -c etcd --namespace=kube-system etcdctl get /skydns/local/cluster/default/服務名 #這樣就能看見相應的clusterIP和域名映射
然後根據kubectl啓動參數的設置(--cluster_dns),kubelet 會在每一個新創建的pod中設置DNS域名解析,配置文件爲:/etc/resolv.conf文件,會在其中加入一條,nameserver和search配置:
nameserver DNS解析服務IP
search default.svc.cluster.local svc.cluster.local cluster.local localdomain
有了這些配置,應用程序就能夠想訪問網站域名一樣,通過服務的名稱訪問到服務。總的來說就是,kube2sky 通過kubernetes master的API 將新增的service持續存儲到etcd中,每一個新增的pod都會有一個/etc/resolv.conf文件,我們在通過服務名稱訪問服務時,通過skyDNS 查詢etcd,獲取服務的IP,然後通過服務的IP就能直接訪問到服務後端的endpoint中的容器中的應用。
(5) 自定義DNS和上游DNS服務
從kubernetes1.6開始,用戶可以在kubernetes集羣內部配置私有的DNS區域和外部的上游域名服務,在kubernetes的pod定義中支持兩個DNS策略,Default和ClusterFirst,dnsPolicy默認是ClusterFirst,如果是Default,域名解析配置則完全從Pod的節點的/etc/resolv.conf中繼承下來。
如果dnsPolicy設置的是ClusterFirst,則DNS查詢會被髮送到kube-dns(skydns)服務。kube-dns服務負責以集羣域名爲後綴(例cluster.local)進行服務的域名解析。
那麼自定義的DNS和上游DNS又是啥呢?
由上圖所示,當dnsPolicy設置爲ClusterFirst時,DNS首先會被髮送到kube-dns的緩存層,從這裏檢查域名的後綴,如果是cluster.local,則被髮送到kube-dns服務,如果是自定義的*.out.of.kubernetes,則被髮送到自定義解析器,如果兩者均不符合,則被髮送到上游的DNS中進行解析。
域名解析順序:kube-dns ------ > 自定義DNS -------- > 上游DNS
自定義DNS方式:
從kubernetes1.6開始,集羣管理者可以使用configMap指定自定義的存根域和上游的DNS Server。
① 安裝dnsmasq作爲自定義的DNS服務
#安裝
[root@zy ~]# yum install -y dnsmasq
#生成一個自定義的DNS記錄文件 /tmp/hosts
[root@zy ~]# echo "192.168.130.131 server.out-of.kubernetes" > /tmp/hosts
#啓動DNS服務
[root@zy ~]# dnsmasq -q -d -h -q -R -H /tmp/hosts
#參數解釋:
-d:以debug模式啓動,在前臺運行,便於觀察日誌
-q:輸出查詢記錄
-h:不使用/etc/hosts
-R:不使用/etc/resolve.conf
-H:使用自定義的文件作爲DNS記錄
② 創建自定義DNS的configMap
#dns-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: kube-dns
namespace: kube-system
data:
stubDomains: |
{"out-of.kubernetes" : ["192.168.130.130"] } #自定義DNS服務器地址
upstreamNameservers: | #上游DNS地址
["8.8.8.8","8.8.4.4"]
注意:
stubDomains:表示存根域名,自定義DNS就在這裏配置,Key是DNS後綴,value是一組DNS服務IP
upstreamNameservers:表示上游DNS配置,如果指定了,那麼從節點/etc/resovl.conf就會被覆蓋。最多指定3個IP。
[root@zy ~]# kubectl create -f dns-configmap.yaml
③ 測試
apiVersion: v1
kind: Pod
metadata:
name: tester
spec:
dnsPolicy: ClusterFirst
containers:
- name: busybox
image: docker.io/busybox
imagePullPolicy: IfNotPresent
command: ["sleep"]
args: ["3600"]
創建一個pod,然後進入其中
[root@zy yaml_file]# kubectl exec -it tester – sh
/ # ping server.out-of.kubernetes
此時就會在dnsmasq的輸出日誌中,看見,server.out-of.kubernetes被轉發到自定義DNS服務:192.168.130.130,然後通過DNS服務器,根據/tmp/hosts域名和IP的映射找到192.168.130.131。
(6) Ingress:HTTP 7層路由機制
1) Ingerss原理:
Ingerss產生的原因:我們知道pod被deployment/RC管理的時候,pod重啓之後其IP可能會改變,爲了能準確的訪問到pod中的服務,kubernetes使用service,而service會在宿主機上提供一個端口用於客戶端訪問,但是如果service很多的話其維護成本就會很高。如果可以藉助於nginx的類似於虛擬主機的方式,通過不同的URL能夠訪問到後端的不同service,那麼就少了service對宿主機的大量的端口映射,如何能做到這樣呢?kubernetes1.1開始,新增了一個Ingress的資源對象,用於解決上述問題。
Ingerss介紹:Ingress 包含兩大組件:Ingress Controller 和 Ingress。
原理圖:
Ingress Controller作用:由於我們是使用nginx的方式實現,那麼每一次有新的service或者新的Ingress規則時,就要修改一次nginx.conf文件,這樣實在太麻煩,所以Ingress Controller 就是專門解決這個問題,通過與 Kubernetes API 交互,動態的去感知集羣中 Ingress 規則變化,然後讀取他,按照他自己模板生成一段 Nginx 配置,再寫到 Nginx Pod 裏,最後 reload 一下。
Ingress Controller-service:爲了讓Ingress Controller可以對外提供服務,這裏需要一個service,而service監聽的端口就是80(http)|443(https)上圖所示,該service映射到物理機的端口是30080和30443。
通過Ingress訪問後端應用服務的過程(以web服務爲例):首先定義一個deployment維持三個web服務的副本,然後給其web服務定義一個名爲myapp的service,此時編寫Ingress的規則通過host:myapp.zzy.com,並綁定了名爲myapp的service,即當客戶端訪問myapp.zzy.com:30080時,會被轉發到Ingress Controller-service的80端口上,根據Ingress Controller更新的Ingress規則,會將請求轉發到
myapp:80,然後就能直接訪問後端的pod中的容器,最後容器將請求響應會客戶端。
注意:Ingress Controller將基於Ingress規則將客戶端請求直接轉發到service對應的後端的endpoint。
2) Ingress的定義策略:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: mywebsite-ingress
spec:
rules:
- host: mywebsite.com
http:
paths:
- path: /demo
backend:
serviceName: webapp
servicePort: 8080
• rules:用於定義當前Ingress資源的轉發規則列表;由rules定義規則,或沒有匹配到規則時,所有的流量會轉發到由backend定義的默認後端。
• backend:默認的後端用於服務那些沒有匹配到任何規則的請求;定義Ingress資源時,必須要定義backend或rules兩者之一,該字段用於讓負載均衡器指定一個全局默認的後端。backend對象的定義由2個必要的字段組成:serviceName和servicePort,分別用於指定流量轉發的後端目標Service資源名稱和端口。
• host:包含 於 使用 的 TLS 證書 之內 的 主機 名稱 字符串 列表
3) Ingress的部署:
部署步驟:
- 安裝部署ingress controller Pod
- 部署後端服務
- 部署ingress-nginx service
- 編寫ingress規則
部署方法小編已經在下面給出:自己動手也是成長的一部分嘛!
小編也從網上了找了許多的ingress 部署博客,好像基本上都是wget一些yaml文件,但是給出的地址好像都不能訪問了,所以還是老老實實的看文檔搭建吧,加油加油!
https://github.com/kubernetes/ingress-nginx/blob/master/docs/deploy/index.md
4) Ingress常見配置策略:
① 轉發到單個後端服務上
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-ingress
spec:
backend:
serviceName: myweb
servicePort: 8080
上面的配置對Ingress Controller的訪問請求都將被轉發到“myweb:8080”這個服務上。
② 同一域名下,不同的URL路徑被轉發到不同的服務上
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-ingress
spec:
rules:
- host: mywebsite.com
http:
paths:
- path: /web
backend:
serviceName: web-service
servicePort: 80
- path: /api
backend:
serviceName: api-service
servicePort: 8081
以上配置當訪問:
mywebsite.com/web:80 ------轉發到------ web-service:80
mywebsite.com/api:80 ------轉發到------ api-service:8081
③ 不同域名被轉發到不同的服務
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test
spec:
rules:
- host: foo.bar.com
http:
paths:
- backend:
serviceName: service1
servicePort: 80
- host:bar.foo.com
http:
paths:
- backend:
serviceName: service2
servicePort: 80
訪問foo.bar.com-- service1:80 訪問bar.foo.com -- service2:80
④ 不使用域名的轉發規則
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-ingress
spec:
rules:
- http:
paths:
- path: /demo
backend:
serviceName: webapp
servicePort: 8080
這種配置,通過任意一條運行的ingress-controller 的node都能訪問到後端的服務。
注意:這種方式默認是不能使用https訪問的,如果想使用https訪問,需要在編寫Ingress規則的時候,加入一個annotation ”ingress.kubernetes.io/ssl-redirect=false” 來關閉強制啓用HTTPS的設置。
錯誤解決
1 .搭建Cassandra問題
由於小編之前用的是單機版的kubernetes集羣,之前遇到過一些問題導致pod無法啓動,然後就修改了apiservice的配置:
就將這個兩個配置刪除了。
然後創建Cassandra 的pod的時候就報錯:
然後查看:[root@zy yaml_file]# kubectl get serviceaccount
解決:
在/etc/kubernetes/apiserver 中的--admission_control加入ServiceAccount:
然後在/etc/kubernetes/controller-manager配置:
--service_account_private_key_file=/var/run/kubernetes/apiserver.key
之後重啓這兩個服務:
再執行命令
[root@zy yaml_file]# kubectl get serviceaccount
小編本來以爲這樣問題就解決了,結果查詢Cassandra 的pod的日誌發現:
小編初步推斷可能是集羣沒有搭建DNS:因爲在查看SeedProvider 源碼時:
後期會慢慢排查,將問題解決!
2. 外部集羣不能通過service訪問其對應的服務
在service暴露端口時,發現外部訪問時,之後 可以使用IP訪問,其他主機或者瀏覽器訪問不到Kubernetes是1.5.2版本,這裏小編設置了service的type爲NodePort,並且nodePort設置了一個值,最終pod和service都啓動正常,使用clusterIP和本機IP都可以訪問,但是外部集羣無法訪問。
原因:
使用service+NodePort時,其中的網絡是上圖所示,客戶端訪問時,需要通過kube-proxy這個服務,但是在1.2以上這個kube-proxy服務在啓動時需要添加參數:
把KUBE_PROXY_ARGS=”“改爲KUBE_PROXY_ARGS=”–proxy-mode=userspace”
解決:
修改master的/etc/kubernetes/proxy
將其中的啓動命令的參數添加:
KUBE_PROXY_ARGS="--proxy-mode=userspace"
重啓kube-proxy服務:
[root@zy yaml_file]# systemctl restart kube-proxy
然後在啓動相應的pod和service,之後瀏覽器訪問:
http://192.168.130.130:30000/
OK:
或者:
在默認的iptables mode下,修改(vim /etc/sysctl.conf)文件,加入:net.ipv4.ip_forward=1重啓主機,然後在通過service訪問即可。
到這裏可能大家還是不太明白爲什麼service不能外部訪問,需要修改kube-proxy的配置,這裏小編就給大家介紹一下kube-proxy與service的關係:
kube-proxy其實就是管理service的訪問入口,包括集羣內Pod到Service的訪問和集羣外訪問service。kube-proxy管理sevice的Endpoints,該service對外暴露一個Virtual IP,也成爲Cluster IP, 集羣內通過訪問這個Cluster IP:Port就能訪問到集羣內對應的serivce下的Pod。service是通過Selector選擇的一組Pods的服務抽象,其實就是一個微服務,提供了服務的LB和反向代理的能力,而kube-proxy的主要作用就是負責service的實現。
而kube-proxy內部原理:kube-proxy當前實現了兩種proxyMode:userspace和iptables。其中userspace mode是v1.0及之前版本的默認模式,從v1.1版本中開始增加了iptables mode,在v1.2版本中正式替代userspace模式成爲默認模式。小編的集羣是1.5.2的默認的是iptables,所以需要做一些配置,因此我們改爲了userspace,就可以讓外部通過service暴露的端口映射到宿主機上來訪問服務啦。
Userspace:userspace是在用戶空間,通過kube-proxy來實現service的代理服務。
Iptables:它完全利用Linux內核iptables來實現service的代理和LB