Consul service definition json is as follows
{
"Address": "192.168.10.10",
"TaggedAddresses": {
"lan": "192.168.10.10",
"wan": "10.0.10.10"
},
"CreateIndex": 51,
"ModifyIndex": 51,
"Node": "foobar",
"ServiceAddress": "172.17.0.3",
"ServiceEnableTagOverride": false,
"ServiceID": "32a2a47f7992:nodea:5000",
"ServiceName": "foobar",
"ServicePort": 5000,
"ServiceTags": [
"tacos"
]
}
Now as per the documentation provided at https://www.consul.io/docs/agent/http/catalog.html#catalog_service
the definition of address and service address is as follows:
Address: IP address of the Consul node on which the service is
registered
ServiceAddress: IP address of the service host — if empty, node
address should be used
A. Does this mean Address is the address of consul server node and service address is address of the node where service resides?
OR
B. Does this mean Address is the address of consul agent residing with the service. If this is the case does this mean address and service address are same?
which of the above is correct?
I suppose, that Address is the address of consul agent and ServiceAddress is the address which is used to access this service. This can be the same addresses, but they can also differ.
For example, you can have a single host with a number of interfaces, one of them is used to make Consul agents interact with each other, and another one is used to access your service.
Or you can have a single node with a number of microservices deployed with Docker. You can start a single Consul Agent with this node's address, and register a number of microservices running in containers and communicated with each other by container inner IP-addresses. In that case, you will get service info where Address is equals to node's IP and ServiceAddress is equals to the IP of the container with service.
Related
I was starting with the Google Cloud Platform's microservice demo. And I was curious how gRPC stubs work when the services are deployed in containers.
As far as my understanding goes, the container of a particular service are addressed by the Service IP specified in the YAML configuration file. So the gRPC server of a service must listen at the service IP? But I came across the following snippet of code:
l, err := net.Listen("tcp", fmt.Sprintf(":%s", port))
if err != nil {
log.Fatal(err)
}
I am wondering how does the server listen to an address without an IP?
:{port} isn't an "address without an IP".
The documentation for Listen includes "if the host in the address parameter is empty or a literal unspecified IP address, Listen listens on all available unicast and anycast IP addresses of the local system".
So, in this case, without a host address, the effective address would be 0.0.0.0 which corresponds to all interfaces. Corollary a common mistake people make when using containers is to bind their code to localhost (127.0.0.1) which cannot be accessed from outside the container.
Using 0.0.0.0 is a common (good) practice, particularly when using containers, as it effectively delegates address binding to the container runtime.
So, your app runs on {port} on all interfaces within the container. The container runtime then binds (one of more of) these interfaces to the host's interface(s) and your e.g. client code connects to the host's IP address.
When your container is being managed by Kubernetes, Kubernetes assigns IP address(es) to the containers running your app and these are often exposed to other services using a Kubernetes Service resource which not only has an IP address but also a cluster DNS.
The Kubernetes YAML probably specifies a Service DNS.
Kubernetes resolves requests to the DNS name to a selected container (IP and port)
The container runtime routes incoming requests on the host's port to the container's port
Your gRPC server will accept traffic from the container runtime on any interface that's on the {port} that you've defined it to net.Listen on.
According to Alibaba Cloud EipAddress Allocation.
An available EIP is randomly allocated in the specified region after this API is called. EIP supports ICMP, TCP, and UDP protocols, but does not support IGMP and SCTP protocols.
I create an EipAddress on Alibaba Cloud VPC using below mentioned Request code:
https://vpc.aliyuncs.com/?Action=AllocateEipAddress
&RegionId=cn-beijing
&CommonParameters
How I can know which IP is assigned to my vpc.
If you want to know which IP address is created try this API call.
https://vpc.aliyuncs.com/?Action=DescribePublicIpAddress
&RegionId=cn-beijing
&<CommonParameters>
Here is sample response.
{
“RequestId”:” 365F4154-92F6-4AE4-92F8-7FF34B540710”,
“Code”:200,
“Success”:”true/false”,
“PublicIpAddress”:[
“110.11.1.0/24”
],
“RegionId”:”cn-beijing”,
“PageNumber”:1,
“PageSize”:100,
“TotalCount”:1000
}
From documentation https://www.alibabacloud.com/help/doc-detail/65592.htm?spm=a2c63.p38356.b99.76.667b30a6zlzLJZ
You can check which IP address is assigned by calling the following API Request:
Request:
https://vpc.aliyuncs.com/?Action=DescribePublicIpAddress
&RegionId=cn-beijing
Please replace your RegionID if you are using it in a different region.
The Action DescribePublicIpAddress is used to query the IP address range in a specified region.
Response:
{
“RequestId”:” 123425345345252”,
“Code”:200,
“Success”:”true”,
“PublicIpAddress”:[
“111.10.1.0/24”
],
“RegionId”:”cn-beijing”,
}
I am very new to consul and have registered a service with consul with following configuration.
{"service": {"name": "wrapper", "tags": ["consul-wrapper"], "port":8000,"address":"127.0.0.1",}}
I have also set up dnsmasq so that dns queries get resolved by consul server running on 127.0.0.1:8600
Now whenever I try to access my service like wrapper.service.consul it gets resolved and goes to port 80 instead of 8000.
What am i missing here?
You have to ask DNS specifically for the port number... it's an SRV request.
by default DNS queries are A(or AAA for ipv6) queries, and you just get the IP address.
try asking for the SRV record directly like so:
dig SRV wrapper.service.consul
Note: I am not asking about Consul HTTP port 8500. Can I call an API exposed by a microservice, which is discovered using Consul, just by the .service.consul/ WITHOUT specifying the port number?
I am using Consul for discovering multiple versions of a microservice. This microservice (written in Java) has port predetermined:
Service registered in consul as - my-service.service.consul (service port is, let us say 3030). I have another version of the same micro service registered with consul: my-servicev2.service.consul (port 3033).
Service definition (altered for the example):
{
"Address": <IP address>,
"CreateIndex": 111,
"ModifyIndex": 000,
"Node": <node name>,
"ServiceAddress": "",
"ServiceEnableTagOverride": false,
"ServiceID": "my-servicev2",
"ServiceName": "my-servicev2",
"ServicePort": 3033,
"ServiceTags": [
"v2"
],
"TaggedAddresses": {
"lan": <LAN IP>,
"wan": <WAN IP>
}
}
I can ping and dig the service using dig #localhost my-service.service.consul' orping -c2 my-service.service.consul`
But, how can I access one of the APIs exposed by this microservice without explicitly using the ServicePort?
Here is what is working:
curl http://my-servicev2.service.consul:3033/health -> resolves the service name, maps it to one of the deployed VM IP, and gives back the API response. In this case something like: `{"build"`: 'OK"}`
However, I should be able to access the API without specifying the port number like this:
curl http://my-servicev2.service.consul/health ->{"build": "OK"}`
Is this possible in Consul?
I've tried registering the service without Port value, and it added 0 as port value.
No in this case consul is acting purely as a DNS server and returning a healthy instance's ip address. As you have seen with your dig and ping commands.
You have to specify port as you did with your curl call.
To hack this you could modify your application to run on http default port 80.
If this is not possible you can setup what is known as a reverse proxy.
Nginx works great for this. Here is a snippet of a configuration that will allow you to handle this:
location / {
proxy_pass http://127.0.0.1:3033;
}
This will pass all your port 80 calls to localhost port 3033. Then your curl calls would work as expected without specifying port.
Imagine a Windows box, which:
hosts a WCF service
has multiple NICs
sits behind NAT
When a user issues a request to the service (on top of the WCF infrastructure), he uses the external address assigned to the target machine by the NAT.
I have to write some piece of code inside the WCF service, which must know which of the several NICs that the machine has was used to actually handle the network traffic. How does this code identify the NIC is less important - it could be its MAC address (the best) or it could be the (internal) IP address of the NIC.
How can I do it?
EDIT1
I will try to supply the question context. There are two agents. Both expose the same WCF service. In addition, one of the agents can be instructed to start probing the network towards the second agent in the following fashion:
Agent A is asked to probe the network to agent B
Agent A negotiates with agent B the UDP port to utilize for the sake of probing using the WCF service exposed by the agent B.
Once negotiation is over, the agent A starts some custom protocol over UDP, where the agent B acts as the server - i.e. it binds to the UDP port negotiated in the previous item.
Binding to a UDP port requires two pieces - the IP address and UDP port, where the IP address can either be a specific IP address or * (to bind to all the IP addresses associated with the machine). The latter option is not good for us - I will omit the reasons. This leaves us the former option - binding to the specific IP address. However, when the agent B is behind NAT, the IP address used to talk to the WCF service is the external IP address assigned to the agent by the NAT. Binding, on the other hand, requires the respective internal IP address - how to get it?
Can you check the OperationContext.Current.Channel.LocalAddress (it's an EndpointAddress) inside a WCF operation?
As a side note, getting the remote address can be done with:
OperationContext context = OperationContext.Current;
MessageProperties prop = context.IncomingMessageProperties;
RemoteEndpointMessageProperty endpoint =
prop[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;
string ip = endpoint.Address;
--larsw
To get the MAC use
System.Net.NetworkInformation.NetworkInterface.GetPhysicalAddress();
All Nics:
System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces();
to find out what is the real listening ip address you can write a code that listen to your port on each address and ping it from an agent emulator to see that the address is valid.
Cheers,
Gilad