DEV Community

Cover image for 5 Open-Source Projects We’re Using to Build Rig.dev
Niklas for Rig.dev

Posted on • Updated on • Originally published at rig.dev

5 Open-Source Projects We’re Using to Build Rig.dev

Outlines
One of the key elements that make our platform, Rig.dev what it is today, is our love for the Open-Source community.

Why? We believe in transparency, community, and the kind of innovation that only comes from a diverse, collaborative effort.

In this article, we will give you a detailed look into the Open-Source projects that powers Rig.dev. From our CLI to our frontend, each tool has been carefully selected to align with our mission and offer the best possible experience for both developers and DevOps teams. Enjoy!

About Rig.dev

Rig.dev offers an Open-Source application platform for Kubernetes. We empower developers to work in their own environments with elevated application abstractions, while still leveraging Kubernetes's reliability, portability, and scalability.

Introducing Rig.dev

Our developer-friendly deployment engine simplifies the process of rolling out, managing, debugging and scaling applications. On top, our platform includes a Dashboard, CLI, and CI/CD pipelines that seamlessly integrate with GitHub Actions.

We need your help

We are not done building yet, but we would love your support on Github along the way. It motivates us to keep making Rig.dev better 🙏
Our Github Project: https://github.com/rigdev/rig


1. Cobra: The Backbone of Our CLI

Cobra is a go-to library for building CLIs in Go (pun intended). What makes it a standout choice is its ease of use right from the get-go (yup, again). You can create a functional CLI with just a few lines of Go code and as your project scales, Cobra scales with you, offering both complexity and extensibility.

Why We Chose Cobra for Our CLI

Rich Functionality Out-of-the-Box
Cobra comes packed with a ton of built-in features that make CLI development a breeze:

Subcommands: Easily create nested commands, making your CLI more organized and intuitive.
Global, Local and Persistent Flags: Define flags that work across all commands, are specific to single commands or are inherited by subcommands.

Positional Arguments: Handle positional arguments effortlessly with validation functions and guards, making your CLI more flexible while retaining control.

Automatic Help Command: Cobra auto-generates help commands saving you the hassle of manual documentation - With the option of customizing the commands of course.

Extensibility: Play Well with Others

One of the key strengths of Cobra is also its extensibility. While Cobra takes care of the CLI's structure and the command-line parsing, you're free to integrate it with other tools to get the job done however you like:

Interactive CLI with PromptKit: We use PromptKit to add interactivity and style to our CLI. This makes the user experience more engaging.

Dependency Injection with UberFX: We leverage UberFX to inject dependencies directly into our commands, making the code cleaner and more maintainable.

Example: Creating and deploying a redis capsule

  1. Create a build with a redis image.
  2. Instances in the capsule listen on port 6379 and the same port is exposed using a load balancer.
  3. We specify that when the container starts, it runs the command "redis-server /usr/local/etc/redis/redis.conf" which is how you start the redis server with a specific configuration file.
  4. We then mount that config file into /usr/local/etc/redis/redis.conf from the local redis.conf file.
  5. Finally, we deploy 3 instances

Create a build with a redis image


2. UberFX: Streamlining Dependency Injection in Go

UberFX is a robust dependency injection framework crafted by Uber for Go. In the absence of dependency injection, developers often find themselves manually constructing a myriad of objects or, worse, depending on unstable global state.

Why we use UberFX

We chose UberFX because we've seen it scale effectively, from small applications to massive codebases. Some of our team members have firsthand experience with its successful implementation at Uber, so we're confident in its ability to scale with Rig.dev as we grow.

Real-World Example: How We Use UberFX in Rig.dev

Structuring Components
In Rig.dev, all our components follow a similar initialization pattern. We specify the dependencies of each component in its constructor, and UberFX takes care of constructing everything in the right order. Here's a simplified example:

type service struct {
    logger         *zap.Logger
    userRepo       repository.User
    secretRepo     repository.Secret
    projectService project_service.Service
}

type newParams struct {
    fx.In
    Logger         *zap.Logger
    UserRepo       repository.User
    SecretRepo     repository.Secret
    ProjectService project_service.Service
}

func NewService(p newParams) Service {
    return &service{
        logger:         p.Logger,
        userRepo:       p.UserRepo,
        secretRepo:     p.SecretRepo,
        projectService: p.ProjectService,
    }
}
Enter fullscreen mode Exit fullscreen mode

We then group the constructors of related components into Fx Modules:

var Module = fx.Module(
    "service",
    fx.Provide(
        capsule.NewService,
        user.NewService,
        auth.NewService,
        project.NewService,
        group.NewService,
    ),
)
Enter fullscreen mode Exit fullscreen mode

and from there it's a simple matter to construct the entire Rig server. We also use FX to execute non-constructor functions needed to setup the server:

// Slightly simplified Rig Server construction 
rigServer := fx.New(
    service.Module,
    repository.Module,
    gateway.Module,
    telemetry.Module,
    fx.Supply(config),
    // Non-constructor function needed to setup the server 
    fx.Invoke(
        func(cfg config.Config, s *pkg_service.Server) {
            s.EmbeddedFileServer()
            s.Init()
        },
    ),
)
Enter fullscreen mode Exit fullscreen mode

Fx also handles the various lifecycles of executing the Rig server, e.g.

// Simplified execution of Fx's lifecycles which power the Rig server
func run(ctx context.Context, rigServer *fx.App) error {
    if err := rigServer.Start(ctx); err != nil {
        return err
    }

    sig := <-rigServer.Wait()
    var err error
    if sig.ExitCode != 0 {
        err = fmt.Errorf("aborted: signal %v", sig.Signal.String())
    }

    if err := rigServer.Stop(ctx); err != nil {
        return err
    }

    return nil
}
Enter fullscreen mode Exit fullscreen mode

