Back to Home to display all posts.
Showing posts with label Kubernetes. Show all posts

06/06/2025

Automate adding vCluster to Argo CD using External Secrets Operator - GitOps

Overview

In KubeZero (an open-source out-of-the-box Platform Orchestrator with GitOps designed for multi-environment Cloud Native setup), virtual clusters are created using vCluster. The main GitOps tool used in KubeZero is Argo CD, so we needed to automate provisioning the cluster and adding it to Argo CD.

If you used Argo CD before, you probably know that Argo CD provides a method for declarative setup (like for GitOps) where you can add new K8s clusters credentials by storing them in secrets, just like repositories or repository credentials.

However, to automate that, you need some way to extract the vClusters credentials and format them as an Argo CD config. There are many ways to do that, I prefer to use a declarative method, which is External Secrets Operator, namely PushSecret and ClusterSecretStore.

Flow

The flow is simple: when a K8s cluster is created via vCluster, the cluster credentials are created as a Secret object in the same namespace as the virtual cluster. Then, using PushSecret templating capabilities, it will read the secret, reformat it, and then push it to the Argo CD cluster using ClusterSecretStore.

vCluster supports multiple installation methods. We use vCluster Helm chart, so the PushSecret is created within the Helm chart to further automate it. Using Helm here is not mandatory; you can use any other installation method you like.

Prerequisites

Assuming you deploy the virtual cluster using vCluster (v4.3.0) Helm chart, you just need this extra Helm values file (here I just copy the example from KubeZero repo):

---
experimental:
  deploy:
    host:
      manifestsTemplate: |
        ---
        # Push the vCluster credentails to KubeZero ClusterSecretStore,
        # which will save it as a Secret in the KubeZero namespace to be used as an Argo CD cluster config
        # (just a secret with a specific label).
        # https://argo-cd.readthedocs.io/en/stable/operator-manual/declarative-setup/#clusters
        apiVersion: external-secrets.io/v1alpha1
        kind: PushSecret
        metadata:
          name: argo-cd-{{ .Release.Name }}-credentials
          namespace: {{ .Release.Name }}
        spec:
          refreshInterval: 5m
          secretStoreRefs:
            - name: kubezero-management
              kind: ClusterSecretStore
          selector:
            secret:
              name: vc-{{ .Release.Name }}
          data:
            - match:
                secretKey: name
                remoteRef:
                  remoteKey: argo-cd-{{ .Release.Name }}-credentials
                  property: name
            - match:
                secretKey: server
                remoteRef:
                  remoteKey: argo-cd-{{ .Release.Name }}-credentials
                  property: server
            - match:
                secretKey: config
                remoteRef:
                  remoteKey: argo-cd-{{ .Release.Name }}-credentials
                  property: config
          template:
            engineVersion: v2
            metadata:
              annotations:
                managed-by: external-secrets
              labels:
                argocd.argoproj.io/secret-type: cluster
            data:
              name: {{ .Release.Name }}
              server: https://{{ .Release.Name }}.{{ .Release.Namespace }}.svc:443
              config: |
                {
                  "tlsClientConfig": {
                    "insecure": false,
                    "caData": "{{ printf "{{ index . "certificate-authority" | b64enc }}" }}",
                    "certData": "{{ printf "{{ index . "client-certificate" | b64enc }}" }}",
                    "keyData": "{{ printf "{{ index . "client-key" | b64enc }}" }}",
                    "serverName": "{{ .Release.Name }}"
                  }
                }

That will create the reformated Secret object in the Argo CD namespace, where the Argo CD controller will read it as an config because of the lable argocd.argoproj.io/secret-type: cluster. The actual output will be something like this:

apiVersion: v1
kind: Secret
metadata:
  annotations:
    managed-by: external-secrets
  labels:
    argocd.argoproj.io/secret-type: cluster
  name: argo-cd-k0-credentials
  namespace: argo-cd
# The base64 is decoded for the sake of the example.
data:
  name: argo-cd-k0
  server: https://argo-cd-k0.mgmt-demo.svc:443
  config: |
    {
      "tlsClientConfig": {
        "insecure": false,
        "caData": "<base64 encoded from vCluster secret>",
        "certData": "<base64 encoded from vCluster secret>",
        "keyData": "<base64 encoded from vCluster secret>",
        "serverName": "argo-cd-k0"
      }
    }

That's it! Enjoy, and don't forget to star the KubeZero project on GitHub :-)

Continue Reading »

03/03/2025

Research Paper: Building a Modern Data Platform Based on the Data Lakehouse Architecture and Cloud-Native Ecosystem

Building a Modern Data Platform Based on the Data Lakehouse Architecture and Cloud-Native Ecosystem

Finally, after months of hard work, I have published my first research paper in a double-blind peer-reviewed scientific journal by the international publisher Springer Nature 🙌

The paper is titled:

Building a Modern Data Platform Based on the Data Lakehouse Architecture and Cloud-Native Ecosystem

This research paper is the result of several months of work and is based on my master's thesis, which was published in 2023 (I got Master of Science with Distinction in Data Engineering from Edinburgh Napier University).

The paper presents a practical application for data management without vendor lock-in, in addition to ensuring platform extensibility and incorporating modern concepts such as Cloud-Native, Cloud-Agnostic, and DataOps.

Why is this paper important? Because data is the backbone of Artificial Intelligence! In today's world, control over data means political and economic independence.

I would like to extend my sincere gratitude to the research team who contributed to this work, supported me, and shared their knowledge to help bring this paper to the highest quality. It was a truly enriching experience on many levels! 🙌

  • Dr. Peter Barclay: Head of the Data Engineering program at the School of Computing, Edinburgh Napier University.
  • Dr. Nikolaos Pitropakis, PhD: Associate Professor of Cybersecurity at the School of Computing, Edinburgh Napier University.
  • Dr. Christos Chrysoulas: Associate Professor in Software Engineering at Heriot-Watt University.

The research group chose these quotes from our respective languages/cultures to emphasize the importance of perseverance and diligence:


