Bazel GitOps Rules

repository·main·Indexed 42 days ago

https://github.com/adobe/rules_gitops

A Bazel ruleset that bridges hermetic builds and GitOps-driven Kubernetes deployments. It automates manifest rendering via the k8s_deploy macro, Kustomize transformations, container image substitution, and the creation of GitOps pull requests for GitHub, GitLab, and Bitbucket using the create_gitops_prs tool. It includes managed toolchains for kustomize and kubectl, and experimental integration testing support via k8s_test_setup.

Tokens
5K
Snippets
13
Records
20
Agent score
52%

What's inside rules_gitops

  1. Explore Bazel GitOps Rules examples

    main

    The examples/ directory contains reference implementations for different integration scenarios with rules_gitops:

    • helloworld: Demonstrates a minimal Go application integrated with k8s_deploy manifests.
    • legacy_docker: Demonstrates how to adapt a minimal container image built with rules_docker for use with rules_gitops.
  2. Use fasttemplate for Go templating

    main

    fasttemplate is a simple and fast template engine for Go. It is a fork of valyala/fasttemplate with the following modifications:

    1. Removal of unsafe usage.
    2. Removal of buffer pools.

    CRITICAL SECURITY NOTE: Unlike the standard html/template package, fasttemplate does not perform any escaping on template values. You must manually escape all values before passing them to the engine to prevent injection vulnerabilities (e.g., XSS if generating HTML).

  3. Use placeholders with the --stamp parameter

    main

    The --stamp parameter allows you to replace placeholders in your manifests. To prevent unnecessary GitOps churn, the tool only performs the replacement if the resulting manifest's digest differs from the one currently saved. The new digest is stored in a .digest file alongside the YAML.

    Supported Placeholders:

    • {{GIT_REVISION}}: The result of git rev-parse HEAD.
    • {{UTC_DATE}}: The current UTC date (result of date -u).
    • {{GIT_BRANCH}}: The value provided to the --branch_name argument in create_gitops_prs.
  4. Configure Trunk-Based GitOps Workflow

    main

    In a trunk-based model, create_gitops_prs is run on the main branch. It identifies gitops targets that match a specific --release_branch (which corresponds to the release_branch_prefix attribute in k8s_deploy) and groups them by their deploy_branch attribute.

    Key Parameters for CI Integration:

    • --workspace: The root directory of your Git workspace.
    • --git_repo: The remote URL of the repository.
    • --git_mirror: Path to a local reference repository to speed up cloning.
    • --git_server: The type of Git server (github, gitlab, or bitbucket).
    • --release_branch: Matches the release_branch_prefix in your k8s_deploy targets.
    • --gitops_pr_into: The target branch for the new PR.
    • --branch_name: The value used in the PR commit message.
    • --git_commit: The specific commit ID to use in the PR.
    • --dry_run: Tests the tool without creating actual PRs (recommended for CI testing).
    GIT_ROOT_DIR=$(git rev-parse --show-toplevel)
    GIT_COMMIT_ID=$(git rev-parse HEAD)
    GIT_BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD)
    if [ "${GIT_BRANCH_NAME}" == "master"]; then
        bazel run //gitops/prer:create_gitops_prs -- \
            --workspace $GIT_ROOT_DIR \
            --git_repo https://github.com/example/repo.git \
            --git_mirror $GIT_ROOT_DIR/.git \
            --git_server github \
            --release_branch master \
            --gitops_pr_into master \
            --gitops_pr_title "This is my pull request title" \
            --gitops_pr_body "This is my pull request body message" \
            --branch_name ${GIT_BRANCH_NAME} \
            --git_commit ${GIT_COMMIT_ID}
    fi
  5. Build and test the project

    main

    To verify the installation and ensure everything is working correctly, run the following commands:

    To test the ruleset itself:

    bazel test //...

    To test the included examples project:

    cd examples/helloworld
    bazel test //...
  6. Implement a Multiple Release Branches GitOps Workflow

    main

    When a trunk-based model is unsuitable, you can use the create_gitops_prs tool to create GitOps pull requests from release branches before they are merged into main.

    To implement this, use the --release_branch parameter to specify the base release branch (e.g., release/team) and the --deployment_branch_suffix parameter to handle the unique suffix of the current release branch (e.g., -20200101). This allows the tool to target specific deployment branches like deploy/monitoring-stage-20200101 for PRs into master.

    In your k8s_deploy rules, use the release_branch_prefix attribute to ensure deployments are only selected when the tool is running against the matching release branch prefix.

    # Example shell command for CI pipeline running on a release branch
    if [ "${RELEASE_BRANCH}" == "release/team"]; then
        bazel run //gitops/prer:create_gitops_prs -- \
            --workspace $GIT_ROOT_DIR \
            --git_repo https://github.com/example/repo.git \
            --git_mirror $GIT_ROOT_DIR/.git \
            --git_server github \
            --release_branch ${RELEASE_BRANCH} \
            --deployment_branch_suffix=${RELEASE_BRANCH_SUFFIX} \
            --gitops_pr_into master \
            --gitops_pr_title "This is my pull request title" \
            --gitops_pr_body "This is my pull request body message" \
            --branch_name ${GIT_BRANCH_NAME} \
            --git_commit ${GIT_COMMIT_ID}
    fi
  7. Automate GitOps PRs with create_gitops_prs

    main

    The create_gitops_prs tool automates the creation of pull requests in your GitOps repository. This is typically run as the final step in a CI pipeline.

    To see all available command-line options, run:

    bazel run @rules_gitops//gitops/prer:create_gitops_prs -- --help

    Supported Git Servers

    Use the --git_server flag to specify the provider. The available options are github, gitlab, and bitbucket. Each provider requires specific parameters:

    ServerRequired/Default Parameters
    github--github_repo_owner, --github_repo, --github_access_token (defaults to $GITHUB_TOKEN), --github_enterprise_host
    gitlab--gitlab_host (defaults to https://gitlab.com), --gitlab_repo, --gitlab_access_token (defaults to $GITLAB_TOKEN)
    bitbucket--bitbucket_api_pr_endpoint, --bitbucket_user (defaults to $BITBUCKET_USER), --bitbucket_password (defaults to $BITBUCKET_PASSWORD)
  8. Configure kustomize and kubectl toolchains

    main

    The ruleset provides managed toolchains for kustomize and kubectl. By default, it uses managed versions, but you can specify custom versions using Bzlmod extensions in your MODULE.bazel file.

    kustomize = use_extension("@rules_gitops//kustomize:defs.bzl", "kustomize")
    kustomize.toolchain(
        version = "5.7.1",  # specify your desired version
    )
    
    kubectl = use_extension("@rules_gitops//kubectl:defs.bzl", "kubectl")
    kubectl.toolchain(
        version = "1.32.2",  # specify your desired version
    )
  9. Set up experimental Integration Testing with k8s_test_setup

    main

    Note: Integration testing support is currently experimental and the public API is subject to change (no semver guarantee).

    To perform integration testing, you must use two rules in tandem:

    1. k8s_test_setup: Manages the Kubernetes environment. It creates a temporary namespace (formatted as [username][5 random digits]) and a kubeconfig file. It also deploys the objects specified in the objects attribute.
    2. A test rule (e.g., java_test): Executes the actual test logic. It must consume the shell script produced by k8s_test_setup as data and use the $(location ...) Bazel function to pass the script path to the test runner.

    Your test code is responsible for:

    • Launching the setup script.
    • Monitoring the script's console output for pod readiness events.
    k8s_test_setup(
        name = "service_it.setup",
        kubeconfig = "@k8s_test//:kubeconfig",
        objects = [
            "//service:mynamespace",
        ],
    )
    
    java_test(
        name = "service_it",
        srcs = ["ServiceIT.java"],
        data = [":service_it.setup"],
        jvm_flags = ["-Dk8s.setup=$(location :service_it.setup)"],
    )
  10. Configure k8s_deploy for release branches

    main

    When using a release branch workflow, configure k8s_deploy with the release_branch_prefix attribute. This ensures that the rule is only active when the create_gitops_prs tool is targeting that specific branch prefix.

    k8s_deploy(
        name = "stage-grafana",
        deploy_branch = "monitoring-stage",
        release_branch_prefix = "release/team",  # Only selected when --release_branch=release/team
        ...
    )
  11. Integrate container images with k8s_deploy

    main

    To connect container images built with rules_img to your k8s_deploy targets, use the k8s_push_info adapter. This ensures that image pushes and registry information are correctly associated with the deployment.

    load("@rules_gitops//adapters:rules_img.bzl", "k8s_push_info")
    load("@rules_gitops//gitops:defs.bzl", "k8s_deploy")
    load("@rules_img//img:image.bzl", "image_manifest")
    load("@rules_img//img:push.bzl", "image_push")
    
    image_manifest(
        name = "my_image",
        # ... image configuration
    )
    
    image_push(
        name = "push",
        image = ":my_image",
        registry = "my-registry.com",
        repository = "my-org/my-image",
    )
    
    k8s_push_info(
        name = "k8s_image",
        image = ":my_image",
        push = ":push",
        registry = "my-registry.com",
        repository = "my-org/my-image",
    )
    
    k8s_deploy(
        name = "my_deployment",
        cluster = "my-cluster",
        images = [":k8s_image"],
        manifests = ["deployment.yaml"],
        namespace = "{BUILD_USER}",
    )