My experience with micro-services is code-bases that have prematurely adopted the pattern. Based on this, my advice is as follows... You can deploy the whole platform and/or refactor to a monolith, and maintain one change log which is simple. That however has its own downsides, so you should find a balance. If you're having trouble keeping track, perhaps re-organize. I read on one HN article that Amazon had 7k employ…
"Amazon had 7k employees before they adopted microservices" Sounds like the services were no longer 'micro' :)
Ask HN: How do you keep track of releases/deployments of dozens micro-services?
21–30 of 56 posts
Re: Ask HN: How do you keep track of releases/deployments of dozens micro-services?
#22Our apps are made by 5-15 (micro)services. I'm not sure if this approach would scale to hundreds of services managed by different teams. We store the source code for all services in subfolders of the same monorepo (one repo one app). Whenever a change in any service is merged to master, the CI rebuilds _all_ the services and pushes new Docker images to our Docker registry. Thanks to Docker layers, if the source code…
Re: Ask HN: How do you keep track of releases/deployments of dozens micro-services?
#23https://github.com/tim-group/orc
Basically, there's a Git repo with files in that specify the desired versions and states of your apps in each environment (the "configuration management database").
The tool has a loops which converges an environment on what is written in the file. It thinks of an app instance as being on a particular version (old or new), started or stopped (up or down), and in or out of the load balancer pool, and knows which transitions are allowed, eg:
(old, up, in) -> (old, up, out) - ok
(old, up, out) -> (old, up, in) - no! don't put the old version in the pool!
(old, up, out) -> (old, down, out) - ok
(old, up, in) -> (old, down, in) - no! don't kill an app that's in the pool!
(old, down, out) -> (new, down, out) - ok
(old, up, out) -> (new, up, out) - no! don't upgrade an app while it's running!
Based on those rules, it plans a series of transitions from the current state to the desired state. You can model state space as a cube, where the three axes of space correspond to the three aspects of the state, vertices are states, and edges are transitions, some allowed, some not. Planning the transitions is then route-finding across the cube. When i realised this, i made a little origami cube to illustrate it, and started waving it at everyone. My colleagues thought i'd gone mad.You need one non-cubic rule: there must be at least one instance in the load balancer at any time. In practice, you can just run the loop against each instance serially, so that you only ever bring down one at a time.
This process is safe, because if the tool dies, it can just start the loop again, look at the current state, and plan again. It's also safe to run at any time - if the environment is in the desired state, it's a no-op, and if it isn't, it gets repaired.
To upgrade an environment, you just change what's in the file, and run the loop.
Re: Ask HN: How do you keep track of releases/deployments of dozens micro-services?
#24Full disclosure: I'm on the Spinnaker team
Re: Ask HN: How do you keep track of releases/deployments of dozens micro-services?
#25Re: Ask HN: How do you keep track of releases/deployments of dozens micro-services?
#26Our apps are made by 5-15 (micro)services. I'm not sure if this approach would scale to hundreds of services managed by different teams. We store the source code for all services in subfolders of the same monorepo (one repo one app). Whenever a change in any service is merged to master, the CI rebuilds _all_ the services and pushes new Docker images to our Docker registry. Thanks to Docker layers, if the source code…
How long do your deployments take on average?
The builds for all services happen in parallel, so the longest one determines the total time. Big Scala services take much longer than small React frontends. We cache both Maven and NPM modules from previous builds.
Ideally, if the pull request only modified a React component and didn't touch any Scala file, no Scala build is triggered because Docker finds a cached layer and skips the "sbt compile" step. To be honest, we are still working to make sure this always happens, we still trigger unnecessary sbt compiles because the Docker cache is not used correctly.
Re: Ask HN: How do you keep track of releases/deployments of dozens micro-services?
#27Our apps are made by 5-15 (micro)services. I'm not sure if this approach would scale to hundreds of services managed by different teams. We store the source code for all services in subfolders of the same monorepo (one repo one app). Whenever a change in any service is merged to master, the CI rebuilds _all_ the services and pushes new Docker images to our Docker registry. Thanks to Docker layers, if the source code…
Why are you rebuilding _all_ the services, wouldn't it make sense to just rebuild the ones that have changes? You're now rebuilding perfectly working services without any new changes just because some other service changed, or am I misunderstanding something here?
Re: Ask HN: How do you keep track of releases/deployments of dozens micro-services?
#28Our apps are made by 5-15 (micro)services. I'm not sure if this approach would scale to hundreds of services managed by different teams. We store the source code for all services in subfolders of the same monorepo (one repo one app). Whenever a change in any service is merged to master, the CI rebuilds _all_ the services and pushes new Docker images to our Docker registry. Thanks to Docker layers, if the source code…
A couple of things different that we do since we are building and then deploying to AWS:
- Build only on dedicated deployment branches (beta, qa, preview, prod)
- Build all functions (transpile, yarn, lint, etc) on every merge into the branch, but only deploy functions with different checksums (saves on api calls to AWS)
- We cache node_modules, but otherwise don't have any special build requirements and babel takes care of targeting node6.10 for Lambda
Total build time is between 8-13 minutes. There are some things we can do to speed up install that we haven't yet because it's not an issue yet but just a short list of things to note.
- Each function has it's own package.json for it's own packages. We maintain a list of npm packages that we download into a single folder first (that doesn't get deployed) to allow yarn to use those files from cache. We will eventually switch to an offline install for each function which essentially just copies the package folder and sets up anything it needs.
- We have a tarball package that includes all of our shared code / config files. Yarn seems to always want to download this file, regardless if we pre-download it.
- We deploy a single api endpoint for all of our micro services through API Gateway which cuts down on the time to deploy since API Gateway has a pretty hard throttle. This means we create a deployment on API Gateway every merge. We have one APIG for each environment
Re: Ask HN: How do you keep track of releases/deployments of dozens micro-services?
#29Our apps are made by 5-15 (micro)services. I'm not sure if this approach would scale to hundreds of services managed by different teams. We store the source code for all services in subfolders of the same monorepo (one repo one app). Whenever a change in any service is merged to master, the CI rebuilds _all_ the services and pushes new Docker images to our Docker registry. Thanks to Docker layers, if the source code…
> Whenever a change in any service is merged to master, the CI rebuilds _all_ the services and pushes new Docker images to our Docker registry. Why are you rebuilding _all_ the services, wouldn't it make sense to just rebuild the ones that have changes? You're now rebuilding perfectly working services without any new changes just because some other service changed, or am I misunderstanding something here?
Re: Ask HN: How do you keep track of releases/deployments of dozens micro-services?
#30Our apps are made by 5-15 (micro)services. I'm not sure if this approach would scale to hundreds of services managed by different teams. We store the source code for all services in subfolders of the same monorepo (one repo one app). Whenever a change in any service is merged to master, the CI rebuilds _all_ the services and pushes new Docker images to our Docker registry. Thanks to Docker layers, if the source code…
We follow a very similar pattern and we are at over 150 micro services right now (AWS Lambda). A couple of things different that we do since we are building and then deploying to AWS: - Build only on dedicated deployment branches (beta, qa, preview, prod) - Build all functions (transpile, yarn, lint, etc) on every merge into the branch, but only deploy functions with different checksums (saves on api calls to AWS) -…
Looks like a pretty solid build process. Thanks for the insight!