I am trying to figure out how the service discovery works in the Kubernetes cluster. Let's say I've got a service running in the cluster, but I don't know the IP or port. I assume the service discovery is the way to go.
Kubernetes DNS specification says that SRV record must be in the following format:
_<port>._<proto>.<service>.<ns>.svc.<zone>. <ttl> IN SRV <weight> <priority> <port-number> <service>.<ns>.svc.<zone>.
Example:
Question:
_https._tcp.kubernetes.default.svc.cluster.local. IN SRV
Answer:
_https._tcp.kubernetes.default.svc.cluster.local. 30 IN SRV 10 100 443 kubernetes.default.svc.cluster.local.
That implies the client needs to know the port (https=443) upfront to query for the port? It seems like it defeats the purpose of the SRV record. Why would the client query for SRV when the port is already known in the question and the only missing piece is the IP?
What am I missing? How to make this work when the discovering client only knows the name of the service and not the port?
SRV records facilitate service discovery by describing the protocol/s and address of certain services:
SRV Records are created for named ports that are part of normal or
Headless Services. For each named port, the SRV record would have the
form
_my-port-name._my-port-protocol.my-svc.my-namespace.svc.cluster-domain.example.
For a regular service, this resolves to the port number and the domain
name: my-svc.my-namespace.svc.cluster-domain.example. For a headless
service, this resolves to multiple answers, one for each pod that is
backing the service, and contains the port number and the domain name
of the pod of the form
auto-generated-name.my-svc.my-namespace.svc.cluster-domain.example.
An SRV record usually defines a symbolic name and the transport protocol (e.g., TCP) used as part of the domain name and defines the priority, weight, port, and target for a given service. For example:
_foo._tcp.example.com. 3600 IN SRV 10 100 5060 servicerecord.example.com
_foo is the service's symbolic name
_tcp is the transport protocol used by the service
the record has a priority of 10
the record has a weight of 100
5060 is the port and servicerecord.example.com is the hostname to connect to in order to communicate with the service
That implies the client needs to know the port (https=443) upfront to
query for the port?
No, the 443 is the answer and not a part of the question.
How to make this work when the discovering client only knows the name
of the service and not the port?
If the client knows the symbolic name of the service and the protocol than the port can be discovered.
Related
Obviously I could listen on a particular IP address, but is it possible to listen on a particular hostname? Specifically, if example1.com and example2.com both point to my server with IP address (say) 12.34.56.78, is it possible to proxy connections to example1.com:5432 to my postgres db, but have connections to example2.com:5432 be rejected?
I have a feeling the hostname is not passed in the initial connection, so it would be impossible to do what can be done with HTTP(S) (e.g. Nginx server block, Caddy, etc.).
No, that is not possible. The database server never sees the host name the client used. Domain Name Service (DNS) resolution of a host name to an IP address has to happen before the server can be contacted.
You will have to use two different IP addresses, for example by defining a second, virtual IP address for the server. You don't need to have a second network card.
https://github.com/coturn/coturn/blob/c4477bfddd2cd51de1ad37032ca88330f3c44ed6/docker/coturn/turnserver.conf#L100
In turnserver.conf , I see a world " For Amazon EC2 users", if the external-ip is only used for aws?
I let the stun server run in the k8s cluster, and then expose it to the public network with the nodeport service, but the srflx returned by stun is a gateway address, not the external-ip which I set. My k8s cluster runs on Alibaba Cloud.
I hope someone can help me solve this problem, thank you!!!
AWS EC2 instances, for the most part, run behind a NAT. Even if you've assigned a public IP address (e.g. 1.2.3.4) via the AWS Console, the instance only knows about the private network its on and is unaware of the public IP address assigned to it. That is, the instance thinks its IP address is 172.31.5.6 because that's what the Operating System discovered at boot time. Port forwarding enables certain TCP and UDP ports to be forwarded from the public IP address to the private IP address that the EC2 instance is running on.
This typically isn't a problem for most services run on an AWS EC2 instance. With STUN running in full "2 IP address and 2 port mode", the server needs to advertise its alternate IP address back to the client, should the client want to conduct NAT behavior and filtering tests. But it would be incorrect for the STUN server to send back 172.31.5.7 as its alternate IP - the client has no way of reaching that IP since its private.
Similarly for TURN, when port allocations occur, the server needs to send back the public IP address of the EC2 isntance to the client who allocated it. It would be bad if the client requested a TURN port to share with another peer - only for the TURN srever to send back 172.31.5.6.
Hence, for a STUN or TURN server to be hosted behind a NAT, a set of command line parameters or configuration parameters are needed to tell the server what its "real" IP addresses are. The STUN/TURN software will use these IP addresses for sending responses back to clients.
My Setup
I have some services that register with Eureka. This registration info is used by Zuul to route requests to my services. Most of these services run on a port like 9999 or 8080. Each service is on it's own EC2 instance, and I have Nginx routing requests from port 80 to the server's port, so that I can keep my Security Group rules simple.
My Problem
When my service registers with Eureka, it gets registered with ${server.port}, which ends up being 8080 or 9999, etc. When Zuul attempts to route to {ec2host}:8080, it gets blocked by my Security Group rules. Based on the documentation, it looks like I should be able to specify a host and port with eureka.instance.hostname and eureka.instance.nonSecurePort. Whether I use those properties or not, my service registers with it's specific port.
Is there a way to get the Eureka client to register my service with port 80, instead of the server's port?
I figured I could skip the resolving step by writing the IP address and port directly in the service name for each server, then browsing for my service by type. Are there any downsides to that?
In Smack API, there is a configuration class for connection, described at this page
ConnectionConfiguration
I am confused about the distinction between service name and server name.
Suppose I have a computer named "mybox.mydomain.com", and I have ejabberd on it with a configured host called "myhost" (using the line {hosts, ["myhost"]}. in ejabbed.cfg),
what is the host name, server name and service name in this case?
myhost: service name (or XMPP domain)
mybox.mydomain.com: hostname and servername.
You can host an XMPP domain over any host, provided that you set the SRV records right in the DNS or if the client specifies to which host it is supposed to connect (like email).
Think of the JID you're using to log in, which contains username # domain. The domain is the logical name of the service you are using. For some services, like jabber.org, the service is run on a box that has the same name as the service. For many others, like WebEx Connect and GoogleTalk, the service domain is a starting point to figure out where to open a socket to, but not the name of the machine. If everything is set up right, you can look up the name of the machine to connect to in the DNS using an SRV record. For example, using dig:
$ dig +short -t SRV _xmpp-server._tcp.gmail.com
20 0 5269 xmpp-server4.l.google.com.
20 0 5269 xmpp-server2.l.google.com.
20 0 5269 xmpp-server1.l.google.com.
5 0 5269 xmpp-server.l.google.com.
20 0 5269 xmpp-server3.l.google.com.
If the service domain is not configured correctly in the DNS, or you're just testing things out, it's often useful to be able to specify this connect host separately from the domain. So for your example, you would use:
ConnectionConfiguration("mybox.mydomain.com",
5222,
"myhost");
If you ever want this service to be accessed by people off of your network (either client-to-server or server-to-server), it would make sense to rename your service domain to be something fully-qualified, to which you can attach SRV records for those external entities to use.