Comment exposer kubernetes service au public sans hardcoding à minion IP?

j'ai un cluster kubernetes avec 2 minions. Actuellement, je rends mon service accessible en 2 étapes:

  1. Démarrer la réplication du contrôleur & pod
  2. Obtenir minion IP (à l'aide de kubectl get minions ) et la définir comme publicIPs pour le Service.

Quelle est la pratique suggérée pour exposer le service au public? Mon approche semble fausse parce que je code dur les IP-s de l'individu minion IP-s. Elle semble également contourner les capacités d'équilibrage de charge des services kubernetes parce que les clients devraient avoir accès à des services fonctionnant sur minions individuels directement.

pour configurer le contrôleur de réplication & pod j'utilise:

id: frontend-controller
kind: ReplicationController
apiVersion: v1beta1
desiredState:
  replicas: 2
  replicaSelector:
    name: frontend-pod
  podTemplate:
    desiredState:
      manifest:
        version: v1beta1
        id: frontend-pod
        containers:
          - name: sinatra-docker-demo
            image: madisn/sinatra_docker_demo
            ports:
              - name: http-server
                containerPort: 4567
    labels:
      name: frontend-pod

pour mettre en place le service (après obtention de minion ip-s):

kind: Service
id: frontend-service
apiVersion: v1beta1
port: 8000
containerPort: http-server
selector:
  name: frontend-pod
labels:
  name: frontend
publicIPs: [10.245.1.3, 10.245.1.4]
22
demandé sur Madis Nõmme 2015-04-21 14:17:25

5 réponses

comme je l'ai mentionné dans le commentaire ci-dessus, le createExternalLoadBalancer est l'abstraction appropriée que vous recherchez, mais malheureusement il n'est pas encore implémenté pour tous les fournisseurs de cloud, et en particulier pour vagrant, que vous utilisez localement.

une option serait d'utiliser l'IPs public pour tous les sous-fifres de votre cluster pour tous les services que vous voulez externaliser. Le trafic destiné au service finira sur un des minions, où il sera intercepté par le processus kube-proxy et redirigé vers un pod qui correspond au sélecteur d'étiquettes du service. Cela pourrait entraîner un saut supplémentaire à travers le réseau (si vous atterrissez sur un noeud qui n'a pas le pod exécuté localement) mais pour les applications qui ne sont pas extrêmement sensibles à la latence du réseau, cela ne sera probablement pas perceptible.

8
répondu Robert Bailey 2015-04-23 04:36:09

comme L'a dit Robert dans sa réponse, c'est quelque chose qui arrive, mais qui n'est malheureusement pas encore disponible.

j'exécute actuellement un cluster Kubernetes sur notre réseau de datacenter. J'ai 1 master et 3 minions qui fonctionnent tous sur CentOS 7 virtuals (vcenter). La façon dont j'ai géré cela a été de créer un serveur dédié "kube-proxy". En gros, Je ne fais qu'exécuter le service Kube-Proxy (avec Flannel pour la mise en réseau) et ensuite attribuer des adresses IP "publiques" à la adaptateur réseau relié à ce serveur. Quand je dis public, je veux dire adresses sur notre réseau local de datacenter. Ensuite, lorsque je crée un service auquel j'aimerais accéder en dehors du cluster, je mets la valeur publicIPs à l'une des adresses IP disponibles sur le serveur kube-proxy. Quand quelqu'un ou quelque chose tente de se connecter à ce service depuis l'extérieur du cluster, il va frapper le Kube-proxy et ensuite être redirigé vers le bon minion.

alors que cela pourrait sembler comme un le travail autour, c'est en fait similaire à ce que je m'attendrais à ce qui se passe une fois qu'ils viennent avec une solution intégrée à cette question.

7
répondu Todd Spayde 2015-04-27 00:48:39

si vous exécutez un cluster localement, une solution que j'ai utilisée était d'exposer le service sur vos noeuds kubernetes en utilisant la directive nodeport dans votre définition de service et ensuite round robin à chaque noeud dans votre cluster avec HAproxy.

voici à quoi ressemble l'exposition du nodeport:

apiVersion: v1
kind: Service
metadata:
  name: nginx-s
  labels:
    name: nginx-s
spec:
  type: NodePort
  ports:
    # must match the port your container is on in your replication controller
    - port: 80
      nodePort: 30000
  selector:
    name: nginx-s

Note: la valeur que vous spécifiez doit se situer dans la plage configurée pour les ports de noeuds. (par défaut: 30000-32767)

