News for hackers. Stuff that matters.
Re:How we reduced deployment times by 95% by marcinzm on Wednesday August 28, 2019 @01:11PM (#20821770)
My read seems to be: don't use ECS at large scale or you'll need some really convoluted hacks.
Re:How we reduced deployment times by 95% by otterley on Wednesday August 28, 2019 @02:17PM (#20822465)
(Disclaimer: I work for AWS, but any opinions expressed here are solely my own and not necessarily the company's.)

I don't know about that. ECS works fine at large scale, but it's not going to replace 4000 tasks immediately. And doing so could potentially be a huge shock to your customers if you tried. (You have to take the time to gracefully drain existing connections, etc.) Nor did the author desire to implement a blue-green type deployment which would use AWS's elasticity to its fullest potential out of unspecified cost concerns.

It's not clear to me that Kubernetes would fare significantly better here. It's not without its own particular performance bottlenecks; and the issues about safely draining connections and blue/green deployments would remain the same there. The issues aren't really related to the particular deployment orchestrator, as much as the fact that 4000 containers is pretty large number by any measure for a single unit of deployment.

Re:How we reduced deployment times by 95% by maerF0x0 on Wednesday August 28, 2019 @02:49PM (#20822762)
Actually OP gave the exact reason ECS does not work for them:

> The rate at which we can start tasks restricts the parallelism of our deploy. Despite us setting the MaximumPercent parameter to 200%, the ECS start-task API call has a hard limit of 10 tasks per call, and it is rate-limited. We need to call it 400 times to place all our containers in production.

That call limit needs to scale with the cluster size

Re:How we reduced deployment times by 95% by otterley on Wednesday August 28, 2019 @02:51PM (#20822785)
That sounds different from the usual way customers perform an ECS deployment, which is to replace the task definition of the ECS Service with a new one and let the control plane manage it. Only a single API call is needed, and the control plane can launch replacement tasks pretty quickly itself.
Re:How we reduced deployment times by 95% by ahmcb on Wednesday August 28, 2019 @03:56PM (#20823468)
We don't actually call the startTask API ourselves, but when we tell an ECS service (using cloudformation) to use a new task definition (which is basically just a new ECR image tag), ECS calls startTask and various other APIs on our behalf.
Re:How we reduced deployment times by 95% by otterley on Wednesday August 28, 2019 @04:35PM (#20823728)
That is true. FWIW, as an experiment I built a 50-node ECS cluster and launched 4000 tasks on it. I couldn't build a single service with 4000 tasks due to soft limits, so I built 4 services with 1000 tasks each (nginx, 256MB, 128 CPU units). No load balancer.

Overall task replacement time was about 15 minutes -- which is pretty respectable, in my view. Obviously not as fast as doing a hot code swap, though. Tradeoffs abound.

Re:How we reduced deployment times by 95% by pojzon on Thursday August 29, 2019 @01:44AM (#20826973)
Can I have a question about the bottlenecks you have mentioned in case of Kubernetes ?

Im really curious about this one. What were the bottlenecks you have faced till now.

Re:How we reduced deployment times by 95% by AYBABTME on Wednesday August 28, 2019 @05:38PM (#20824255)
Why exactly is it an expensive task? Where's the bottleneck? I worked on this problem before, so curious how it's handled (or not) at AWS.
Re:How we reduced deployment times by 95% by jbob2000 on Wednesday August 28, 2019 @01:24PM (#20821913)
You could also read this as "don't run 4,000 of anything".

4,000 node processes? Wow. Just wow. Surely there is a better solution for this. Maybe this is one of those weird edge cases where you would craft a bespoke infrastructure tool, rather than trying to hack a bunch of off-the-shelf products.

Re:How we reduced deployment times by 95% by bjacokes on Wednesday August 28, 2019 @01:56PM (#20822258)
Glad you pointed this out! We could have gone into a lot more detail on the reasons that we've arrived at our current system architecture, but it would've distracted from the root problem we were solving in the post. Happy to go into it a bit here.

Node event loop blockages are the primary reason we have so many processes running. We have enough integrations and iterate on them quickly enough that our infrastructure essentially treats them as untrusted/breakable. We want to avoid ReDoS-style bugs from affecting more than the current request, so we handle one request per process. A little inelegant, but we've still been able to horizontally scale the system, and frankly the extra infrastructure cost hasn't been enough to be worth the effort to change it.

To get around the start-task rate limit, we've tried running multiple identical containers per ECS task. However, they need to be marked as "essential" in CloudFormation to make sure our capacity doesn't degrade on container exits, and this means that one container exiting will also exit other containers in the same task.

Multiple processes per container is another interesting approach. We've used Node subprocesses in the past, but we found them tricky for reasons that are unrelated to deploy speed.

One thing we've really liked about rolling our own approach is that we decide when to declare a deploy complete. ECS is pretty conservative about not declaring a deploy complete until the final container has finished draining, which can take minutes for some of our requests. With our fast deploys, we declare a deploy complete when the final container running old code stops accepting new requests, which is significantly sooner. This makes follow-on deploys and rollbacks much smoother.

Re:How we reduced deployment times by 95% by twic on Wednesday August 28, 2019 @02:23PM (#20822519)
Specifically, the problem is that your integrations may block, right? If they crashed or never returned, Node would deal with that okay, wouldn't it?

What are these "integrations"? Could you farm them out to a flock of subprocesses, so you needed fewer top-level Node processes? What are they written in? If Node, how do you even get them to block?

And, of course, have you considered rewriting it in ... carrier lost

Re:How we reduced deployment times by 95% by bjacokes on Wednesday August 28, 2019 @03:05PM (#20822922)
If we handled N concurrent requests per process, a crash would definitely have the bleed-over effect we're trying to avoid, where a problem in a single request caused the other N-1 to fail. "Crash" meaning primarily OOM or unhandled rejections (which we exit on). And yes, the other big problem is blocking the event loop with an inefficient regexp, massive sort operation, clumsy use of Ramda, etc. This sort of blockage causes our ECS health checks to fail, so the container eventually gets killed.

"Never returning" is an interesting problem in Node. We have gRPC request timeouts, so the request fails on the client side after a set amount of time. Our Node server gets a cancellation event when this happens, but there's no guarantee that the in-flight request ever stops processing or gives up its resources, even if it's not blocking the event loop. E.g. our request handler could have a while(true) loop that continually does an async network request, and even though each gRPC request eventually times out, we would eventually have a swarm of zombie while(true) loops that are operating. To address this problem, we thread a lightweight context object into our framework which can essentially call an isCancelled() method. Before doing most low-level async operations (e.g. network requests), we check isCancelled() and throw if the gRPC request has timed out.

The integrations are all written in Typescript. As mentioned in another comment, we've attempted multiple processes per container and multiple containers per task. Right now, we see the bigger win as being able to fix "all of the above" and run multiple requests per Node process, but it'll take some legwork to get there :)

Re:How we reduced deployment times by 95% by jbob2000 on Wednesday August 28, 2019 @02:17PM (#20822460)
Great insights, thanks for replying!
Re:How we reduced deployment times by 95% by crgwbr on Wednesday August 28, 2019 @01:35PM (#20822039)
You don’t even need a bespoke tool. Just make each container run 4–8 processes by means on something like PM2. That cuts your CI container count down to 500. No reason a container should mean 1 process.
Re:How we reduced deployment times by 95% by latchkey on Wednesday August 28, 2019 @01:49PM (#20822191)
Good topic for the next hackathon.
Re:How we reduced deployment times by 95% by marcinzm on Wednesday August 28, 2019 @01:42PM (#20822101)
I'd expect any decent infrastructure tool to be able to handle 4000 processes/containers. Kubernetes, for example, claims to support 300000 containers across 5000 nodes. Mesos supported 50k+ from what I understand. Hadoop scales to over 10000 nodes.
Re:How we reduced deployment times by 95% by ravenstine on Wednesday August 28, 2019 @01:56PM (#20822268)
ECS can be good for really small things but, even when I worked in public radio, we discovered that ECS is pretty hot garbage without writing a bunch of stuff to deal with its quirks. Scaling worked kinda wonky, and ECS has its own jargon for terminology that already exists with Docker in general, making it unnecessarily confusing. Why they call a container a "task" when the term "container" already exists is beyond me. We ended up using Rancher to manage Kubernetes.
Re:How we reduced deployment times by 95% by otterley on Wednesday August 28, 2019 @02:04PM (#20822344)
ECS tasks are not containers. Tasks are a collection of one or more containers. They're the equivalent of a Pod in Kubernetes.
Re:How we reduced deployment times by 95% by rcfox on Wednesday August 28, 2019 @04:51PM (#20823842)
In Docker terminology, that would be a service?
Re:How we reduced deployment times by 95% by yebyen on Thursday August 29, 2019 @03:18PM (#20832684)
In Kubernetes and ECS, a Service is already used to name the abstraction that represents a collection of Pods/Tasks.

(Actually K8s collection of Pods is usually a ReplicaSet, fronted by Deployment, from the perspective of making sure they run. The Deployment is related to a Service by labels and selectors, K8s service only decides what pods it will route traffic to. An ECS service is more like a Kubernetes deployment, and I guess what Kubernetes calls a Service, basically a load balancer, is just called a load balancer, and I guess you manage the ALB's configuration together somehow for your service group, manually or somehow other, or you can just create a new ELB each time, and pay again ...)

I had never heard of a Docker Service, but from the looks of it, the Deployment (or Task), Service, ReplicaSet and Pods are all rolled into one single abstraction, the "Service" in Docker Compose.

Re:How we reduced deployment times by 95% by ravenstine on Wednesday August 28, 2019 @02:21PM (#20822493)
Ah, gotcha.
Re:How we reduced deployment times by 95% by weberc2 on Wednesday August 28, 2019 @02:23PM (#20822511)
We use ECS via Fargate and I'm mostly happy. Deployments are pretty slow, but that's our only qualm. We PoCed EKS, but it has no integration with CloudWatch or IAM for all intents and purposes. They had roadmap items to address those things, but you absolutely have to reinvent a lot of wheels with Kubernetes compared to the things you get for free with ECS/Fargate.
Re:How we reduced deployment times by 95% by viraptor on Thursday August 29, 2019 @09:01AM (#20829065)
> Why they call a container a "task" when the term "container" already exists

Likely for the same reason they call it ECS and not EDS. Making everything docker-specific could be a bad idea is more container tech becomes popular and they want to allow you to start Frobnicator tasks as well as Docker tasks on the same platform.

Re:How we reduced deployment times by 95% by bjacokes on Wednesday August 28, 2019 @01:39PM (#20822087)
In a way you're right, which is why we are exploring kubernetes. At the same time, ECS has worked really well for us as we've grown to this point. It's worth noting that we have some other motivating reasons to switch off ECS beyond deploy limitations, such as poor observability of ECS agent logs.

It's inevitable that early systems are going to bend and break at various points of the scaling process, and the interesting question is how to navigate that – fight fires for awhile or fix things immediately, hack together a stopgap solution or do the full fix, etc. We thought ours might be an interesting data point to share.