我们如果创建了一些容器(pod),那么它们之间是怎么通信的呢?因为容器(pod)的ip地址是有可能变化的,这里我们主要讨论几个场景

  • 同一网络下的不同容器(pod)间是怎么通信的?
  • 同一个容器(pod)中不同的容器是怎么通信的?
  • 不同的网络下不同的容器(pod)是怎么通信的?

一、同一网络下的不同容器(pod)间通信

第一种场景可能是应用最多的场景,比如我写了一个web应用,它使用python作为后端,使用redis作为数据库,redis和python分别创建在不同的容器(pod)里,我会使用deployment创建rs的方式再创建容器(pod),正常情况下,我们是不希望这个redis被外面的应用访问到的,只允许在python的应用访问到,

如上图,用户可以使用python应用暴露出来的6000端口(其实是k8s里的service暴露出来的)来访问应用,但是并不能直接访问里面redis的6379端口。redis只有里面的python应用可以访问。

1.1 创建redis pod

我们先创建一个redis pod

apiVersion: apps/v1
kind: Deployment
metadata:labels:app: redisname: redis-master
spec:selector:matchLabels:app: redisreplicas: 1template:metadata:labels:app: redisspec:containers:- image: redisname: redis-master2ports:- containerPort: 6379

查看pod详细信息

# kubectl create -f r-deployment.yaml
deployment.apps/redis-master created
kubectl get pods -o wide
NAME                            READY   STATUS    RESTARTS   AGE   IP          NODE             NOMINATED NODE   READINESS GATES
redis-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 yanxing
# datetime:2020/2/10 16:07
# software: PyCharmfrom flask import Flask
from flask_redis import FlaskRedis
import timeREDIS_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"% nameapp.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的初始化时加上一点判断

if os.environ.get("envname") == "k8s": # 说明是在k8s中REDIS_URL = "redis://{}:{}/{}".format('redisIP', "redispord", 1)
else:REDIS_URL = "redis://{}:{}/{}".format('127.0.0.1', 6380, 1)

现在主要的问题在于,REDIS_URL = "redis://{}:{}/{}".format('redisIP', "redispord", 1)k8s中的redisIP和redispord这里该填写什么呢?

上面使用kubectl get pods -o wide 查看到redis的ip为10.1.0.59 ,那么我们试试能不能通过这个IP和端口来访问redis呢?

if os.environ.get("envname") == "k8s": # 说明是在k8s中REDIS_URL = "redis://{}:{}/{}".format('10.1.0.59', 6379, 1)
else:REDIS_URL = "redis://{}:{}/{}".format('127.0.0.1', 6380, 1)

先创建一个Dockerfile

# Use an official Python runtime as a parent image
From python:3.5.7
# Set the working directory to /app
WORKDIR /app
# ADD requirements.txt
COPY requirements.txt /app/
# Install any needed packages specified in requirement.txt
RUN pip install --trusted-host mirrors.aliyun.com -i https://mirrors.aliyun.com/pypi/simple/ -r requirements.txt && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
# Make port 6000 available to the world outside this container
EXPOSE 6000
# Define environment variable
ENV envname=k8s
# ADD application.py to /app
ADD application.py /app/
CMD ["python", "application.py"]

创建镜像

docker build -t flaskk8s .

之后就可以在本地查看到镜像 falskk8s,使用这个k8s创建pod,创建flask-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:labels:app: flasktestname: flasktest
spec:selector:matchLabels:app: flasktestreplicas: 1template:metadata:labels:app: flasktestspec:containers:- image: flaskk8sname: flaskwebimagePullPolicy: Neverports:- containerPort: 6000

因为是本地的镜像,所以在加上imagePullPolicy: Never ,否则k8s默认是会从dockerhub上去拉取,拉取不到就会报错

# kubectl get pod
NAME                            READY   STATUS    RESTARTS   AGE
flasktest-68cfdcc66d-d2tb7      1/1     Running   0          7s
redis-master-7f88b489b9-k4c58   1/1     Running   0          126m
# kubectl get deployment
NAME           READY   UP-TO-DATE   AVAILABLE   AGE
flasktest      1/1     1            1           44s
redis-master   1/1     1            1           127m

创建flasktest的service,让其可以通过浏览器访问

apiVersion: v1
kind: Service
metadata:name: flask-servicelabels:name: flaskservice
spec:type: NodePortports:- port: 6000nodePort: 30002selector:app: flasktest
# kubectl get service
NAME              TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
flask-service     NodePort    10.97.54.167    <none>        6000:30002/TCP   15s
kubernetes        ClusterIP   10.96.0.1       <none>        443/TCP          3d5h
redis-master-sr   ClusterIP   10.99.187.220   <none>        6379/TCP         79m

可以看到30002端口已经被暴露出来,之后我们访问http://127.0.0.1:30002/ ,看到可以正常的访问

