try plausible CE for web analytics
All checks were successful
Helm Charts / Detect changed charts (push) Successful in 3m52s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped

This commit is contained in:
2025-12-10 13:51:04 +01:00
parent d7130b1635
commit 11de19ef91
14 changed files with 503 additions and 1 deletions

View File

@@ -0,0 +1,62 @@
---
# template source: https://github.com/bretfisher/docker-build-workflow/blob/main/templates/call-docker-build.yaml
name: Plausible
on: #[push,pull_request]
workflow_dispatch: {}
push: &plausiblePaths
paths:
- 'plausible/**/*.tf'
pull_request: *plausiblePaths
# cancel any previously-started, yet still active runs of this workflow on the same branch
concurrency:
group: ${{ github.ref }}-${{ github.workflow }}
cancel-in-progress: true
.vault_step: &vault_step
name: read vault secret
uses: https://gitea.arcodange.duckdns.org/arcodange-org/vault-action.git@main
id: vault-secrets
with:
url: https://vault.arcodange.duckdns.org
jwtGiteaOIDC: ${{ needs.gitea_vault_auth.outputs.gitea_vault_jwt }}
role: gitea_cicd_plausible
method: jwt
path: gitea_jwt
secrets: |
kvv1/google/credentials credentials | GOOGLE_BACKEND_CREDENTIALS ;
kvv1/gitea/tofu_module_reader ssh_private_key | TERRAFORM_SSH_KEY ;
jobs:
gitea_vault_auth:
name: Auth with gitea for vault
runs-on: ubuntu-latest
outputs:
gitea_vault_jwt: ${{steps.gitea_vault_jwt.outputs.id_token}}
steps:
- name: Auth with gitea for vault
id: gitea_vault_jwt
run: |
echo -n "${{ secrets.vault_oauth__sh_b64 }}" | base64 -d | bash
tofu:
name: Tofu - plausible IAC
needs:
- gitea_vault_auth
runs-on: ubuntu-latest
env:
OPENTOFU_VERSION: 1.8.2
TERRAFORM_VAULT_AUTH_JWT: ${{ needs.gitea_vault_auth.outputs.gitea_vault_jwt }}
steps:
- *vault_step
- uses: actions/checkout@v4
# - uses: dflook/terraform-plan@v1
# with:
# path: hashicorp-vault/iac
- name: terraform apply
uses: dflook/terraform-apply@v1
with:
path: plausible/iac
auto_approve: true

View File

@@ -6,4 +6,5 @@ tools:
crowdsec: {}
redis: {}
clickhouse: {}
grafana: {}
grafana: {}
plausible: {}

View File

@@ -10,4 +10,8 @@ applications = [
name = "crowdsec"
service_account_namespaces = ["tools"]
},
{
name = "plausible"
service_account_namespaces = ["tools"]
},
]

View File

@@ -0,0 +1,36 @@
- op: add
path: /spec/template/spec/containers/0/volumeMounts/-
value:
name: generated-secrets
mountPath: /run/secrets
- op: add
path: /spec/template/spec/initContainers/0/volumeMounts
value:
name: generated-secrets
mountPath: /run/secrets
- op: add
path: /spec/template/spec/initContainers/0
value:
name: build-database-url
image: alpine:3.19
command: ["/bin/sh", "-c"]
args:
- |
echo "postgres://${DB_USER}:${DB_PASS}@${DB_HOST}:${DB_PORT}/${DB_NAME}" > /run/secrets/DATABASE_URL
volumeMounts:
- name: generated-secrets
mountPath: /run/secrets
env:
- name: DB_USER
valueFrom:
secretKeyRef:
name: plausible-db-credentials
key: username
- name: DB_PASS
valueFrom:
secretKeyRef:
name: plausible-db-credentials
key: password
envFrom:
- configMapRef:
name: plausible-config

6
plausible/iac/backend.tf Normal file
View File

@@ -0,0 +1,6 @@
terraform {
backend "gcs" {
bucket = "arcodange-tf"
prefix = "tools/plausible/main"
}
}

30
plausible/iac/main.tf Normal file
View File

@@ -0,0 +1,30 @@
module "app_roles" {
source = "git::ssh://git@192.168.1.202:2222/arcodange-org/tools.git//hashicorp-vault/iac/modules/app_roles?depth=1&ref=main"
name = "plausible"
service_account_namespaces = ["tools"]
}
# https://github.com/plausible/community-edition/wiki/configuration#database
#SECRET_KEY_BASE (openssl rand -base64 48)
#
resource "random_password" "secret" {
for_each = toset(["48","32"])
length = tonumber(each.value)
special = false
}
locals {
config = {
SECRET_KEY_BASE = base64encode(random_password.secret["48"].result)
TOTP_VAULT_KEY = base64encode(random_password.secret["32"].result)
}
}
resource "vault_kv_secret_v2" "config" {
mount = "kvv2"
name = "plausible/config"
cas = 1
# delete_all_versions = true
data_json = jsonencode(local.config)
}

