How Confluent deploys 1,000 microservices across 5,000 Kubernetes clusters
Watch on YouTubeVideo summary
Mustajib from Confluent presents a comprehensive overview of how his organization manages an immense scale by deploying over 1,000 microservices across more than 5,000 Kubernetes clusters using their Unified Deployment Platform, formerly known as Halyard. This platform is essential for supporting real-time data streaming solutions built on Apache Kafka and Flink, enabling continuous deployment practices where code changes are automatically validated and promoted without heavy developer intervention. The system handles a daily peak load of approximately 100,000 operations by intelligently managing deployments across both control plane and data plane environments, ensuring that services like telemetry or logging reach the correct clusters while others remain restricted to specific regions or cloud providers based on their configuration needs.
At the core of this architecture is a flexible versioning system where each microservice is defined by YAML specifications stored in GitHub repositories, containing metadata about ownership, permissions, and target cluster groupings. When changes are merged into the master branch, these updates trigger an orchestration layer that batches eligible clusters for deployment while performing rigorous pre-deployment checks to prevent errors. The platform supports various rollout strategies, including sequential waves based on regions or parallel deployments across all targeted areas simultaneously, allowing service owners to define complex workflows and monitor metrics to ensure stability before proceeding to the next phase of a release.
A significant challenge addressed in the talk is the "chicken-and-egg" problem encountered during cluster bootstrapping, where new clusters require an operator to be installed first but cannot have one deployed without existing infrastructure definitions. To solve this, Confluent utilizes a dedicated provisioner service that manually applies the initial operator manifest and fetches default versions from their internal database rather than relying solely on GitOps models for every scenario. This hybrid approach ensures that even newly created clusters can immediately begin hosting necessary services like Kafka while maintaining strict security controls through Role-Based Access Control (RBAC) to manage who is authorized to deploy specific components.
Looking toward the future, Confluent is actively transitioning from custom controllers and operators to open-source solutions like Flux CD to enhance cloud-native capabilities and reduce maintenance overheads. Although they have explored third-party tools extensively, their current system was built in-house five years ago due to a lack of existing products that offered deep integration with the Confluent ecosystem and specific lifecycle management requirements. The team is also developing CLI tooling integrated with internal Large Language Models (LLMs) to accelerate investigations into deployment states and cluster configurations, demonstrating an ongoing commitment to evolving their platform while balancing custom needs with industry-standard open-source technologies.
Read the full video transcript
Okay.
Hi. Um hi everyone. Uh thank you for
joining me today in the talk about
scaling microservices with Halyard at
Confluent. Uh
yeah, before I get started Sorry.
You getting something? Okay, yeah.
Uh yeah, I'll introduce myself here.
Sorry.
Louder?
Okay.
Uh I'm Mustajib. I'm a senior software
developer here at Confluent. And today
I'll be talking about scaling
microservices with Halyard at Confluent.
And before we get started, uh I would
like to know how many of you here have
heard about Confluent?
Uh can you can I get a raise of hands?
Okay, that's a few people.
How many of you have heard about uh
Apache Kafka?
Okay, that is a few more.
Uh
how many of you have heard about
Apache Flink?
Okay, that is a little less number.
Okay, uh for those of you who don't know
about Confluent it's a data streaming
platform that empowers organizations to
make real-time decisions by using
uh
using data streams.
Right? And uh Confluent provides uh
Apache Flink and Apache Kafka-based
solutions which help uh
con- help companies take AI-driven
decisions with uh real-time data. I
mean, AI requires real-time data for it
to take the best decision, right? So, uh
Confluent comes in handy there. And you
also have event-driven architectures
which come which happen because of this.
And we have
shift-left data which comes into picture
because as uh
which basically means that you move to
the
closer to the source and process the
data there as much as possible so that
the downstream systems end up having the
data in the right format and they work
as expected.
Uh
yeah, and many other things that
Confluent helps you
Uh we discussed about the
the products that Confluent has to offer
Apache Flink, Apache Kafka and there are
many more like table flow and then
a few more that it does connect and
things like that. So in order to make
all of these happen
Confluent has like two offerings that it
has. One is the cloud based offering and
one is the
on-premise based offering. For the
purpose of this talk we will be limiting
it to the cloud based offering that
Confluent has to offer and the
deployments that go through in in the
cloud based offering.
Yeah and we are deployed across like
across all the public clouds that are
there. So we have like 90 plus regions
where we are deployed and this basically
helps us meet the customer where they
are and
and fit their needs when required.
Yeah there is another distinction in the
deployments that we have. We have like
we have services which get deployed in
the control plane and we also have
services which get deployed in the data
plane. Now most of the services that get
deployed in the control plane are helm
based services like most of them. But in
data plane we also have helm as well as
non-helm based services and we and this
deployment platform that we're going to
talk about today takes care of both of
them and we'll look into it how.
Now
we discussed about the landscape but
what is the scale that we handle at?
Right? So
to
talk about the scale
Confluent has like
1,400
microservices running. Trust me these
are needed but not that we have made up
these services or just doing it like
that.
Yeah and we have
we have around
5,000 clusters which are present and all
these
all these services are running on on a
bunch of these clusters and given this
given we have 5,000 more than 5,000
service clusters, and we have these many
microservices present, you might expect
that the peak load that we see is a
multiple of these two. Like, that's the
combination, right? But that's not
actually what we see. It The peak load
that we see is around 10 ^ 5 per day.
Because not all all services that get
deployed, they're not deployed to all
clusters. They might be limited to just
the control plane or just the data
plane. And even in data plane, they
might just be limited to a certain set,
like maybe Azure clusters or maybe GCP
clusters or things like that. Right?
And
uh
uh yeah. Uh before we get into the crux
of the uh
crux of the uh platform that I'll be
discussing, I also wanted to talk about
what uh are we trying to achieve? So,
basically, continuous deployment, right?
And what does it mean? I mean, what Most
of you might know about it, but just to
jog your memory, uh it is a practice
where you automatically validated code
uh change gets directly sent to the
customers uh without the without the
involvement of developers a lot. I mean,
it's a dream scenario, right? Well,
customers where developer just clicks a
button, and then uh the code change gets
validated, it it makes sure that nothing
is breaking, and then after that, it
gets promoted to the next environment,
and and things like that. And and
ultimately, the customer receives the uh
receives the code and the feature which
had to be released gets released as
easily as possible.
Now, uh introducing our unified
deployment platform or Halyard, which uh
which we used to call it previously, uh
which solved the uh
solved the deployment problem at Halyard
at Confluent.
Uh so,
Con- uh
Unified Deployment Platform is a fully
integrated,
uh
continuous deployment platform. Like I
mentioned, it was present across We need
to be present across environments and
need to make sure that everything
all the customer workloads are working
as expected. And we need to manage both
Helm as well as non-Helm based uh
based internal microservices in
Confluent Cloud.
Yeah, and there are a few These are some
of the features that we that we have in
this platform. Uh
I'll be going through a few of them as
as a part of this talk and in in the in
future.
Yeah.
Uh
so, we have a bunch of technologies
which which make which we used to make
this happen and these are a few that
I've I've listed here.
Now, uh to crux
the crux of any deployment platform is
the version that gets created, right?
The version or
uh you know, uh
the version basically what gets deployed
and where it gets deployed. So, that is
what we'll be talking about in this. So,
the version is in Confluent is basically
uh a YAML spec that uh uses uh uses the
developers define in their own
repository. So, we have like uh 1,000 uh
services. So, we have 1,004 YAML 1,000
YAML files that are present in their own
repositories across GitHub. And the
complete ownership of that is present
with the service owner. Now, for example
here, we have service as the as the
ultimate uh object which which has the
metadata about the service and it also
has information about what
uh about who can deploy and and many
other R back details like that. And you
have multiple cluster groupings present
within a service. So, this cluster
grouping is basically a target of
clusters that that is defined for this
particular service. So, for a particular
service you can have like devil
development
cluster groups which are present and you
can have like fraud develop fraud
cluster group which is present. And the
configuration for each of them is I mean
the target is defined in this YAML file
again. We'll discuss about how the
cluster grouping happens and
and and in in the future in the next
slide.
The version
The version the the next next object in
this is the version, right? So, the
version is basically a snapshot of all
the configurations which
which are
which the service will use in order to
come up and connect to whatever
the relevant microservices or whatever
it needs it needs to do.
Now,
how does this change in GitHub? I
mentioned that this was present in
GitHub, right? How does this change in
GitHub get
come to our system the unified
deployment platform? And
I mean, that happens with a merge to
master when there's a merge to master
in the GitHub which happens. Um the YAML
spec, if there's an update to the
service service level details that we
have,
uh we would update that in our UDP in
our platform. And this in a similar
fashion, if there's any update to the
cluster group, it would again contain
again the
cluster would be either updated or
created or depending on what happens, it
would be like
it would it would be updated. And we
also have the version which gets
created. The version is basically like
a number which is a number or a tag
which is given to the service owner
which they can use to deploy that
particular configuration on their
clusters whichever they intend to.
And uh Uh, within a service I have
mentioned this before, but within a
service there are multiple cluster
groups and each cluster group will have
one version. Uh, like multiple versions
associated over a period of time, right?
But at one point of time, like it'll
it's a snapshot.
The version.
Now, coming to the cluster targeting, I
mentioned that we have
some services running on just a few
clusters, while some of the services
might be running across clusters, right?
For example, if there is a a telemetry
service or maybe the logging service,
which uh, which is needed for collecting
the logs and metrics, it would be it
should be present in all the clusters,
right? You know, you want to understand
what is happening in all the clusters.
Uh, so
we want to provide the users the
flexibility to
to define where they want their service
to be installed in and with what
configuration, if it's possible.
And to do this, we have the cluster
grouping uh, that we that we discussed
previously. The cluster group So, here
service A has two two groups. Uh,
group A service A will of service A will
target just the cluster one, but group B
of service uh, A would target cluster
three. It can so happen that all of
these clusters are again targeted by
just one group, but that's not the case
here.
And in in service B, we can see that
there are
uh, multiple uh, again cluster groups
present. And this is all these cluster
groups are
can be defined by the
owner uh, by the service owner itself.
We don't uh, mandate that this cluster
one and cluster two are supposed to be
present in just the the group A or group
B. They They give that flexibility to
the to the service owner. And how do we
do this? Like
To get into the details of this, we have
a cluster which has some metadata
present with it. So, it has a bunch of
regions, tiers, labels, which are
present. And these labels are then used
by the the targeting defined in the
group to like
target the specific cluster. So, for for
example, in this case, it is a simple
example that I've taken. Cluster
contains label A. If the cluster
contains label A, target that. That's
what That's where we end up deploying a
group
versions related to group B on that
cluster. But
But this can be way more complicated,
right? It can It can be just that the
cluster
the cluster It can be like cluster
contains label A, but label not label B.
It can be a multitude of things which
come in. And this label that we define,
it can be very fine-grained. It can be
just the cluster ID, which is unique to
every cluster. So, it can be like target
cluster two. Or it can also be like
a broad thing, like target all the
clusters in the prod environment. Or
target all the clusters in the
staging environment. Something like
that. It can be It can be way broader.
It can be like GCP cluster All the GCP
clusters. So, it's it's
All of that is
is a possibility and flexibility that we
provide to the to the service owners.
Now,
uh we spoke about how the version gets
created and how the targeting happens.
We we uh we'll be looking at how the
version gets deployed, right? So, in
order for the version to get deployed,
we have
uh the service owner would need to
trigger
uh installation request on on the CI or
through the UI. We We provide a bunch of
options like this, uh where they specify
which service, which version, which
deployment, which cluster grouping to
that they want to deploy to. And they
also need to specify the In case they
need, specify the clusters that it needs
to be deployed to.
Uh After this comes the orchestration
layer,
uh which takes care of batching these
batching the eligible clusters or maybe
even selecting which are the eligible
clusters. This is needed because
in case
the cluster mentioned by the
by the user is not a valid cluster for
that particular service for that
particular cluster group, then we need
to
then we need to make sure
we need to cross-check that, right? So,
this basically does that. We can't be
completely dependent on the user's input
because we might end up installing wrong
services where where we don't intend it
to.
And
after the
after this batching is done, in the
orchestration layer, we also provide a
way to like do progressive rollouts. So,
this is very important in case you want
to to reduce the blast radius. So, you
want to first release the change to like
5% of the cluster, then then the rest
five, and then so on proceed like that,
right? So, the orchestration layer also
helps you batch it. It It gets the list
of all the clusters, then it creates
batches in the way that is needed, and
then it it issues install command on all
those clusters to our platform. And this
uh
this install request which comes in, it
it
it involves like rendering the manifest
and
and getting the exact details of what
need to be deployed. Like we have
multiple templates which are present,
those need to be like resolved.
Like we need to
understand
what what are the cluster groups and all
of that happens in based on the cluster.
There might be some parameter some
metadata from the cluster used in the
charts, use that using that
using the data again, we need we render
the charts and then once we have the
chart rendered, we we
have
something called as an operator present
on all the clusters. So, we had like
5,000 odd clusters, all of these have
like an operator which is shown here.
So, the first object that you see on all
of these clusters is the operator and
it's present on all the clusters. Now,
when when once the rendered manifest is
generated and stored with the platform,
the operator keeps continuously polling
our
platform and given this
platform is a
it's acts like a
core service and then there are multiple
agents which are present on on on all
the clusters that we have. Now, with
this
with this polling which happens, the as
soon as there's a change to the rendered
manifest, what ends up happening is the
the operator picks this change up and
and then starts applying it.
It might we currently use Kubernetes
manifest apply and then we are moving
slowly towards Helm based application
and the
operator applies it.
Now, you might also notice that there's
an other operator for non-Helm based
based things, right? So, this is
basically required for
non-Helm the operator this operator is
deployed by the
base operator that you have and that
takes care of all the
scaling of
pod pod that needs to be present,
managing stateful sets, all of that in
the non-Helm based
based products that we have in place.
Now,
yeah, this is about the install and
coming to the next part, yeah.
There might be some cases where you
don't want any deployment to go through
like like we recently had Christmas
holidays and that tends to be a lean
period where people don't want to deploy
anything or
many people are on leave. Like they
don't want to work. And in that case,
you don't want someone deploying a
change where it it breaks something and
then everybody has to come and work and
figure out what is happening. And in
order to solve for this, we have
something called as maintenance block
which we which is applied. And this is
again very configurable to uh you know,
uh to to have a certain number of
clusters or it can have
certain number of services and once the
service or the cluster matches, the
installations wouldn't happen. It's
basically blocked from happening and
yeah, uh that's that's about the version
deployment flow.
Now, uh
I spoke about continuous deployment and
I mentioned to you that it it's it's
very important that continuous
deployment happens where there is
real-time monitoring which is taking
place and and it happens in phases
basically, right? From one one
environment to another and in between
there are
big there is big time and then there is
there is you know, monitoring which
happens on all the required metrics
making sure that everything is fine.
Now,
in case of progressive rollout, we have
this case that we support both
sequential rollouts which is basically
uh
given a phase like the customer is free
to define I mean the service owner is
free to define whatever cluster set as
the first
phase that they want to. So, they can
have first re uh
first set of clusters defined.
In this case, it's based on region. So,
there are multiple regions which which
the service is getting deployed on and
that is happening in waves. Uh now, uh
with serial, we allow
it's it's pretty simple.
We allow the deployment happens one
after the other. And after each wave is
complete, we can we have some big time.
And then we have post-deployment and
pre-deployment checks which run in order
to make sure everything is fine. And if
if something has gone wrong, then we
roll back the change or we make it stop
there. Like depending on how the
customer I mean, the service owner has
configured it. It can It can easily be
that uh they just want to roll back or
the other way around.
And
uh in this case, it was successful, so
it proceeded to the next wave. And
sequentially, this happens. Uh now, this
is a very uh simple thing that I've
shown. We uh
the
the service owners are free to create
more customized and more complex
workflows if they need to.
Now, uh coming to the parallel workflow
that the progressive workflow allows, I
mean, in in within a wave, you can have
like all the regions targeted just at
once. Uh
and again, you'll have
uh big time after everything is
successful, and then deployment, making
sure that everything is fine.
Uh
Now, this was This is an other
requirement that you had where we had
like three four services which need to
go in together. Like Kafka goes in, then
there's a R back change along with that
which needs to go in. And then there is
an other uh different service which is
also needed, like something like
networking for the Kafka change to work
as expected. In in those cases,
uh
again, uh
we support that
uh we support that functionality where
users are able to specify multiple
services that need to happen. And it can
either be sequential, parallel, however
they intend it to, like. And the
deployment checks are pre- deployment
checks that would happen. It would
happen either based on the configuration
of the user. Where we basically go look
at the monitors uh that they would have
given to given us. So,
uh these monitors are basically uh
metrics based on metrics where
uh you where the services emit metrics,
right? So, we use that and have defined
some monitors, and those monitors get
used to understand what the state of the
uh
of the services and then proceed.
Now, uh in all of the cases that I
discussed till now, uh the deployment
the installation had happened
through
uh a user triggering it. Uh like user
had I mean, the service owner had
triggered it. Uh this was
this this would go through a CI or maybe
a UI, and then
uh and then it would trigger the unified
the deployment platform, and then that
would trigger an installation, right?
But then, there is uh
uh there is also a case where called
case of cluster bootstrapping where the
customer Confluent customer is is takes
an action due to which uh it triggers a
cluster creation. Now, in this case, uh
we encounter a chicken-and-egg problem.
I'll talk about that. So, basically,
once uh the customer has triggered and
cluster creation due to some reason, it
can either be that they've asked for a
dedicated cluster or the multi-tenant
cluster has run out of its capacity, and
then we need to new use a new cluster or
something like that.
Uh in in such cases
the provisioner we have a provisioner
service. This this is a thing different
from the deployment platform, but
this basically sets up the
infrastructure at uh at
uh
of the cluster that is needed. It makes
sure that all the basic infra which is
needed, like
uh networking and uh pods that need to
come up, auto scaler, and all of that
are present on the cluster, and and uh
and those things nodes that need to be
assigned. All of that is taken by care
by the provisional service.
Now,
uh but but the problem is we don't have
the operator which does the deployment
of the services on this cluster. Now, if
this is a Kafka cluster, we want Kafka
uh related services to be deployed on
it, but we don't have the
we don't have the operator here. Now,
who deploys the operator? So, like it's
it's a chicken and egg problem that we
end up at. And here uh the
the provisioner solves this solves this
by going to the
deployment platform, understanding what
getting the operator manifest, and then
manually applying it on the cluster, and
then creating the operator for for us.
Now, once this operator is up,
it uh goes and fetches all the default
versions that need to be installed on
the cluster. Now, these default versions
uh if they were present in a GitHub
file, we wouldn't be able to uh
like do it. And this is why we have had
to move away from the GitOps model in in
our deployment because
the default version that is present, it
it needs to be present in our DB. And
and our deployment platform needs to be
aware of what the default version is at
a given point of point in time. And this
uh
this is why we store uh the default
version and version information in our
DB. And then after the operator fetches
all the default version, it gets stored
in
uh it you it then brings up all the
services that are needed, and a bunch of
services that are needed on the cluster
would come up. And that's how this whole
flow would complete.
Uh
yeah. Uh now
coming to the
current and future developments that we
have at here. I mentioned that we are
currently using the
uh highly
uh custom CRD that that gets that is the
operator that is there, which is a
custom
custom controller which which is there
which which I've written and this
applies all the manifests on the
clusters and makes sure that all the
resources or whatever is needed comes
up. Now we are moving to a open source
open source controller there which is
flux CD which would support more cloud
native features and and things like
that. And we are also looking at
possibility of getting rid of the
operator all together. That's the agent
that I'll be talking about here and
manage the deployments completely
centrally. This has some scale issues
but yeah, we are exploring how we can
fix that and get around it. And we are
also looking we have CLI tooling which
is present so that users can interact
with our platform, understand what is
deployed,
how what are the targeted clusters, what
what are the service details that are
currently present on in the DB.
Interaction of all of that is taken care
by our CLI and that CLI we are looking
at integrating it with our LLM tools
that we have in house to help make
investigations faster.
Cool.
I ranted about this for about half an
hour but you might be wondering why do I
why do we need this? Can't we use an
open source solution or a third third
party solution that we have in place? Uh
and and why
why do I have a job around this and why
does my team work on this? But the the
the crux of the
the thing was when we did the evaluation
there were not a lot of products which
were cloud native and finished and had
all the
and had all the features that we
requested. And it it did not either have
the
uh the integration with the Confluent
ecosystem which was present, like we had
a bunch of
Confluent specific lifecycle tools which
with which the integration was needed.
And for that, we had we needed uh
we we had to build our own uh system.
And uh and there were a bunch of other
security requirements which which was uh
which which was uh which was to be taken
care as well. Like the RBA that I
mentioned, like we had to control who
could deploy a particular service and
that had to be present with the service
owner. They had to take the decision on
who could control the deployments and
things like that. All of that was not
possible at that point of time. Uh so,
yeah, we had built this. And and we're
actively, like I mentioned that we are
moving towards a Flux CD controller,
right? Which takes care of the
deployment on the cluster. The the
operator is now moving to a Flux CD
controller. And that uh things like that
are we are trying to integrate uh open
source tools as as and where possible
and maybe even third-party tools. So,
yeah, this evaluation was done 5 day 5
years back and
I think that's it. Thank you. If you
have any questions, please.
Sure.
Uh
you
Flux controller or Argo controller?
Flux controller.
Uh we had done
a comparative study on that. Uh I don't
remember the exact uh reasons. Maybe
I'll get back to you on that. Yeah.
Uh so, the pro- the question was what is
the reason why we picked Argo CD, why we
picked Flux control Flux CD controllers
instead of Argo CD controllers. I think
one reason that I remember was uh, we
had uh, already used Flux uh,
controllers in one of the other projects
that we were building, and we we knew
what to expect uh, from that, and that
we decided to use it here as well. So,
yeah.
Yeah.
Yeah. This decision predates me, but uh,
from what I understand, this this was
considered. Argo CD was considered uh,
as one of the options that we could have
taken, but the we uh, like I mentioned,
right? There were a few missing features
like uh, that were present, and
integration with the other tools that
were needed was not was not there at the
Sorry.
Yeah.
Yeah, good.
Correct.
So, uh,
in the GitOps model, everything that we
have would would stay uh, would reflect
what is present in the in the Git,
right? Git repository. But the problem
with that was
uh, when there's an actual deployment,
it makes sense. Uh, when the deployment
is triggered by user, then it makes
sense. But then when there's when
there's a new cluster which comes up
which was not previously targeted by any
of these clusters, we still need to
figure out where this cluster fits in,
right?
So, that information we'll have to again
either go back to
GitHub and then fetch it from there and
then do it. That we found it a little
tedious and we instead chose to do it in
the DB where we have all the information
present and then use that.
Yeah.
So.
Correct.
It It It would require, but we're still
evaluating that, yeah. I mean, that's
that's that's one of the possibilities
that you mentioned. You can do it that
way.
Yeah, that that can be.
Any other
questions?
Thank you.
Uh