Demo Day 1: Proof-of-Concept - July 4th, 2025

6:30

In this demo, I walkthrough the current state of Blueberry IDP, showcasing the major resource types and their management capabilities.

This demo covers the foundational architecture of Blueberry IDP, including our design constraints, Kubernetes fundamentals, and the ArgoCD App-of-Apps pattern. I demonstrate how we manage ephemeral environments for pull request testing, showcasing the core resource types and their lifecycle management.

Topics Covered

Design Constraints

GCP architecture using GKE Autopilot for running workloads and Firebase Auth for authentication

Kubernetes Fundamentals

Kubernetes resources (namespaces, pods, services, etc.), Helm charts, and configuration overrides for multi-tenant environment isolation

ArgoCD App-of-Apps Pattern

Using ArgoCD's app-of-apps pattern for managing environment resources

Key Features Shipped

  • Repository Management - Connect GitLab repositories for automatic environment creation
  • Environment Lifecycle - Create, manage, and auto-expire ephemeral testing environments
  • Config Sets - Reusable configuration templates for consistent environment provisioning
  • API Tokens - Secure programmatic access with authentication
  • Real-time Observability - Live pod logs, resource manifests, and Kubernetes events
  • CICD Integration - Everything deployed through ArgoCD for full auditability

App-of-Apps Architecture

This diagram shows our ArgoCD App-of-Apps pattern customized for Blueberry IDP constraints: single backend with 0+ frontends per environment.

App-of-Apps Architecture Diagram showing ArgoCD pattern with single backend and multiple frontends

ArgoCD App-of-Apps pattern: Parent application manages child applications for backend, frontends, and shared resources

Transcript

[00:00] Hi, everyone.

[00:04] This is me testing out ScreenStudio to go over

[00:08] this cool app that I created called Blueberry

[00:12] IDP, it's an internal deployment

[00:15] platform to create ephemeral environments

[00:20] so that whenever a team has

[00:23] CI running, they can go

[00:27] and deploy ephemeral environments,

[00:31] essentially spin up their app with some configuration.

[00:35] I run some tests on it, see if everything succeeds, there's

[00:39] connectivity, whatever it is, and then the environment

[00:42] is taken down. Usually, you're making

[00:46] changes to your code pretty often,

[00:50] so those environments don't have to live for too long.

[00:54] After around 24 hours, those environments are deleted, and there's going to be

[00:57] a lot of environments, every single commit that you push to your repository

[01:01] will trigger an environment. Let's

[01:05] dig in. Let's sign

[01:09] in. Right now, I'm going to sign in with my

[01:13] preexisting email and password.

[01:18] However, you can sign up as well.

[01:22] There's a get started button. I still want to save my password.

[01:27] Cool. Here we are. This is the main dashboard.

[01:31] Let's take a look at

[01:35] our system status.

[01:39] Here we are. All systems operation are functional. When this is running

[01:42] in Kubernetes, right here, you

[01:46] will see the Docker image.

[01:50] That's good for verifying what version of the code you're

[01:54] looking at. Here, it'll show any environment variables that are

[01:58] running within the blueberry environment. That's really useful.

[02:02] It'll show whether we're able to connect

[02:06] to all these other backing services

[02:10] that we need, like our cache,

[02:14] our data store, our container

[02:18] registry, our secret manager,

[02:22] things like that. It's pretty

[02:26] cool. I see that I have a secret token here.

[02:30] I'm going to have to update this.

[02:35] Let's take a look

[02:39] at repositories.

[02:44] The way that this application is set up, the idea is that there is one backend

[02:48] service, and there are multiple front-end services

[02:52] that connect to that backend. Whenever we are creating an ephemeral

[02:55] environment, there will always be at least a backend. There

[02:59] don't need to be any front-ends deployed, but at least

[03:03] a backend is deployed. I created

[03:06] some sample applications. Let's see.

[03:11] What happened here? Blueberry.

[03:17] Here it is. I

[03:20] created three applications

[03:25] to show how this

[03:29] all works. Our backend application,

[03:32] the default one here, and then two different

[03:36] front-ends that I've confirmed connect

[03:40] to the backend when I'm