عِندَ الصَّباحِ يَحمَدُ القومُ السُّرَى
(In the morning, the people praise the night's journey)
Arabic Proverb

Αρχή ήμισυ παντός
(The beginning is half of everything)
Greek Proverb

Is obair latha tòiseachadh
(Beginning is a day's work)
Scottish Gaelic Proverb


I will write a community blog post about it soon :-)

Continue Reading »

31/12/2024

2024 Highlights

Finally, 2024 is over! Another crazy year but I like it! 🤩 This year was a bit chill compared to previous ones, but also I did many new things.

Top 5 highlights in 2024

1. Career

In 2022, I formed the Distribution team at Camunda, which is responsible for building and deploying the Camunda Platform 8 Self-Managed, which is an umbrella Helm chart with 10+ systems. In 2023, the main mission was to increase the team size to 4. In 2024, the onboarding was done for all members, and the team became more autonomous and worked at full capacity. I like the process of building and leading the team and am excited for the next steps in 2025. 🤩

2. Dynamic DevOps Roadmap

Dynamic DevOps Roadmap

In 2023, I wrote why the DevOps linear roadmaps are broken by default and then sow the seed of the Dynamic DevOps Roadmap to become a DevOps Engineer.

In 2024, I finished 100% of the roadmap and launched the roadmap website, making reading and following progress much easier. I'm pretty happy that many people like the approach of that roadmap instead of other roadmaps that list tons of DevOps tools! (which doesn't really work!). Here are some other highlights:

  • The roadmap repo got more than 1.6k stars on GitHub.
  • Added around 250 quiz questions (embedded in each module).
  • Added around 200 general interview questions.
  • Added interview best practices, which are the same as important as technical skills.
Experience-Driven DevOps: Beyond Tools, Where Concepts Meet Real-World Challenges

A FREE pragmatic DevOps roadmap to kickstart your DevOps career in the Cloud Native era following the Agile MVP style! A DevOps Engineer or Software Engineer, this roadmap is all that you need to start, grow, and expand!

3. Public Speaking

This year, I conducted some nice sessions (in Arabic) with awesome people.

As usual, JobStack_ continues to set the bar higher each year! It is an unmissable event for tech enthusiasts. I really enjoyed participating as both a speaker and a listener. 🤩

In November, I had 2 sessions, the kick-off and another specialized in DevOps.

Also, in December, I participated in a live podcast with Ahmed Elemam covering ⭐ How to start with the Dynamic DevOps Roadmap.

4. Activities

Besides these highlights, I had some nice stuff during the year. For example:

  • Updated my main website aabouzaid.com, listed my projects, blog posts, publications, tech talks, and more.
  • Traveled to 3 countries, Oman, Saudi Arabia, and Dominican Republic to attend tech and work-related events. I also had the chance to meet a lot of friends in those travels. Saudi Arabia wasn't my first time there, but the last time was too long ago, happy to be back again. 🤩
  • After 5 years of OnePlus 6, I got a new phone. First, I tried for a couple of months Samsung Galaxy S23 Ultra, a great device but super heavy! So I swtiched to Samsung Galaxy S24, which is high-quality and perfect in size.
  • Since 2020, I've been using the ergonomic mouse (standard vertical) and keyboard (Microsoft Sculpt) and totally like them. Recently, I changed the mouse to Logitech MX Vertical. It's pretty good for me; my only concern is that the clicks are a bit noisy!
  • Lost some weight, which is great 😄

And since we are on this topic, here are the top 5 visited blog posts in 2024!

Top 5 posts in 2024

  1. 2 ways to route Ingress traffic across namespaces - Kubernetes
  2. How to create Makefile targets with dynamic parameters and autocompletion - Make
  3. Validate, format, lint, secure, and test Terraform IaC - CI/CD
  4. Your DevOps learning roadmap is broken! - Career
  5. 3 ways to customize off-the-shelf Helm charts with Kustomize - Kubernetes

Almost the same as last year, 2023, DevOps, Kubernetes, and Kustomize posts are still in the top.

What's next?

As usual, I don't plan the whole year in advance, I just put some high-level directions then work on them as I go in Agile iterative style (yes, I use Agile for personal goals too).

What I know, I will focuse on growing the Dynamic DevOps Roadmap community and work on the Career Growth and Advanced Topics section.

Previous Years


Enjoy, and looking forward to 2024! 🤩

Continue Reading »

08/08/2024

Bootstrap Cloud-Native bootstrappers like Crossplane with K3d - Automation

Crossplane Bootstrapper
I created a logo for the Crossplane Bootstrapper because all good projects deserve a logo. 😁

TL;DR

My contribution to K3d to support embedded files was one of the smoothest open-source contributions, although I needed to refactor my PR fully! I did that happily, thanks to the fruitful discussion with the K3d creator and maintainer, Thorsten Klein 🙌

Let's dive into that a bit more using the STAR method.

Situation

It has always been challenging to initiate the initiator dilemma (the same as Infinite regress in philosophy). For example, what will monitor the monitoring system? Or What will backup the backup system?

The same applies to Cloud-Native tools that run only on Kubernetes, where you need an initial Kubernetes cluster to run those bootstrapping tools to create your resources (like Argo CD and Crossplane).

Task

I wanted to fix this issue once and for all! (a generic way that works with many tools) I found that the best way to do that is to have a declarative way to setup the initial local cluster, which will create the Cloud resources afterward.

Action

I've reviewed a couple of tools and found the best tool to achieve that is K3d, a wrapper around K3s, a Rancher's lightweight Kubernetes distribution. It's like KIND but way more customizable (e.g., it comes with a built-in Helm controller).

In March 2024, I made a K3d PR that added functionality to embed manifests in the K3d cluster configuration. Now, we can have one file to bootstrap the local cluster with bootstrapping tools ready to provision your Cloud resources.

In July 2024, K3d 5.7.0 was released with my feature, so I can use it to bootstrap Crossplane instead of a bunch of Makefiles.

I also created Crossplane Bootstrapper, which makes that process even easier.

Result

With my new feature, it's possible to have 1 YAML file using 1 tool to bootstrap the initial cluster, which will create the reset of your Cloud resources.

Here is an example from Crossplane Bootstrapper. That solution works with any tool (e.g., Argo CD). It also supports external files, which is better for linting and so on.

---
apiVersion: k3d.io/v1alpha5
kind: Simple
metadata:
  name: crossplane-bootstrapper

# Cluster resources.
servers: 1
agents: 1

