Skip to content

MVP: Cost attribution #37659

MVP: Cost attribution

MVP: Cost attribution #37659

name: ci
on:
push:
branches:
- main
- r[0-9]+ # Trigger builds after a push to weekly branches
tags:
# The following regex matches the Mimir release tag. Tag filters not as strict due to different regex system on Github Actions.
- mimir-[0-9]+.[0-9]+.[0-9]+**
pull_request:
concurrency:
# Cancel any running workflow for the same branch when new commits are pushed.
# We group both by ref_name (available when CI is triggered by a push to a branch/tag)
# and head_ref (available when CI is triggered by a PR).
group: "${{ github.ref_name }}-${{ github.head_ref }}"
cancel-in-progress: true
jobs:
prepare:
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Get build image from Makefile
id: build_image_step
run: echo "build_image=$(make print-build-image)" >> "$GITHUB_OUTPUT"
outputs:
build_image: ${{ steps.build_image_step.outputs.build_image }}
# Determine if we will deploy (aka push) the image to the registry.
is_deploy: ${{ (startsWith(github.ref, 'refs/tags/') || startsWith(github.ref, 'refs/heads/r')) && github.event_name == 'push' && github.repository == 'grafana/mimir' }}
goversion:
runs-on: ubuntu-latest
needs: prepare
container:
image: ${{ needs.prepare.outputs.build_image }}
steps:
- uses: actions/checkout@v4
- name: Run Git Config
run: git config --global --add safe.directory '*'
- name: Get Go Version
id: go-version
run: |
echo "version=$(make BUILD_IN_CONTAINER=false print-go-version)" >> "$GITHUB_OUTPUT"
outputs:
version: ${{ steps.go-version.outputs.version }}
lint:
runs-on: ubuntu-latest
needs: prepare
container:
image: ${{ needs.prepare.outputs.build_image }}
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Run Git Config
run: git config --global --add safe.directory '*'
# Commands in the Makefile are hardcoded with an assumed file structure of the CI container
# Symlink ensures paths specified in previous commands don’t break
- name: Symlink Expected Path to Workspace
run: |
mkdir -p /go/src/github.com/grafana/mimir
ln -s $GITHUB_WORKSPACE/* /go/src/github.com/grafana/mimir
- name: Get golangci-lint cache path
id: golangcilintcache
run: |
echo "path=$(golangci-lint cache status | grep 'Dir: ' | cut -d ' ' -f2)" >> "$GITHUB_OUTPUT"
- name: Cache golangci-lint cache
uses: actions/cache@v4
with:
key: lint-golangci-lint-${{ runner.os }}-${{ hashFiles('go.mod', 'go.sum', '.golangci.yml', 'Makefile') }}
path: ${{ steps.golangcilintcache.outputs.path }}
- name: Get Go cache paths
id: goenv
run: |
echo "gocache=$(go env GOCACHE)" >> "$GITHUB_OUTPUT"
echo "gomodcache=$(go env GOMODCACHE)" >> "$GITHUB_OUTPUT"
- name: Cache Go build cache
uses: actions/cache@v4
with:
key: lint-go-build-${{ runner.os }}-${{ hashFiles('go.mod', 'go.sum') }}
path: ${{ steps.goenv.outputs.gocache }}
# Although we use vendoring, this linting job downloads all modules to verify that what is vendored is correct,
# so it'll use GOMODCACHE. Other jobs don't need this.
- name: Cache Go module cache
uses: actions/cache@v4
with:
key: lint-go-mod-${{ runner.os }}-${{ hashFiles('go.mod', 'go.sum') }}
path: ${{ steps.goenv.outputs.gomodcache }}
- name: Lint
run: make BUILD_IN_CONTAINER=false lint
- name: Check Vendor Directory
run: make BUILD_IN_CONTAINER=false mod-check
- name: Check Protos
run: make BUILD_IN_CONTAINER=false check-protos
- name: Check Generated Documentation
run: make BUILD_IN_CONTAINER=false check-doc
- name: Check White Noise
run: make BUILD_IN_CONTAINER=false check-white-noise
- name: Check License Header
run: make BUILD_IN_CONTAINER=false check-license
- name: Check Docker-Compose YAML
run: make BUILD_IN_CONTAINER=false check-mimir-microservices-mode-docker-compose-yaml check-mimir-read-write-mode-docker-compose-yaml
- name: Check Generated OTLP Code
run: make BUILD_IN_CONTAINER=false check-generated-otlp-code
doc-validator:
runs-on: ubuntu-latest
container:
image: grafana/doc-validator:v5.2.0
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Run Git Config
run: git config --global --add safe.directory '*'
- name: Run doc-validator tool (mimir)
run: >
doc-validator
'--skip-checks=^canonical-does-not-match-pretty-URL|image.+$'
docs/sources/mimir
/docs/mimir/latest
| reviewdog
-f=rdjsonl
--fail-on-error
--filter-mode=nofilter
--name=doc-validator
--reporter=github-pr-review
env:
REVIEWDOG_GITHUB_API_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
- name: Run doc-validator tool (helm-charts)
run: >
doc-validator
docs/sources/helm-charts
/docs/helm-charts/mimir-distributed/latest
| reviewdog
-f=rdjsonl
--fail-on-error
--filter-mode=nofilter
--name=doc-validator
--reporter=github-pr-review
env:
REVIEWDOG_GITHUB_API_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
lint-jsonnet:
runs-on: ubuntu-latest
needs:
- prepare
container:
image: ${{ needs.prepare.outputs.build_image }}
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Run Git Config
run: git config --global --add safe.directory '*'
# Commands in the Makefile are hardcoded with an assumed file structure of the CI container
# Symlink ensures paths specified in previous commands don’t break
- name: Symlink Expected Path to Workspace
run: |
mkdir -p /go/src/github.com/grafana/mimir
ln -s $GITHUB_WORKSPACE/* /go/src/github.com/grafana/mimir
- name: Check Mixin
run: make BUILD_IN_CONTAINER=false check-mixin
- name: Check Mixin Tests
run: make BUILD_IN_CONTAINER=false check-mixin-tests
- name: Check Mixin with Mimirtool rules check
run: make BUILD_IN_CONTAINER=false check-mixin-mimirtool-rules
- name: Check Jsonnet Manifests
run: make BUILD_IN_CONTAINER=false check-jsonnet-manifests
- name: Check Jsonnet Getting Started
run: make BUILD_IN_CONTAINER=false check-jsonnet-getting-started
- name: Check Jsonnet Tests
run: make BUILD_IN_CONTAINER=false check-jsonnet-tests
lint-helm:
runs-on: ubuntu-latest
needs:
- prepare
container:
image: ${{ needs.prepare.outputs.build_image }}
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Run Git Config
run: git config --global --add safe.directory '*'
# Commands in the Makefile are hardcoded with an assumed file structure of the CI container
# Symlink ensures paths specified in previous commands don’t break
- name: Symlink Expected Path to Workspace
run: |
mkdir -p /go/src/github.com/grafana/mimir
ln -s $GITHUB_WORKSPACE/* /go/src/github.com/grafana/mimir
- name: Set up Helm
uses: azure/setup-helm@v4
with:
version: v3.8.2
- name: Check Helm Tests
run: make BUILD_IN_CONTAINER=false check-helm-tests
test:
runs-on: ubuntu-latest
strategy:
# Do not abort other groups when one fails.
fail-fast: false
# Split tests into 4 groups.
matrix:
test_group_id: [0, 1, 2, 3]
test_group_total: [4]
needs:
- prepare
container:
image: ${{ needs.prepare.outputs.build_image }}
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Run Git Config
run: git config --global --add safe.directory '*'
- name: Symlink Expected Path to Workspace
run: |
mkdir -p /go/src/github.com/grafana/mimir
ln -s $GITHUB_WORKSPACE/* /go/src/github.com/grafana/mimir
- name: Get Go build cache path
id: gocache
run: |
echo "path=$(go env GOCACHE)" >> "$GITHUB_OUTPUT"
- name: Cache Go build cache
uses: actions/cache@v4
with:
# Cache is shared between test groups.
key: test-go-build-${{ runner.os }}-${{ hashFiles('go.mod', 'go.sum') }}
path: ${{ steps.gocache.outputs.path }}
- name: Run Tests
run: |
echo "Running unit tests (group ${{ matrix.test_group_id }} of ${{ matrix.test_group_total }}) with Go version: $(go version)"
./.github/workflows/scripts/run-unit-tests-group.sh --index ${{ matrix.test_group_id }} --total ${{ matrix.test_group_total }}
test-docs:
uses: ./.github/workflows/test-docs.yml
build:
runs-on: ubuntu-latest
needs:
- prepare
container:
image: ${{ needs.prepare.outputs.build_image }}
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Run Git Config
run: git config --global --add safe.directory '*'
- name: Install Docker Client
run: ./.github/workflows/scripts/install-docker.sh
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v3
- name: Symlink Expected Path to Workspace
run: |
mkdir -p /go/src/github.com/grafana/mimir
ln -s $GITHUB_WORKSPACE/* /go/src/github.com/grafana/mimir
- name: Get Go build cache path
id: gocache
run: |
echo "path=$(go env GOCACHE)" >> "$GITHUB_OUTPUT"
- name: Cache Go build cache
uses: actions/cache@v4
with:
key: build-go-build-${{ runner.os }}-${{ hashFiles('go.mod', 'go.sum') }}
path: ${{ steps.gocache.outputs.path }}
- name: Build Multiarch Docker Images Locally
# Ignore mimir-build-image and mimir-rules-action.
run: |
./.github/workflows/scripts/build-images.sh /tmp/images $(make list-image-targets | grep -v -E '/mimir-build-image/|/mimir-rules-action/')
- name: Build Archive With Docker Images
run: |
tar cvf images.tar /tmp/images
- name: Upload Archive with Docker Images
uses: actions/upload-artifact@v4
with:
name: Docker Images
path: ./images.tar
- name: Build Mimir with race-detector
run: |
# When building uptodate_race target, we create two images since
# a Dockerfile.alpine exists. The alpine image is built with
# the `-alpine` suffix.
# We build both until we have finished migrating to distroless.
# We test the distroless race image in every integration test.
# We test the (legacy) alpine race image when deploying (aka pushing).
make BUILD_IN_CONTAINER=false cmd/mimir/.uptodate_race
export IMAGE_TAG_RACE=$(make image-tag-race)
export MIMIR_DISTROLESS_IMAGE="grafana/mimir:$IMAGE_TAG_RACE"
export MIMIR_ALPINE_IMAGE="grafana/mimir-alpine:$IMAGE_TAG_RACE"
docker save $MIMIR_DISTROLESS_IMAGE -o ./mimir_race_image_distroless
docker save $MIMIR_ALPINE_IMAGE -o ./mimir_race_image_alpine
- name: Upload archive with race-enabled Mimir
uses: actions/upload-artifact@v4
with:
name: Race-enabled Mimir
path: |
./mimir_race_image_alpine
./mimir_race_image_distroless
integration:
needs: [goversion, build, prepare]
runs-on: ubuntu-latest
strategy:
# Do not abort other groups when one fails.
fail-fast: false
# Split tests into 6 groups.
matrix:
test_group_id: [0, 1, 2, 3, 4, 5]
test_group_total: [6]
steps:
- name: Upgrade golang
uses: actions/setup-go@v5
with:
go-version: ${{ needs.goversion.outputs.version }}
cache: false # We manage caching ourselves below to maintain consistency with the other jobs that don't use setup-go.
- name: Check out repository
uses: actions/checkout@v4
- name: Run Git Config
run: git config --global --add safe.directory '*'
- name: Install Docker Client
run: sudo ./.github/workflows/scripts/install-docker.sh
- name: Symlink Expected Path to Workspace
run: |
sudo mkdir -p /go/src/github.com/grafana/mimir
sudo ln -s $GITHUB_WORKSPACE/* /go/src/github.com/grafana/mimir
- name: Get Go build cache path
id: gocache
run: |
echo "path=$(go env GOCACHE)" >> "$GITHUB_OUTPUT"
- name: Cache Go build cache
uses: actions/cache@v4
with:
# Cache is shared between test groups.
key: integration-go-build-${{ runner.os }}-${{ hashFiles('go.mod', 'go.sum') }}
path: ${{ steps.gocache.outputs.path }}
- name: Download Archive with Docker Images
uses: actions/download-artifact@v4
with:
name: Docker Images
- name: Extract Docker Images from Archive
run: tar xvf images.tar -C /
- name: Load Mimirtool Image into Docker
run: |
export IMAGE_TAG=$(make image-tag)
# skopeo will by default load system-specific version of the image (linux/amd64).
# note that this doesn't use skopeo version from our build-image, because we don't use build-image when running integration tests.
# that's why we use docker run to run latest version.
docker run -v /tmp/images:/tmp/images -v /var/run/docker.sock:/var/run/docker.sock quay.io/skopeo/stable:v1.15.1 copy oci-archive:/tmp/images/mimirtool.oci "docker-daemon:grafana/mimirtool:$IMAGE_TAG"
- name: Download Archive with Docker Images
uses: actions/download-artifact@v4
with:
name: Race-enabled Mimir
- name: Load race-enabled mimir into Docker
run: |
export IMAGE_TAG_RACE=$(make image-tag-race)
docker load -i ./mimir_race_image_distroless
docker run "grafana/mimir:$IMAGE_TAG_RACE" --version
- name: Preload Images
# We download docker images used by integration tests so that all images are available
# locally and the download time doesn't account in the test execution time, which is subject
# to a timeout
run: go run ./tools/pre-pull-images | xargs -n1 -P4 docker pull
- name: Integration Tests
run: |
export IMAGE_TAG_RACE=$(make image-tag-race)
export MIMIR_IMAGE="grafana/mimir:$IMAGE_TAG_RACE"
export IMAGE_TAG=$(make image-tag)
export MIMIRTOOL_IMAGE="grafana/mimirtool:$IMAGE_TAG"
export MIMIR_CHECKOUT_DIR="/go/src/github.com/grafana/mimir"
echo "Running integration tests with image: $MIMIR_IMAGE (Mimir), $MIMIRTOOL_IMAGE (Mimirtool)"
echo "Running integration tests (group ${{ matrix.test_group_id }} of ${{ matrix.test_group_total }}) with Go version: $(go version)"
./.github/workflows/scripts/run-integration-tests-group.sh --index ${{ matrix.test_group_id }} --total ${{ matrix.test_group_total }}
integration-alpine:
needs: [goversion, build, prepare]
runs-on: ubuntu-latest
if: needs.prepare.outputs.is_deploy == 'true'
strategy:
# Do not abort other groups when one fails.
fail-fast: false
# Split tests into 6 groups.
matrix:
test_group_id: [0, 1, 2, 3, 4, 5]
test_group_total: [6]
steps:
- name: Upgrade golang
uses: actions/setup-go@v5
with:
go-version: ${{ needs.goversion.outputs.version }}
cache: false # We manage caching ourselves below to maintain consistency with the other jobs that don't use setup-go.
- name: Check out repository
uses: actions/checkout@v4
- name: Run Git Config
run: git config --global --add safe.directory '*'
- name: Install Docker Client
run: sudo ./.github/workflows/scripts/install-docker.sh
- name: Symlink Expected Path to Workspace
run: |
sudo mkdir -p /go/src/github.com/grafana/mimir
sudo ln -s $GITHUB_WORKSPACE/* /go/src/github.com/grafana/mimir
- name: Get Go build cache path
id: gocache
run: |
echo "path=$(go env GOCACHE)" >> "$GITHUB_OUTPUT"
- name: Cache Go build cache
uses: actions/cache@v4
with:
# Cache is shared between test groups.
key: integration-go-build-${{ runner.os }}-${{ hashFiles('go.mod', 'go.sum') }}
path: ${{ steps.gocache.outputs.path }}
- name: Download Archive with Docker Images
uses: actions/download-artifact@v4
with:
name: Docker Images
- name: Extract Docker Images from Archive
run: tar xvf images.tar -C /
- name: Load Mimirtool Image into Docker
run: |
export IMAGE_TAG=$(make image-tag)
# skopeo will by default load system-specific version of the image (linux/amd64).
# note that this doesn't use skopeo version from our build-image, because we don't use build-image when running integration tests.
# that's why we use docker run to run latest version.
docker run -v /tmp/images:/tmp/images -v /var/run/docker.sock:/var/run/docker.sock quay.io/skopeo/stable:v1.15.1 copy oci-archive:/tmp/images/mimirtool.oci "docker-daemon:grafana/mimirtool:$IMAGE_TAG"
- name: Download Archive with Docker Images
uses: actions/download-artifact@v4
with:
name: Race-enabled Mimir
- name: Load race-enabled mimir into Docker
run: |
export IMAGE_TAG_RACE=$(make image-tag-race)
docker load -i ./mimir_race_image_alpine
docker run "grafana/mimir-alpine:$IMAGE_TAG_RACE" --version
- name: Preload Images
# We download docker images used by integration tests so that all images are available
# locally and the download time doesn't account in the test execution time, which is subject
# to a timeout
run: go run ./tools/pre-pull-images | xargs -n1 -P4 docker pull
- name: Integration Tests
run: |
export IMAGE_TAG_RACE=$(make image-tag-race)
export MIMIR_IMAGE="grafana/mimir-alpine:$IMAGE_TAG_RACE"
export IMAGE_TAG=$(make image-tag)
export MIMIRTOOL_IMAGE="grafana/mimirtool:$IMAGE_TAG"
export MIMIR_CHECKOUT_DIR="/go/src/github.com/grafana/mimir"
echo "Running integration tests with image: $MIMIR_IMAGE (Mimir), $MIMIRTOOL_IMAGE (Mimirtool)"
echo "Running integration tests (group ${{ matrix.test_group_id }} of ${{ matrix.test_group_total }}) with Go version: $(go version)"
./.github/workflows/scripts/run-integration-tests-group.sh --index ${{ matrix.test_group_id }} --total ${{ matrix.test_group_total }}
deploy:
needs: [prepare, build, test, lint, integration, integration-alpine]
# Only deploy images on pushes to the grafana/mimir repo, which either are tag pushes or weekly release branch pushes.
if: needs.prepare.outputs.is_deploy == 'true'
runs-on: ubuntu-latest
container:
image: ${{ needs.prepare.outputs.build_image }}
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Run Git Config
run: git config --global --add safe.directory '*'
- name: Install Docker Client
run: ./.github/workflows/scripts/install-docker.sh
- name: Symlink Expected Path to Workspace
run: |
mkdir -p /go/src/github.com/grafana/mimir
ln -s $GITHUB_WORKSPACE/* /go/src/github.com/grafana/mimir
- name: Download Archive with Docker Images
uses: actions/download-artifact@v4
with:
name: Docker Images
- name: Extract Docker Images from Archive
run: tar xvf images.tar -C /
- name: Deploy
run: |
if [ -n "$DOCKER_PASSWORD" ]; then
printenv DOCKER_PASSWORD | skopeo login -u "$DOCKER_USERNAME" --password-stdin docker.io
fi
./.github/workflows/scripts/push-images.sh /tmp/images grafana/ $(make image-tag)
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}