[03:44] running on Docker compose.

[03:49] Those repositories, they're configured somewhere. I can go over that

[03:53] in a different moment or a different chat.

[03:56] These are the three repositories

[04:00] that are configured. We can deploy the backend with any

[04:04] of these two front-ends, and even both front-ends.

[04:08] Here we have a link to the repository in GitLab.

[04:12] That can be really useful. We can see

[04:16] our GitLab pipelines for the

[04:20] repository. We can see that

[04:23] the default branch is main,

[04:27] but in terms of the latest commit to this

[04:31] repository, it's actually this

[04:35] commit. Thankfully, that run passed.

[04:39] That's great. Now that we see our repositories,

[04:43] I hadn't seen this. I got

[04:47] to remove this button. Those

[04:51] are the repositories. Something

[04:55] has occurred. These are the repositories we can

[05:00] deploy. Now let's take

[05:04] a look at an environment.

[05:09] These are some environments that already exist. Let me

[05:13] show you how to create an environment. We'll just

[05:16] create one right now. We'll

[05:20] call it demo one.

[05:24] For right now, we're just going to use the defaults. You can see that

[05:27] automatically a backend repository was chosen, our

[05:31] sample backend one. By default, it's going

[05:34] to deploy whatever is the latest commit on main.

[05:38] Right now, that commit happens to be this one. It checks

[05:42] that there's a corresponding Docker image that exists, which

[05:46] is totally needed. Otherwise, we can't deploy our instance.

[05:50] This may happen if you just push a change and your

[05:54] build pipeline is still running and it hasn't yet pushed the

[05:58] Docker image. We cannot create manually or

[06:02] any other way for that matter in environment

[06:06] unless the image exists or rather

[06:11] when that image exists.

[06:15] Right now, it's only selected a sample backend one,

[06:20] but we can also choose to run a front end.

[06:23] I think I'm going to run both of these front

[06:27] ends. You can see here that it's defaulting to the main

[06:31] branch for both. These are the good messages for

[06:35] those commits. For right now, I'm okay with

[06:38] it here, but I can put in a commit shot there. Short,

[06:42] long, doesn't matter. This will be able to tell and

[06:45] it'll check whether a Docker image exists.

[06:50] Let's create an environment. Awesome.

[06:57] The environment

[07:03] was created and we're immediately taken to

[07:06] the dashboard for that environment. Right

[07:11] away, we can see in the overview that we are

[07:14] given these links. Eventually, once the

[07:18] different apps are up, we can go to these endpoints, to

[07:22] these URLs, and we can access the app there.

[07:26] We can also see the versions of those services

[07:30] that were deployed. It'll tell you the

[07:34] commit and the commit message. A pretty

[07:38] key thing is that Docker images are tagged

[07:41] with the commit shot. You push a change

[07:45] and that has a commit shot, some unique hash.

[07:49] That same hash is attached to the Docker image

[07:53] that is built from the version of the code

[07:57] known as your unique hash.

[08:01] That will show that.

[08:05] Right now, they're not yet up. Even if we

[08:08] click on this, we're not going to be able to see anything. We can click here and we can

[08:12] go to Argo CD and we can take a look at how

[08:16] our deployment is doing by looking at

[08:19] the Argo CD UI. However, I'm

[08:23] not a huge fan of the UI. It's not

[08:27] super intuitive at first. Or maybe

[08:31] when I was learning it, there

[08:35] was just a lot going on. Just quickly,

[08:39] this application uses home. We know that there are Kubernetes

[08:43] manifests. There are specific YAML files with specific

[08:47] schemas. Let's say that you want

[08:50] to create a configuration map resource.

[08:55] You would create a YAML file. You

[08:58] would put API v1, kind config

[09:02] map, name, backend app, config

[09:06] map, let's say. Help charts allow

[09:10] you to create templates out of these

[09:13] manifest. You can pass in values

[09:17] to create that template.

[09:21] The thing about help charts is that they always have a values

[09:25] file which sets all the defaults.

[09:29] What you can do when you use a help chart and this is how they work is you provide

[09:33] overrides for the help chart. You have your default values