UberFX has significantly simplified the way we build and run Rig.dev. It allows us to construct our application out of reusable components, streamlining the development process and ensuring that we can scale efficiently as our codebase grows.


3. Kubebuilder

Kubebuilder has established itself as the go-to tool when it comes to creating API extensions for Kubernetes. Sure, one can craft controllers using a raw Kubernetes API client, and technically, you could do this in any programming language.

Kubebuilder

But here's the catch: Kubernetes is written in Go, and so is a significant chunk of its ecosystem. To ensure seamless integration and reduce potential issues with tooling, it's makes perfect sense to stick with the most widely adopted tool in the ecosystem.

Insights into Our Upcoming Integration with Kubebuilder

As Rig.dev evolves, we're constantly looking for ways to enhance our platform's capabilities. One of the significant shifts we're planning is transitioning some of our APIs from being solely within Rig.dev to being more deeply integrated with Kubernetes. Our vision? To introduce a Custom Resource Definition (CRD) that will encapsulate our "capsule" concept (pun very much intended).

The Potential Benefits This Integration Will Bring to Our Users

By making this move, we're essentially making Rig.dev more compatible with the broader Kubernetes ecosystem. This has a couple of key advantages:

Ecosystem Compatibility: As we integrate our APIs more deeply into Kubernetes, Rig.dev becomes more compatible with the broader Kubernetes ecosystem. This means better interoperability with other tools and platforms that Kubernetes professionals use daily.

Familiarity: Developers who are already well-versed with Kubernetes APIs will find our APIs more intuitive and familiar. This reduces the learning curve and allows them to be productive right off the bat.

Flexibility: With our APIs being more Kubernetes-native, developers gain more flexibility in how they deploy, manage, and scale their applications on Rig.dev.

Our upcoming integration with Kubebuilder is all about reducing friction and making life easier for devs and DevOps teams that are already knee-deep in Kubernetes. We're excited about the added compatibility and the doors it will open for more integrated and streamlined operations.


4. Go-ContainerRegistry: Simplifying Remote Registry Operations

Go-ContainerRegistry is a Go library that provides a straightforward way to interact with container image registries. If you've ever needed to explore remote registries, pull images, or manipulate image metadata, this is the tool you'd likely reach for.

Go-ContainerRegistry

Why Do We Use Go-ContainerRegistry?

The primary reason we use Go-ContainerRegistry in Rig.dev is for its unified approach to working with container images. Whether you're dealing with various remote registries, a local daemon, or even local image files, Go-ContainerRegistry provides a consistent interface for all these operations. Here's why that's crucial for us:

Unified Interface: No need to juggle different tools or libraries when working with images. Go-ContainerRegistry offers a single, unified API for all your needs.

Cross-Registry Support: Whether you're pulling from Docker Hub, Google Container Registry, or any other registry, you can do it all through the same API calls.

Local and Remote: The library isn't just for remote operations; you can also use it to interact with your local Docker daemon or manipulate local image files.


5. Vue + Nuxt: Powering Our Frontend Development

Why We Chose Vue & Nuxt

When it comes to frontend development, time-to-market is often a critical factor. Vue, known for its simplicity, coupled with Nuxt, allowed us to roll out an MVP in record time. But don't let the simplicity fool you; Vue and Nuxt are among the most powerful frameworks you can use for frontend development.

Benefits of Using Vue & Nuxt

Simplicity & Quick Onboarding: If you're comfortable with HTML, CSS, and JavaScript, you'll find Vue to be incredibly approachable. The learning curve is less steep compared to other popular frameworks like React and Angular, making it easier to onboard new developers.

Performance & Lightweight Footprint: Vue is lightweight, which translates to better performance. When pitted against other popular frameworks like React and Angular, Vue consistently outperforms them (Benchmarks: https://krausest.github.io/js-framework-benchmark/current.html), especially in terms of initial load times and runtime efficiency.

Development Productivity: Nuxt takes Vue's simplicity and supercharges it, making it even easier to build complex applications. It handles a lot of the boilerplate and configuration for you, allowing devs to focus more on application logic and less on the underlying infrastructure.

Stellar Documentation: Both Vue and Nuxt come with comprehensive documentation, making it easier for new or existing developers to get up to speed. This is a significant advantage when it comes to scaling the team or introducing new features.

Why Do We Use Vue & Nuxt in Rig.dev?

The unified approach that Vue and Nuxt offer aligns well with our philosophy at Rig.dev. Just like we aim for a unified way of working with images across registries, daemons, and local files in the backend, Vue and Nuxt provide a cohesive and efficient way to build and manage our frontend.


Wrapping Up

Our journey with these open-source projects is not just about leveraging their capabilities; it's about being part of a larger community. A community that thrives on collaboration, innovation, and the shared goal of making technology more accessible and efficient.

As we continue to grow and refine Rig.dev, we remain grateful to the developers and communities behind these projects. Their dedication and expertise will have an instrumental role in our future growth. We're excited about the what's coming, and we're committed to giving back to the open-source world, contributing to its growth, and ensuring that Rig.dev remains at the forefront of Kubernetes application platforms.


Join our community

Also, please join our Slack Community to share feedback, report bugs, suggest features, and stay tuned for future updates.

Team Rig.dev Thanks from Team Rig.dev 🙏

Top comments (3)

Collapse
 
scorcism profile image
Abhishek Pathak

rig team looks like a music band.
great blog buddy

Collapse
 
niklasrefnov profile image
Niklas

Thanks, it means a lot!
I've suggested to the team that we start a band as a side-project 😎

Collapse
 
scorcism profile image
Abhishek Pathak

We can expect new blog then "dev + band".
Name also suites for band the rig