View File

@@ -0,0 +1,16 @@
terraform {
required_providers {
vault = {
source = "vault"
version = "4.4.0"
}
}
}
provider "vault" {
address = "https://vault.arcodange.duckdns.org"
auth_login_jwt { # TERRAFORM_VAULT_AUTH_JWT environment variable
mount = "gitea_jwt"
role = "gitea_cicd_plausible"
}
}

View File

@@ -0,0 +1,66 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
helmCharts:
- name: plausible
repo: https://charts.pascaliske.dev
version: 2.0.0
releaseName: plausible
valuesFile: plausibleValues.yaml
patches:
- target:
kind: IngressRoute
name: plausible-route
patch: |-
- op: add
path: /spec/tls
value:
certResolver: letsencrypt
domains:
- main: arcodange.duckdns.org
sans:
- analytics.arcodange.duckdns.org
resources:
- resources/vaultauth.yaml
- resources/vaultdynamicsecret.yaml
- resources/vaultsecret.yaml
- resources/configmap.yaml
- resources/geoipsecret.yaml
patchesJson6902:
- target:
version: v1
kind: Deployment
name: plausible
patch: |-
- op: replace
path: /spec/template/spec/containers/1/env/2
value:
name: GEOIPUPDATE_LICENSE_KEY
valueFrom:
secretKeyRef:
name: plausible-geoip
key: LICENSE_KEY
- op: add
path: /spec/template/spec/volumes/-
value:
name: generated-secrets
emptyDir:
medium: Memory
- op: add
path: /spec/template/spec/containers/0/envFrom
value:
- configMapRef:
name: plausible-config
- op: add
path: /spec/template/spec/initContainers/0/envFrom
value:
- configMapRef:
name: plausible-config
- target:
version: v1
kind: Deployment
name: plausible
path: add-initcontainer.yaml

View File

@@ -0,0 +1,180 @@
image:
# -- The registry to pull the image from.
registry: ghcr.io
# -- The repository to pull the image from.
repository: plausible/community-edition
# -- The docker tag, if left empty chart's appVersion will be used.
# @default -- `.Chart.AppVersion`
tag: ''
# -- The pull policy for the controller.
pullPolicy: IfNotPresent
nameOverride: ''
fullnameOverride: ''
controller:
# -- Create a workload for this chart.
enabled: true
# -- Type of the workload object.
kind: Deployment
# -- The number of replicas.
replicas: 1
# -- Additional annotations for the controller object.
annotations: {}
# -- Additional labels for the controller object.
labels: {}
service:
# -- Create a service for exposing this chart.
enabled: true
# -- The service type used.
type: ClusterIP
# -- ClusterIP used if service type is `ClusterIP`.
clusterIP: ''
# -- LoadBalancerIP if service type is `LoadBalancer`.
loadBalancerIP: ''
# -- Allowed addresses when service type is `LoadBalancer`.
loadBalancerSourceRanges: []
# -- Additional annotations for the service object.
annotations: {}
# -- Additional labels for the service object.
labels: {}
serviceMonitor:
# -- Create a service monitor for prometheus operator.
enabled: false
# -- How frequently the exporter should be scraped.
interval: 30s
# -- Timeout value for individual scrapes.
timeout: 10s
# -- Additional annotations for the service monitor object.
annotations: {}
# -- Additional labels for the service monitor object.
labels: {}
ingressRoute:
# -- Create an IngressRoute object for exposing this chart.
create: true
# -- List of [entry points](https://doc.traefik.io/traefik/routing/routers/#entrypoints) on which the ingress route will be available.
entryPoints: [websecure]
# -- [Matching rule](https://doc.traefik.io/traefik/routing/routers/#rule) for the underlying router.
rule: 'Host(analytics.arcodange.duckdns.org)'
# -- List of [middleware objects](https://doc.traefik.io/traefik/routing/providers/kubernetes-crd/#kind-middleware) for the ingress route.
middlewares:
- name: localIp@file
# -- Use an existing secret containing the TLS certificate.
tlsSecretName: ''
# -- Additional annotations for the ingress route object.
annotations: {}
# -- Additional labels for the ingress route object.
labels: {}
certificate:
# -- Create an Certificate object for the exposed chart.
create: false
# -- List of subject alternative names for the certificate.
dnsNames: []
# -- Name of the secret in which the certificate will be stored. Defaults to the first item in dnsNames.
secretName: ''
issuerRef:
# -- Type of the referenced certificate issuer. Can be "Issuer" or "ClusterIssuer".
kind: ClusterIssuer
# -- Name of the referenced certificate issuer.
name: ''
# -- Additional annotations for the certificate object.
annotations: {}
# -- Additional labels for the certificate object.
labels: {}
env:
# -- Timezone for the container.
- name: TZ
value: Europe/Paris
ports:
http:
# -- Enable the port inside the `Deployment` and `Service` objects.
enabled: true
# -- The port used as internal port and cluster-wide port if `.service.type` == `ClusterIP`.
port: 8000
# -- The external port used if `.service.type` == `NodePort`.
nodePort: null
# -- The protocol used for the service.
protocol: TCP
secret:
# -- Create a new secret object.
create: false
# -- Use an existing secret object.
existingSecret: 'plausible-config'
# -- Secret values used when not using an existing secret. Helm templates are supported for values.
values:
# -- Secret key for session tokens.
SECRET_KEY_BASE: '{{ randAlphaNum 42 | b64enc }}'
# -- Encryption token for TOTP secrets.
TOTP_VAULT_KEY: '{{ randAlphaNum 32 | b64enc }}'
# -- Additional annotations for the secret object.
annotations: {}
# -- Additional labels for the secret object.
labels: {}
geoip:
# -- Enable support for MaxMinds GeoLite2 database.
enabled: true
image:
# -- The repository for the geoip image.
repository: ghcr.io/maxmind/geoipupdate
# -- The docker tag for the geoip image.
tag: v7.1.1
# -- Required. MaxMind account ID.
accountId: '1266329'
# -- Required. Case-sensitive MaxMind license key.
# licenseKey: 'kvv2/data/plausible/geoip LICENSE_KEY'
# -- Optional. Database update frequency. Defaults to "168" which equals 7 days.
frequency: 168
# -- Optional. Specify the database mount path inside the containers.
mountPath: /geoip
serviceAccount:
# -- Create a `ServiceAccount` object.
create: true
# -- Specify the service account used for the controller.
name: ''
# -- Additional annotations for the service account object.
annotations: {}
# -- Additional labels for the service account object.
labels: {}
# -- Pod-level security attributes. More info [here](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#security-context).
securityContext: {}
# fsGroup: 1000
# runAsNonRoot: true
# runAsGroup: 1000
# runAsUser: 1000
# -- Compute resources used by the container. More info [here](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/).
resources: {}
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
# -- Pod-level affinity. More info [here](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#scheduling).
affinity: {}
# nodeAffinity:
# requiredDuringSchedulingIgnoredDuringExecution:
# nodeSelectorTerms:
# - matchExpressions:
# - key: kubernetes.io/hostname
# operator: In
# values:
# - my-node-xyz
# -- Pod-level tolerations. More info [here](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#scheduling).
tolerations: []
# - key: node-role.kubernetes.io/control-plane
# operator: Exists
# effect: NoSchedule