[09:37] and then if you provide,

[09:41] let's say our help chart has

[09:45] this field, environment.

[09:50] It has a namespace. Maybe the default

[09:53] value for a namespace is just an empty string.

[09:58] If we then provide an override, let's say we create

[10:02] another file and we type in environment namespace

[10:06] and we provide this value, when we create

[10:10] a helm release, those overridden values

[10:14] will be shown. We can see here

[10:18] the help chart values, what they look like

[10:21] at the end after rendering the values

[10:26] from the overrides. We can also see here the

[10:29] activity logs. You can see we're keeping track of who created

[10:33] the environment, what the status of the Argo CD

[10:37] application is. Just to quickly

[10:40] go over that, in order to not

[10:44] have to manage when we create a deployment,

[10:49] because we're not only creating a deployment

[10:53] resource with, let's say one pod, we're also

[10:57] creating secrets, we're creating configuration

[11:01] maps. When we want to both create, modify,

[11:05] and delete any of those resources,

[11:08] we don't really want to be managing that

[11:12] manually and so we're using Argo CD for that.

[11:15] We create an Argo CD application and depending

[11:19] on the annotations that the application

[11:23] has, it'll know how to manage the state

[11:26] of the application. You can send an HTTP request and you can say

[11:30] create a patch for this application that says

[11:34] that these resources can now be deleted,

[11:39] let's say. Then Argo CD will take care of

[11:43] deleting all those resources or modifying them, whatever it

[11:46] is that you chose.

[11:51] This UI is meant to make it a bit more intuitive to look

[11:54] at it. We can see here some of the Argo CD information,

[12:00] but just in a better way, in my opinion,

[12:03] we can look at Kubernetes resources that were created so we

[12:07] can filter, let's say, our backend. We can

[12:10] see that we have a service and this

[12:14] is the value of the services file

[12:18] or the services manifest rather.

[12:22] This is the full manifest. With

[12:25] a Helm chart, you don't need to set every

[12:30] single possible value. It's not

[12:33] really how it works. Some values

[12:38] are left empty and that means that you're not using that field, which means you're not creating

[12:42] certain things, things like that. We can also look at our

[12:45] events, which is pretty cool. It says here

[12:49] that DNS record provisioning succeeded.

[12:53] Here, it'll give you events for these different

[12:58] resources. So cool. DNS records updated.

[13:02] That's great. Let's look at our deployment.

[13:07] This is our manifest for the deployment. Let's look

[13:11] at the events. Scaled up.

[13:15] Finally, let's look at our ingress.

[13:21] You can see here how it's progressing.

[13:26] This ingress resource is still

[13:30] being provisioned.

[13:33] This is still not up.

[13:37] That's pretty important to know because

[13:42] using Argo CD, you can set the

[13:45] order of resources like

[13:50] startup. You can say,

[13:54] "Okay, I always want my back

[13:58] end application to be started first. If that application becomes

[14:02] healthy, then I want to create the

[14:05] front end apps." Right now,

[14:10] we can take a look at

[14:14] how our front end is doing.

[14:22] The React dashboard, right? We have the deployment, the ingresses,

[14:25] whatever. These are all for the front ends. We can see

[14:29] the status out of sync. We see that the namespace

[14:33] was created. But all these

[14:37] other resources are out of sync.

[14:41] That's because the ingress

[14:45] resource is not active yet for the back

[14:48] end, which means that the front

[14:52] end resources will not start up. That's something

[14:56] that the UI doesn't really tell you intuitively.

[15:00] It's important to know the help chart. We can also take

[15:04] a look at the pod logs, which is pretty cool. We can

[15:08] take a look at, let's see, MySQL.

[15:11] Another thing about this setup is that at least

[15:15] the client that I was working with, their

[15:19] back end connects to both MySQL instance

[15:23] and Redis cache. For the sample applications

[15:27] that I'm using for the demo,

[15:31] I also made sure that those

[15:35] apps hit those services as well. When we are ready to

[15:39] create the environment, we also need instances

[15:43] of those two services. We can take a

[15:46] look at the logs for the MySQL service

[15:51] here. We can take a look. Our pods

