之前的文章kubernetes中pod間的通信 中,我們使用環境變量來解析服務的IP,但是可以使用環境變量有一個限制,所有的pods須在一個namespace中,也就是說在同一個namespace中的pod才會共享環境變量,如果不在同一個namespace該如何訪問呢?我們還是一個python的flask應用為例,這次我們將redis放到default的namespace中,flask的應用放到yyxtest的namespace中。
創建redis的pod與service
redis.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: redis
name: redis-master
spec:
selector:
matchLabels:
app: redis
replicas: 1
template:
metadata:
labels:
app: redis
spec:
containers:
- image: redis
name: redis-master2
ports:
- containerPort: 6379
redis-service.yaml
apiVersion: v1
kind: Service
metadata:
name: redis-master-sr
labels:
name: redis-master
spec:
ports:
- port: 6379
targetPort: 6379
selector:
app: redis
查看pod與service信息
# kubectl get pods
NAME READY STATUS RESTARTS AGE
redis-master-wjq6t 1/1 Running 0 8m55s
C:\Users\54523\Desktop\k8stest>kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
redis-master-sr ClusterIP 10.97.140.58 <none> 6379/TCP 3m3s
創建python應用
#-*- coding:utf-8 -*-
# author:Yang
# datetime:2020/2/10 16:07
# software: PyCharm
from flask import Flask
from flask_redis import FlaskRedis
import time
import os
if os.environ.get("envname") == "k8s": # 說明是在k8s中
redis_server = os.environ.get("REDIS_MASTER_SR_SERVICE_HOST")
redis_port = os.environ.get("REDIS_MASTER_SR_SERVICE_PORT")
REDIS_URL = "redis://{}:{}/{}".format(redis_server, redis_port, 1)
else:
REDIS_URL = "redis://{}:{}/{}".format('127.0.0.1', 6380, 1)
app = Flask(__name__)
app.config['REDIS_URL'] = REDIS_URL
redis_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)
上面是之前的代碼,采用環境變量的方式,獲取到redis_server和redis_port,之前創建flask的應用的pod和service都沒有指定namespace,如果沒有指定的話,默認是創建在了default的namespace,由於redis也沒有指定,所以它們之間是可以通過共享環境變量來解決服務地址的,那現在我們將python應用創建在yyxtest的namespace中,看看情況如何。
將先之前python應用打包 docker build -t flaskk8s:dns .
創建deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: flasktest
name: flasktest
namespace: yyxtest
spec:
selector:
matchLabels:
app: flasktest
replicas: 2
template:
metadata:
labels:
app: flasktest
spec:
containers:
- image: flaskk8s:dns
name: flaskweb
imagePullPolicy: Never
ports:
- containerPort: 6000
再創建service.yaml
apiVersion: v1
kind: Service
metadata:
name: flask-service
labels:
name: flaskservice
namespace: yyxtest
spec:
type: NodePort
ports:
- port: 6000
nodePort: 30003
selector:
app: flasktest
這次在deployment和service中的metadata中都添加了namespace: yyxtest
,它們將會被創建到 yyxtest的namespace中
使用kubectl get pods --namespace=yyxtest
來查看pods,此時pods直接顯示error了,通過查看pods里的日志發現, redis_port = os.environ.get("REDIS_MASTER_SR_SERVICE_PORT")
這行代碼沒有獲取到REDIS_MASTER_SR_SERVICE_PORT
的值,返回的是個None,所以在之后的redis初始化時就報錯失敗了,這也說明,在yyxtesxt的名稱空間中的pod里是沒有REDIS_MASTER_SR_SERVICE_PORT
這個環境變量的。
我們同樣在default的namespace中也創建flask的pod和service,此時就可以正常的訪問。
我們使用kubectl exec命令分別進入到兩個namespace空間中的flask應用的pod中
在default的名稱空間中
# env
...
FLASK_SERVICE_SERVICE_HOST=10.109.55.91
REDIS_MASTER_SR_SERVICE_PORT=6379
...
它包含有這兩個環境變量,但是在yyxtest的pod中卻沒有這兩個環境變量,這也就說明,原來的代碼在非default空間(准確的說是和redis不在同一個空間中)是不能正常運行的。
使用dns來解析服務地址
除了可以使用環境變量來解析服務地址,用的更多的應該是使用dns來解析了,在創建redis的service時,Kubernetes 會創建一個相應的 DNS 條目,該條目的形式是 <service-name>.<namespace-name>.svc.cluster.local
,這意味着如果容器只使用 <service-name>
,它將被解析到本地命名空間的服務。比如在yaml文件中設置了
metadata:
name: redis-master-sr
則會創建一個 redis-master-sr.default.svc.cluster.local
的記錄, 我們在default名稱空間中的pod試一下
# ping redis-master-sr
PING redis-master-sr.default.svc.cluster.local (10.97.140.58) 56(84) bytes of data.
在yyxtest名稱空間中的pod再試一下
# ping redis-master-sr
ping: redis-master-sr: Name or service not known
說明服務名只能中它所在的空間中(本例中的default)有dns記錄,不在它的空間(本例中的yyxtest)中則不存在,但是我們注意中,在default空間中 redis-master-sr解析到了redis-master-sr.default.svc.cluster.local
,那么在非default空間中是否可以正常解析redis-master-sr.default.svc.cluster.local
這個名稱呢?
在yyxtest的pod中執行
ping redis-master-sr.default.svc.cluster.local
PING redis-master-sr.default.svc.cluster.local (10.97.140.58) 56(84) bytes of data.
也是可以正常解析的,所以這時我們來修改一下python的代碼
if os.environ.get("envname") == "k8s": # 說明是在k8s中
REDIS_URL = "redis://{}:{}/{}".format("redis-master-sr.default.svc.cluster.local", 6379, 1)
else:
REDIS_URL = "redis://{}:{}/{}".format('127.0.0.1', 6380, 1)
這時,我們就可以和redis不同的名稱空間創建應用了。
參考文章