Kubernetes和Docker:如何让两个服务正确通信

时间:2019-01-18 07:49:21

标签: docker kubernetes environment-variables load-balancing microservices

我有两个Java微服务( caller.jar ,它会调用 Called.jar

我们可以通过 env-var CALLERPORT 设置 caller 服务的http端口,并通过env-var < em> CALLEDADDRESS 。 因此呼叫者使用了两个env-var。

我们还必须设置被调用服务env-var CALLEDPORT ,以便设置被调用服务正在侦听HTTP请求的特定http端口。

我不知道如何确切地从Dockerfile中公开这些变量,以便使用Kubernetes进行设置。

这是我制作两个Dockerfile的方法:

调用方的Dockerfile

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"]

被调用的Dockerfile

FROM openjdk:8-jdk-alpine

# ENV CALLEDPORT (it's own port)

ADD called.jar /

CMD ["java", "-jar", "called.jar"]

借助这些,我制作了两个 Docker映像

  • myaccount / caller
  • myaccount /被叫

然后我做了两个Deployment.yaml,以便让K8s使用副本和负载平衡器部署(在minikube上)两个微服务。

deployment-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

部署称为.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:称为

pod已正确运行且处于活动状态,但是我想问题是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的这一行中,则可以使用。 那么在这一行中要放什么呢?

3 个答案:

答案 0 :(得分:4)

简短的答案是,您不需要在Dockerfile中公开它们。您可以在启动容器时设置所需的任何环境变量,而不必在Dockerfile中预先指定它们。

您可以通过使用“ docker run”,“-e”设置环境变量和“ -it”来获得交互式会话来启动容器,从而验证这一点。回显您的env var的值,您将看到它已设置。

您还可以使用'kubectl exec'(https://kubernetes.io/docs/tasks/debug-application-cluster/get-shell-running-container/)与正在运行的kubernetes Pod中的一个容器进行终端会话。从那里您可以从那里回显环境变量以查看它们是否已设置。在使用“ kubectl get pods”获得豆荚名称后,您可以使用“ kubectl describe pod”更快地查看它们。

由于遇到问题,您还想检查服务是否正常运行。由于您使用的是minikube,因此您可以执行“ minikube服务”来检查它们是否可以从外部访问。您还需要检查内部访问权限-参见Accessing spring boot controller endpoint in kubernetes pod

您使用服务名称和端口的方法是有效的。进行一些调试,您应该就能使其工作。您的设置类似于我在https://dzone.com/articles/kubernetes-namespaces-explained中所做的说明,因此引用可能会有所帮助(除非您直接使用env vars而不是通过configmap来使用,但等同)。

我认为,在调用方中,您将错误的端口注入到env var中-您是在放置调用方自己的端口,而不是尝试调用的端口。

答案 1 :(得分:1)

答案 2 :(得分:1)

首先-完全不可能理解您想要什么。您的帖子开始于:

  

我们可以设置...

     

我们必须设置...

这里没有人不知道您想做什么,而查看您期望完成的一些定义可能会更有用。

现在已经说了这一点,我必须转向您的实质性问题...

  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

或(取决于lib)

caller-loadbalancer
called-loadbalancer

关于containerPort / targetPort的一些事情!为什么使用80818080?谁在乎内部集装箱港口?我同意会发生不同的情况,但是在这种情况下,您内部只有一个进程,并且您肯定不会在那里运行更多的进程,是吗?因此它们也可以相同。

我想建议您以不同的方式使用stackoverflow。不要问如何按照自己的方式做事,最好不要问如何以最好的方式做事