一切看着都很顺利对不对,但是我们来考虑两个问题

  1. 如果redis的pod挂掉会怎么样?
  1. 如果创建redis时replicas为大于1时,那么指定某个POD的的IP是否妥当?

第一个问题,由于是使用deployment创建的rs,再创建的pod,此时如果redis的某个pod挂了,由于rs中定义了replicas: 1,它会重新再起一个redis的pod,此时的IP可能就会变了。我们来试验一下,只需要将原来的pod删除掉即可,k8s会自动再创建一个新的pod

# kubectl get pod
NAME                            READY   STATUS    RESTARTS   AGE
flasktest-68cfdcc66d-d2tb7      1/1     Running   0          27m
redis-master-7f88b489b9-k4c58   1/1     Running   0          154m# kubectl delete pod redis-master-7f88b489b9-k4c58
pod "redis-master-7f88b489b9-k4c58" deleted# kubectl get pod
NAME                            READY   STATUS    RESTARTS   AGE
flasktest-68cfdcc66d-d2tb7      1/1     Running   0          27m
redis-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: v1
kind: Service
metadata:name: redis-master-srlabels:name: redis-master
spec:ports:- port: 6379targetPort: 6379selector:app: redis

通过 kubectl get service -o wide 查看service详情

kubectl get service -o wide
NAME              TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE    SELECTOR
kubernetes        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作为对外端口,ClusterIP是虚拟IP,外面是不能通过这个IP的6379端口访问到redis-master-sr这个service,但是如果在k8s里的相同网络应用,是可以通过这个CLUSTER-IP 来访问到的。

我们来试一下

if os.environ.get("envname") == "k8s": # 说明是在k8s中REDIS_URL = "redis://{}:{}/{}".format('10.99.187.220', 6379, 1)
else:REDIS_URL = "redis://{}:{}/{}".format('127.0.0.1', 6380, 1)

重新打镜像包 docker build -t flaskk8s:ClusterIP . 创建一个flaskk8s,tag为ClusterIP,修改flask-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:labels:app: flasktestname: flasktest
spec:selector:matchLabels:app: flasktestreplicas: 1template:metadata:labels:app: flasktestspec:containers:- image: flaskk8s:ClusterIPname: flaskwebimagePullPolicy: Neverports:- 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命令查看系统的环境变量

# kubectl get pod
NAME                            READY   STATUS    RESTARTS   AGE
flasktest-74865c4b59-6l86m      1/1     Running   0          19m
flasktest-74865c4b59-k4pkk      1/1     Running   0          19m
redis-master-7f88b489b9-6kk8l   1/1     Running   0          160m# kubectl exec -it flasktest-74865c4b59-6l86m /bin/bash
root@flasktest-74865c4b59-6l86m:/app# env
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_SERVICE_PORT=443
REDIS_MASTER_SR_PORT_6379_TCP_PROTO=tcp
HOSTNAME=flasktest-74865c4b59-6l86m
PYTHON_VERSION=3.5.7
envname=k8s
REDIS_MASTER_SR_PORT_6379_TCP_PORT=6379
PWD=/app
REDIS_MASTER_SR_SERVICE_HOST=10.103.116.170
REDIS_MASTER_SR_PORT=tcp://10.103.116.170:6379
HOME=/root
LANG=C.UTF-8
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
REDIS_MASTER_SR_PORT_6379_TCP=tcp://10.103.116.170:6379
GPG_KEY=97FC712E4C024BBEA48A61ED3A5CA953F73C700D
TERM=xterm
SHLVL=1
REDIS_MASTER_SR_PORT_6379_TCP_ADDR=10.103.116.170
KUBERNETES_PORT_443_TCP_PROTO=tcp
PYTHON_PIP_VERSION=19.3.1
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
REDIS_MASTER_SR_SERVICE_PORT=6379
PYTHON_GET_PIP_SHA256=b86f36cc4345ae87bfd4f10ef6b2dbfa7a872fbff70608a1e43944d283fd0eee
KUBERNETES_SERVICE_HOST=10.96.0.1
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP_PORT=443
PYTHON_GET_PIP_URL=https://github.com/pypa/get-pip/raw/ffe826207a010164265d9cc807978e3604d18ca0/get-pip.py
PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
_=/usr/bin/env

看到有两个和redis service有关的环境变量

REDIS_MASTER_SR_SERVICE_HOST=10.103.116.170
REDIS_MASTER_SR_SERVICE_PORT=6379

k8s会为每个pod的容器里都增加一组service相关的环境变量,也会随着pod或者service的变化而变化,有了这两个环境变量,我们就可以动态获取IP,修改代码

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)

这时我们就可以不用修改IP来适应容器(pod)或者service的变动了。

