Continuous Integration and Continuous Delivery (CI/CD)
The provided codebase for the Balena Prometheus Exporter, while not explicitly incorporating CI/CD, has a clear foundation for automation.
Workflow:
Build: The
Dockerfile
defines the process for building the Docker image.FROM python:3.10-alpine WORKDIR /usr/src/app COPY requirements.txt ./ RUN pip install --no-cache-dir -r requirements.txt COPY main.py . USER nobody CMD [ "python", "./main.py" ]
Test: Tests are provided in
tests/test_exporter.py
.import unittest from unittest import mock from main import BalenaCollector class TestBalenaCollector(unittest.TestCase): def setUp(self): self.collector = BalenaCollector() @mock.patch("main.BalenaCollector.get_fleet_metrics") def test_collect(self, mock_metrics): with mock.patch.object(self.collector, "get_balena_fleets") as mock_fleets: mock_fleets.return_value = ["fleet1", "fleet2"] mock_metrics.side_effect = [("test_fleet", 3), ("test_fleet", 3)] result = list(self.collector.collect()[0].samples) expected = [('balena_devices_online', {'fleet_name': 'test_fleet'}, 3), ('balena_devices_online', {'fleet_name': 'test_fleet'}, 3)] result = [(s.name, s.labels, s.value) for s in result] self.assertEqual(result, expected) def test_get_balena_fleets(self): with mock.patch("main.requests.get") as mock_get: mock_get.return_value.ok = True mock_get.return_value.json.return_value = {"d": [{"id": "fleet1"}, {"id": "fleet2"}]} result = list(self.collector.get_balena_fleets()) expected = ["fleet1", "fleet2"] self.assertEqual(result, expected) def test_get_fleet_metrics(self): with mock.patch("main.requests.get") as mock_get: mock_get.return_value.ok = True mock_get.return_value.json.return_value = {"d": [{"owns__device": 3, "app_name": "test_fleet"}]} result = self.collector.get_fleet_metrics("fleet1") expected = ("test_fleet", 3) self.assertEqual(result, expected) unittest.main()
Deploy: The
README.md
demonstrates a basic Docker run command for local deployment.$ docker build -t balena-exporter . $ docker run -d \ --name balena-exporter \ -p 8000:8000 \ -e BALENA_TOKEN= \ balena-exporter
CI/CD Implementation:
GitHub Actions:
- GitHub Actions is a popular choice for CI/CD pipelines within GitHub repositories.
- A workflow could be defined to automatically build the Docker image, run tests, and deploy to a container registry or directly to a Balena cloud application.
- https://docs.github.com/en/actions/using-workflows
- https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions
Jenkins:
- Jenkins is a widely used CI/CD server that can be integrated with the project.
- Jenkins pipelines can be created to automate the build, test, and deployment processes.
- https://www.jenkins.io/
Balena Cloud:
- Balena Cloud offers a built-in CI/CD system.
- It provides a workflow for building Docker images, running tests, and deploying them to devices.
- https://www.balena.io/docs/
Considerations:
- Security: Securely store the
BALENA_TOKEN
and other sensitive credentials. - Testing: Expand the test suite to cover more code paths and edge cases.
- Monitoring: Integrate with monitoring tools to track the performance and health of the exporter.
- Deployment Strategy: Choose the appropriate deployment strategy, considering factors like blue-green deployments or canary releases.
Example CI/CD Pipeline (GitHub Actions):
name: CI/CD
on:
push:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build Docker Image
run: docker build -t balena-exporter .
- name: Run Tests
run: pytest tests/test_exporter.py
- name: Push Image to Registry
run: docker push balena-exporter
deploy:
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v3
- name: Deploy to Balena Cloud
uses: balena-io/[email protected]
with:
balenaToken: ${{ secrets.BALENA_TOKEN }}
applicationId: ${{ secrets.APPLICATION_ID }}
release: balena-exporter
Top-Level Directory Explanations
tests/ - This directory contains all the unit and integration tests for the project. It includes the __init__.py
file which makes it a package, and specific test files like test_exporter.py
.