[15:54] will all be able to communicate with each

[15:58] other. We can take a look at the logs for

[16:02] Redis. Let's see the logs for my back end app that I created.

[16:06] Cool. Health check pass for database, it pass for Redis.

[16:10] We can see here that it's calling these

[16:14] endpoints, these health endpoints.

[16:18] The way that Kubernetes allows you to set

[16:22] up startup probes, liveness probes, readiness

[16:27] probes. The way that they work is you

[16:30] specify some endpoint. Let's say

[16:34] that your liveness probe, it can tell

[16:38] whether your application is up. It will hit an endpoint

[16:42] called /health. It will respond with

[16:45] service degraded or all operational things like

[16:49] that. Basically things that are on the status page.

[16:53] That's how it determines the status through all of the different services that it needs to connect

[16:57] to. That endpoint responds with the

[17:01] 200 success code to Kubernetes.

[17:05] Then Kubernetes, you set some interval. Let's

[17:09] say every five minutes, it's usually more than that.

[17:12] We'll say every five minutes it will hit that endpoint. If it was

[17:16] successful, then Kubernetes will just leave

[17:20] your pod up. If it hits that endpoint several

[17:24] times and it keeps getting failure codes,

[17:28] then Kubernetes will just bring your pod down,

[17:32] just destroy it because it will say, "I can't possibly run

[17:35] this. I'm not going to waste more resources." That's interesting

[17:39] to know about the pods. You can also take a look at events.

[17:43] This is really helpful. These are events from all

[17:46] the different resources in our Argo

[17:50] CD application. Our Argo CD application,

[17:54] it follows this pattern of app of apps where you have a master

[17:58] app that manages other applications. For each

[18:01] environment, we create a master app called,

[18:05] let's say, ephemeral

[18:09] demo one. Then that one manages

[18:14] another application, which is

[18:17] the back end. Another application, which is the front

[18:21] end. These environment events are events coming from

[18:25] all of the resources that exist

[18:29] within our Argo CD application. In

[18:32] our case, each ephemeral environment is

[18:36] created in its own namespace. That's a good

[18:39] way to isolate and to know what you're looking at when you're

[18:43] debugging. Here we can see events from the back end pod.

[18:47] Here, it gives it some prefix, like

[18:51] ephemeral environment. Then here, it gave it the

[18:54] name of the environment that I added. Here,

[18:58] it added the component. This is the back

[19:02] end. Then here is a random hash because

[19:05] we want to make sure that we never have named

[19:09] clashes. We can see events from that pod.

[19:13] It was able to pull the image, create the pod, schedule

[19:17] it. Let's see. We can see that

[19:21] our deployment had to scale up the

[19:25] replica set to go from

[19:29] zero pods to one. Things

[19:34] like that. Those are the events.

[19:38] There can be a lot of events. Here, we just see

[19:41] some basic things. Here, we can take a

[19:45] look at the Helm values. These

[19:49] are the final Helm values

[19:53] that were used. This is what

[19:57] this environment uses for the Helm chart. There's

[20:00] one Helm chart. It's an environment Helm chart.

[20:04] Let's see. Here it is in charts. We have two charts

[20:08] in the repository, one for the actual blueberry application and

[20:12] one for the environment. Each environment that we create

[20:15] follows a certain template. In our case, that template is we

[20:19] have one back end deployment and we have one front end deployment

[20:23] and a second front end deployment. Every

[20:28] time that we create a helm release,

[20:32] let's say, we create a new environment.

[20:36] It will create all these resources.

[20:40] These are all the default values for the chart. That means if

[20:44] you don't override them, it will just use these

[20:48] values. For example, let's

[20:52] see. Did we override anything here?

[20:56] Yeah. You can see

[21:00] here, the environment name

[21:04] says ephemeral demo one. However,

[21:10] environment name here is empty. We did

[21:13] override that value. Cool.

[21:19] That is the main functionality for creating the environments.

[21:24] That's the main of it. I'll

[21:28] also go over just a two more features

[21:33] that we have. I mentioned that we create these

[21:36] releases, these deployments. Of course,

[21:40] they each have their own set of or

[21:44] rather there's a default set of values.