# Auto deployed manifests.
files:
  - description: Setup Crossplane
    destination: k3s-manifests/crossplane-bootstrapper.yaml
    nodeFilters:
      - "server:*"
    # Source as a file.
    # source: manifest-crossplane-bootstrapper.yaml
    # Source as an embedded manifest.
    source: |
      ---
      apiVersion: v1
      kind: Namespace
      metadata:
        name: crossplane-system
      ---
      # Install Crossplane.
      apiVersion: helm.cattle.io/v1
      kind: HelmChart
      metadata:
        name: crossplane
        namespace: crossplane-system
      spec:
        repo: https://charts.crossplane.io/stable
        chart: crossplane
        targetNamespace: crossplane-system
        valuesContent: |-
          provider:
            packages:
            # Docs: https://marketplace.upbound.io/providers/upbound/provider-family-gcp
            - "xpkg.upbound.io/upbound/provider-gcp-gke:v1.0.2"
          configuration:
            packages:
            # Docs: https://marketplace.upbound.io/configurations/upbound/platform-ref-gcp
            - "xpkg.upbound.io/upbound/platform-ref-gcp:v0.9.0"
      ---
[...]

That's it! Happy DevOpsing :-)

Continue Reading »

31/12/2023

2023 Highlights


Image generated with Craiyon.

Finally, 2023 is over! What a year! One more crazy year, but it was the culmination of many actions I've started previously.

Starting with the fun facts ... this is the post no. 100!

After 9 years of tech blogging in English (I had another 10 in Arabic before that). It should be 108 posts since the plan was to post 1 per month, but I missed some, still not bad!

Top 5 highlights in 2023

1. Career

Image by vectorjuice on Freepik

In 2022, I formed the Distribution team at Camunda which is responsible for building and deploying the Camunda Platform 8 Self-Managed which is an umbrella Helm chart with 10+ systems. In 2023, the biggest challenge was increasing the team headcount to 4 and building the workflow to handle that!

2. Academia

I've always been into data! So in 2020, I started a part-time master's in Data Engineering at Edinburgh Napier University. After almost 3 years, I was awarded a Master of Science with Distinction in Data Engineering 🎉. In June, I got the result after I successfully defended my dissertation titled Modern Data Platform with DataOps, Kubernetes, and Cloud-Native Ecosystem. Then in October, I traveled to Scotland to attend the graduation ceremony. All I can say today is that it was a great experience by all means! (and that's actually why I had some unusual gaps in blog posts in 2023 because I was working on the master's thesis).

3. Mentorship

Dynamic DevOps Roadmap

In the last 5 years, I mentored many people in different career stages (starting their first job, career shift, moving to another work style or company). Almost every day, I see people struggling on their way to the DevOps field. I already wrote why the DevOps linear roadmaps are broken by default! So I decided to fix that and launched a Dynamic DevOps Roadmap to become a DevOps Engineer which under the DevOps Hive identity! The nice thing that I saw many people already like the idea and want to do it that way!

ℹ️ Check out the Dynamic Roadmap content ℹ️

4. Public Speaking

Jobstack is one of my favorite tech events all the time! And as usual, this year was awesome! As a speaker, I had 2 sessions, and as an attendee, I enjoyed many sessions on different topics.

5. Activities

Besides these highlights, I had some nice stuff during the year. For example:

And since we are on this topic, here are the top 5 visited blog posts in 2023!

Top 5 posts in 2023

  1. 2 ways to route Ingress traffic across namespaces - Kubernetes
  2. Validate, format, lint, secure, and test Terraform IaC - CI/CD
  3. Your DevOps learning roadmap is broken! - Career
  4. Delete a manifest from Kustomize base - Kubernetes
  5. 3 ways to customize off-the-shelf Helm charts with Kustomize - Kubernetes

The same as last year, 2022, Kustomize posts are still in the top; that's because there is not much content about it even though it's built-in kubectl now! (since v1.14). That's why I created a Kustomize Awesome list, which is a curated and collaborative list of awesome Kustomize resources.

But this year, 2023, for the first time, a blog post posted in the same year appears in the top 5 posts! Which is discussing how the linear DevOps learning roadmap is broken by default! That's why I had a follow-up post showing the solution that suggests a better way to Become a DevOps Engineer with the Dynamic DevOps Roadmap. ⭐

What's next?

As usual, I don't plan the whole year in advance, I just put some high-level directions then work on them as I go in Agile iterative style (yes, I use Agile for personal goals too).

What I know already is that I need to reward myself and take a good break after the master 😁

Also, I want to put more effort to grow the DevOps Hive community to help more people to land their first DevOps Engineer role!


Enjoy, and looking forward to 2024!

Continue Reading »

11/11/2023

Platform Engineering: Manage your infrastructure using Kubernetes and Crossplane - Presentation

Just fresh out of the kitchen, part of JobStack 2023, today I conducted a session about a great tool ... Crossplane, the open-source control plane!

I've been using Crossplane for over a year and a half, and it helped me a lot to manage my infrastructure without the need to use Terraform (I still love Terraform, but it wasn't the best for my use case).

In this session I shed the light on how Crossplane could unify infrastructure management within Kubernetes.

I gave a brief how Crossplane extends the functionality of Kubernetes and allows you to create external infrastructure. You can create Cloud resources the same way you create Kubernetes resources! I really love its declarative, cloud-native, GitOps-friendly approach to code-driven infrastructure management.

Agenda:

  1. Scenario
  2. What is Crossplane?
  3. How it look like?
  4. Crossplane Concepts
  5. How Crossplane Works
  6. Pros and Cons
  7. Conclusion
  8. Resources
  9. Questions

Note: For more resources, checkout this Awesome Crossplane list.



A shot from the recoding 🙌
Watch the full session on YouTube: Platform Engineering: Manage your infrastructure using Kubernetes and Crossplane (Arabic)

Conclusion:

Crossplane is a great framework for managing infrastructure using the Kubernetes style and benefits from the that ecosystem (ArgoCD, Helm, Kustomize, etc.).

There are many use cases where it can perfectly fit in already. And at the time of writing these words (November 2023), the Marketplace has numerous enterprise and community providers configurations. Also, Composition Functions graduated to beta.