kubernetes中容器(pod)间的通信及环境变量设置相关推荐

  1. 微前端之实践环境变量设置、快照沙箱隔离、代理沙箱隔离、css 样式隔离、父子应用间通信和子应用间通信

    一.微前端之实践环境变量设置.快照沙箱隔离.代理沙箱隔离.css 样式隔离.父子应用间通信和子应用间通信 微前端环境变量设置,如下所示: 在 micro 下的 sandbox 中 performScr ...

  2. docker添加新的环境变量_Docker容器环境变量设置与查看

    设置环境变量 在编写Dockerfile时, 我们可以通过ENV来为Docker容器设置相关的环境变量,设置的环境变量在Docker容器中可以通过环境变量来进行引用. Docker容器环境变量设置方法 ...

  3. jar java classpath_win7中java编程工具安装 java环境变量设置

    win7中java编程工具安装 java环境变量设置 Question:编译是显示'javac'不是内部或外部命令,也不是可运行的程序或批处理文件 解决: 在[系统变量]里编辑java_home.cl ...

  4. @PropertySource读取外部配置文件中的k-v保存到运行的环境变量中,加载完微博的配置文件以后使用${}取配置文件中的键值

    @PropertySource读取外部配置文件中的k-v保存到运行的环境变量中,加载完微博的配置文件以后使用${}取配置文件中的键值 该注解value={},可以使用String数组形式,读取多个配置 ...

  5. Linux环境变量设置中配置文件分析(/etc/profile,~/.bashrc等)(转)

    说明:在研究中发现,对于不同版本的Linux系统有着不同的文件,但是总的入口是不变的/etc/profile,下面只是展示加载顺序的研究过程,所以会有些系统没有这个文件等问题. 一.配置文件与作用域: ...

  6. ug更改java的环境变量_UG中的语言环境变量设置

    原标题:UG中的语言环境变量设置 今天与大家分享怎样更改UG中的语言环境变量,语言的更改经常要用,特别是在英语和中文之间切换. 在Windows的操作系统中,UG软件的工作路径是由系统注册表和环境变量 ...

  7. java环境变量设置 win2003_Windows中java环境变量的设置

    AVA中常用需要设置的三个环境变量: JAVA_HOME .CLASSPATH.PATH (一)配置环境变量∶(相对路径) 1.JAVA_HOME=x:\jdk1.6.0 JAVA_HOME 2.用% ...

  8. shell中的环境变量设置

    1. 环境变量 环境变量也称为全局变量,可以在创建他们的Shell及其派生出来的任意子进程Shell中使用,环境变量又可以分为自定义环境变量和bash内置的环境变量,环境变量可以在命令行中设置和创建, ...

  9. centos 6.4 java环境变量_CentOS中JAVA_HOME的环境变量设置

    http://blog.csdn.net/wind520/article/details/9308809 运行Java应用的时候,提示无法找到JAVA_HOME,查询java -version [ji ...

  10. JAVA中配置环境变量设置方法大全

    JAVA中常用需要设置的三个环境变量: JAVA_HOME .CLASSPATH.PATH (一) 配置环境变量:(相对路径) 1. JAVA_HOME=x:\jdk1.6.0 JAVA_HOME 2 ...

最新文章

  1. 常见面试题:为什么MySQL索引要用B+Tree呢?(看完你就能和面试官笑谈人生了)
  2. 深度学习必懂的 13 种概率分布(附链接)
  3. RocketMQ生产者流程篇
  4. android movie studio 下载,Movie Studio+ Video Editor
  5. Tomcat的配置文件server.xml叙述
  6. MySQL快速生成连续整数
  7. JS——基础知识--变量类型和变量计算
  8. StringHelper--封转自己的字符串工具类
  9. Spring4Shell 漏洞已遭Mirai 僵尸网络利用
  10. 微信小程序input安卓手机获取焦点时候上移
  11. 常用编程软件站点、镜像站、科技类 PDF
  12. 【汇编语言】通用数据处理指令——位操作类指令
  13. [精华]世界500强面试题----[完整版]
  14. mysql类型float_Mysql数据类型---FLOAT
  15. 漏洞C:/Windows/Fonts/csrss.exe文件找不到简单查找方法
  16. 国外各国统计机构网址
  17. python编程知识大全_python编程入门之二:必备基础知识
  18. 修改 UITabBar的背景颜色
  19. 大屏制作 | 完成一个美观大屏到底多简单?四步完成
  20. html5怎么修改图片大小,HTML5 javascript修改canvas的大小

热门文章

  1. python图片爬虫,指定关键字爬取Google图片+搜狗图片
  2. 一文了解基金投资的方法
  3. 应聘客户端主程需做哪些准备
  4. Linux 安装.deb软件包之前 dpkg-deb 命令查看.deb文件详细信息 版本号 包名
  5. oracle IF_Oracle实时同步大数据平台解决方案
  6. 无绳园林设备行业调研报告 - 市场现状分析与发展前景预测
  7. Dex.top社区绿皮书 (试运行)
  8. 利用EXCEL将中文汉字转为拼音
  9. 基于FPGA的超声波测距(verilog)
  10. 免费开源的图像处理软件GIMP下载安装(Windows)