Kubernetes 与Docker:如何让两个服务正确通信
Kubernetes and Docker: how to let two service to communicate correctly
我有两个 Java 微服务(caller.jar 调用 called.jar)
我们可以通过 env-var CALLERPORT 设置 caller 服务 http 端口和通过 env-var CALLEDADDRESS 调用服务的地址。
所以调用者使用了两个环境变量。
我们还必须设置 called service env-var CALLEDPORT 以设置被调用服务正在侦听的特定 http 端口http 请求。
我不知道如何简单地从 Docker 文件公开这些变量,以便使用 Kubernetes 设置它们。
这是我制作两个 Docker 文件的方法:
Docker来电者档案
FROM openjdk:8-jdk-alpine
# ENV CALLERPORT (it's own port)
# ENV CALLEDADDRESS (the other service address)
ADD caller.jar /
CMD ["java", "-jar", "caller.jar"]
Docker调用的文件
FROM openjdk:8-jdk-alpine
# ENV CALLEDPORT (it's own port)
ADD called.jar /
CMD ["java", "-jar", "called.jar"]
用这些我制作了两张 Docker 图片:
- myaccount/caller
- myaccount/called
然后我制作了两个 deployments.yaml 以便让 K8s 使用副本和负载均衡器部署(在 minikube 上)这两个微服务。
部署-caller.yaml
apiVersion: v1
kind: Service
metadata:
name: caller-loadbalancer
spec:
type: LoadBalancer
ports:
- port: 8080
targetPort: 8080
selector:
app: caller
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: caller
labels:
app: caller
spec:
replicas: 2
minReadySeconds: 15
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
selector:
matchLabels:
app: caller
tier: caller
strategy:
type: Recreate
template:
metadata:
labels:
app: caller
tier: caller
spec:
containers:
- image: myaccount/caller
name: caller
env:
- name: CALLERPORT
value: "8080"
- name: CALLEDADDRESS
value: called-loadbalancer # WHAT TO PUT HERE?!
ports:
- containerPort: 8080
name: caller
和部署-called.yaml
apiVersion: v1
kind: Service
metadata:
name: called-loadbalancer
spec:
type: LoadBalancer
ports:
- port: 8081
targetPort: 8081
selector:
app: called
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: called
labels:
app: called
spec:
replicas: 2
minReadySeconds: 15
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
selector:
matchLabels:
app: called
tier: called
strategy:
type: Recreate
template:
metadata:
labels:
app: called
tier: called
spec:
containers:
- image: myaccount/called
name: called
env:
- name: CALLEDPORT
value: "8081"
ports:
- containerPort: 8081
name: called
重要提示:
如果单独调用单个服务(例如调用健康检查端点),则单个服务运行良好,但是当调用涉及两个服务之间通信的端点时,则会出现此错误:
java.net.UnknownHostException: called
pods 正确 运行 并且处于活动状态,但我想问题出在 deployment.yaml 的部分,我必须在其中定义如何找到指向的服务,所以在这里:
spec:
containers:
- image: myaccount/caller
name: caller
env:
- name: CALLERPORT
value: "8080"
- name: CALLEDADDRESS
value: called-loadbalancer # WHAT TO PUT HERE?!
ports:
- containerPort: 8080
name: caller
都没有
called
也不
called-loadbalancer
也不
http://caller
kubectl get pods,svc -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/called-855cc4d89b-4gf97 1/1 Running 0 3m23s 172.17.0.4 minikube <none> <none>
pod/called-855cc4d89b-6268l 1/1 Running 0 3m23s 172.17.0.5 minikube <none> <none>
pod/caller-696956867b-9n7zc 1/1 Running 0 106s 172.17.0.6 minikube <none> <none>
pod/caller-696956867b-djwsn 1/1 Running 0 106s 172.17.0.7 minikube <none> <none>
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service/called-loadbalancer LoadBalancer 10.99.14.91 <pending> 8081:30161/TCP 171m app=called
service/caller-loadbalancer LoadBalancer 10.107.9.108 <pending> 8080:30078/TCP 65m app=caller
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 177m <none>
如果放在 deployment.yaml 的那一行就可以工作。
那么这一行应该放什么呢?
简短的回答是您不需要在 Dockerfile 中公开它们。您可以在启动容器时设置所需的任何环境变量,而不必预先在 Dockerfile 中指定它们。
您可以通过使用 'docker run' 启动容器来验证这一点,使用“-e”设置环境变量,使用“-it”获取交互式会话。回显您的环境变量的值,您会看到它已设置。
您还可以使用 运行 kubernetes Pod 中的一个容器与 'kubectl exec' (https://kubernetes.io/docs/tasks/debug-application-cluster/get-shell-running-container/) 进行终端会话。从那里您可以从那里回显环境变量以查看它们是否已设置。使用 'kubectl get pods' 获取 pod 名称后,您可以使用 'kubectl describe pod ' 更快地查看它们。
既然您遇到了问题,您还想检查您的服务是否正常运行。由于您使用的是 minikube,因此您可以执行 'minikube service ' 来检查它们是否可以从外部访问。您还需要检查内部访问 - 请参阅
您使用服务名称和端口的方法是有效的。通过一些调试,你应该能够让它工作。您的设置类似于我在 https://dzone.com/articles/kubernetes-namespaces-explained 中所做的插图,因此参考它可能会有所帮助(除非您直接使用环境变量而不是通过配置映射,但它是一样的)。
我认为在调用者中,您在环境变量中注入了错误的端口 - 您放置了调用者自己的端口,而不是它试图调用的端口。
要访问 Kubernetes 内的服务,您应该使用此 DNS:
首先-完全不可能理解你想要什么。您的 post 起始于:
We can set...
We must set...
这里没有人不知道您想做什么,如果能看到您期望的完成的一些定义会更有用。
说到这里,我要转向你的实质性问题了...
env:
- name: CALLERPORT
value: "8080"
- name: CALLEDADDRESS
value: called-loadbalancer # WHAT TO PUT HERE?!
ports:
- containerPort: 8080
name: caller
这个东西会被k8s自动导出。例如,我的服务 kibana
在服务定义中带有 port:80
:
svc/kibana ClusterIP 10.222.81.249 <none> 80/TCP 1y app=kibana
这就是我在同一命名空间中的不同 pod 中获取它的方法:
root@some-pod:/app# env | grep -i kibana
KIBANA_SERVICE_PORT=80
KIBANA_SERVICE_HOST=10.222.81.249
展望未来,您为什么使用 LoadBalancer?没有任何云,它将类似于 NodePort,但似乎 ClusterIP 就是您所需要的。
接下来,服务端口可以相同,不会有任何端口冲突,只是因为 ClusterIP 每次都是唯一的,因此每个服务的套接字都是唯一的。您的服务可以这样描述:
apiVersion: v1
kind: Service
metadata:
name: caller-loadbalancer
spec:
type: LoadBalancer
ports:
- port: 80 <--------------------
targetPort: 8080
selector:
app: caller
apiVersion: v1
kind: Service
metadata:
name: called-loadbalancer
spec:
type: LoadBalancer
ports:
- port: 80 <------------------
targetPort: 8081
selector:
app: called
这将简化仅通过名称而不指定端口的服务名称的使用:
http://caller-loadbalancer.default.svc.cluster.local
http://called-loadbalancer.default.svc.cluster.local
或
http://caller-loadbalancer.default
http://called-loadbalancer.default
或(在类似的命名空间内):
http://caller-loadbalancer
http://called-loadbalancer
或(取决于库)
caller-loadbalancer
called-loadbalancer
containerPort/targetPort 也一样!为什么使用 8081
和 8080
?谁关心内部集装箱港口?我同意会发生不同的情况,但在这种情况下,您内部只有一个进程,您肯定不会 运行 那里有更多进程,是吗?所以他们也可能是一样的。
我想建议您以不同的方式使用 Whosebug。不要问如何以你的方式做事,最好问如何以最好的方式做事
我有两个 Java 微服务(caller.jar 调用 called.jar)
我们可以通过 env-var CALLERPORT 设置 caller 服务 http 端口和通过 env-var CALLEDADDRESS 调用服务的地址。 所以调用者使用了两个环境变量。
我们还必须设置 called service env-var CALLEDPORT 以设置被调用服务正在侦听的特定 http 端口http 请求。
我不知道如何简单地从 Docker 文件公开这些变量,以便使用 Kubernetes 设置它们。
这是我制作两个 Docker 文件的方法:
Docker来电者档案
FROM openjdk:8-jdk-alpine
# ENV CALLERPORT (it's own port)
# ENV CALLEDADDRESS (the other service address)
ADD caller.jar /
CMD ["java", "-jar", "caller.jar"]
Docker调用的文件
FROM openjdk:8-jdk-alpine
# ENV CALLEDPORT (it's own port)
ADD called.jar /
CMD ["java", "-jar", "called.jar"]
用这些我制作了两张 Docker 图片:
- myaccount/caller
- myaccount/called
然后我制作了两个 deployments.yaml 以便让 K8s 使用副本和负载均衡器部署(在 minikube 上)这两个微服务。
部署-caller.yaml
apiVersion: v1
kind: Service
metadata:
name: caller-loadbalancer
spec:
type: LoadBalancer
ports:
- port: 8080
targetPort: 8080
selector:
app: caller
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: caller
labels:
app: caller
spec:
replicas: 2
minReadySeconds: 15
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
selector:
matchLabels:
app: caller
tier: caller
strategy:
type: Recreate
template:
metadata:
labels:
app: caller
tier: caller
spec:
containers:
- image: myaccount/caller
name: caller
env:
- name: CALLERPORT
value: "8080"
- name: CALLEDADDRESS
value: called-loadbalancer # WHAT TO PUT HERE?!
ports:
- containerPort: 8080
name: caller
和部署-called.yaml
apiVersion: v1
kind: Service
metadata:
name: called-loadbalancer
spec:
type: LoadBalancer
ports:
- port: 8081
targetPort: 8081
selector:
app: called
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: called
labels:
app: called
spec:
replicas: 2
minReadySeconds: 15
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
selector:
matchLabels:
app: called
tier: called
strategy:
type: Recreate
template:
metadata:
labels:
app: called
tier: called
spec:
containers:
- image: myaccount/called
name: called
env:
- name: CALLEDPORT
value: "8081"
ports:
- containerPort: 8081
name: called
重要提示: 如果单独调用单个服务(例如调用健康检查端点),则单个服务运行良好,但是当调用涉及两个服务之间通信的端点时,则会出现此错误:
java.net.UnknownHostException: called
pods 正确 运行 并且处于活动状态,但我想问题出在 deployment.yaml 的部分,我必须在其中定义如何找到指向的服务,所以在这里:
spec:
containers:
- image: myaccount/caller
name: caller
env:
- name: CALLERPORT
value: "8080"
- name: CALLEDADDRESS
value: called-loadbalancer # WHAT TO PUT HERE?!
ports:
- containerPort: 8080
name: caller
都没有
called
也不
called-loadbalancer
也不
http://caller
kubectl get pods,svc -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/called-855cc4d89b-4gf97 1/1 Running 0 3m23s 172.17.0.4 minikube <none> <none>
pod/called-855cc4d89b-6268l 1/1 Running 0 3m23s 172.17.0.5 minikube <none> <none>
pod/caller-696956867b-9n7zc 1/1 Running 0 106s 172.17.0.6 minikube <none> <none>
pod/caller-696956867b-djwsn 1/1 Running 0 106s 172.17.0.7 minikube <none> <none>
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service/called-loadbalancer LoadBalancer 10.99.14.91 <pending> 8081:30161/TCP 171m app=called
service/caller-loadbalancer LoadBalancer 10.107.9.108 <pending> 8080:30078/TCP 65m app=caller
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 177m <none>
如果放在 deployment.yaml 的那一行就可以工作。 那么这一行应该放什么呢?
简短的回答是您不需要在 Dockerfile 中公开它们。您可以在启动容器时设置所需的任何环境变量,而不必预先在 Dockerfile 中指定它们。
您可以通过使用 'docker run' 启动容器来验证这一点,使用“-e”设置环境变量,使用“-it”获取交互式会话。回显您的环境变量的值,您会看到它已设置。
您还可以使用 运行 kubernetes Pod 中的一个容器与 'kubectl exec' (https://kubernetes.io/docs/tasks/debug-application-cluster/get-shell-running-container/) 进行终端会话。从那里您可以从那里回显环境变量以查看它们是否已设置。使用 'kubectl get pods' 获取 pod 名称后,您可以使用 'kubectl describe pod ' 更快地查看它们。
既然您遇到了问题,您还想检查您的服务是否正常运行。由于您使用的是 minikube,因此您可以执行 'minikube service ' 来检查它们是否可以从外部访问。您还需要检查内部访问 - 请参阅
您使用服务名称和端口的方法是有效的。通过一些调试,你应该能够让它工作。您的设置类似于我在 https://dzone.com/articles/kubernetes-namespaces-explained 中所做的插图,因此参考它可能会有所帮助(除非您直接使用环境变量而不是通过配置映射,但它是一样的)。
我认为在调用者中,您在环境变量中注入了错误的端口 - 您放置了调用者自己的端口,而不是它试图调用的端口。
要访问 Kubernetes 内的服务,您应该使用此 DNS:
首先-完全不可能理解你想要什么。您的 post 起始于:
We can set...
We must set...
这里没有人不知道您想做什么,如果能看到您期望的完成的一些定义会更有用。
说到这里,我要转向你的实质性问题了...
env:
- name: CALLERPORT
value: "8080"
- name: CALLEDADDRESS
value: called-loadbalancer # WHAT TO PUT HERE?!
ports:
- containerPort: 8080
name: caller
这个东西会被k8s自动导出。例如,我的服务 kibana
在服务定义中带有 port:80
:
svc/kibana ClusterIP 10.222.81.249 <none> 80/TCP 1y app=kibana
这就是我在同一命名空间中的不同 pod 中获取它的方法:
root@some-pod:/app# env | grep -i kibana
KIBANA_SERVICE_PORT=80
KIBANA_SERVICE_HOST=10.222.81.249
展望未来,您为什么使用 LoadBalancer?没有任何云,它将类似于 NodePort,但似乎 ClusterIP 就是您所需要的。 接下来,服务端口可以相同,不会有任何端口冲突,只是因为 ClusterIP 每次都是唯一的,因此每个服务的套接字都是唯一的。您的服务可以这样描述:
apiVersion: v1
kind: Service
metadata:
name: caller-loadbalancer
spec:
type: LoadBalancer
ports:
- port: 80 <--------------------
targetPort: 8080
selector:
app: caller
apiVersion: v1
kind: Service
metadata:
name: called-loadbalancer
spec:
type: LoadBalancer
ports:
- port: 80 <------------------
targetPort: 8081
selector:
app: called
这将简化仅通过名称而不指定端口的服务名称的使用:
http://caller-loadbalancer.default.svc.cluster.local
http://called-loadbalancer.default.svc.cluster.local
或
http://caller-loadbalancer.default
http://called-loadbalancer.default
或(在类似的命名空间内):
http://caller-loadbalancer
http://called-loadbalancer
或(取决于库)
caller-loadbalancer
called-loadbalancer
containerPort/targetPort 也一样!为什么使用 8081
和 8080
?谁关心内部集装箱港口?我同意会发生不同的情况,但在这种情况下,您内部只有一个进程,您肯定不会 运行 那里有更多进程,是吗?所以他们也可能是一样的。
我想建议您以不同的方式使用 Whosebug。不要问如何以你的方式做事,最好问如何以最好的方式做事