However, it's a relatively new ecosystem and still evolving, so it might not be the optimal solution for every workload. But it's probably a matter of time to grow more. So, if it's not your fit now, consider revisiting in the future.


That's it, enjoy :-)

Continue Reading »

09/09/2023

🔀Merger🔀, a schemaless strategic merge plugin - Kustomize

Kustomize is a great tool. I've been using Kustomize for almost 4 years and am happy with it. However, it's known for its strict merging methods, where it needs to have an OpenAPI schema to merge files properly.

There were many use cases where I needed a more flexible way to merge resources (away from Kustomize's strict merging). So, I've developed a new Kustomize generator plugin (Containerized KRM and Exec KRM) that extends Kustomize's merge strategies (schemaless StrategicMerge).

I wanted to:

  • Generate multiple resources from a single resource without the need to multi-import (you can patch multiple resources with a single patch but not the other way around)
  • An easy way to merge CustomResources without the need to provide the OpenAPI schema for it (that's actually a lot of work)
  • An easy way to merge non-k8s resources and put them in a ConfigMap.
  • A way to split long files into smaller ones.

...

Say Hi to 🔀Merger🔀

Merger is a generator provides schemaless merges with different strategies (StrategicMerge) like replace, append, and combine.

Here is an example:

apiVersion: generators.kustomize.aabouzaid.com/v1alpha1
kind: Merger
metadata:
  name: merge
    annotations:
      config.kubernetes.io/function: |
        container:
          image: ghcr.io/aabouzaid/kustomize-generator-merger
          mounts:
          - type: bind
            src: ./
            dst: /mnt
spec:
  resources:
  - name: example
    input:
      # Available options: overlay,patch.
      # - Overlay: Produce multiple outputs by merging each source with the destination.
      # - Patch: Produce a single output by merging all sources together then with the destination.
      method: overlay
      files:
        # The same as in the KRM container above, omit it if Exec KRM is used.
        root: /mnt
        sources:
        - src01.yaml
        - src02.yaml
        destination: dst.yaml
    merge:
      # Available options: replace,append,combine.
      # - Replace: All keys in source will merge and replace what's in the destination.
      # - Append: Maps from source merged with destination, but the lists will be appended from source to destination.
      # - Combine: Maps from source merged with destination, but the lists will be combined together.
      strategy: combine
    output:
      # Available options: raw.
      # In the next releases also ConfigMap and Secret will be supported.
      format: raw

For more details, check the common use cases section.

...

Some takeaways I learned while developing this project:

  • KubeBuilder markers could be used with the client side to auto-generate the OpenAPI YAML schema from the code.
  • Golang compression methods (like UPX and LZMA) can reduce the binary size up to 80% compared to the standard build method.
  • Cosign keyless artifacts sign is pretty easy to add to the CI pipeline (no need to manage any extra keys).
  • OpenSSF Scorecard offers a great integration assessing the security health metrics of open-source projects.

Enjoy :-)

Continue Reading »

08/08/2023

Helm chart keyless signing with Sigstore/Cosign - DevSecOps

Software supply chain security has been one of the hot topics because of the continues attacks and exploits shown in the latest few years. So having a proper security practices like signing artifacts in today's CI/CD pipeline is not a luxury! Which became a standard DevSecOps practice.

However, for a long time it needed a lot of work to implement those practices, hence, projects like Open Source Security Foundation (OpenSSF) which created security framework like Supply-chain Levels for Software Artifacts (SLSA) and Sigstore which created tools like Cosign to standardize and reduce that fatigue.

Today I want to shed some lights on Helm chart signing with Cosign (part of Sigstore project). This post will focus on GitHub Actions and 2 ways for Helm chart signing based on the type of the Helm registry (simple or OCI-based).

1. Intro

Before starting, what is actually Cosign? I will start with quoting from the project website:

Cosign is a command line utility that can sign and verify software artifact, such as container images and blobs.

Cosign aims to make signatures invisible infrastructure, and one of its main features what's known as "Keyless signing". Keyless signing means rather than using keys like GPG/PGP, it uses associates identities via OpenID Connect (i.e. it auth against providers like Microsoft, Google, and GitHub to issues short-lived certificates binding an ephemeral key).

Cosign could be used as a CLI also integrated part of other build/release tools like GoReleaser.

2. Identity setup

As mentioned, no need for signing keys here, Cosign will use the identity context like GitHub. Let's take GitHub Actions as a base here, but it is worth mentioning that Cosign works with many identity providers.

From the GitHub Actions workflow point of view, you just need to have job permission id-token: write, which allows the job to use OICD and generate JWT (which works as a key).

name: Sign Helm chart artifact
[...]
jobs:
  sign:
    name: Sign
    permissions:
      id-token: write
    [...]

You can find a full example in the repo: https://github.com/DevOpsHiveHQ/cosign-helm-chart-keyless-signing-example

3.1. Keyless signing for simple Helm repository

A simple Helm repository is just a file called index.yaml which reference to the actual chart files URLs. A popular way for that is using Chart Releaser to host the Helm charts using GitHub Pages and Releases.

The simplest way to sign Helm chart using Cosign is to sign the artifact then upload the signature to GitHub release page.

First, sign the chart file:

# For explicitly, it's also possible to add '--oidc-provider=github-actions',
# but no need for that, cosign will discover the context if the GH job permission is correct.
cosign sign-blob my-app-1.0.0.tgz --bundle my-app-1.0.0.tgz.cosign.bundle

That will create a bundle file my-app-1.0.0.tgz.cosign.bundle which contains signing metadata like the signature and certificate (also it's possible to have separate sig and pem files) which should be uploaded to GitHub release page.

Now anyone can download the Helm chart file and Cosign bundle file to verify its integrity:

cosign verify-blob my-app-1.0.0.tgz \
  --bundle my-app-1.0.0.tgz.cosign.bundle \
  --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
  --certificate-identity "https://github.com/DevOpsHiveHQ/cosign-helm-chart-keyless-signing-example/.github/workflows/sign.yaml@refs/heads/main"

If the file is valid the command will show Verified OK, otherwise it will show something like Error: none of the expected identities matched what was in the certificate ....

On the other hand, that's still some work! Maybe if Chart Releaser has a native support for Cosign. Also, the Helm plugin helm-sigstore could help a bit but you need to download the Helm plugin first.

3.2. Keyless signing for OCI-based Helm repository

Using container image to store config like Helm chart or Terraform module is one of the brilliant ideas.

One of the biggest changes in Helm 3 was ability to use container registries with OCI support to store and share chart packages. It started as an experimental feature, but by Helm v3.8.0, OCI support is enabled by default.

So instead that simple index.yaml an OCI-based registry could be used as a Helm repository and chart storage too. Any hosted registries that support OCI will work for that like Docker Hub, Amazon ECR, Azure Container Registry, Google Artifact Registry, etc.

In that setup, Cosign works a bit differently where it signs the chart as an OCI image (the same way it signs the Docker images) and store the signature in the OCI repository. But in that case it only makes sense to sign the digest not the tags since the digest is immutable.

There are two steps to make that, first push the chart to an OCI-based Helm repository which generates the chart digest, then push the signed digest.

# After login to the registry using "helm registry login ...".
helm push my-app-1.0.0.tgz oci://ttl.sh/charts &> push-metadata.txt

CHART_DIGEST=$(awk '/Digest: /{print $2}' push-metadata.txt)
cosign sign -y "ttl.sh/charts/my-app@${CHART_DIGEST}"

Finally, to verify that:

cosign verify "ttl.sh/charts/my-app@${CHART_DIGEST}" \
  --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
  --certificate-identity "https://github.com/DevOpsHiveHQ/cosign-helm-chart-keyless-signing-example/.github/workflows/sign.yaml@refs/heads/main"

4. Recap

Nowadays, it's critical to have standard DevSecOps practices in the whole SDLC, and validating integrity is one of the most essential practices in securing the software supply chain.

Any publicly distributed artifact should be signed to ensure the origin of it, and Helm charts are no different. Cosign keyless signing made it much easier to apply such practices without the hassles of managing singing keys.

Continue Reading »

07/07/2023

My Master's Dissertation: Modern Data Platform with DataOps, Kubernetes, and Cloud-Native Ecosystem

Almost 3 years ago (September 2020), I enrolled in a part-time master's program in data engineering at Edinburgh Napier University. Finally, two weeks ago, I got an email informing me that I successfully completed my master's and the program board of examiners awarded me Master of Science with Distinction in Data Engineering 🎉🎉🎉

My graduation ceremony would have been today, but I postponed it to October 2023 for some personal matters. So it's just a matter of time till the official graduation.

So today, I'd like to share my master's dissertation: Modern Data Platform with DataOps, Kubernetes, and Cloud-Native Ecosystem.

The dissertation builds a proof of concept for the core of Modern Data Platform using DataOps, Kubernetes, and Cloud-Native ecosystem to build a resilient Big Data platform based on Data Lakehouse architecture, which is the basis for Machine Learning (MLOps) and Artificial Intelligence (AIOps).

It was a super challenging topic, given the fact that Data Lakehouse architecture emerged just in 2020! But it was great to dive into it. I've been into data for years, and it's exciting to step up my skills from T-Shaped to Pi-Shaped (DevOps and DataOps) :-)

Continue Reading »

05/05/2023

KubeconformValidator, my first Kustomize validator plugin - Golang

TL;DR

In the past, Kustomize suggested using transformers to validate resources, but later, it introduced validators, which are like transformers but read-only.

Say Hi to KubeconformValidator, a plugin built around Kubeconform to validate manifests schema within Kustonize 🚀

Details

  • Kubeval is not maintained anymore, and their repo suggests using Kubeconform as a replacement.
  • The KRM model is used in the plugin, so no more Kustomize legacy plugins.
  • During the weekend, I did it in 5 short iterations (in hours) to discover different options and structures.
  • In the past, I used kpt-functions-sdk/fn to work with KRM, but I decided to try Kustomize's kyaml/fn/framework, and it's great 😍
  • The kyaml/fn/framework saved a lot of work with KRM and let met to just focus on the plugin logic. For example, I don't need to deal with OpenAPI Schema validation, it does it perfectly.

Example

apiVersion: validators.kustomize.aabouzaid.com/v1alpha1
kind: KubeconformValidator
metadata:
  name: validate
  annotations:
    config.kubernetes.io/function: |
      # Exec KRM functions.
      exec:
       path: ../dist/kubeconformvalidator

      # # Containerized KRM functions.
      # container:
      #   image: aabouzaid/kubeconformvalidator
      #   network: true
spec:
  # Configure Kubeconform.
  config:
    output: json
    skip:
    - AlertmanagerConfig
  # Also, direct Kubeconform args could be used
  # but "spec.args" has lower priority over "spec.config".
  # https://github.com/yannh/kubeconform#Usage
  # args:
  # - -output
  # - json
  # - -skip
  # - AlertmanagerConfig

That's it! Enjoy, and don't forget to take a look at awesome Kustomize list! :-)