[21:48] The default set of values is a combination of what

[21:52] we have in the default values YAML as

[21:56] well as some stuff that is

[22:00] injected.

[22:05] If we have overrides, we can create configuration sets so

[22:09] that we can use these preset overrides basically.

[22:12] For example, we have this override called front end

[22:16] two. All it does is disable front end one so

[22:19] that only front end two runs. We

[22:23] can create configuration sets.

[22:27] When we create a configuration set, there is this nice legend

[22:31] here. It's a preview and it'll tell you which values are

[22:35] set at runtime. You can't override them. Which

[22:39] ones are computed as well.

[22:43] There's a few that you can't override. For example, front end two,

[22:47] we're thinking about a company that only has

[22:51] one big back end application in multiple front ends

[22:54] that connect. That back end application clearly

[22:58] has many functionalities, whatever

[23:02] it is. For this company,

[23:06] they already know that they have,

[23:10] let's say, my dashboard, where

[23:14] another one could be like financial reporting.

[23:19] The whole point is that the

[23:23] applications that can possibly

[23:27] run in an environment,

[23:30] they're preset. These are the set

[23:34] of repos. There's only one back end and

[23:37] it's exactly at, it'll always

[23:41] be, this will always be the image

[23:46] repository. So we can't override

[23:50] that. If we wanted to change the repository

[23:54] that one of these applications is pointing

[23:57] to, we can go and change it in the master settings.

[24:01] Just any user that's coming in, they probably

[24:05] shouldn't be overriding those fields.

[24:08] You can see that, for example, this environment variable

[24:12] here, it says computed, basically at runtime, depending

[24:16] on what the, so this

[24:20] has to be fixed. But depending on,

[24:23] oh no, sorry, this is just a sample.

[24:27] But this is actually computed. This byte back end public

[24:31] URL computed means that from some other values, it's

[24:35] going to come up with this and it's going to set it itself.

[24:38] So for the computed variables, you don't really override

[24:43] them. But if you look at the chart, you can look at

[24:47] the template and see that they're really composed of other

[24:51] template variables. So that's how you can create a

[24:55] configuration set. And there's one

[24:58] more feature that we can use,

[25:02] which is pretty cool. We can create

[25:06] API tokens. So we can interact with

[25:10] Blueberry through the UI or through

[25:14] an API. And we would want to use API tokens

[25:17] to connect to the app, let's say from CI/CD.

[25:22] So let's say we have a GitLab pipeline, and

[25:25] we want that pipeline to create an environment.

[25:31] When let's say once front end two is has

[25:35] a new image and it's built, then we want

[25:39] to automatically create an environment where we're running just

[25:42] the back end and front end two. So we can hit

[25:46] an API endpoint. And we can send in some information.

[25:51] And it'll create that environment for us. So here we can create

[25:55] the API tokens. We can rotate them. Let's say somebody

[25:59] saw the token, it was exposed, so we can

[26:02] go ahead and just rotate it here. So that's

[26:07] pretty cool. And you can set

[26:10] the permissions that the token

[26:15] has. And delete them, of course.

[26:19] Let's see. There are a

[26:22] few features that I added.

[26:26] One of them being some Slack reporting.

[26:30] I just wanted to know what was going on. I wanted to hear the little

[26:34] Slack sound when a build was ready. So this

[26:38] was incorporated to the Blueberry app

[26:42] already. So I know, let's say there

[26:45] was obviously a push.

[26:49] And it had this commit.

[26:53] So it created this pipeline,

[26:57] which I can go to if I want to. And the message

[27:01] here is that it's starting to build a Docker image. So I want to know when it's

[27:05] building a Docker image. I want to know when that image was a

[27:08] success. Basically when

[27:12] I'm deployment ready.

[27:16] I got to cut down on these. And then I see

[27:20] when the pipeline finished. In case I have some other

[27:23] steps in there after building the image that

[27:28] I want to know about. I

[27:31] also receive notifications

[27:35] when an environment is

[27:39] created. So that's pretty cool.

[27:43] It'll give me the info. And then

[27:47] when they are deleted as well.

[27:51] Let's see if we can

