Kubernetes - передать общедоступный IP-адрес баланса нагрузки в качестве переменной среды в модуль Pod - PullRequest
5 голосов
/ 16 октября 2019

Gist

У меня есть ConfigMap, который предоставляет необходимые переменные среды для моих модулей:

apiVersion: v1
kind: ConfigMap
metadata:
  name: global-config
data:
  NODE_ENV: prod
  LEVEL: info

  # I need to set API_URL to the public IP address of the Load Balancer
  API_URL: http://<SOME IP>:3000

  DATABASE_URL: mongodb://database:27017
  SOME_SERVICE_HOST: some-service:3000

Я запускаю свой кластер Kubernetes в Google Cloud, поэтому он автоматически создастобщедоступная конечная точка для моей службы:

apiVersion: v1
kind: Service
metadata:
  name: gateway
spec:
  selector:
    app: gateway
  ports:
    - name: http
      port: 3000
      targetPort: 3000
      nodePort: 30000
  type: LoadBalancer

Issue

У меня есть веб-приложение, которое должно отправлять HTTP-запросы из браузера клиента в службу gateway. Но чтобы сделать запрос к внешней службе, веб-приложение должно знать его IP-адрес.

Итак, я настроил модуль, который обслуживает веб-приложение таким образом, чтобы он принимал его. переменная окружения "API_URL" и в результате делает все HTTP-запросы к этому URL.

Так что мне просто нужен способ установить переменную окружения API_URL в публичный IP-адрес gatewayслужба, чтобы передать его в стручок, когда он начинается.

Ответы [ 3 ]

1 голос
/ 20 октября 2019

Я знаю, что это не тот подход, к которому вы стремились, но я обнаружил, что создание статического IP-адреса и его явная передача в , как правило, с ним легче работать.

Сначала создайте статический IP-адрес:

gcloud compute addresses create gke-ip --region <region>

, где region - это область GCP, в которой расположен ваш кластер GKE.

Затем вы можете получить новый IP-адрес с помощью:

gcloud compute addresses describe gke-ip --region <region>

Теперь вы можете добавить свой статический IP-адрес к своей службе, указав явный loadBalancerIP. 1

apiVersion: v1
kind: Service
metadata:
  name: gateway
spec:
  selector:
    app: gateway
  ports:
    - name: http
      port: 3000
      targetPort: 3000
      nodePort: 30000
  type: LoadBalancer
  loadBalancerIP: "1.2.3.4"

. На этом этапе вытакже можно жестко запрограммировать его в ConfigMap и не беспокоиться о получении значения из самого кластера.

1 Если вы уже создали LoadBalancer с автоматическимназначенный IP-адрес, установка IP-адреса не изменит IP-адрес базового балансировщика нагрузки GCP. Вместо этого вам следует удалить службу LoadBalancer в вашем кластере, подождать ~ 15 минут, чтобы очистить базовые ресурсы GCP, а затем воссоздать LoadBalancer с явным IP-адресом.

1 голос
/ 22 октября 2019

Вы пытаетесь получить доступ к службе шлюза из браузера клиента.

Я хотел бы предложить вам другое решение, немного отличающееся от того, что вы пытаетесь достичь, но оно может решить вашу проблему.

Из вашего вопроса я смог сделать вывод, что ваше веб-приложение и приложение шлюза находятся в одном кластере.

В моем решении вам не нужен сервис типа LoadBalancer, а базового Ingress достаточно, чтобы он работал.

Вам нужно только создать объект Service (обратите внимание, что опция type: LoadBalancer теперь отсутствует)

apiVersion: v1
kind: Service
metadata:
name: gateway
spec:
selector:
  app: gateway
ports:
  - name: http
    port: 3000
    targetPort: 3000
    nodePort: 30000

, и вам также нужен входной объект (помните, что на Ingress Controller нужнобыть развернутым в кластер, чтобы заставить его работать), как показано ниже: Подробнее о том, как развернуть контроллер Nginx Ingress, вы можете найти здесь , и если вы уже используете один (может быть, другой), то вы можете пропустить этоstep.

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: gateway-ingress
annotations:
  nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
  - host: gateway.foo.bar.com
    http:
      paths:
      - path: /
          backend:
            serviceName: gateway
            servicePort: 3000

Обратите внимание на поле хоста.

То же самое вам нужно повторить для вашего веб-приложения. Не забудьте использовать соответствующее имя хоста (DNS-имя), например, для веб-приложения: foo.bar.com и для шлюза: gateway.foo.bar.com, а затем просто используйте имя gateway.foo.bar.com dns для подключения к приложению-шлюзу из клиентского веб-браузера.

Вам также необходимо создать запись DNS, которая указывает *.foo.bar.com на публичный IP-адрес Ingress, поскольку контроллер Ingress создаст свой собственный балансировщик нагрузки.

Поток трафика будет таким, как показано ниже:

+-------------+   +---------+   +-----------------+   +---------------------+
| Web Browser |-->| Ingress |-->| gateway Service |-->| gateway application |
+-------------+   +---------+   +-----------------+   +---------------------+

Этот подход лучше, потому что он не вызовет проблем с Cross-Origin Resource Sharing (CORS) в клиентском браузере.

Примеры манифестов Ingress и Service, которые я взял из официальной документации kubernetes и немного изменил.

Подробнее о входе вы можете найти здесь и об услугах здесь

1 голос
/ 20 октября 2019

Следующее развертывание считывает внешний IP-адрес данной службы, используя kubectl каждые 10 секунд, и исправляет с ним заданную конфигурационную карту:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: configmap-updater
  labels:
    app: configmap-updater
spec:
  selector:
    matchLabels:
      app: configmap-updater
  template:
    metadata:
      labels:
        app: configmap-updater
    spec:
      containers:
      - name: configmap-updater
        image: alpine:3.10
        command: ['sh', '-c' ]
        args:
        - | #!/bin/sh
            set -x

            apk --update add curl
            curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.16.0/bin/linux/amd64/kubectl
            chmod +x kubectl

            export CONFIGMAP="configmap/global-config"
            export SERVICE="service/gateway"

            while true
            do
                IP=`./kubectl get services $CONFIGMAP -o go-template --template='{{ (index .status.loadBalancer.ingress 0).ip }}'`
                PATCH=`printf '{"data":{"API_URL": "https://%s:3000"}}' $IP`
                echo ${PATCH}
                ./kubectl patch --type=merge -p "${PATCH}" $SERVICE

                sleep 10
            done

Возможно, в вашем кластере GKE включен RBAC, и он все равно будетнеобходимо создать соответствующие Role и RoleBinding для правильной работы.

У вас есть несколько возможностей:

  • Если вам действительно нужноэто может быть взломано в вашей настройке, вы можете использовать аналогичный подход с контейнером коляски в вашем модуле или глобальной службой, как указано выше. Имейте в виду, что вам нужно будет воссоздать ваши модули, если карта конфигурации действительно изменилась, чтобы изменения были восприняты переменными среды ваших контейнеров.

  • Наблюдайте и запрашивайте Kubernetes-APIдля внешнего IP-адреса непосредственно в вашем приложении, исключая необходимость в переменной среды.

  • Примите ваши приложения, чтобы не зависеть напрямую от внешнего IP-адреса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...