kubernetes之service深入(四)

前言

  在談kubernetes的service之前,小編向帶大家複習一下負載均衡的概念,那麼何爲負載均衡呢,小編舉一個簡單的例子,能力相同的兩個人同時進入一家公司,一個人天天加班到深夜,另一個人則天天優哉遊哉到點下班,但兩個人的工資一樣,此時那個埋頭苦幹的人就會抱怨了,憑什麼我天天累死累活,這不公平!相對於機器而言也是一樣的,一臺機器一直幹活,另一臺機器一直空閒,總有一臺幹活的機器會罷工的!那麼如何解決這個問題呢?小編這裏舉一個web集羣的例子:
kubernetes之service深入(四)
  客戶端訪問一個虛擬的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 #創建
kubernetes之service深入(四)

[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 #訪問
kubernetes之service深入(四)

#創建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

kubernetes之service深入(四)

[root@zy yaml_file]# curl  10.254.90.131:8081 #通過serviceIP訪問pod中的應用

kubernetes之service深入(四)
② 多端口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 

此時:
kubernetes之service深入(四)
這個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
kubernetes之service深入(四)

[root@zy yaml_file]# kubectl get rc #查看RC

kubernetes之service深入(四)

[root@zy yaml_file]# kubectl scale rc cassandra --replicas=2 #副本擴容到2個

kubernetes之service深入(四)

[root@zy yaml_file]# kubectl exec -ti cassandra -- nodetool status #查看Cassandra Pod中運行nodetool

kubernetes之service深入(四)
看見以上的頁面,表示擴容的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發現新的節點,並加入到集羣。
kubernetes之service深入(四)
參考文檔: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 

kubernetes之service深入(四)
訪問瀏覽器:http://192.168.130.130:8070/
kubernetes之service深入(四)
案例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 #訪問

kubernetes之service深入(四)
案例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服務的健康檢查功能
kubernetes之service深入(四)

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又是啥呢?
kubernetes之service深入(四)
  由上圖所示,當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記錄

kubernetes之service深入(四)
② 創建自定義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。
原理圖:
kubernetes之service深入(四)
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個必要的字段組成:serviceNameservicePort,分別用於指定流量轉發的後端目標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的配置:
kubernetes之service深入(四)
就將這個兩個配置刪除了。
然後創建Cassandra 的pod的時候就報錯:
kubernetes之service深入(四)
然後查看:[root@zy yaml_file]# kubectl get serviceaccount
kubernetes之service深入(四)
解決:
在/etc/kubernetes/apiserver 中的--admission_control加入ServiceAccount:
kubernetes之service深入(四)
然後在/etc/kubernetes/controller-manager配置:
--service_account_private_key_file=/var/run/kubernetes/apiserver.key
kubernetes之service深入(四)
之後重啓這兩個服務:
再執行命令

[root@zy yaml_file]# kubectl get serviceaccount

kubernetes之service深入(四)
小編本來以爲這樣問題就解決了,結果查詢Cassandra 的pod的日誌發現:
kubernetes之service深入(四)
小編初步推斷可能是集羣沒有搭建DNS:因爲在查看SeedProvider 源碼時:
kubernetes之service深入(四)
後期會慢慢排查,將問題解決!

2. 外部集羣不能通過service訪問其對應的服務

  在service暴露端口時,發現外部訪問時,之後 可以使用IP訪問,其他主機或者瀏覽器訪問不到Kubernetes是1.5.2版本,這裏小編設置了service的type爲NodePort,並且nodePort設置了一個值,最終pod和service都啓動正常,使用clusterIP和本機IP都可以訪問,但是外部集羣無法訪問。
原因
kubernetes之service深入(四)
使用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"
kubernetes之service深入(四)
重啓kube-proxy服務:

[root@zy yaml_file]# systemctl restart kube-proxy

然後在啓動相應的pod和service,之後瀏覽器訪問:
http://192.168.130.130:30000/
OK:
kubernetes之service深入(四)
或者:
在默認的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的代理服務。
kubernetes之service深入(四)
Iptables:它完全利用Linux內核iptables來實現service的代理和LB
kubernetes之service深入(四)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章