Continue Reading »

01/01/2023

Awesome Kustomize list - Kubernetes

After 3 years of using Kustomize intensively to manage Kubernetes manifests, I just created a list of "Awesome Kustomize" resources 🤩️

If you are using Kubernetes, this repo will be a pretty good starting point for Kustomize plugins, guides, tips and tricks, and more.

Kustomize is not a new tool, it started in 2018, and now it's built into "kubectl" (since v1.14), which means it's now considered the official method to deal with advanced Kubernetes scenarios (e.g., GitOps).

If you are SysOps, DevOps, SRE, or anyone working intensively with Kubernetes, you definitely should read more about Kustomize!

Also, if you just use "kubectl" or Helm, then consider using Kustomize. It could help you in many different ways (it's not a replacement for Helm, you can use both).

Follow the repo to get the updates 🚀️

https://github.com/aabouzaid/awesome-kustomize

Continue Reading »

31/12/2022

2022 Highlights


Just a random image generated with AI!

Finally, 2022 is over! What a crazy year! In many countries, the Covid-19 pandemic is about to come to an end, but a global economic recession is almost at the door!

On a personal level, it wasn't an easy year for sure, but it was good in many different ways.

Top 5 highlights in 2022

  1. Career: Started the Distribution team at Camunda 🤩️ which is responsible for building and deploying the Camunda Platform 8 Self-Managed (now using an umbrella [Helm chart). Later on, there will be a Kubernetes Operator. That's a great career boost; I just started with many new and exciting challenges. And BTW, my team will begin hiring in 2023!

  2. Coding for Kubernetes: Big refactoring for Bank-Vaults operator which is the biggest open-source contribution to a project I don't own/manage. It polished my Golang skills, and I learned many new things (and had fun where I redesigned the operator logo 😂️).

  3. Security Knowledge-sharing: In 2021, I got my CKS certificate. Then, at the beginning of 2022, I started a security initiative at Camunda to enhance security practices. Then, later on, I conducted a session about Kubernetes Security Best Practices (with some tips for the CKS exam) which was a great case that includes theory, applied practice, and knowledge-sharing!

  4. Advanced CI/CD Knowledge-sharing: I wrote a detailed post about my experience with custom step conditionalRetry, which handles failures on spot/preemptible infrastructure so you could save up to 90% of the costs and have stable builds as well! It's been released as open source, and you can use that in your pipeline!

  5. Activities: Helped more people in their careers, once by moderating the DevOps circle at [JobStack 2022, and also in the voluntary mentorship that I do from time to time.

Besides these highlights, I had some nice stuff during the year. For example:

  • Added more features to kubech (which is a tool to set kubectl context/namespace per shell/terminal )
  • Virtually attended KubeCon Europe 2022, and the content was great!
  • Reached my writing goal this year and wrote 12 blog posts in 2022!

And since we are on this topic, here are the top 5 visited blog posts in 2022!

Top 5 posts in 2022

  1. Delete a manifest from Kustomize base - Kubernetes

  2. 3 ways to customize off-the-shelf Helm charts with Kustomize - Kubernetes

  3. Validate, format, lint, secure, and test Terraform IaC - CI/CD

  4. Now I'm a Certified Kubernetes Application Developer + 10 exam tips

  5. Continuous Delivery and Maturity Model - DevOps

No wonder that Kustomize post is the hights post; that's because there is not much content about it even though it's built-in kubectl now! (since v1.14), I probably need to give it more attention since there is an increase in the demand for it.

For that reason, I just started Awesome Kustomize, which is a curated and collaborative list of awesome Kustomize resources 🎉️


Enjoy 🚀️

Continue Reading »

12/12/2022

22/11/2022

Set OpenAPI patch strategy for Kubernetes Custom Resources - Kustomize

Kustomize supports 2 main client-side patching methods for Kubernetes manifests, JSON Patching and Strategic Merge Patch. In the JSON Patching method, you have a "meta" syntax that specifies operation/target/value. In the Strategic Merge Patch method, you can override values by providing a patch file with the same structure but with new values, and it will override the original values (it simply merges the 2 files with the same structure).

Each method has pros and cons but generally speaking, I would arguably say that Strategic Merge Patch is better for big changes/patches, and JSON Patching is better for smaller fine-grained patches. And for my use case, I will use Strategic Merge Patch, but I just faced a problem with patching Kubernetes Custom Resources!

ToC

TL;DR

Kustomize's default patch strategy for the lists (arrays) is replace. That means the patch list will override the original list, which is not always the desired behavior. That behavior could be changed only if an OpenAPI schema for a Kubernetes resource is available to define the patch strategy.

The OpenAPI schema for Kustomize core resources (like Namespace, Deployment, Pod, etc.) is already part of Kustomize, so changing the patch strategy works out of the box for these resources. However, if you have a Kubernetes Custom Resource, you need to provide to Kustomize the OpenAPI schema of that custom resource. And that's only useful if the custom resource includes the OpenAPI extensions related to merging strategy.

This post shows how to add those extensions to have control over the patch strategy. You can jump directly to the solution section if you already know all these details.

1. Task

I want to use Kustomize to patch Kubernetes Custom Resources like Prometheus AlertmanagerConfig), and I want to use merge as a patch strategy for lists. That means the original lists in the same path should be merged, not overridden by the patch list. That works out of the box for Kustomize core resources but not for custom resources. First, let's see that in action, then dive into the explanation afterward.

2. Issue reproduction

Let's have a look at this example using the core resource Pod, given this Kustomization file:

# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- pod.yaml

patches:
- pod-patch01.yaml
- pod-patch02.yaml

And these resources and patches files:

# pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    env:
    - name: MY_ENV_VAR_01
      value: source

# pod-patch01.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    env:
    - name: MY_ENV_VAR_01
      value: patch 01

# pod-patch02.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    env:
    - name: MY_ENV_VAR_02
      value: patch 02

The kustomize build . will return:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    env:
    - name: MY_ENV_VAR_02
      value: patch 02
    - name: MY_ENV_VAR_01
      value: patch 01

As you see, the env key MY_ENV_VAR_01 overrode by the value from pod-patch01.yaml, and the env key MY_ENV_VAR_02 has just been added from pod-patch02.yaml. That's great; the lists are merged based on the name key.

...

However, if you tried to do that with a CustomResource like AlertmanagerConfig, it would not work! Let's give it a try! Given this Kustomization file:

# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- alertmanagerconfig.yaml

patches:
- alertmanagerconfig-patch01.yaml
- alertmanagerconfig-patch02.yaml

And these resources and patches files:

# alertmanagerconfig.yaml
apiVersion: monitoring.coreos.com/v1alpha1
kind: AlertmanagerConfig
metadata:
  name: example
spec:
  receivers:
  - name: 'webhook01'
    webhookConfigs:
    - url: 'http://example.com/'

# alertmanagerconfig-patch01.yaml
apiVersion: monitoring.coreos.com/v1alpha1
kind: AlertmanagerConfig
metadata:
  name: example
spec:
  receivers:
  - name: 'webhook01'
    webhookConfigs:
    - url: 'http://example01.com/'

# alertmanagerconfig-patch02.yaml
apiVersion: monitoring.coreos.com/v1alpha1
kind: AlertmanagerConfig
metadata:
  name: example
spec:
  receivers:
  - name: 'webhook02'
    webhookConfigs:
    - url: 'http://example02.com/'

The kustomize build . will return:

apiVersion: monitoring.coreos.com/v1alpha1
kind: AlertmanagerConfig
metadata:
  name: example
spec:
  receivers:
  - name: webhook02
    webhookConfigs:
    - url: http://example02.com/

As you see, the last patch from the file alertmanagerconfig-patch02.yaml replaced everything in the spec.receivers list, and that's the default behavior in Kustomize. The patch list will replace everything in the original list. Why? Because that's the safest choice since Kustomize doesn't know anything about AlertmanagerConfig schema! Before diving into the fix, let's learn more about the why.

3. Background

The Strategic Merge Patch is a client-side merge method that merges 2 or more Kubernetes manifests together based on the manifest apiVersion, kind, and metadata.name. To merge 2 YAML files, you need to decide the "merge strategy" for different data types, i.e., what should happen for the "string", "int", "list", "map", and so on? Should they merge together? Or do the patch values override the original values?

Also, each data type could be patched differently; for example, how to patch a list? Kustomize provides different patch formats like merge, replace, and delete. In fact, in a previous post (Delete a manifest from Kustomize base), I mentioned the delete patch strategy, which works out of the box with core Kubernetes primitive (namespace, deployment, pod, etc.), but not the CustomResources.

Why does it work with core resources only? Because of 2 things.

  1. The Kubernetes project includes specific keys (extensions) in the core resources OpenAPI schema to deal with that. Namely the OpenAPI extensions x-kubernetes-patch-strategy and x-kubernetes-patch-merge-key (see them in Kubernetes swagger.json).
  2. The OpenAPI schema for Kubernetes' core resources is embedded in Kustomize.

If those keys are not included in the OpenAPI schema, and Kustomize doesn't have access to the OpenAPI schema, the default behavior will be applied, which in Kustomize, the patch list will fully replace the original list.

4. Solution

Now there are 2 cases, First, if the custom resource definition already has the x-kubernetes-patch-*`, and second, if the custom resource definition doesn't have them at all. The Kustomize supports "openapi" field, which specifies where Kustomize gets its OpenAPI schema.

For the first case, it's easy; you just need to point Kustomize to the OpenAPI schema and that's it!

# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

openapi:
  # It could be also a URL.
  path: monitoring.coreos.com_v1alpha1_alertmanagerconfig.json
[...]

However, for the second case, in a Platonic world, you should contact the upstream to add the OpenAPI extension keys x-kubernetes-patch-strategy and x-kubernetes-patch-merge-key. But as you know, in reality, that will take ages, and in the best-case scenario, it will not happen overnight! So the pragmatic solution is to tell Kustomize how to deal with that custom resource via OpenAPI schema.

We will simply get the Custom Resource's OpenAPI schema and add the x-kubernetes-patch-* keys to it with the merge strategy, which can also be customized using different patch formats like merge, replace, and delete.

The following are the step to get the OpenAPI schema of a custom resource, clean it, add the merge strategy keys, and finally use it in kustomization.yaml file.

4.1 Get the custom resource OpenAPI schema

You can get the OpenAPI schema for the resource from the upstream project, or if you have already installed its CustomResourceDefinition, then you can get it directly by calling Kubernetes API. And since K8s API will return every definition it has (probably thousands of lines), we will use jq to get the exact custom resource OpenAPI schema.

Here is a snippet that will help to get the OpenAPI definition for a particular resource:

get_openapi_definition () {
    jq \
        --arg group "${1}" \
        --arg version "${2}" \
        --arg kind "${3}" \
        '.definitions | with_entries(select(.value."x-kubernetes-group-version-kind"[0] |
            .group==$group and
            .version==$version and
            .kind==$kind
        ))'
}

And we can get the schema for the exact resource from Kubernetes API by running the following (remember, you should have installed the CRD for that resource into your Kubernetes cluster to be able to do that):

kustomize openapi fetch | get_openapi_definition "monitoring.coreos.com" "v1alpha1" "AlertmanagerConfig" > alertmanagerconfig_openapi_schema_map.json

4.2 Find the desired key path

Here is most of the manual work, but the good news is that you need to do it once. We need 2 things, the data of the path spec.receivers and the key x-kubernetes-group-version-kind. Open the schema file and remove everything not under the hierarchy of the path we want to customize.

Here is what it looks like after removing everything unrelated:

# alertmanagerconfig_openapi_schema_map.json
{
  "com.coreos.monitoring.v1alpha1.AlertmanagerConfig": {
    "properties": {
      "spec": {
        "properties": {
          "receivers": {
            "type": "array"
          }
        },
        "type": "object"
      }
    },
    "type": "object",
    "x-kubernetes-group-version-kind": [
      {
        "group": "monitoring.coreos.com",
        "kind": "AlertmanagerConfig",
        "version": "v1alpha1"
      }
    ]
  }
}

4.3 Create the custom OpenAPI schema file

Now we just need to put everything together adding x-kubernetes-patch-* keys and the definitions parent. The final result will look like the following:

# monitoring.coreos.com_v1alpha1_alertmanagerconfig.json
{
  "definitions": {
    "com.coreos.monitoring.v1alpha1.AlertmanagerConfig": {
      "properties": {
        "spec": {
          "properties": {
            "receivers": {
              "x-kubernetes-patch-merge-key": "name",
              "x-kubernetes-patch-strategy": "merge",
              "type": "array"
            }
          },
          "type": "object"
        }
      },
      "type": "object",
      "x-kubernetes-group-version-kind": [
        {
          "group": "monitoring.coreos.com",
          "kind": "AlertmanagerConfig",
          "version": "v1alpha1"
        }
      ]
    }
  }
}

4.4 Update kustomization.yaml with the OpenAPI schema file

The final step, we need to tell Kustomize about our custom OpenAPI schema file as follows (it also accepts YAML files in case you like to convert it):

# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

openapi:
  path: monitoring.coreos.com_v1alpha1_alertmanagerconfig.json

resources:
- alertmanagerconfig.yaml

patches:
- alertmanagerconfig-patch01.yaml
- alertmanagerconfig-patch02.yaml

Now the kustomize build . will return:

apiVersion: monitoring.coreos.com/v1alpha1
kind: AlertmanagerConfig
metadata:
  name: example
spec:
  receivers:
  - name: webhook02
    webhookConfigs:
    - url: http://example02.com/
  - name: webhook01
    webhookConfigs:
    - url: http://example01.com/

Great, it works as expected! 🎉️ And the custom resource list is merged based on the name key (you can choose any merge key based on your use case).

Conclusion

Kustomize is super powerful and has many capabilities to manage your entire Kubernetes infrastructure as code! And the most fantastic thing? It's now part of kubectl, so it's almost the standard way to deal with advanced Kubernetes manifest structure.

Enjoy :-)

Continue Reading »

11/11/2022

08/08/2022

2 ways to route Ingress traffic across namespaces - Kubernetes

The tech industry is full of workarounds, and you probably rely on one or more. There is no problem with that per se, but it's important to review your workarounds from time to time because there could be a new standard/intuitive way to make it.

The Problem

A couple of years ago I had a use case where a single domain has 2 sub-paths each of them using its own service in different namespaces. Let's see this example:

example.com/app => service "backend" in namespace "app"
example.com/blog => service "wordpress" in namespace "blog"

The problem was that the Ingress object is namespaced which means that it interacts with services within the same namespace. Also, only one ingress object per host/domain is allowed.

So at that time I found a generic solution which looks like a workaround. Actually, by thinking about it now, it was not a bad workaround. It depends on how you manage your infrastructure, and you can think about it as a centralized vs decentralized approach.

The Solution

So here are the 2 ways to route Ingress traffic across namespaces in Kubernetes. The 1st is a generic way that will work with any Ingress controller. The 2nd relies on the Ingress controller capabilities NGINX Ingress Controller by NGINX, Inc. (NOT Ingress-NGINX Controller by Kubernetes).

Option One: Generic method - ExternalName Service

This method relies on native Kubernetes ExternalName Service which is simply a DNS CNAME! This method is centralized where it uses the normal Ingress object in addition to ExternalName Service within the same namespace as a bridge to the services in any other namespace.

The following is an example of that setup with a single Ingress resource and 2 ExternalName services (3 endpoints which are /, /coffee, and /tea).

Config for shop.example.com including the 2 sub-paths /coffee and /tea in addition to the root /.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: shop-ingress
  namespace: shop
  annotations:
    kubernetes.io/ingress.class: "nginx"
spec:
  tls:
  - hosts:
    - shop.example.com
    secretName: shop-secret
  rules:
  - host: shop.example.com
    http:
      paths:
      - path: /coffee
        pathType: Prefix
        backend:
          service:
            name: coffee-svc-bridge
            port:
              number: 80
      - path: /tea
        pathType: Prefix
        backend:
          service:
            name: tea-svc-bridge
            port:
              number: 80

The coffee-svc-bridge service in the shop namespace is a CNAME for the coffee-svc service in coffee namespace:

apiVersion: v1
kind: Service
metadata:
  name: coffee-svc-bridge
  namespace: shop
spec:
  type: ExternalName
  externalName: coffee-svc.coffee

The tea-svc-bridge service in the shop namespace is a CNAME for the tea-svc service in tea namespace:

apiVersion: v1
kind: Service
metadata:
  name: tea-svc-bridge
  namespace: shop
spec:
  type: ExternalName
  externalName: tea-svc.tea

As you see, the Ingress config comes in 1 part and is normal. And use the ExternalName services as a bridge to access the services in the other namespaces.

Option Two: Controller-specific method - Mergeable Ingress Resources

The other option is using controller-specific capabilities to achieve that goal. There are dozens of Ingress controllers for Kubernetes like the Ingress-NGINX (by Kubernetes project), NGINX Ingress Controller (by NGINX, Inc.), Traefik, HAProxy, Istio, and many more.

Here I will cover only NGINX Ingress Controller by NGINX, Inc., but the idea is the same, using the controller-specific features.

If you took a look at the official Nginx docs you will find the Cross-namespace Configuration page suggests using Mergeable Ingress Resources.

That approach relies on a simple idea, there is a single Ingress resource that has all configurations related to the host/domain and that resource is called "master", and any number of the Ingress resources handles the paths under that host/domain and each of these resources is called "minion".

Each one of the master or minion can or can not contain some Ingress annotations based on their role. Here I will use here the examples from the official documentation.

Config for shop.example.com like TLS and host-level annotations.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: shop-ingress-master
  namespace: shop
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.org/mergeable-ingress-type: "master"
spec:
  tls:
  - hosts:
    - shop.example.com
    secretName: shop-secret
  rules:
  - host: shop.example.com

Config for shop.example.com/coffee which is in the coffee namespace and routes the traffic of the coffee-svc service.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: shop-ingress-coffee-minion
  namespace: coffee
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.org/mergeable-ingress-type: "minion"
spec:
  rules:
  - host: shop.example.com
    http:
      paths:
      - path: /coffee
        pathType: Prefix
        backend:
          service:
            name: coffee-svc
            port:
              number: 80

Config for shop.example.com/tea which is in the tea namespace and routes the traffic of the tea-svc service.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: shop-ingress-tea-minion
  namespace: tea
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.org/mergeable-ingress-type: "minion"
spec:
  rules:
  - host: shop.example.com
    http:
      paths:
      - path: /tea
        pathType: Prefix
        backend:
          service:
            name: tea-svc
            port:
              number: 80

As you see, the Ingress config is split into 2 parts, the host/domain config, and the paths config. Each one of them could be in a different namespace and handles the services in that namespace.

Conclusion

Maybe the first approach looks like a workaround, but for many workloads could be better and easier to follow and digest. But in general, it's good to have different ways to use what's fit better.

Enjoy :-)

Continue Reading »
Powered by Blogger.

Hello, my name is Ahmed AbouZaid, I'm a passionate Tech Lead DevOps Engineer. 👋

I specialize in Cloud-Native and Kubernetes. I'm also a Free/Open source geek and book author. My favorite topics are DevOps transformation, DevSecOps, automation, data, and metrics.

More about me ➡️

Contact Me

Name

Email *

Message *

Start Your DevOps Engineer Journey!

Start Your DevOps Engineer Journey!
Start your DevOps career for free the Agile way in 2024 with the Dynamic DevOps Roadmap ⭐

Latest Post

Automate adding vCluster to Argo CD using External Secrets Operator - GitOps

Overview In KubeZero (an open-source out-of-the-box Platform Orchestrator with GitOps designed for multi-environment Clo...

Popular Posts

Blog Archive