View File

@@ -0,0 +1,14 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: plausible-config
namespace: tools
# Doc: https://github.com/plausible/community-edition/wiki/Configuration
data:
DB_HOST: pgbouncer.tools
DB_PORT: !!str 5432
DB_NAME: plausible
BASE_URL: https://analytics.arcodange.duckdns.org
CLICKHOUSE_DATABASE_URL: http://plausible:plausiblearcodange@plausible.tools:8123/plausible

View File

@@ -0,0 +1,24 @@
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultStaticSecret
metadata:
name: plausible-geoip
namespace: tools
spec:
type: kv-v2
# mount path
mount: kvv2
# path of the secret
path: plausible/geoip
# dest k8s secret
destination:
name: plausible-geoip
create: true
# static secret refresh interval
refreshAfter: 30s
# Name of the CRD to authenticate to Vault
vaultAuthRef: plausible

View File

@@ -0,0 +1,14 @@
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultAuth
metadata:
name: plausible
namespace: tools
spec:
vaultConnectionRef: default
method: kubernetes
mount: kubernetes
kubernetes:
role: plausible
serviceAccount: plausible
audiences:
- vault

View File

@@ -0,0 +1,25 @@
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultDynamicSecret
metadata:
name: plausible-db-credentials
namespace: tools
spec:
# Mount path of the secrets backend
mount: postgres
# Path to the secret
path: creds/plausible
# Where to store the secrets, VSO will create the secret
destination:
create: true
name: plausible-db-credentials
# Restart these pods when secrets rotated
rolloutRestartTargets:
- kind: Deployment
name: plausible
# Name of the CRD to authenticate to Vault
vaultAuthRef: plausible

View File

@@ -0,0 +1,24 @@
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultStaticSecret
metadata:
name: plausible
namespace: tools
spec:
type: kv-v2
# mount path
mount: kvv2
# path of the secret
path: plausible/config
# dest k8s secret
destination:
name: plausible-config
create: true
# static secret refresh interval
refreshAfter: 30s
# Name of the CRD to authenticate to Vault
vaultAuthRef: plausible