[27:55] find a deleted one.

[28:00] Environment deleted. So when

[28:03] you're thinking about a company, maybe you wouldn't want to

[28:07] see every time an environment is deleted or created

[28:11] or every time that an image was

[28:15] built. But what I've seen in my career is

[28:19] people have exactly these channels and they just mute them and they just set

[28:22] special rules so that they can be notified

[28:26] based on some criteria. So we

[28:31] can do that.

[28:37] There's a lot that went into the setup. And

[28:41] I can go into that briefly. Let's look at our repository.

[28:45] We have a lot in our repository.

[28:49] So the Blueberry platform has

[28:53] Blueberry Terraform. So basically the

[28:57] Terraform code creates all the resources that it needs

[29:01] to run the application. It does assume that there's already

[29:05] a GCP organization and project created, but it creates

[29:08] the VPC, it creates the cluster, it creates service accounts.

[29:13] It creates a lot. Let's just quickly look at the

[29:17] modules here. It sets up Firebase.

[29:21] So Blueberry uses Firebase for authentication.

[29:25] So Firebase will manage the email and password

[29:29] and they'll manage the reset emails, the

[29:33] reset password emails, so that's nice.

[29:37] In here we also , we create some static

[29:41] IPs. So for example for

[29:44] Blueberry.Florenciacomuzzi.com, we always

[29:48] have this website up and so if we didn't have a static

[29:52] IP every time that this application updated, the

[29:56] IP of it would change. And when we're thinking

[30:00] about creating DNS records, so that when somebody

[30:04] goes to, let's say Blueberry.florenciacomuzzi.com,

[30:08] they're rerouted to a specific IP address. We need to

[30:12] have a static IP. So that'll create the static

[30:16] IP here. It'll create workload identity as well and that's

[30:20] because we want some of our, we want

[30:24] our applications to use workload

[30:28] identity. Basically anything that is running within Kubernetes,

[30:32] we want it to use workload identity because

[30:36] that way we don't have to actually

[30:40] load credentials files into

[30:44] our environment. It'll just know it's

[30:48] workload identity, it'll identify the

[30:52] workload. There are some secret manager secrets

[30:56] that have to be created that we want to create them ahead

[30:59] of time and there

[31:04] are various secrets

[31:10] that we have to

[31:15] create. Let's see. Okay.

[31:21] Secret manager secret.

[31:26] Here it is. So

[31:29] for example, our

[31:33] Blueberry, the application, it connects to GitLab to retrieve

[31:37] commit information, things like

[31:41] that. And so

[31:45] we need

[31:49] to, that is a personal access token that's created on the GitLab side

[31:52] and then we actually want to set that value. We

[31:56] actually want to retain that value in secret manager.

[32:00] So that's why we create a secret.

[32:04] So that's one secret

[32:10] that we use right

[32:15] there. So we create

[32:19] various things and I won't go too much

[32:22] into that but I did want to go into Argo CD

[32:26] and the setup for Argo CD. So the way

[32:29] that Argo CD is, it's GitOps which means

[32:33] that whatever version of the code is checked

[32:37] into the repository, it has some unique

[32:41] cache, and that is declared.

[32:45] And so that is what Argo CD will use.

[32:48] And so instead of having code

[32:52] with some variables, it'll say, why

[32:56] don't you write down the values of the

[32:59] variables in the file and I'll just pick

[33:03] it up. Maybe I can explain that a little

[33:07] better. But the Argo

[33:11] CD application will always look for

[33:14] how Argo CD, the applications that

[33:18] Argo CD has to manage, it'll look into

[33:22] usually some repository and the path

[33:25] is Argo CD dash apps. So in here we have

[33:30] our root application.

[33:35] Let's take a quick look at our root application here, the Blueberry

[33:39] root dev. So we can see these are the applications

[33:43] that the root Argo CD application is using. So

[33:47] we're using the app of apps pattern, which means

[33:50] our root is our master app and it manages all these applications

[33:54] like the actual Blueberry platform, an application for

[33:58] secrets. And then Blueberry

[34:02] also creates app of apps, right?

[34:07] For each environment, it'll create a master app

