Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions sample-apps/docker/.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
METRICS_FILE=expected_metrics
JOB_LABEL=integrations/<INTEGRATION_SNIPPET_SLUG>
1 change: 1 addition & 0 deletions sample-apps/docker/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cloud-init.yaml
41 changes: 41 additions & 0 deletions sample-apps/docker/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
VM_NAME ?= docker-sample-app
CONFIG_FILE_DIR := jinja/variables
CONFIG_FILE := $(CONFIG_FILE_DIR)/cloud-init.yaml
LOKI_INSTANCE ?= your-loki-instance:3100
PROMETHEUS_INSTANCE ?= your-prometheus-instance:9090

# Import last to ensure expected parameters are set and available to import from this file
include ../Makefile

.PHONY: run run-ci stop exporter fetch-prometheus-metrics render-config launch-vm clean defaultconfig

run: launch-vm
@echo "VM $(VM_NAME) launched and configured."

run-ci: clean defaultconfig launch-vm
@echo "Running in CI mode"

stop:
@multipass stop $(VM_NAME)
@multipass delete $(VM_NAME)
@multipass purge

render-config:
@docker run --rm -v $(shell pwd)/jinja/templates:/templates -v $(shell pwd)/jinja/variables:/variables dinutac/jinja2docker:latest /templates/cloud-init-template.yaml /variables/cloud-init.yaml --format=yaml > cloud-init.yaml

launch-vm: render-config
@multipass launch -n $(VM_NAME) --cloud-init cloud-init.yaml

clean:
@rm -f cloud-init.yaml
@rm -rf $(CONFIG_FILE_DIR)

defaultconfig:
@mkdir -p $(CONFIG_FILE_DIR)
@echo "interval: \"10s\"" >> jinja/variables/cloud-init.yaml
@echo "loki_url: http://$(LOKI_INSTANCE)/loki/api/v1/push" >> jinja/variables/cloud-init.yaml
@echo "loki_user: your_loki_username" >> jinja/variables/cloud-init.yaml
@echo "loki_pass: your_loki_password" >> jinja/variables/cloud-init.yaml
@echo "prom_url: http://$(PROMETHEUS_INSTANCE)/api/v1/push" >> jinja/variables/cloud-init.yaml
@echo "prom_user: your_prometheus_username" >> jinja/variables/cloud-init.yaml
@echo "prom_pass: your_prometheus_password" >> jinja/variables/cloud-init.yaml
64 changes: 64 additions & 0 deletions sample-apps/docker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Docker sample app

This sample application creates an Ubuntu VM integrated with Alloy for metric and log collection. This sample app utilizes cloud-init and Make commands to facilitate the setup, configuration, and monitoring of Docker using the node-exporter.

