Kubernetes и Docker: как позволить двум сервисам правильно общаться - PullRequest
0 голосов
/ 18 января 2019

У меня есть два Java-сервиса ( caller.jar , который вызывает said.jar )

Мы можем установить вызывающий сервисный HTTP-порт через env-var CALLERPORT и адрес вызываемой службы через env-var CALLEDADDRESS . Так что вызывающая сторона использует два env-var.

Мы также должны установить вызываемый service env-var CALLEDPORT , чтобы установить конкретный порт http, на котором вызываемая служба прослушивает запросы http.

Я не знаю точно, как просто выставить эти переменные из Dockerfile, чтобы установить их с помощью Kubernetes.

Вот как я сделал два файла Docker:

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

Докер-файл вызываемого

FROM openjdk:8-jdk-alpine

# ENV CALLEDPORT (it's own port)

ADD called.jar /

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

С их помощью я сделал два изображения Docker :

  • myaccount / caller
  • MyAccount / называется

Затем я создал два deployments.yaml, чтобы позволить K8 развернуть (на мини-кубе) два микросервиса с использованием реплик и балансировщиков нагрузки.

развертывание-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: вызывается

Модули работают правильно и активны, но я полагаю, что проблема заключается в части deploy.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>

работает, если поместить в эту строку файл deploy.yaml. Так что же поставить в эту строку?

Ответы [ 3 ]

0 голосов
/ 18 января 2019

Чтобы получить доступ к услугам внутри Kubernetes, вы должны использовать этот DNS:

0 голосов
/ 18 января 2019

Прежде всего - совершенно невозможно понять, чего ты хочешь. Ваш пост начинается с:

Мы можем установить ...

Мы должны установить ...

Никто здесь не знает, что вы хотите сделать, и было бы гораздо полезнее увидеть какое-то определение того, что вы ожидаете.

Это было сказано сейчас, я должен перейти к вашему основному вопросу ...

  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

вот как я могу получить это в другом модуле, который находится в том же пространстве имен:

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? Кто заботится о внутренних портах контейнера? Я согласен, что бывают разные случаи, но в этом случае у вас внутри один процесс, и вы определенно не собираетесь запускать еще несколько процессов, не так ли? Так что они тоже могут быть одинаковыми.

Я бы посоветовал вам использовать stackoverflow по-другому. Не спрашивайте, как сделать что-то по-своему, гораздо лучше спросить, как сделать что-то лучше

0 голосов
/ 18 января 2019

Короткий ответ: вам не нужно показывать их в Dockerfile. Вы можете установить любые переменные окружения, которые захотите, при запуске контейнера, и их не нужно указывать заранее в Dockerfile.

Вы можете убедиться в этом, запустив контейнер, используя 'docker run' с '-e', чтобы установить env vars, и '-it', чтобы получить интерактивный сеанс. Выведите значение вашего env var, и вы увидите, что оно установлено.

Вы также можете получить сеанс терминала с одним из контейнеров в вашем запущенном модуле kubernetes с помощью 'kubectl exec' (https://kubernetes.io/docs/tasks/debug-application-cluster/get-shell-running-container/). Оттуда вы можете оттуда выводить переменные окружения, чтобы убедиться, что они установлены. Вы можете увидеть их быстрее с помощью «kubectl description pod» после получения имени модуля с помощью «kubectl get pods».

Поскольку у вас возникли проблемы, вы также хотите проверить, правильно ли работают ваши службы. Поскольку вы используете миникуб, вы можете воспользоваться «сервисом миникуб», чтобы проверить, что к ним можно получить доступ извне. Вы также захотите проверить внутренний доступ - см. Доступ к конечной точке контроллера пружинной загрузки в модуле kubernetes

Ваш подход к использованию имен служб и портов действителен. Немного отладки, и вы сможете заставить его работать. Ваша настройка похожа на иллюстрацию, которую я сделал в https://dzone.com/articles/kubernetes-namespaces-explained, поэтому ссылка на это может помочь (за исключением того, что вы используете env vars напрямую, а не через карту конфигурации, но это то же самое).

Я думаю, что в вызывающей стороне вы вводите неправильный порт в env var - вы вводите собственный порт вызывающей стороны, а не порт того, что он пытается вызвать.

...