[34:10] that inside of it has one backend app and

[34:14] you know, zero or more front ends. So

[34:18] we see these four applications here

[34:22] and let's see what that looks like.

[34:26] What is this telling it to do?

[34:29] This is the application root and then here

[34:33] it is. It's saying, okay, go to this

[34:38] repository and then look at this

[34:41] path and this path is what our root

[34:45] application is. So the path is Argo

[34:49] CD apps overlays dev. So you see we have

[34:52] two folders. Basically, this is how we override

[34:56] Kubernetes manifest values through

[35:00] Argo CD a little different than with Helm

[35:03] charts. So in dev,

[35:10] we see that for the Blueberry app, Argo CD will

[35:14] override these variables. And

[35:18] in prod, we don't yet have values.

[35:22] When you look at the customization, you see, well, I'll

[35:26] have to look into this and get back to you

[35:29] with the bootstrap. Basically, we have this

[35:34] problem where Argo CD needs to, it's

[35:38] configured to look at code in this

[35:42] repo. And so it needs to be able to access

[35:46] GitLab. And so it needs a token for GitLab,

[35:49] right? And then once it's able to read those

[35:53] repositories, it's able to go on and use Secret

[35:56] Manager or whatever. But

[36:03] that GitLab token, we have to get it from somewhere. And so the approach that

[36:06] we're taking is we're creating an application called external

[36:10] secrets. External secrets basically brings into the

[36:14] environment secrets that are in Secret Manager,

[36:18] it'll essentially create a Kubernetes secret

[36:22] that points to the Secret Manager secret. So that's

[36:26] just a little bit about the setup

[36:30] there. So we're running Blueberry, we're running

[36:33] external secrets, and we're running Argo CD image updater.

[36:38] So when we're talking about the Blueberry

[36:41] platform, every time that we push code of

[36:45] the actual platform, we're going to build the image,

[36:49] we're going to push it, and then we're going to have this

[36:52] application called Argo CD image updater, which basically

[36:56] looks for new images and artifact registry.

[37:00] And as soon as the sees a new one, it'll just update your application. So

[37:04] in that way, Blueberry will be synced, right? That's the

[37:08] terminology that Argo CD uses, sync syncing. So

[37:11] that is the Argo CD image updater. For

[37:15] you'll notice that here, you don't see anything about an environment, and

[37:19] that's because there's not just one environment.

[37:23] So we're not declaring any environments

[37:27] here. The way that it works is now we have

[37:30] our Blueberry app, and our Blueberry app,

[37:34] you hit the end point, you go through the UI, whatever it is, and you

[37:37] create an environment there. You delete environments

[37:42] through different buttons or end

[37:45] points. Let's

[37:49] see. Okay,

[37:53] I think one last

[37:57] thing is, there are various

[38:01] variable defaults, and it's difficult

[38:04] to centralize that too much,

[38:08] right? Because there are certain

[38:12] places that just demand a default

[38:15] value, you can't just leave it empty. I'm going to

[38:19] think through this more. But basically, the app

[38:23] will first look at this file, and look at the values in

[38:26] this file. And then if there's an environment

[38:30] variable set, it'll override whatever's

[38:35] in the file. And if there's nothing in

[38:38] the app config, if there's nothing in the environment,

[38:42] then it typically has some default value,

[38:46] or it'll throw an

[38:49] error. This app was made

[38:54] using Python Fast API,

[38:59] HTMX, and Alpine JS. So far, it was

[39:02] a good experience. I feel like Alpine makes

[39:06] it easier to separate out logic, keep

[39:10] it clean, JavaScript. So I

[39:14] really enjoyed that. And of course,

[39:17] I use Claude. I use Cursor. I use the

[39:21] models o3, Sonnet 04, and

[39:25] Opus 04. Thank you. Chat soon.

Demo Highlights

  • Environment Dashboard - real-time pod logs and resource monitoring
  • Resource Manifest Search - quickly find and view Kubernetes resources
  • Configuration Overview - understand the deployed configuration (Helm charts, config sets, etc.)

Keyboard Shortcuts

Space Play/Pause
←/→ Skip 10s
F Fullscreen
M Mute