servicios - ¿Cómo exponer el servicio de kubernetes al público sin codificación para miniar IP?
requerimientos para instalar kubernetes (5)
Como dijo Robert en su respuesta, esto es algo que se avecina, pero desafortunadamente todavía no está disponible.
Actualmente estoy ejecutando un clúster Kubernetes en nuestra red de centros de datos. Tengo 1 maestro y 3 minions todos corriendo en CentOS 7 virtuales (vcenter). La forma en que manejé esto fue crear un servidor dedicado "kube-proxy". Básicamente, solo ejecuto el servicio Kube-Proxy (junto con Flannel para redes) y luego asigno direcciones IP "públicas" al adaptador de red conectado a este servidor. Cuando digo público me refiero a direcciones en nuestra red de centros de datos locales. Luego, cuando creo un servicio al que me gustaría acceder fuera del clúster, simplemente establezco el valor de publicIPs en una de las direcciones IP disponibles en el servidor proxy de Kube. Cuando alguien o algo intenta conectarse a este servicio desde fuera del clúster, llegará al proxy kube y luego será redirigido al siervo adecuado.
Si bien esto puede parecer una solución alternativa, en realidad es similar a lo que esperaría que sucediera una vez que hayan encontrado una solución integrada para este problema.
Tengo un grupo de kubernetes corriendo con 2 minions. Actualmente hago accesible mi servicio en 2 pasos:
- Iniciar el controlador de replicación y el pod
- Obtenga minion IP (usando
kubectl get minions
) y configúrelo como publicIPs para el Servicio.
¿Cuál es la práctica sugerida para exponer el servicio al público? Mi enfoque parece incorrecto porque codifico las IP-s de los IP-s de minions individuales. También parece pasar por alto las capacidades de equilibrio de carga de los servicios kubernetes porque los clientes tendrían que acceder a los servicios que se ejecutan directamente en los minions individuales.
Para configurar el controlador de replicación y el pod utilizo:
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
Para configurar el servicio (después de obtener 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]
Como mencioné en el comentario anterior, createExternalLoadBalancer es la abstracción adecuada que está buscando, pero desafortunadamente aún no está implementado para todos los proveedores de la nube, y en particular para vagrant, que está utilizando localmente.
Una opción sería usar las direcciones IP públicas para todos los minions en su grupo para todos los servicios que desea que se externalicen. El tráfico destinado al servicio terminará en uno de los minions, donde será interceptado por el proceso kube-proxy y redirigido a un pod que coincida con el selector de etiquetas para el servicio. Esto podría resultar en un salto adicional a través de la red (si aterriza en un nodo que no tiene el pod ejecutándose localmente) pero para las aplicaciones que no son extremadamente sensibles a la latencia de la red, esto probablemente no se notará.
Esto es para MrE. No tenía suficiente espacio en el área de comentarios para publicar esta respuesta, así que tuve que crear otra respuesta. Espero que esto ayude:
Nos hemos alejado de Kubernetes desde que publicamos esta respuesta. Si recuerdo correctamente, todo lo que tenía que hacer era ejecutar el ejecutable kube-proxy en una máquina virtual CentOS dedicada. Aquí esta lo que hice:
Primero quité Firewalld y puse iptables en su lugar. Kube-proxy se basa en iptables para manejar su redirección y NAT.
En segundo lugar, debes instalar flanneld para poder tener un adaptador de puente en la misma red que los servicios de Docker que se ejecutan en tus minions.
Entonces, lo que hice fue asignar varias direcciones IP al adaptador de red local instalado en la máquina. Estas serán las direcciones IP que puede utilizar al configurar un servicio. Estas serán las direcciones disponibles FUERA de su grupo.
Una vez que todo esté cuidado, puede iniciar el servicio proxy. Se conectará al maestro y tomará una dirección IP para la red del puente de franela. Luego sincronizará todas las reglas de IPtables y deberás configurarlas. Cada vez que se agrega un nuevo servicio, creará las reglas de proxy y replicará esas reglas en todos los minions (y su proxy). Siempre que haya especificado una dirección IP disponible en su servidor proxy, ese servidor proxy reenviará todo el tráfico para esa dirección IP al servidor correspondiente.
Espero que esto sea un poco más claro. Recuerde que no he sido parte del proyecto Kubernetes durante aproximadamente 6 meses, así que no estoy seguro de qué cambios se han hecho desde que me fui. Incluso pueden tener una característica en su lugar que maneja este tipo de cosas. Si no es de esperar, esto te ayuda a cuidarlo.
Puede utilizar el recurso Ingress para permitir que las conexiones externas desde fuera de un clúster Kubernetes lleguen a los servicios del clúster.
Suponiendo que ya tiene un Pod desplegado, ahora necesita un recurso de Servicio, por ejemplo:
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
Y necesita un recurso de 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
Para poder utilizar los recursos de Ingress, necesita un controlador de ingreso implementado.
Ahora, siempre que conozca su IP maestra Kubernetes, puede acceder a su aplicación desde fuera de un clúster Kubernetes con: curl http://<master_ip>:80/ -H ''Host: foo.bar.com''
Si usa algún servidor DNS, puede agregar este registro: foo.bar.com IN A <master_ip>
o agregar esta línea a su /etc/hosts
: <master_ip> foo.bar.com
y ahora solo puede ejecutar: curl foo.bar.com
Tenga en cuenta que de esta manera siempre foo.bar.com
a foo.bar.com
usando el puerto 80. Si desea usar algún otro puerto, le recomiendo usar un Servicio de tipo NodePort, solo para ese puerto que no sea 80. Hará que el puerto se pueda resolver, independientemente de la IP de Kubernetes VM que uses (cualquier Master o cualquier Minion IP está bien). Ejemplo de un servicio de este tipo: 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
Y si tiene <master_ip> foo.bar.com
en su archivo / etc / hosts, entonces puede acceder a: foo.bar.com:2222
Si está ejecutando un clúster localmente, una solución que utilicé fue exponer el servicio en sus nodos kubernetes mediante la directiva nodeport en su definición de servicio y luego redirigir a todos los nodos de su clúster con HAproxy.
Aquí es cómo se ve la exposición del nodo:
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
Nota: el valor que especifique debe estar dentro del rango configurado para los puertos de nodo. (predeterminado: 30000-32767)
Esto expone el servicio en el puerto de nodo dado en cada nodo de su grupo. Luego, configuro una máquina separada en la red interna que ejecuta haproxy y un firewall al que se puede acceder externamente en los puertos de puertos específicos que desea exponer.
Si observa su tabla nat en uno de sus hosts, puede ver lo que está haciendo.
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:~#
Particularmente esta linea
DNAT tcp -- anywhere anywhere /* default/nginx-s: */ tcp dpt:30000 to:169.55.21.75:42422
Y finalmente, si miras netstat, puedes ver que kube-proxy está escuchando y esperando ese servicio en ese puerto.
root@kube01:~# netstat -tupan | grep 42422
tcp6 0 0 :::42422 :::* LISTEN 20748/kube-proxy
root@kube01:~#
Kube-proxy escuchará en un puerto para cada servicio y realizará la traducción de la dirección de red a su subred virtual en la que residen sus contenedores. (¿Creo?) Usé franela.
Para un clúster de dos nodos, la configuración de HAproxy puede parecer similar a esto:
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
Y su servicio ahora es accesible en el puerto 80 a través de HAproxy. Si alguno de sus nodos se cae, los contenedores se moverán a otro nodo gracias a los controladores de replicación y HAproxy solo se enrutará a los nodos que estén vivos.
Sin embargo, tengo curiosidad por saber qué métodos han usado otros, eso es justo lo que se me ocurrió. Normalmente no publico en el desbordamiento de pila, así que disculpas si no sigo las convenciones o el formato correcto.