J'ai un cluster kubernetes fonctionnant avec 2 serviteurs. Actuellement, je rend mon service accessible en 2 étapes:
kubectl get minions
) et définissez-le comme publicIPs pour le service.Quelle est la pratique suggérée pour exposer le service au public? Mon approche semble erronée car je code en dur les IP des IP de sbires individuels. Il semble également contourner les capacités d'équilibrage de charge des services kubernetes car les clients devraient accéder directement aux services s'exécutant sur des serviteurs individuels.
Pour configurer le contrôleur de réplication et le module que 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 configurer le service (après avoir obtenu les ip des sbires):
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]
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 consisterait à utiliser les adresses IP publiques pour tous les serviteurs de votre cluster pour tous les services que vous souhaitez externaliser. Le trafic destiné au service se retrouvera sur l'un des serviteurs, où il sera intercepté par le processus kube-proxy et redirigé vers un pod qui correspond au sélecteur d'étiquettes pour le service. Cela pourrait entraîner un bond supplémentaire sur le réseau (si vous atterrissez sur un nœud sur lequel le pod n'est pas 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.
Comme Robert l'a dit 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 centre de données. J'ai 1 maître et 3 sbires fonctionnant tous sur des systèmes virtuels CentOS 7 (vcenter). La façon dont j'ai géré cela était de créer un serveur "kube-proxy" dédié. En gros, j'exécute simplement le service Kube-Proxy (avec Flannel pour la mise en réseau), puis j'attribue des adresses IP "publiques" à la carte réseau connectée à ce serveur. Quand je dis public, je veux dire des adresses sur notre réseau de centre de données local. Ensuite, lorsque je crée un service auquel j'aimerais accéder en dehors du cluster, je définis simplement la valeur publicIPs sur l'une des adresses IP disponibles sur le serveur proxy de cube. Quand quelqu'un ou quelque chose tente de se connecter à ce service depuis l'extérieur du cluster, il va frapper le proxy de cube, puis être redirigé vers le serviteur approprié.
Bien que cela puisse sembler être une solution de contournement, cela est en fait similaire à ce à quoi je m'attendrais une fois qu'ils auront trouvé une solution intégrée à ce problème.
Si vous exécutez un cluster localement, une solution que j'ai utilisée consistait à exposer le service sur vos nœuds kubernetes à l'aide de la directive nodeport dans votre définition de service, puis à effectuer un round robin sur chaque nœud de 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
Remarque: la valeur que vous spécifiez doit se situer dans la plage configurée pour les ports de noeud. (par défaut: 30000-32767)
Cela expose le service sur le port de nœud donné sur chaque nœud de votre cluster. Ensuite, j'ai configuré une machine distincte sur le réseau interne exécutant haproxy et un pare-feu accessible en externe sur le ou les ports de noeud spécifiés que vous souhaitez 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 que 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 des adresses réseau dans votre sous-réseau virtuel dans lequel vos conteneurs résident. (Je pense?) J'ai utilisé de la flanelle.
Pour un cluster à deux nœuds, cette configuration HAproxy peut 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 désormais accessible sur le port 80 via HAproxy. Si l'un de vos nœuds tombe en panne, les conteneurs seront déplacés vers un autre nœud grâce aux contrôleurs de réplication et HAproxy ne routera que vers vos nœuds vivants.
Je suis curieux de savoir quelles méthodes les autres ont utilisées, c'est juste ce que j'ai trouvé. Je ne poste généralement pas sur le débordement de la pile, donc je m'excuse si je ne respecte pas les conventions ou le formatage approprié.
C'est pour MrE. Je n'avais pas assez d'espace dans la zone des commentaires pour poster cette réponse, j'ai donc dû créer une autre réponse. J'espère que cela t'aides:
Nous avons en fait quitté Kubernetes depuis la publication de cette réponse. Si je me souviens bien, je n'avais qu'à exécuter l'exécutable kube-proxy sur une machine virtuelle CentOS dédiée. Voici ce que j'ai fait:
J'ai d'abord supprimé Firewalld et mis en place iptables. Kube-proxy s'appuie sur iptables pour gérer ses NAT et redirections.
Deuxièmement, vous devez installer flanneld afin d'avoir un adaptateur de pont sur le même réseau que les services Docker exécutés sur vos serviteurs.
Ensuite, j'ai attribué plusieurs adresses IP à la carte réseau locale installée sur la machine. Ce seront les adresses IP que vous pourrez utiliser lors de la configuration d'un service. Ce seront les adresses disponibles EN DEHORS de votre cluster.
Une fois que tout est réglé, vous pouvez démarrer le service proxy. Il se connectera au maître et récupérera une adresse IP pour le réseau de 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 proxy et répliquera ces règles sur tous les serviteurs (et votre proxy). Tant que vous avez spécifié une adresse IP disponible sur votre serveur proxy, ce serveur proxy transmettra tout le trafic pour cette adresse IP au serviteur approprié.
J'espère que c'est un peu plus clair. N'oubliez pas que je ne fais pas partie du projet Kubernetes depuis environ 6 mois maintenant, donc je ne sais pas ce qui a changé depuis mon départ. Ils pourraient même avoir une fonctionnalité en place qui gère ce genre de chose. Si ce n'est pas à espérer, cela vous aidera à le prendre en charge.
Vous pouvez utiliser la ressource Ingress pour permettre aux connexions externes de l'extérieur d'un cluster Kubernetes d'atteindre les services du cluster.
En supposant que vous avez déjà déployé un pod, 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 Ingress: 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
Pour pouvoir utiliser les ressources Ingress, vous avez besoin de contrôleur d'entrée déployé.
Maintenant, à condition que vous connaissiez votre 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 fichier /etc/hosts
: <master_ip> foo.bar.com
Et maintenant vous pouvez simplement exécuter: curl foo.bar.com
Notez que de cette façon, vous accéderez toujours à foo.bar.com
En utilisant le port 80. Si vous voulez utiliser un autre port, je recommande d'utiliser un service de type NodePort, uniquement pour ce port non 80. Cela rendra ce port résolvable, peu importe quelle Kubernetes VM IP vous utilisez (n'importe quel IP maître ou minion 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 avoir <master_ip> foo.bar.com
dans votre fichier/etc/hosts, alors vous pouvez accéder à: foo.bar.com:2222