cette exposition le service sur le port nodeport donné sur chaque noeud dans votre cluster. Puis j'ai mis en place une machine séparée sur le réseau interne qui exécute haproxy et un pare-feu qui est accessible extérieurement sur le(s) Port (s) nodeport (s) spécifié (s) que vous voulez exposer.

si vous regardez votre table nat sur l'un de vos hôtes, vous pouvez voir ce qu'elle fait.

root@kube01:~# kubectl create -f nginx-s.yaml
You have exposed your service on an external port on all nodes in your
cluster.  If you want to expose this service to the external internet, you may
need to set up firewall rules for the service port(s) (tcp:30000) to serve traffic.

See http://releases.k8s.io/HEAD/docs/user-guide/services-firewalls.md for more details.
services/nginx-s
root@kube01:~# iptables -L -t nat
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
KUBE-PORTALS-CONTAINER  all  --  anywhere             anywhere             /* handle ClusterIPs; NOTE: this must be before the NodePort rules */
DOCKER     all  --  anywhere             anywhere             ADDRTYPE match dst-type LOCAL
KUBE-NODEPORT-CONTAINER  all  --  anywhere             anywhere             ADDRTYPE match dst-type LOCAL /* handle service NodePorts; NOTE: this must be the last rule in the chain */

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
KUBE-PORTALS-HOST  all  --  anywhere             anywhere             /* handle ClusterIPs; NOTE: this must be before the NodePort rules */
DOCKER     all  --  anywhere            !127.0.0.0/8          ADDRTYPE match dst-type LOCAL
KUBE-NODEPORT-HOST  all  --  anywhere             anywhere             ADDRTYPE match dst-type LOCAL /* handle service NodePorts; NOTE: this must be the last rule in the chain */

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  172.17.0.0/16        anywhere

Chain DOCKER (2 references)
target     prot opt source               destination
RETURN     all  --  anywhere             anywhere

Chain KUBE-NODEPORT-CONTAINER (1 references)
target     prot opt source               destination
REDIRECT   tcp  --  anywhere             anywhere             /* default/nginx-s: */ tcp dpt:30000 redir ports 42422

Chain KUBE-NODEPORT-HOST (1 references)
target     prot opt source               destination
DNAT       tcp  --  anywhere             anywhere             /* default/nginx-s: */ tcp dpt:30000 to:169.55.21.75:42422

Chain KUBE-PORTALS-CONTAINER (1 references)
target     prot opt source               destination
REDIRECT   tcp  --  anywhere             192.168.3.1          /* default/kubernetes: */ tcp dpt:https redir ports 51751
REDIRECT   tcp  --  anywhere             192.168.3.192        /* default/nginx-s: */ tcp dpt:http redir ports 42422

Chain KUBE-PORTALS-HOST (1 references)
target     prot opt source               destination
DNAT       tcp  --  anywhere             192.168.3.1          /* default/kubernetes: */ tcp dpt:https to:169.55.21.75:51751
DNAT       tcp  --  anywhere             192.168.3.192        /* default/nginx-s: */ tcp dpt:http to:169.55.21.75:42422
root@kube01:~#

en particulier cette ligne

DNAT       tcp  --  anywhere             anywhere             /* default/nginx-s: */ tcp dpt:30000 to:169.55.21.75:42422

Et enfin, si vous regardez netstat, vous pouvez voir kube-proxy écoute et attend ce service sur ce port.

root@kube01:~# netstat -tupan | grep 42422
tcp6       0      0 :::42422                :::*                    LISTEN      20748/kube-proxy
root@kube01:~#

Kube-proxy écoutera sur un port pour chaque service, et fera la traduction d'adresse réseau dans votre sous-réseau virtuel que vos conteneurs résident. (Je pense?), J'ai utilisé de la flanelle.


pour un cluster à deux noeuds, que la configuration de HAproxy pourrait ressembler à ceci:

listen sampleservice 0.0.0.0:80
    mode http
    stats enable
    balance roundrobin
    option httpclose
    option forwardfor
    server noname 10.120.216.196:30000 check
    server noname 10.155.236.122:30000 check
    option httpchk HEAD /index.html HTTP/1.0

et votre service est maintenant accessible sur le port 80 via HAproxy. Si l'un de vos noeuds descend, les conteneurs seront déplacés vers un autre noeud grâce à des contrôleurs de réplication et HAproxy ne dirigera que vers vos noeuds qui sont vivants.

je suis curieux de savoir quelles méthodes les autres ont utilisées, c'est exactement ce que j'ai trouvé. Je ne Poste pas habituellement sur le débordement de pile, donc des excuses si Je ne suis pas les conventions ou le formatage approprié.