It is largely based off of [Canonical's cloud-init for Docker](https://raw.githubusercontent.com/canonical/multipass/refs/heads/main/data/cloud-init-yaml/cloud-init-docker.yaml), which is also used for our database spinup, with added Alloy configuration steps.

## Prerequisites

Before you begin, ensure you have the following installed:

- [Multipass](https://multipass.run/)
- Docker (for rendering the cloud-init configuration)
- Git (for cloning the repository)

## Quick Start for new users

To get started with the sample app, follow these steps:

1. **Clone the repository**:
```sh
git clone https://github.com/grafana/integration-sample-apps.git
cd integration-sample-apps/docker
```

2. **Set up default config**:
Execute `make defaultconfig` to create a template file with default configuration variables. Modify `jinja/variables/cloud-init.yaml` to connect Alloy to an external Prometheus compatible TSDB and/or Loki server.

3. **Render cloud-init configuration**:
Run `make render-config` to generate the `cloud-init.yaml` file based on your configuration.

4. **Create and set up VMs**:
Use `make run` to start the Docker sample app.

6. **Stop and clean Up**:
Use `make stop` to clean up the VM and `make clean` to remove temporary files.

## Make commands

- `make defaultconfig`: Initializes the configuration file with default values for cloud-init templates.
- `make render-config`: Generates the `cloud-init.yaml` configuration file using the defined variables.
- `make run`: Creates the Docker sample app.
- `make clean`: Deletes all created VMs and performs cleanup.

## Default configuration variables

- `prom_pass`: Your Prometheus password.
- `prom_user`: Your Prometheus username.
- `prom_url`: URL for Prometheus push endpoint (e.g., `http://your-prometheus-instance:9090/api/v1/push`).
- `loki_url`: URL for Loki push endpoint (e.g., `http://your-loki-instance:3100/loki/api/v1/push`).
- `loki_user`: Your Loki username.
- `loki_pass`: Your Loki password.

## Validating services

### Alloy
- **Check service status**: Confirm that Alloy is running.
```bash
systemctl status alloy.service
```
- **Review configuration**: Verify the configuration in `/etc/alloy/config.alloy` is correct.
- **Check logs**: Review Alloy logs for any connectivity or configuration issues.
```bash
journalctl -u alloy.service
```
279 changes: 279 additions & 0 deletions sample-apps/docker/jinja/templates/cloud-init-template.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
# jinja/templates/cloud-init-template.yaml
# Cloud-init configuration for setting up Alloy and required Docker sample-app
# Largely based on https://raw.githubusercontent.com/canonical/multipass/refs/heads/main/data/cloud-init-yaml/cloud-init-docker.yaml
# With added configuration for Grafana Alloy

apt:
sources:
docker:
source: |
deb https://download.docker.com/linux/ubuntu $RELEASE stable
key: |
-----BEGIN PGP PUBLIC KEY BLOCK-----

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
YT90qFF93M3v01BbxP+EIY2/9tiIPbrd
=0YYh
-----END PGP PUBLIC KEY BLOCK-----
grafana:
source: deb https://apt.grafana.com stable main
keyid: 963FA27710458545
keyserver: https://apt.grafana.com/gpg.key

packages:
- git
- gpg
- alloy
- binfmt-support
- docker-ce
- docker-ce-cli
- docker-compose
- containerd.io
- jq
- qemu-user-static
- skopeo

snap:
commands:
- snap install yq

runcmd:
# General setup
- sudo apt-get update

# Configure Alloy
- sudo systemctl enable alloy.service
- sudo systemctl start alloy.service


# General setup
- sudo apt-get update

- |
# add `ubuntu` to the `docker` group
adduser ubuntu docker

- |
# disable swap
sysctl vm.swappiness=0
echo "vm.swappiness = 0" | tee -a /etc/sysctl.conf

- |
# disable unnecessary services
systemctl disable man-db.timer man-db.service --now
systemctl disable apport.service apport-autoreport.service --now
systemctl disable apt-daily.service apt-daily.timer --now
systemctl disable apt-daily-upgrade.service apt-daily-upgrade.timer --now
systemctl disable unattended-upgrades.service --now
systemctl disable motd-news.service motd-news.timer --now
systemctl disable bluetooth.target --now
systemctl disable ua-messaging.service ua-messaging.timer --now

- |
# portainer, to easily manage containers
# available on http://<IP>:9000
docker run -d \
-p 9000:9000 \
--name=portainer \
--restart=always \
-v /var/run/docker.sock:/var/run/docker.sock \
-v portainer_data:/data \
portainer/portainer-ce

- |
# apt cleanup
apt-get autoremove -y

# Configure Docker for Alloy
- sudo usermod -a -G docker alloy
- sudo sed -i 's/User=alloy/User=root/' /etc/systemd/system/alloy.service
- sudo systemctl daemon-reload

# Configure Alloy
- sudo systemctl restart alloy.service

write_files:
# Alloy configuration
- owner: root:root
path: /etc/alloy/config.alloy
content: |
prometheus.exporter.self "alloy_check" { }

discovery.relabel "alloy_check" {
targets = prometheus.exporter.self.alloy_check.targets

rule {
target_label = "instance"
replacement = constants.hostname
}

rule {
target_label = "alloy_hostname"
replacement = constants.hostname
}

rule {
target_label = "job"
replacement = "integrations/alloy-check"
}
}

prometheus.scrape "alloy_check" {
targets = discovery.relabel.alloy_check.output
forward_to = [prometheus.relabel.alloy_check.receiver]

scrape_interval = "60s"
}

prometheus.relabel "alloy_check" {
forward_to = [prometheus.remote_write.metrics_service.receiver]

rule {
source_labels = ["__name__"]
regex = "(prometheus_target_sync_length_seconds_sum|prometheus_target_scrapes_.*|prometheus_target_interval.*|prometheus_sd_discovered_targets|alloy_build.*|prometheus_remote_write_wal_samples_appended_total|process_start_time_seconds)"
action = "keep"
}
}

prometheus.remote_write "metrics_service" {
endpoint {
url = "{{ prom_url }}"

{% if prom_user and prom_pass -%}
basic_auth {
username = "{{ prom_user }}"
password = "{{ prom_pass }}"
}
{%- endif %}
}
}

loki.write "grafana_cloud_loki" {
endpoint {
url = "{{ loki_url }}"

{% if loki_user and loki_pass -%}
basic_auth {
username = "{{ loki_user }}"
password = "{{ loki_pass }}"
}
{%- endif %}
}
}

prometheus.exporter.cadvisor "integrations_cadvisor" {
docker_only = true
}

discovery.relabel "integrations_cadvisor" {
targets = prometheus.exporter.cadvisor.integrations_cadvisor.targets

rule {
target_label = "job"
replacement = "integrations/docker"
}

rule {
target_label = "instance"
replacement = constants.hostname
}
}

prometheus.scrape "integrations_cadvisor" {
targets = discovery.relabel.integrations_cadvisor.output
forward_to = [prometheus.remote_write.metrics_service.receiver]
}

discovery.docker "logs_integrations_docker" {
host = "unix:///var/run/docker.sock"
refresh_interval = "5s"
}

discovery.relabel "logs_integrations_docker" {
targets = []

rule {
target_label = "job"
replacement = "integrations/docker"
}

rule {
target_label = "instance"
replacement = constants.hostname
}

rule {
source_labels = ["__meta_docker_container_name"]
regex = "/(.*)"
target_label = "container"
}

rule {
source_labels = ["__meta_docker_container_log_stream"]
target_label = "stream"
}
}

loki.source.docker "logs_integrations_docker" {
host = "unix:///var/run/docker.sock"
targets = discovery.docker.logs_integrations_docker.targets
forward_to = [loki.write.grafana_cloud_loki.receiver]
relabel_rules = discovery.relabel.logs_integrations_docker.rules
refresh_interval = "5s"
}
1 change: 1 addition & 0 deletions sample-apps/docker/tests/configs/docker_metrics.config
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
JOB_LABEL=integrations/docker
Loading
Loading