feat: добавить аддоны Harbor, Gitea, ownCloud OCIS, Nextcloud

Harbor (harbor/harbor, авто-версия):
- Values-шаблон с полной конфигурацией expose/ingress/tls/persistence
- external DB при addon_postgresql=true (Job для создания user/db)
- internal PostgreSQL + Redis в противном случае
- Метрики + ServiceMonitor при addon_prometheus_stack=true

Gitea (gitea-charts/gitea, авто-версия):
- Values-шаблон, встроенный PostgreSQL отключается при addon_postgresql=true
- Job для создания dedicated user/db в shared PostgreSQL
- Опциональный SSH NodePort (gitea_ssh_enabled)
- ServiceMonitor при addon_prometheus_stack=true

ownCloud OCIS (owncloud/ocis, авто-версия):
- Values-шаблон с insecure-режимом для HTTP
- Persistence для storageusers/storagesystem/nats/search/thumbnails
- Пароль admin через extraEnv IDM_ADMIN_PASSWORD
- ServiceMonitor при addon_prometheus_stack=true

Nextcloud (nextcloud/nextcloud, авто-версия):
- Values-шаблон, external PostgreSQL при addon_postgresql=true
- Job для создания dedicated user/db в shared PostgreSQL
- Встроенный Redis для file locking
- nextcloud-exporter (metrics sidecar) + ServiceMonitor
- Cron-задача для фоновых операций

Авто-версия: helm search repo ... --output json | from_json[0].version
Применяется при version: "" — переопределяется через ARGS="-e *_version=X.Y.Z"
This commit is contained in:
Sergey Antropoff
2026-04-25 11:49:29 +03:00
parent c24b8af395
commit e1e84aeb86
19 changed files with 1071 additions and 0 deletions

View File

@@ -0,0 +1,7 @@
---
- name: Install unextcloud
hosts: k3s_master[0]
gather_facts: false
become: true
roles:
- role: "{{ playbook_dir }}/role"

View File

@@ -0,0 +1,45 @@
---
nextcloud_version: "" # "" = автоматически последняя версия чарта
nextcloud_namespace: "nextcloud"
nextcloud_chart_repo: "https://nextcloud.github.io/helm/"
# Администратор
nextcloud_admin_username: "admin"
nextcloud_admin_password: "{{ vault_nextcloud_admin_password | default('changeme-nextcloud') }}"
# Ingress
nextcloud_ingress_enabled: true
nextcloud_ingress_host: "nextcloud.local"
nextcloud_ingress_class: "{{ ingress_nginx_class_name | default('nginx') }}"
nextcloud_ingress_tls: false
nextcloud_ingress_cert_issuer: "{{ cert_manager_default_issuer_name | default('letsencrypt-prod') }}"
# Хранилище файлов
nextcloud_storage_size: "20Gi"
nextcloud_storage_class: ""
# База данных
# При addon_postgresql: true — создаётся отдельный user/db в shared PostgreSQL
# При addon_postgresql: false — встроенный SQLite (не рекомендуется для prod)
nextcloud_db_name: "nextcloud"
nextcloud_db_username: "nextcloud"
nextcloud_db_password: "{{ vault_nextcloud_db_password | default('changeme-nextcloud') }}"
nextcloud_postgresql_admin_password: "{{ vault_postgresql_postgres_password | default('changeme-postgres') }}"
# Redis — встроенный (для file locking и кэширования)
nextcloud_redis_enabled: true
# Автоматическое обновление Nextcloud (cron-задача внутри пода)
nextcloud_cronjob_enabled: true
# Метрики (nextcloud-exporter — отдельный sidecar)
nextcloud_metrics_enabled: true
# ServiceMonitor создаётся только когда addon_prometheus_stack: true
nextcloud_resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 1000m
memory: 1Gi

View File

