首頁>技術>

同一網路下的不同pod間是怎麼通訊的?同一個pod中不同的容器是怎麼通訊的?不同的網路下不同的pod是怎麼通訊的?一、同一網路下的不同pod間通訊

第一種場景可能是應用最多的場景,比如我寫了一個web應用,它使用python作為後端,使用redis作為資料庫,redis和python分別建立在不同的pod裡,我會使用deployment建立rs的方式再建立pod,正常情況下,我們是不希望這個redis被外面的應用訪問到的,只允許在python的應用訪問到,

如上圖,使用者可以使用python應用暴露出來的6000埠(其實是k8s裡的service暴露出來的)來訪問應用,但是並不能直接訪問裡面redis的6379埠。

1.1 建立redis pod

我們先建立一個redis pod

apiVersion: apps/v1kind: Deploymentmetadata:  labels:   app: redis  name: redis-masterspec:  selector:   matchLabels:    app: redis  replicas: 1  template:   metadata:    labels:     app: redis   spec:    containers:    - image: redis     name: redis-master2     ports:     - containerPort: 6379

檢視pod詳細資訊

# kubectl create -f r-deployment.yamldeployment.apps/redis-master createdkubectl get pods -o wideNAME               READY  STATUS   RESTARTS  AGE  IP      NODE       NOMINATED NODE  READINESS GATESredis-master-7f88b489b9-k4c58  1/1   Running  0      27s  10.1.0.59  docker-desktop  <none>      <none>​
1.2 建立python應用

我先使用docker run 本地啟一個redis用於程式碼除錯,為了和上面啟的redis pod 區分(其實也不用區分,上面的redis pod 本身也沒有對外暴露埠),這裡使用6380作為對外埠

docker run --name myredistest -d -p 6380:6379 redis

之後就可以使用redis客戶端進行訪問了,我在db1中建立了一個redistest的key

寫一個python應用,讀取redis中的資料

#-*- coding:utf-8 -*-# author:Yang# datetime:2020/2/10 16:07# software: PyCharm​from flask import Flaskfrom flask_redis import FlaskRedisimport time​REDIS_URL = "redis://{}:{}/{}".format('127.0.0.1', 6380, 1)​​app = Flask(__name__)app.config['REDIS_URL'] = REDIS_URLredis_client = FlaskRedis(app)​@app.route("/")def index_handle():  redis_client.set("reidstest",time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(time.time())))  name = redis_client.get("reidstest").decode()  return "hello %s"% name​app.run(host='0.0.0.0', port=6000, debug=True)​

之後用瀏覽器訪問127.0.0.1:6000 就可以得到正常的輸出了

1.3 在pod中訪問redis

上面只是將python訪問本地的redis,我們最終是要將這個python應用打包成映象,放到k8s中,那麼如果在k8s中這個flask應用該如果訪問到redis呢?

為了實現一套程式碼可以在不同的環境中執行,我在redis的初始化時加上一點判斷

現在主要的問題在於,REDIS_URL = "redis://{}:{}/{}".format('redisIP', "redispord", 1) k8s中的redisIP和redispord這裡該填寫什麼呢?

上面使用kubectl get pods -o wide 檢視到redis的ip為10.1.0.59 ,那麼我們試試能不能通過這個IP和埠來訪問redis呢?

先建立一個Dockerfile

建立映象

docker build -t flaskk8s .

之後就可以在本地檢視到映象 falskk8s,使用這個k8s建立pod,建立flask-deployment.yaml

apiVersion: apps/v1kind: Deploymentmetadata:  labels:   app: flasktest  name: flasktestspec:  selector:   matchLabels:    app: flasktest  replicas: 1  template:   metadata:    labels:     app: flasktest   spec:    containers:    - image: flaskk8s     name: flaskweb     imagePullPolicy: Never     ports:     - containerPort: 6000

因為是本地的映象,所以在加上imagePullPolicy: Never ,否則k8s預設是會從dockerhub上去拉取。

# kubectl get podNAME               READY  STATUS   RESTARTS  AGEflasktest-68cfdcc66d-d2tb7   1/1   Running  0      7sredis-master-7f88b489b9-k4c58  1/1   Running  0      126m# kubectl get deploymentNAME      READY  UP-TO-DATE  AVAILABLE  AGEflasktest   1/1   1      1      44sredis-master  1/1   1      1      127m​

建立flasktest的service,讓其可以通過瀏覽器訪問

apiVersion: v1kind: Servicemetadata:  name: flask-service  labels:   name: flaskservicespec:  type: NodePort  ports:  - port: 6000   nodePort: 30002  selector:   app: flasktest
# kubectl get serviceNAME        TYPE     CLUSTER-IP    EXTERNAL-IP  PORT(S)      AGEflask-service   NodePort  10.97.54.167   <none>    6000:30002/TCP  15skubernetes     ClusterIP  10.96.0.1    <none>    443/TCP      3d5hredis-master-sr  ClusterIP  10.99.187.220  <none>    6379/TCP     79m

