diff --git a/apps/kustomization.yaml b/apps/kustomization.yaml index 30760f5..26a4a9a 100644 --- a/apps/kustomization.yaml +++ b/apps/kustomization.yaml @@ -15,3 +15,4 @@ resources: - ispeak3 - openwebui - garm + - woodpecker diff --git a/apps/woodpecker/kustomization.yaml b/apps/woodpecker/kustomization.yaml new file mode 100644 index 0000000..ded6608 --- /dev/null +++ b/apps/woodpecker/kustomization.yaml @@ -0,0 +1,8 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - namespace.yaml + - postgres-volume.yaml + - postgres-cluster.yaml + - release.yaml + - secret.yaml diff --git a/apps/woodpecker/namespace.yaml b/apps/woodpecker/namespace.yaml new file mode 100644 index 0000000..3c08baf --- /dev/null +++ b/apps/woodpecker/namespace.yaml @@ -0,0 +1,5 @@ +--- +apiVersion: v1 +kind: Namespace +metadata: + name: woodpecker diff --git a/apps/woodpecker/postgres-cluster.yaml b/apps/woodpecker/postgres-cluster.yaml new file mode 100644 index 0000000..f7d45e2 --- /dev/null +++ b/apps/woodpecker/postgres-cluster.yaml @@ -0,0 +1,23 @@ +--- +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: woodpecker-postgresql-cluster + namespace: woodpecker +spec: + instances: 1 + + imageName: ghcr.io/cloudnative-pg/postgresql:17.4 + + bootstrap: + initdb: + database: woodpecker + owner: woodpecker + + storage: + pvcTemplate: + storageClassName: ssd-lvmpv + resources: + requests: + storage: 10Gi + volumeName: woodpecker-postgresql-cluster-lvmssd diff --git a/apps/woodpecker/postgres-volume.yaml b/apps/woodpecker/postgres-volume.yaml new file mode 100644 index 0000000..5045b68 --- /dev/null +++ b/apps/woodpecker/postgres-volume.yaml @@ -0,0 +1,33 @@ +apiVersion: local.openebs.io/v1alpha1 +kind: LVMVolume +metadata: + labels: + kubernetes.io/nodename: anapistula-delrosalae + name: woodpecker-postgresql-cluster-lvmssd + namespace: openebs +spec: + capacity: 10Gi + ownerNodeID: anapistula-delrosalae + shared: "yes" + thinProvision: "no" + vgPattern: ^openebs-ssd$ + volGroup: openebs-ssd +--- +kind: PersistentVolume +apiVersion: v1 +metadata: + name: woodpecker-postgresql-cluster-lvmssd +spec: + capacity: + storage: 10Gi + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain + storageClassName: ssd-lvmpv + volumeMode: Filesystem + csi: + driver: local.csi.openebs.io + fsType: btrfs + volumeHandle: woodpecker-postgresql-cluster-lvmssd +--- +# PVC is dynamically created by the Postgres operator diff --git a/apps/woodpecker/release.yaml b/apps/woodpecker/release.yaml new file mode 100644 index 0000000..d25c0fc --- /dev/null +++ b/apps/woodpecker/release.yaml @@ -0,0 +1,115 @@ +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: HelmRepository +metadata: + name: woodpecker + namespace: woodpecker +spec: + interval: 24h + url: https://woodpecker-ci.org/ +--- +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: woodpecker + namespace: woodpecker +spec: + interval: 30m + chart: + spec: + chart: woodpecker + version: 3.5.1 + sourceRef: + kind: HelmRepository + name: woodpecker + namespace: woodpecker + interval: 12h + values: + server: + enabled: true + statefulSet: + replicaCount: 1 + + persistentVolume: + enabled: false # Using Postgresql database + + env: + WOODPECKER_HOST: "https://woodpecker.lumpiasty.xyz" + # Gitea integration + WOODPECKER_GITEA: "true" + WOODPECKER_GITEA_URL: "https://gitea.lumpiasty.xyz" + # PostgreSQL database configuration + WOODPECKER_DATABASE_DRIVER: postgres + # Password is loaded from woodpecker-postgresql-cluster-app secret (created by CNPG) + WOODPECKER_DATABASE_DATASOURCE: + valueFrom: + secretKeyRef: + name: woodpecker-postgresql-cluster-app + key: fqdn-uri + # Allow logging in from all accounts on Gitea + WOODPECKER_OPEN: true + # Make lumpiasty admin + WOODPECKER_ADMIN: GiteaAdmin + + createAgentSecret: true + + extraSecretNamesForEnvFrom: + - woodpecker-secrets + + ingress: + enabled: true + ingressClassName: nginx-ingress + annotations: + cert-manager.io/cluster-issuer: letsencrypt + acme.cert-manager.io/http01-edit-in-place: "true" + hosts: + - host: woodpecker.lumpiasty.xyz + paths: + - path: / + backend: + serviceName: woodpecker-server + servicePort: 80 + tls: + - hosts: + - woodpecker.lumpiasty.xyz + secretName: woodpecker-ingress + + resources: + requests: + cpu: 100m + memory: 256Mi + + service: + type: ClusterIP + port: 80 + + agent: + enabled: true + replicaCount: 2 + + env: + WOODPECKER_SERVER: "woodpecker-server:9000" + WOODPECKER_BACKEND: kubernetes + WOODPECKER_BACKEND_K8S_NAMESPACE: woodpecker + WOODPECKER_BACKEND_K8S_STORAGE_CLASS: ssd-lvmpv + WOODPECKER_BACKEND_K8S_VOLUME_SIZE: 10G + WOODPECKER_BACKEND_K8S_STORAGE_RWX: false + WOODPECKER_CONNECT_RETRY_COUNT: "5" + + mapAgentSecret: true + + extraSecretNamesForEnvFrom: + - woodpecker-secrets + + persistence: + enabled: false + + serviceAccount: + create: true + rbac: + create: true + + resources: + requests: + cpu: 100m + memory: 128Mi diff --git a/apps/woodpecker/secret.yaml b/apps/woodpecker/secret.yaml new file mode 100644 index 0000000..32c6d91 --- /dev/null +++ b/apps/woodpecker/secret.yaml @@ -0,0 +1,62 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: woodpecker-secret + namespace: woodpecker +--- +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultAuth +metadata: + name: woodpecker + namespace: woodpecker +spec: + method: kubernetes + mount: kubernetes + kubernetes: + role: woodpecker + serviceAccount: woodpecker-secret +--- +# Main woodpecker secrets from Vault +# Requires vault kv put secret/woodpecker \ +# WOODPECKER_AGENT_SECRET="$(openssl rand -hex 32)" \ +# WOODPECKER_GITEA_CLIENT="" \ +# WOODPECKER_GITEA_SECRET="" +# Note: Database password comes from CNPG secret (woodpecker-postgresql-cluster-app) +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultStaticSecret +metadata: + name: woodpecker-secrets + namespace: woodpecker +spec: + type: kv-v2 + mount: secret + path: woodpecker + destination: + create: true + name: woodpecker-secrets + type: Opaque + transformation: + excludeRaw: true + vaultAuthRef: woodpecker +--- +# Container registry credentials for Kaniko +# Requires vault kv put secret/container-registry \ +# REGISTRY_USERNAME="" \ +# REGISTRY_PASSWORD="" +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultStaticSecret +metadata: + name: container-registry + namespace: woodpecker +spec: + type: kv-v2 + mount: secret + path: container-registry + destination: + create: true + name: container-registry + type: Opaque + transformation: + excludeRaw: true + vaultAuthRef: woodpecker diff --git a/vault/kubernetes-roles/woodpecker.yaml b/vault/kubernetes-roles/woodpecker.yaml new file mode 100644 index 0000000..afaf68f --- /dev/null +++ b/vault/kubernetes-roles/woodpecker.yaml @@ -0,0 +1,6 @@ +bound_service_account_names: + - woodpecker-secret +bound_service_account_namespaces: + - woodpecker +token_policies: + - woodpecker diff --git a/vault/policy/woodpecker.hcl b/vault/policy/woodpecker.hcl new file mode 100644 index 0000000..ac83317 --- /dev/null +++ b/vault/policy/woodpecker.hcl @@ -0,0 +1,7 @@ +path "secret/data/woodpecker" { + capabilities = ["read"] +} + +path "secret/data/container-registry" { + capabilities = ["read"] +}