2
répondu Carlin 2016-05-05 00:15:37

c'est pour MrE. Je n'ai pas assez d'espace dans la zone de commentaires pour poster cette réponse, j'ai donc dû créer une autre réponse. Espérons que cela aide:

nous avons en fait déménagé loin de Kubernetes depuis l'affichage de cette réponse. Si je me souviens bien, tout ce que j'avais à faire était de lancer L'exécutable Kube-proxy sur une VM CentOS dédiée. Voici ce que j'ai fait:

J'ai d'abord retiré Firewalld et mis iptables en place. Kube-proxy s'appuie sur iptables pour gérer son NAT et les redirections.

Deuxièmement, vous devez installer flanneld de sorte que vous pouvez avoir un adaptateur de pont sur le même réseau que les services Docker fonctionnant sur vos minions.

ensuite, j'ai assigné plusieurs adresses ip à l'adaptateur réseau local installé sur la machine. Ce seront les adresses ip, vous pouvez utiliser lors de la configuration d'un service. Ce sont les adresses disponibles en dehors de votre cluster.

une fois que c'est tous ceux qui ont pris soin de vous peuvent commencer le service de procuration. Il se connectera au maître, et saisira une adresse IP pour le réseau du pont de flanelle. Ensuite, il synchronisera toutes les règles IPtables et vous devriez être défini. Chaque fois qu'un nouveau service est ajouté, il créera les règles de procuration et répliquera ces règles à travers tous les sous-fifres (et votre mandataire). Aussi longtemps que vous avez spécifié une adresse ip disponible sur votre serveur mandataire, ce serveur mandataire acheminera tout le trafic pour cette adresse ip vers le bon minion.

Espère que c'est un peu plus clair. Rappelez-vous bien que je n'ai pas participé au projet Kubernetes depuis environ 6 mois maintenant donc je ne suis pas sûr que ce qui a changé ont été faites depuis que je suis parti. Ils pourraient même avoir une fonctionnalité en place qui gère ce genre de chose. Si ce n'est pas avec un peu de chance, cela vous aidera à vous en occuper.

1
répondu Todd Spayde 2015-12-20 13:16:58

Vous pouvez utiliser d'entrée pour autoriser les connexions externes de l'extérieur d'un Kubernetes cluster pour atteindre les services de cluster.

en supposant que vous avez déjà un Pod déployé, vous avez maintenant besoin d'une ressource de Service, par exemple:

apiVersion: v1 kind: Service metadata: name: frontend-service labels: tier: frontend spec: type: ClusterIP selector: name: frontend-pod ports: - name: http protocol: TCP # the port that will be exposed by this service port: 8000 # port in a docker container; defaults to what "port" has set targetPort: 8000

et vous avez besoin d'une ressource: apiVersion: extensions/v1beta1 kind: Ingress metadata: name: frontend-ingress spec: rules: - host: foo.bar.com http: paths: - path: / backend: serviceName: frontend-service # the targetPort from service (the port inside a container) servicePort: 8000 Afin d'être en mesure d'utiliser les ressources Ingress, vous avez besoin de quelques ingress controller déployé.

maintenant, à condition que vous connaissiez votre adresse IP maître Kubernetes, vous pouvez accéder à votre application depuis l'extérieur d'un cluster Kubernetes avec: curl http://<master_ip>:80/ -H 'Host: foo.bar.com'


si vous utilisez un serveur DNS, Vous pouvez ajouter cet enregistrement: foo.bar.com IN A <master_ip> ou ajouter cette ligne à votre /etc/hosts fichier: <master_ip> foo.bar.com et maintenant vous pouvez juste exécuter: curl foo.bar.com


avis, que ce vous accéderez toujours à foo.bar.com en utilisant le port 80. Si vous voulez utiliser un autre port, je vous recommande d'utiliser un Service de type NodePort, seulement pour ce port pas-80. Il va rendre ce port résoluble, peu importe ce que Kubernetes VM IP vous utilisez (n'importe quel maître ou n'importe quel Minion IP est très bien). Exemple d'un tel Service: apiVersion: v1 kind: Service metadata: name: frontend-service-ssh labels: tier: frontend spec: type: NodePort selector: name: frontend-pod ports: - name: ssh targetPort: 22 port: 22 nodePort: 2222 protocol: TCP Et si vous avez <master_ip> foo.bar.com dans votre fichier / etc / hosts, alors vous pouvez accéder à: foo.bar.com:2222

0
répondu Ewa 2017-03-28 15:25:43