可以看到30002埠已經被暴露出來,之後我們訪問http://127.0.0.1:30002/ ,看到可以正常的訪問

一切看著都很順利對不對,但是我們來考慮兩個問題

如果redis的pod掛掉會怎麼樣?如果建立redis時replicas為大於1時,那麼指定某個POD的的IP是否妥當?

第一個問題,由於是使用deployment建立的rs,再建立的pod,此時如果redis的某個pod掛了,由於rs中定義了replicas: 1,它會重新再起一個redis的pod,此時的IP可能就會變了。我們來試驗一下,只需要將原來的pod刪除掉即可,k8s會自動再建立一個新的pod

# kubectl get podNAME               READY  STATUS   RESTARTS  AGEflasktest-68cfdcc66d-d2tb7   1/1   Running  0      27mredis-master-7f88b489b9-k4c58  1/1   Running  0      154m​# kubectl delete pod redis-master-7f88b489b9-k4c58pod "redis-master-7f88b489b9-k4c58" deleted​# kubectl get podNAME               READY  STATUS   RESTARTS  AGEflasktest-68cfdcc66d-d2tb7   1/1   Running  0      27mredis-master-7f88b489b9-6kk8l  1/1   Running  0      12s

我們先將redis-master-7f88b489b9-k4c58這個pod刪除掉,之後k8s會自動又建立了新的pod redis-master-7f88b489b9-6kk8l

此時再訪問 http://127.0.0.1:30002/ 則報錯

redis.exceptions.ConnectionError: Error 113 connecting to 10.1.0.59:6379. No route to host.

報 10.1.0.59:6379 連線失敗了。

第二個問題,我們設定了replicas的數量是為了做負載均衡,所以如果你在應用裡將ip寫死的話那就起不到負載均衡了。

所以使用了k8s,如果要訪問其它pod的話,則不可以將對方的ip直接寫死到應用中的,我們需要通過 服務 來將各個pod進行通訊。

1.4 建立redis的service

Service 就是為了能讓應用有個穩定的入口,如這裡的redis訪問我們的應用服務,我們想

先將上面建立redis的pod通過service將埠暴露出來

apiVersion: v1kind: Servicemetadata:  name: redis-master-sr  labels:   name: redis-masterspec:  ports:  - port: 6379   targetPort: 6379  selector:   app: redis

通過 kubectl get service -o wide 檢視service詳情

kubectl get service -o wideNAME        TYPE     CLUSTER-IP    EXTERNAL-IP  PORT(S)   AGE   SELECTORkubernetes     ClusterIP  10.96.0.1    <none>    443/TCP   3d3h  <none>redis-master-sr  ClusterIP  10.99.187.220  <none>    6379/TCP  44s  name=redis-master​

可以看到有一個type為ClusterIP的service,這有一個ip,10.99.187.220 使用了6379作為對外埠,我們是不能通過這個IP的6379埠訪問到redis-master-sr這個service。但是如果在k8s裡的相同網路應用,是可以通過這個CLUSTER-IP 來訪問到的。

我們來試一下

重新打映象包 docker build -t flaskk8s:ClusterIP . 建立一個flaskk8s,tag為ClusterIP,修改flask-deployment.yaml

apiVersion: apps/v1kind: Deploymentmetadata:  labels:   app: flasktest  name: flasktestspec:  selector:   matchLabels:    app: flasktest  replicas: 1  template:   metadata:    labels:     app: flasktest   spec:    containers:    - image: flaskk8s:ClusterIP     name: flaskweb     imagePullPolicy: Never     ports:     - containerPort: 6000

執行 kubectl apply -f flask-deployment.yaml 生效,再重新訪問http://127.0.0.1:30002/ 則又可以正常訪問了。

1.5 使用環境變數來訪問service

使用service的ClusterIP雖然可以解決了由於pod的重啟更換IP的問題,但是如果一個service重啟,或者環境重新部署了,那麼service的IP又會變了,此時就要重新修改程式碼了,這肯定是不行的。

我們使用exec命令進入到pod內部,使用env命令檢視系統的環境變數

看到有兩個和redis service有關的環境變數

REDIS_MASTER_SR_SERVICE_HOST=10.103.116.170REDIS_MASTER_SR_SERVICE_PORT=6379

k8s會為每個pod的容器裡都增加一組service相關的環境變數,也會隨著pod或者service的變化而變化,有了這兩個環境變數,我們就可以動態獲取IP,修改程式碼

這時我們就可以不用修改IP來適應pod或者service的變動了。

最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • python快速進階9-實現多執行緒及執行緒間通訊的簡單方法