-
Notifications
You must be signed in to change notification settings - Fork 134
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Registering containers as separate nodes in consul #162
Comments
+1 For me this occurs when Triton containers are removed or fail. I will also see multiple containers on the same node within the consul UI. |
Few days ago, I made some comtainer that include both the containerpilot and consul. If you want register the container as a consul node, please try it. In the dockerfile, entrypoint should contain some shell script that include running consul node for containerpilot's argument. And the consul will execute itself as a foreground, so you can't execute some apllication what you want. So, you can use nohup for consul. |
@jgillis01 someone at a asked me about this offline recently and I'm going to admit I'm a little unclear as to what we're doing wrong here. But obviously the behavior you're describing isn't ideal. We're currently using Should we be using
Do you have a minimal test case I could use to exercise the bad behavior so we can verify this? |
The documentation seems to suggest that the agent endpoint is used to interact with a consul agent running locally on the node:
I agree the catalog endpoint should not be used to register services due to the health check restrictions:
The following steps can be used to reproduce the behavior I am experiencing:
Navigating to the consul ui on one of the other consul nodes, I notice the first consul node state is failing the serf health check, and the service health check still reports the last known health of the service. At this point, changes to the service container state are not seen by consul since containerpilot is trying to communicate (report health check results) with a non-existent consul node. |
@jgillis01 I want to dive into this but I'll be on the road the next couple days so it might take until later this week to get back to you. In the meantime, are you deploying on Triton or on another platform? |
@tgross I am deploying on Triton |
@tgross - I think I had harassed you at ContainerSummit Vegas about this. tl;dr It's a SPOF that we would like to stomp out. We are in Joyent PC as well as our own SDC install on our gear. We've a team of people ready to work the issue, I just want to make sure we are working together in the right direction. |
@zadunn @jgillis01 how are you discovering Consul? Is it via a Docker link or CNS name? If ContainerPilot is connecting to the Consul cluster via CNS service name (I'm playing with apps connected to consul.svc.d42e7882-89d2-459e-bc0a-e9af0bca409c.us-sw-1.cns.joyent.com now), it will connect to any available Consul instance. Doesn't that eliminate the SPOF issues? |
@misterbisson right now we're injecting the ip of the consul node as an env var into all the containerpilot containers. From a code perspective, we could easily switch that to injecting a CNS name. I don't really understand networking protocols in any detail, so @zdunn or @jgillis01 will need to answer the latter question for you. Would containerpilot connecting to any instance mean that the service information containerpilot registered on one node got "consensus'd" to the others? Or does it mean that if the node stuff is registered on fails, it won't have a hard time finding another? And if the latter, is containerpilot set up to know what to do in that situation? |
@yarmiganosca ah, yes. Linking by IP number or Docker links can be problematic. Take a look at this alternative that uses Triton Container Name Service (CNS): We give Consul a label that names the CNS service, https://github.com/autopilotpattern/wordpress/blob/master/docker-compose.yml#L80 We can then set an environment var that identifies the Consul service by DNS. This is the pattern for our public cloud: https://github.com/autopilotpattern/wordpress/blob/master/setup.sh#L176 Learn more about Triton CNS: https://www.joyent.com/blog/introducing-triton-container-name-service |
@misterbisson we're not using Docker Networking links. We're just injecting the env var into the container at runtime and interpolating it into the containerpilot config file. As to my questions about the HA properties of your solution, do you have any further information? |
@misterbisson So our issue isn't so much of one at boot can we speak to consul. It's the fact that the services that are created by container pilot are pnned to a single consul node. So if that CONSUL node goes away, our service "fails". Which in the autopilot pattern is going to kick off a bunch of changes. This is a lot different than the standard consul-template method of registering as a node in the cluster, then registering services onto yourself. With that pattern we are part of the cluster, and a consul server node failing doesn't cause a freak out (insert appropriate .wav here). So we have two concerns:
|
EDIT: |
On reading the Consul documentation carefully, Consul expects to have local agents in each server/container/vm. I'm not sure there is a way to express the behaviour we want without running a consul agent in each container (which I did in my vault-containerpilot docker image). CONSUL AGENTThe Consul agent is the core process of Consul. The agent maintains membership information, registers services, runs checks, responds to queries, and more. The agent must run on every node that is part of a Consul cluster. Any agent may run in one of two modes: client or server. A server node takes on the additional responsibility of being part of the consensus quorum. These nodes take part in Raft and provide strong consistency and availability in the case of failure. The higher burden on the server nodes means that usually they should be run on dedicated instances -- they are more resource intensive than a client node. Client nodes make up the majority of the cluster, and they are very lightweight as they interface with the server nodes for most operations and maintain very little state of their own. |
What about registering all services in all Consul nodes? It is very hacky but will provide the desired resiliency. |
I've had a chance to dig into this now and @zadunn has described the problem well at this point:
And I think @mterron has hit the root of the problem on the head:
Although the data about the service is replicated via the raft to all nodes, Consul includes data about what agent you've registered with. So we need to come up with a workaround for that. I suspect but haven't proved yet that we can do this by using the catalog API directly. I'll be attempting this today and maybe try to reach out to some folks at Hashicorp to see what they would suggest, given that this is a non-standard topology for them. @mterron wrote:
In the environment where this is a problem, we typically are going to be using CNS/DNS to reach the Consul cluster, so we probably don't have a good way to enumerate all the nodes. |
@jgillis01 is trying an experiment using containerpilot to start consul We would also have issue of managing of all the parts needed for consul |
Yeah another similar approach could be if ContainerPilot was acting as a Consul client node instead of as a HTTP client (this distinction is a little weird but check out the docs for details). We'd get the same effect, but we'd have special-cased Consul behaviors to an extent I'm not comfortable with for portability's sake. I'm currently digging into catalog API and seeing whether we can live without anti-entropy in this use case. Edit: we wouldn't lose anti-entropy entirely, as the agents would still run it periodically depending on cluster size. |
@tgross @zadunn I can confirm that having containerpilot start a supervisord process which manages a consul agent and service shows the desired behavior. From there you just point containerpilot to the agent running on the local node. Telemetry and health checks still work the same. If the service is terminated (not SIGTERM), supervisord will restart it. |
Ok, good to hear that there's a workaround that works for you. Lots of folks don't want to run multi-process containers w/ a supervisor, though, so I'm still going to see if we can come up with a workaround inside the ContainerPilot. |
I'm getting somewhere on this. The {
"Datacenter": "dc1",
"Node": "triton",
"Address": "192.168.10.10",
"Service": {
"ID": "redis1",
"Service": "redis",
"Tags": [
"master",
"v1"
],
"Address": "127.0.0.1",
"TaggedAddresses": {
"wan": "127.0.0.1"
},
"Port": 8000
},
"Check": {
"Node": "triton",
"CheckID": "service:redis1",
"Name": "Redis health check",
"Notes": "Script based health check",
"Status": "passing",
"ServiceID": "redis1"
}
} |
I've opened this post in the Hashicorp Consul mailing list to get suggestions: https://groups.google.com/forum/#!topic/consul-tool/09OkySyoSnA
|
@tgross - I am not seeing any real activity on the mailing list for this issue. Have you been able to get any ones attention on this? |
@zadunn You're right about the mailing list thread. If you want to help bump the issue there or in Twitter, it can't hurt. @tgross outlined some options with Consul above, but he's been exploring what it would take to do everything via Etcd while we've been waiting for feedback on the Consul questions above. We have not had a chance to dig into the Consul code deeply enough to understand the implications of incorporating that in ContainerPilot so that it behaves like and appears to be a Consul agent. Perhaps you're in a position to look at that? |
While I certainly would prefer to get Consul working because I like it better, autopilotpattern/etcd#1 has an initial pass at making sure we have a working etcd implementation on Triton. I'll give a couple of our blueprints a try against this cluster to make sure the semantics are we expect. Addendum getting #171 (comment) done would help us out with |
I've been thinking about this one and have 3 alternatives to suggest:
Hope this helps to start exploring a solution. Cheers |
While that would be an interesting project, it means giving up all portability. We want to be able to support
I raised that suggestion in the thread on the Consul mailing group, but without adding the complexity of incorporating this behavior into ContainerPilot. You could just have a process tree like this:
If we wanted to bake any behavior into ContainerPilot itself then we'd do it as library code where the Consul backend spins up a goroutine and does the Consul RPC work there. I've looked into this a little bit and it is a lot of extra work but it's doable. And in any case, if we were to go down this path I'd recommend that we have a second Consul backend (call it
It's not enough to register them, you also have to send health checks to all of them. Assuming the Consul API will actually allow us to do this (I'm not sure it will), this means we have to do a lookup of the A-Record that CNS gives us and then send to all of them. Also, how do we handle partial partitions? Will we have a race where one Consul server is saying we're unhealthy and the other is saying we're healthy (Consul is CP but we don't know whether the TTL API call is what's synced on the raft or whether the state of the instance is what's synced)? |
Update on this from Hashicorp hashicorp/consul#2089:
|
Tim, why do you think about TNS for this? You can do pure Consul HTTP for the query and use the .node.consul addresses for updating the TTL. I don't think the problem is Triton related at all, it will happen in any environment. I can see how this will put a high load on the servers, so I'll keep building multi process containers, but thanks for pushing the conversation forward. |
Sure but then you need to track changes to the .node.consul addresses and expire them too. I guess you could do that via a
It'll happen in any environment where you're using a CNAME to reach Consul. But the typical deployment scenario they envision is having an agent on the local machine (i.e. in the container or on the host where your apps live) which you can reach over localhost. This way the application is guaranteed to hit the same Consul agent. But this doesn't work on Triton or any PaaS unless you pack Consul in the container. |
Here's a demonstration of using |
Here's a demonstration of having an HA etcd deployment using ContainerPilot, for those who want to go down that path instead: autopilotpattern/etcd#1 |
I've opened #174 so that we have some documentation on this issue. |
Hi guys, And my problem is that I would want to shut down one of my Consul Servers and to do that I need to deregister all my Triton instances that are using that server as an agent and register them elsewhere onto a different "server/agent". Basically restarting all those healthy services so that they can jump to a different agent. A solution would be to register services via the Another solution, which @tgross already mentioned, is to make Containerpilot act as a Consul Agent node, which in my opinion would be the best solution. Running the Consul Agent as an extra process in my container is currently what comes closest to what Consul expects, but it introduces complexity and maintenance I would rather be without. |
@fannarsh thanks for the link to that thread. https://github.com/jmcarbo/consul-externalservice looks like a promising workaround and small enough in scope that maybe we could incorporate it directly into a ContainerPilot backend. Edit: still has a localhost Consul but it looks like that shouldn't be a limitation.
Yeah, this is an accurate summary of the problem.
I don't think we should be willing to give up health checks. |
Some more digging into this if we wanted to go down the road of having ContainerPilot participate as a Consul agent: I've traced how the agent updates the servers (via serf) to here. So the agents just use the RPC equivalent of It'd be trivial to maintain the TTL state in ContainerPilot to do this, but then we'd just have the last problem to solve of what happens when our fake Consul agent disappears because we stopped the container. Our agent also needs to participate in the LAN gossip pool. |
@tgross is it fair to summarize your your point in #162 (comment) as follows? The Consul catalog knows that a service is unhealthy because:
You're feeling confident about the feasibility of item 1, but item 2 is more complex and requires more research to have confidence about? |
That's exactly correct. |
In the interest of saving folks some research, I've been thru the source of every tool in https://www.consul.io/downloads_tools.html and done a bunch of digging on my own and haven't found a single alternate implementation of the serf membership protocol that we might be able to borrow w/o lifting large chunks of Consul into ContainerPilot. That being said, much of the low-level work is being done in https://github.com/hashicorp/memberlist and then the Consul agent package is putting some higher-level behaviors on top of that. |
I've spent the last two days looking into whether we could make ContainerPilot join as a Consul agent, and while it's just barely technically feasible, it's my feeling that this would unacceptably expand the complexity of ContainerPilot for a single use case. In lieu of this, I'm proposing Co-Process Hooks. See #175 We've provided documentation and recommendation for workarounds on this issue. At this point if there are no objections I'd like to close this issue and provide a solution via the co-process hook work. |
Thanks @tgross. @jgillis01 is on vacation but I think this a good way forward for now. Thanks for the follow through and for an awesome product! |
Services register health checks with a specific Consul agent, and this makes health checks fail if we try to treat the cluster as a single Consul as we do in Triton deployments or PaaS-like environments. ref TritonDataCenter/containerpilot#162 Adding a Consul agent as a co-process with the ContainerPilot 2.3.0 coprocesses feature allows us to have the container join Consul and get/set health updates as part of the LAN gossip. - bumps ContainerPilot version to 2.3.0. - uses templating so that Consul co-process is optional
Is there a way for containerpilot to register a container as its own node in consul? Currently, containerpilot registers a service against a particular node in consul (given a clustered setting). If that consul node becomes unavailable, we lose service health visibility until that consul node is restored.
The text was updated successfully, but these errors were encountered: