之前的文章kubernetes中pod间的通信 中,我们使用环境变量来解析服务的IP,但是可以使用环境变量有一个限制,所有的pods须在一个namespace中,也就是说在同一个namespace中的pod才会共享环境变量,如果不在同一个namespace该如何访问呢?我们还是一个python的flask应用为例,这次我们将redis放到default的namespace中,flask的应用放到yyxtest的namespace中。

创建redis的pod与service

redis.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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

1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: v1
kind: Service
metadata:
name: redis-master-sr
labels:
name: redis-master
spec:
ports:
- port: 6379
targetPort: 6379
selector:
app: redis

查看pod与service信息

1
2
3
4
5
6
7
# 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应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#-*- 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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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的名称空间中

1
2
3
4
5
# 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文件中设置了

1
2
metadata:
name: redis-master-sr

则会创建一个 redis-master-sr.default.svc.cluster.local的记录, 我们在default名称空间中的pod试一下

1
2
# ping redis-master-sr
PING redis-master-sr.default.svc.cluster.local (10.97.140.58) 56(84) bytes of data.

在yyxtest名称空间中的pod再试一下

1
2
# 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中执行

1
2
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的代码

1
2
3
4
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不同的名称空间创建应用了。

参考文章

命名空间