@@ -0,0 +1,120 @@
---
- name: Add Nextcloud Helm repo
kubernetes.core.helm_repository:
name: nextcloud
repo_url: "{{ nextcloud_chart_repo }}"
environment:
KUBECONFIG: "{{ k3s_kubeconfig_path }}"
- name: Fetch latest Nextcloud chart version
ansible.builtin.command: helm search repo nextcloud/nextcloud --output json
register: _nextcloud_chart_search
changed_when: false
when: nextcloud_version == ""
environment:
KUBECONFIG: "{{ k3s_kubeconfig_path }}"
- name: Set effective Nextcloud chart version
ansible.builtin.set_fact:
_nextcloud_chart_version: >-
{{ nextcloud_version if nextcloud_version != '' else
(_nextcloud_chart_search.stdout | from_json)[0].version }}
- name: Show Nextcloud chart version that will be installed
ansible.builtin.debug:
msg: "Устанавливаю Nextcloud chart {{ _nextcloud_chart_version }}"
- name: Create dedicated PostgreSQL user and database for Nextcloud
kubernetes.core.k8s:
state: present
definition:
apiVersion: batch/v1
kind: Job
metadata:
name: nextcloud-pg-provision
namespace: "{{ postgresql_namespace | default('postgresql') }}"
spec:
ttlSecondsAfterFinished: 300
template:
spec:
restartPolicy: OnFailure
containers:
- name: psql
image: postgres:16-alpine
command:
- /bin/sh
- -c
- |
PGPASSWORD="$ADMIN_PASS" psql -h "$HOST" -U postgres -c "
DO \$\$
BEGIN
IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = '${DB_USER}') THEN
CREATE USER ${DB_USER} WITH PASSWORD '${DB_PASS}';
END IF;
END \$\$;
" &&
PGPASSWORD="$ADMIN_PASS" psql -h "$HOST" -U postgres -tc \
"SELECT 1 FROM pg_database WHERE datname = '${DB_NAME}'" \
| grep -q 1 || \
PGPASSWORD="$ADMIN_PASS" psql -h "$HOST" -U postgres -c \
"CREATE DATABASE ${DB_NAME} OWNER ${DB_USER};"
env:
- name: HOST
value: "{{ postgresql_external_host }}"
- name: ADMIN_PASS
value: "{{ nextcloud_postgresql_admin_password }}"
- name: DB_USER
value: "{{ nextcloud_db_username }}"
- name: DB_PASS
value: "{{ nextcloud_db_password }}"
- name: DB_NAME
value: "{{ nextcloud_db_name }}"
environment:
KUBECONFIG: "{{ k3s_kubeconfig_path }}"
when: addon_postgresql | default(false) | bool
- name: Wait for Nextcloud PostgreSQL provision Job to complete
ansible.builtin.command: >
k3s kubectl -n {{ postgresql_namespace | default('postgresql') }}
wait job/nextcloud-pg-provision
--for=condition=complete --timeout=120s
changed_when: false
when: addon_postgresql | default(false) | bool
- name: Template Nextcloud values
ansible.builtin.template:
src: nextcloud-values.yaml.j2
dest: /tmp/nextcloud-values.yaml
mode: '0644'
- name: Install Nextcloud via Helm
kubernetes.core.helm:
name: nextcloud
chart_ref: nextcloud/nextcloud
chart_version: "{{ _nextcloud_chart_version }}"
release_namespace: "{{ nextcloud_namespace }}"
create_namespace: true
wait: true
timeout: "15m0s"
values_files:
- /tmp/nextcloud-values.yaml
environment:
KUBECONFIG: "{{ k3s_kubeconfig_path }}"
- name: Wait for Nextcloud to be ready
ansible.builtin.command: >
k3s kubectl -n {{ nextcloud_namespace }}
rollout status deployment/nextcloud --timeout=300s
changed_when: false
retries: 3
delay: 15
- name: Show Nextcloud access info
ansible.builtin.debug:
msg:
- "Nextcloud установлен в namespace: {{ nextcloud_namespace }}"
- "URL: http{{ 's' if nextcloud_ingress_tls else '' }}://{{ nextcloud_ingress_host }}"
- "Логин: {{ nextcloud_admin_username }}"
- "Пароль: {{ nextcloud_admin_password }}"
- "БД: {{ 'PostgreSQL ' + postgresql_external_host if addon_postgresql | default(false) | bool else 'встроенный SQLite (только для тестов!)' }}"
- "Для обновления до новой версии: make addon-nextcloud (nextcloud_version='' → автопоиск)"

View File

@@ -0,0 +1,111 @@
## Nextcloud Helm values — Ansible managed
nextcloud:
host: "{{ nextcloud_ingress_host }}"
username: "{{ nextcloud_admin_username }}"
password: "{{ nextcloud_admin_password }}"
# Доверенные домены
configs:
custom.config.php: |-
<?php
$CONFIG = array(
'trusted_domains' => ['{{ nextcloud_ingress_host }}'],
'overwrite.cli.url' => 'http{{ "s" if nextcloud_ingress_tls else "" }}://{{ nextcloud_ingress_host }}',
'overwriteprotocol' => '{{ "https" if nextcloud_ingress_tls else "http" }}',
'default_phone_region' => 'RU',
);
# Cron через sidecar
extraSidecarContainers: []
persistence:
enabled: true
accessMode: ReadWriteOnce
size: "{{ nextcloud_storage_size }}"
{% if nextcloud_storage_class %}
storageClass: "{{ nextcloud_storage_class }}"
{% endif %}
{% if addon_postgresql | default(false) | bool %}
internalDatabase:
enabled: false
externalDatabase:
enabled: true
type: postgresql
host: "{{ postgresql_external_host }}"
port: {{ postgresql_external_port }}
user: "{{ nextcloud_db_username }}"
password: "{{ nextcloud_db_password }}"
database: "{{ nextcloud_db_name }}"
{% else %}
internalDatabase:
enabled: true # SQLite — только для тестов, не для prod
externalDatabase:
enabled: false
{% endif %}
redis:
enabled: {{ nextcloud_redis_enabled | lower }}
auth:
enabled: false
master:
resources:
requests:
cpu: 25m
memory: 32Mi
limits:
cpu: 100m
memory: 64Mi
cronjob:
enabled: {{ nextcloud_cronjob_enabled | lower }}
resources:
requests:
cpu: "{{ nextcloud_resources.requests.cpu }}"
memory: "{{ nextcloud_resources.requests.memory }}"
limits:
cpu: "{{ nextcloud_resources.limits.cpu }}"
memory: "{{ nextcloud_resources.limits.memory }}"
tolerations:
- key: "node-role.kubernetes.io/control-plane"
operator: "Exists"
effect: "NoSchedule"
ingress:
enabled: {{ nextcloud_ingress_enabled | lower }}
{% if nextcloud_ingress_enabled %}
className: "{{ nextcloud_ingress_class }}"
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "0"
nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
{% if nextcloud_ingress_tls %}
cert-manager.io/cluster-issuer: "{{ nextcloud_ingress_cert_issuer }}"
{% endif %}
tls:
{% if nextcloud_ingress_tls %}
- secretName: nextcloud-tls
hosts:
- "{{ nextcloud_ingress_host }}"
{% else %}
[]
{% endif %}
{% endif %}
metrics:
enabled: {{ nextcloud_metrics_enabled | lower }}
serviceMonitor:
enabled: {{ (nextcloud_metrics_enabled | bool and addon_prometheus_stack | default(false) | bool) | lower }}
additionalLabels:
release: kube-prometheus-stack
resources:
requests:
cpu: 10m
memory: 16Mi
limits:
cpu: 50m
memory: 32Mi