Merge branch 'development_gitea_installer' into development_nile_installers

* development_gitea_installer:
  feat: Add PostgreSQL support for Gitea installer
  feat: Add Gitea Kubernetes installer
This commit is contained in:
2025-11-25 18:39:42 +01:00
10 changed files with 992 additions and 1 deletions

View File

@@ -1,2 +1,3 @@
cryptpad
element_chat
element_chat
gitea

View File

@@ -0,0 +1,44 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import incubaid.herolib.installers.k8s.gitea
// This example demonstrates how to use the Gitea installer.
// 1. Create a new installer instance with a specific hostname.
// Replace 'mygitea' with your desired hostname.
// Note: Use only alphanumeric characters (no underscores or dashes).
mut installer := gitea.get(
name: 'kristof'
create: true
)!
// 2. Configure the installer (all settings are optional with sensible defaults)
// installer.hostname = 'giteaapp' // Default: 'giteaapp'
// installer.namespace = 'forge' // Default: 'forge'
// // Gitea server configuration
// installer.http_port = 3000 // Default: 3000
// installer.disable_registration = false // Default: false (allow new user registration)
// // Database configuration - Option 1: SQLite (default)
// installer.db_type = 'sqlite3' // Default: 'sqlite3'
// installer.db_path = '/data/gitea/gitea.db' // Default: '/data/gitea/gitea.db'
// // Database configuration - Option 2: PostgreSQL
// // When using postgres, a PostgreSQL pod will be automatically deployed
installer.db_type = 'postgres' // Use PostgreSQL instead of SQLite
installer.db_host = 'postgres' // Default: 'postgres' (PostgreSQL service name)
installer.db_name = 'gitea' // Default: 'gitea' (database name)
installer.db_user = 'gitea' // Default: 'gitea' (database user)
installer.db_password = 'gitea' // Default: 'gitea' (database password)
installer.storage_size = '5Gi' // Default: '5Gi' (PVC storage size)
// 3. Install Gitea.
// This will generate the necessary Kubernetes YAML files and apply them to your cluster.
installer.install()!
// println('Gitea installation started.')
// println('You can access it at: https://${installer.hostname}.gent01.grid.tf')
// 4. To destroy the deployment, you can run the following:
// installer.destroy()!

View File

@@ -0,0 +1,12 @@
!!hero_code.generate_installer
name:''
classname:'GiteaK8SInstaller'
singleton:0
templates:1
default:0
title:''
supported_platforms:''
startupmanager:0
hasconfig:1
build:0

View File

@@ -0,0 +1,141 @@
# Gitea Kubernetes Installer
A Kubernetes installer for Gitea with TFGrid Gateway integration.
## Overview
This installer deploys a complete Git hosting solution:
- **Gitea**: A lightweight self-hosted Git service
- **TFGW (ThreeFold Gateway)**: Provides public FQDNs with TLS termination
## Quick Start
```v
import incubaid.herolib.installers.k8s.gitea
// Create and install Gitea with defaults
mut installer := gitea.get(
name: 'mygitea'
create: true
)!
installer.install()!
```
## Configuration Options
All configuration options are optional and have sensible defaults:
### Hostname and Namespace
```v
installer.hostname = 'giteaapp' // Default: 'giteaapp'
installer.namespace = 'forge' // Default: '${installer.name}-gitea-namespace'
```
**Note**: Use only alphanumeric characters in hostnames (no underscores or dashes).
### Gitea Server Configuration
```v
// Server port
installer.http_port = 3000 // Default: 3000
// Database configuration
installer.db_type = 'sqlite3' // Default: 'sqlite3' (options: 'sqlite3', 'postgres')
installer.db_path = '/data/gitea/gitea.db' // Default: '/data/gitea/gitea.db' (for sqlite3)
// PostgreSQL configuration (only used when db_type = 'postgres')
installer.db_host = 'postgres' // Default: 'postgres' (PostgreSQL service name)
installer.db_name = 'gitea' // Default: 'gitea' (PostgreSQL database name)
installer.db_user = 'gitea' // Default: 'gitea' (PostgreSQL user)
installer.db_password = 'gitea' // Default: 'gitea' (PostgreSQL password)
// Registration
installer.disable_registration = false // Default: false (allow new user registration)
// Storage
installer.storage_size = '5Gi' // Default: '5Gi' (PVC storage size)
```
**Note**: When using `db_type = 'postgres'`, a PostgreSQL pod will be automatically deployed in the same namespace. The installer only supports `sqlite3` and `postgres` database types.
## Full Example
```v
import incubaid.herolib.installers.k8s.gitea
mut installer := gitea.get(
name: 'mygitea'
create: true
)!
// Configure hostname and namespace
installer.hostname = 'mygit'
installer.namespace = 'forge'
// Configure Gitea
installer.http_port = 3000
installer.db_type = 'sqlite3'
installer.disable_registration = true // Disable public registration
installer.storage_size = '10Gi' // Increase storage
// Install
installer.install()!
println('Gitea: https://${installer.hostname}.gent01.grid.tf')
```
## PostgreSQL Example
To use PostgreSQL instead of SQLite:
```v
import incubaid.herolib.installers.k8s.gitea
mut installer := gitea.get(
name: 'mygitea'
create: true
)!
// Configure to use PostgreSQL
installer.db_type = 'postgres' // Use PostgreSQL
installer.storage_size = '10Gi' // Storage for both Gitea and PostgreSQL
// Optional: customize PostgreSQL settings
installer.db_host = 'postgres' // PostgreSQL service name
installer.db_name = 'gitea' // Database name
installer.db_user = 'gitea' // Database user
installer.db_password = 'securepassword' // Database password
// Install (PostgreSQL pod will be deployed automatically)
installer.install()!
println('Gitea with PostgreSQL: https://${installer.hostname}.gent01.grid.tf')
```
## Management
### Check Installation Status
```v
if gitea.installed()! {
println('Gitea is installed')
} else {
println('Gitea is not installed')
}
```
### Destroy Deployment
```v
installer.destroy()!
```
This will delete the entire namespace and all resources within it.
## See Also
- [Gitea Documentation](https://docs.gitea.io/)
- [Gitea GitHub Repository](https://github.com/go-gitea/gitea)

View File

@@ -0,0 +1,240 @@
module gitea
import incubaid.herolib.osal.core as osal
import incubaid.herolib.ui.console
import incubaid.herolib.installers.ulist
import time
const max_deployment_retries = 30
const deployment_check_interval_seconds = 2
//////////////////// following actions are not specific to instance of the object
// checks if a certain version or above is installed
pub fn installed() !bool {
installer := get()!
mut k8s := installer.kube_client
// Try to get the gitea deployment
deployments := k8s.get_deployments(installer.namespace) or {
// If we can't get deployments, it's not running
return false
}
// Check if gitea deployment exists
for deployment in deployments {
if deployment.name == 'gitea' {
return true
}
}
return false
}
// get the Upload List of the files
fn ulist_get() !ulist.UList {
// optionally build a UList which is all paths which are result of building, is then used e.g. in upload
return ulist.UList{}
}
// uploads to S3 server if configured
fn upload() ! {
// installers.upload(
// cmdname: 'gitea'
// source: '${gitpath}/target/x86_64-unknown-linux-musl/release/gitea'
// )!
}
fn install() ! {
console.print_header('Installing Gitea...')
// Get installer config to access namespace
installer := get()!
mut k8s := installer.kube_client
configure()!
// 1. Check for dependencies.
console.print_info('Checking for kubectl...')
kubectl_installed()!
console.print_info('kubectl is installed and configured.')
// 2. Apply the YAML files using kubernetes client
console.print_info('Applying Gateway YAML file to the cluster...')
res1 := k8s.apply_yaml('/tmp/gitea/tfgw-gitea.yaml')!
if !res1.success {
return error('Failed to apply tfgw-gitea.yaml: ${res1.stderr}')
}
console.print_info('Gateway YAML file applied successfully.')
// 3. Verify TFGW deployment
verify_tfgw_deployment(tfgw_name: 'gitea', namespace: installer.namespace)!
// 4. Apply PostgreSQL YAML if postgres is selected
if installer.db_type == 'postgres' {
console.print_info('Applying PostgreSQL YAML file to the cluster...')
res_postgres := k8s.apply_yaml('/tmp/gitea/postgres.yaml')!
if !res_postgres.success {
return error('Failed to apply postgres.yaml: ${res_postgres.stderr}')
}
console.print_info('PostgreSQL YAML file applied successfully.')
// Verify PostgreSQL pod is ready
verify_postgres_pod(namespace: installer.namespace)!
}
// 5. Apply Gitea App YAML
console.print_info('Applying Gitea App YAML file to the cluster...')
res2 := k8s.apply_yaml('/tmp/gitea/gitea.yaml')!
if !res2.success {
return error('Failed to apply gitea.yaml: ${res2.stderr}')
}
console.print_info('Gitea App YAML file applied successfully.')
// 6. Verify deployment status
console.print_info('Verifying deployment status...')
mut is_running := false
for i in 0 .. max_deployment_retries {
if installed()! {
is_running = true
break
}
console.print_info('Waiting for Gitea deployment to be ready... (${i + 1}/${max_deployment_retries})')
time.sleep(deployment_check_interval_seconds * time.second)
}
if is_running {
console.print_header('Gitea installation successful!')
console.print_header('You can access Gitea at https://${installer.hostname}.gent01.grid.tf')
} else {
return error('Gitea deployment failed to start.')
}
}
// params for verifying the generating of the FQDN using tfgw crd
@[params]
struct VerifyTfgwDeployment {
pub mut:
tfgw_name string // tfgw serivce generating the FQDN
namespace string // namespace name for gitea deployments/services
}
// params for verifying postgres pod is ready
@[params]
struct VerifyPostgresPod {
pub mut:
namespace string // namespace name for postgres pod
}
// Function for verifying postgres pod is ready
fn verify_postgres_pod(args VerifyPostgresPod) ! {
console.print_info('Verifying PostgreSQL pod is ready...')
installer := get()!
mut k8s := installer.kube_client
mut is_ready := false
for i in 0 .. max_deployment_retries {
// Check if postgres pod exists and is running
result := k8s.kubectl_exec(
command: 'get pod ${installer.db_host} -n ${args.namespace} -o jsonpath="{.status.phase}"'
) or {
console.print_info('Waiting for PostgreSQL pod to be created... (${i + 1}/${max_deployment_retries})')
time.sleep(deployment_check_interval_seconds * time.second)
continue
}
if result.success && result.stdout == 'Running' {
is_ready = true
break
}
console.print_info('Waiting for PostgreSQL pod to be ready... (${i + 1}/${max_deployment_retries})')
time.sleep(deployment_check_interval_seconds * time.second)
}
if !is_ready {
console.print_stderr('PostgreSQL pod failed to become ready.')
return error('PostgreSQL pod failed to become ready.')
}
console.print_info('PostgreSQL pod is ready.')
}
// Function for verifying the generating of of the FQDN using tfgw crd
fn verify_tfgw_deployment(args VerifyTfgwDeployment) ! {
console.print_info('Verifying TFGW deployment for ${args.tfgw_name}...')
installer := get()!
mut k8s := installer.kube_client
mut is_fqdn_generated := false
for i in 0 .. max_deployment_retries {
// Use kubectl_exec for custom resource (TFGW) with jsonpath
result := k8s.kubectl_exec(
command: 'get tfgw ${args.tfgw_name} -n ${args.namespace} -o jsonpath="{.status.fqdn}"'
) or {
console.print_info('Waiting for FQDN to be generated for ${args.tfgw_name}... (${i + 1}/${max_deployment_retries})')
time.sleep(deployment_check_interval_seconds * time.second)
continue
}
if result.success && result.stdout != '' {
is_fqdn_generated = true
break
}
console.print_info('Waiting for FQDN to be generated for ${args.tfgw_name}... (${i + 1}/${max_deployment_retries})')
time.sleep(deployment_check_interval_seconds * time.second)
}
if !is_fqdn_generated {
console.print_stderr('Failed to get FQDN for ${args.tfgw_name}.')
// Use describe_resource to get detailed information about the TFGW resource
result := k8s.describe_resource(
resource: 'tfgw'
resource_name: args.tfgw_name
namespace: args.namespace
) or { return error('TFGW deployment failed for ${args.tfgw_name}.') }
console.print_stderr(result.stdout)
return error('TFGW deployment failed for ${args.tfgw_name}.')
}
console.print_info('TFGW deployment for ${args.tfgw_name} verified successfully.')
}
fn destroy() ! {
console.print_header('Destroying Gitea...')
installer := get()!
mut k8s := installer.kube_client
console.print_debug('Attempting to delete namespace: ${installer.namespace}')
// Delete the namespace using kubernetes client
result := k8s.delete_resource('namespace', installer.namespace, '') or {
console.print_stderr('Failed to delete namespace ${installer.namespace}: ${err}')
return error('Failed to delete namespace ${installer.namespace}: ${err}')
}
console.print_debug('Delete command completed. Exit code: ${result.exit_code}, Success: ${result.success}')
if !result.success {
// Namespace not found is OK - it means it's already deleted
if result.stderr.contains('NotFound') {
console.print_info('Namespace ${installer.namespace} does not exist (already deleted).')
} else {
console.print_stderr('Failed to delete namespace ${installer.namespace}: ${result.stderr}')
return error('Failed to delete namespace ${installer.namespace}: ${result.stderr}')
}
} else {
console.print_info('Namespace ${installer.namespace} deleted successfully.')
}
}
fn kubectl_installed() ! {
// Check if kubectl command exists
if !osal.cmd_exists('kubectl') {
return error('kubectl is not installed. Please install it to continue.')
}
// Check if kubectl is configured to connect to a cluster
installer := get()!
mut k8s := installer.kube_client
if !k8s.test_connection()! {
return error('kubectl is not configured to connect to a Kubernetes cluster. Please check your kubeconfig.')
}
}

View File

@@ -0,0 +1,188 @@
module gitea
import incubaid.herolib.core.base
import incubaid.herolib.core.playbook { PlayBook }
import incubaid.herolib.ui.console
import json
__global (
gitea_global map[string]&GiteaK8SInstaller
gitea_default string
)
/////////FACTORY
@[params]
pub struct ArgsGet {
pub mut:
name string = 'gitea'
fromdb bool // will load from filesystem
create bool // default will not create if not exist
}
pub fn new(args ArgsGet) !&GiteaK8SInstaller {
mut obj := GiteaK8SInstaller{
name: args.name
}
set(obj)!
return get(name: args.name)!
}
pub fn get(args_ ArgsGet) !&GiteaK8SInstaller {
mut context := base.context()!
mut args := args_
if args.name == 'gitea' && gitea_default != '' {
args.name = gitea_default
}
if args.fromdb || args.name !in gitea_global {
mut r := context.redis()!
if r.hexists('context:gitea', args.name)! {
data := r.hget('context:gitea', args.name)!
if data.len == 0 {
print_backtrace()
return error('GiteaK8SInstaller with name: ${args.name} does not exist, prob bug.')
}
mut obj := json.decode(GiteaK8SInstaller, data)!
set_in_mem(obj)!
} else {
if args.create {
new(args)!
} else {
print_backtrace()
return error("GiteaK8SInstaller with name '${args.name}' does not exist")
}
}
return get(name: args.name)! // no longer from db nor create
}
return gitea_global[args.name] or {
print_backtrace()
return error('could not get config for gitea with name:${args.name}')
}
}
// register the config for the future
pub fn set(o GiteaK8SInstaller) ! {
mut o2 := set_in_mem(o)!
gitea_default = o2.name
mut context := base.context()!
mut r := context.redis()!
r.hset('context:gitea', o2.name, json.encode(o2))!
}
// does the config exists?
pub fn exists(args ArgsGet) !bool {
mut context := base.context()!
mut r := context.redis()!
return r.hexists('context:gitea', args.name)!
}
pub fn delete(args ArgsGet) ! {
mut context := base.context()!
mut r := context.redis()!
r.hdel('context:gitea', args.name)!
}
@[params]
pub struct ArgsList {
pub mut:
fromdb bool // will load from filesystem
}
// if fromdb set: load from filesystem, and not from mem, will also reset what is in mem
pub fn list(args ArgsList) ![]&GiteaK8SInstaller {
mut res := []&GiteaK8SInstaller{}
mut context := base.context()!
if args.fromdb {
// reset what is in mem
gitea_global = map[string]&GiteaK8SInstaller{}
gitea_default = ''
}
if args.fromdb {
mut r := context.redis()!
mut l := r.hkeys('context:gitea')!
for name in l {
res << get(name: name, fromdb: true)!
}
return res
} else {
// load from memory
for _, client in gitea_global {
res << client
}
}
return res
}
// only sets in mem, does not set as config
fn set_in_mem(o GiteaK8SInstaller) !GiteaK8SInstaller {
mut o2 := obj_init(o)!
gitea_global[o2.name] = &o2
gitea_default = o2.name
return o2
}
pub fn play(mut plbook PlayBook) ! {
if !plbook.exists(filter: 'gitea.') {
return
}
mut install_actions := plbook.find(filter: 'gitea.configure')!
if install_actions.len > 0 {
for mut install_action in install_actions {
heroscript := install_action.heroscript()
mut obj2 := heroscript_loads(heroscript)!
set(obj2)!
install_action.done = true
}
}
mut other_actions := plbook.find(filter: 'gitea.')!
for mut other_action in other_actions {
if other_action.name in ['destroy', 'install', 'build'] {
mut p := other_action.params
reset := p.get_default_false('reset')
if other_action.name == 'destroy' || reset {
console.print_debug('install action gitea.destroy')
destroy()!
}
if other_action.name == 'install' {
console.print_debug('install action gitea.install')
install()!
}
}
other_action.done = true
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////# LIVE CYCLE MANAGEMENT FOR INSTALLERS ///////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// load from disk and make sure is properly intialized
pub fn (mut self GiteaK8SInstaller) reload() ! {
switch(self.name)
self = obj_init(self)!
}
@[params]
pub struct InstallArgs {
pub mut:
reset bool
}
pub fn (mut self GiteaK8SInstaller) install(args InstallArgs) ! {
switch(self.name)
if args.reset || (!installed()!) {
install()!
}
}
pub fn (mut self GiteaK8SInstaller) destroy() ! {
switch(self.name)
destroy()!
}
// switch instance to be used for gitea
pub fn switch(name string) {
gitea_default = name
}

View File

@@ -0,0 +1,185 @@
module gitea
import incubaid.herolib.ui.console
import incubaid.herolib.data.encoderhero
import incubaid.herolib.virt.kubernetes
import incubaid.herolib.core.pathlib
import strings
pub const version = '0.0.0'
const singleton = false
const default = false
struct ConfigValues {
pub mut:
hostname string // The Gitea hostname
backends string // The backends for the TFGW
namespace string // The namespace for the Gitea deployment
root_url string // Gitea ROOT_URL
domain string // Gitea domain
http_port int // Gitea HTTP port
disable_registration bool // Disable user registration
db_type string // Database type (sqlite3, postgres, mysql)
db_path string // Database path for SQLite
storage_size string // PVC storage size
// Postgres-specific settings
db_host string // Database host (for postgres)
db_name string // Database name (for postgres)
db_user string // Database user (for postgres)
db_password string // Database password (for postgres)
}
@[heap]
pub struct GiteaK8SInstaller {
pub mut:
name string = 'gitea'
hostname string // Gitea hostname for TFGW
namespace string // Kubernetes namespace
// Gitea configuration
root_url string
domain string
http_port int = 3000
disable_registration bool
db_type string = 'sqlite3'
db_path string = '/data/gitea/gitea.db'
storage_size string = '5Gi'
// PostgreSQL configuration (only used when db_type = 'postgres')
db_host string = 'postgres' // PostgreSQL host (service name)
db_name string = 'gitea' // PostgreSQL database name
db_user string = 'gitea' // PostgreSQL user
db_password string = 'gitea' // PostgreSQL password
// Internal paths
gitea_app_path string = '/tmp/gitea/gitea.yaml'
tfgw_path string = '/tmp/gitea/tfgw-gitea.yaml'
postgres_path string = '/tmp/gitea/postgres.yaml'
kube_client kubernetes.KubeClient @[skip]
}
// your checking & initialization code if needed
fn obj_init(mycfg_ GiteaK8SInstaller) !GiteaK8SInstaller {
mut mycfg := mycfg_
if mycfg.name == '' {
mycfg.name = 'gitea'
}
// Replace the dashes, dots, and underscores with nothing
mycfg.name = mycfg.name.replace('_', '')
mycfg.name = mycfg.name.replace('-', '')
mycfg.name = mycfg.name.replace('.', '')
if mycfg.namespace == '' {
mycfg.namespace = '${mycfg.name}-gitea-namespace'
}
if mycfg.namespace.contains('_') || mycfg.namespace.contains('.') {
console.print_stderr('namespace cannot contain _, was: ${mycfg.namespace}, use dashes instead.')
return error('namespace cannot contain _, was: ${mycfg.namespace}')
}
if mycfg.hostname == '' {
mycfg.hostname = '${mycfg.name}giteaapp'
}
// Validate database type
if mycfg.db_type !in ['sqlite3', 'postgres'] {
console.print_stderr('Only sqlite3 and postgres databases are supported. Got: ${mycfg.db_type}')
return error('Unsupported database type: ${mycfg.db_type}. Only sqlite3 and postgres are supported.')
}
mycfg.kube_client = kubernetes.get(create: true)!
mycfg.kube_client.config.namespace = mycfg.namespace
return mycfg
}
// called before start if done
fn configure() ! {
mut installer := get()!
master_ips := get_master_node_ips()!
console.print_info('Master node IPs: ${master_ips}')
mut backends_str_builder := strings.new_builder(100)
for ip in master_ips {
backends_str_builder.writeln(' - "http://[${ip}]:80"')
}
console.print_info('Generating configuration files from templates...')
// Get FQDN for root_url and domain
fqdn := '${installer.hostname}.gent01.grid.tf'
// Create config_values for template generation
mut config_values := ConfigValues{
hostname: installer.hostname
backends: backends_str_builder.str()
namespace: installer.namespace
root_url: 'https://${fqdn}/'
domain: fqdn
http_port: installer.http_port
disable_registration: installer.disable_registration
db_type: installer.db_type
db_path: installer.db_path
storage_size: installer.storage_size
// Postgres connection details (use full DNS name for service)
db_host: '${installer.db_host}.${installer.namespace}.svc.cluster.local'
db_name: installer.db_name
db_user: installer.db_user
db_password: installer.db_password
}
// Ensure the output directory exists
_ := pathlib.get_dir(path: '/tmp/gitea', create: true)!
// Generate TFGW YAML
tfgw_yaml := $tmpl('./templates/tfgw.yaml')
mut tfgw_path := pathlib.get_file(
path: installer.tfgw_path
create: true
check: true
)!
tfgw_path.write(tfgw_yaml)!
// Generate gitea-app YAML
gitea_app_yaml := $tmpl('./templates/gitea.yaml')
mut gitea_app_path := pathlib.get_file(path: installer.gitea_app_path, create: true)!
gitea_app_path.write(gitea_app_yaml)!
// Generate postgres YAML if postgres is selected
if installer.db_type == 'postgres' {
postgres_yaml := $tmpl('./templates/postgres.yaml')
mut postgres_path := pathlib.get_file(path: installer.postgres_path, create: true)!
postgres_path.write(postgres_yaml)!
console.print_info('PostgreSQL configuration file generated.')
}
console.print_info('Configuration files generated successfully.')
}
// Get Kubernetes master node IPs
fn get_master_node_ips() ![]string {
mut master_ips := []string{}
installer := get()!
// Get all nodes using the kubernetes client
mut k8s := installer.kube_client
nodes := k8s.get_nodes()!
// Extract IPv6 internal IPs from all nodes (dual-stack support)
for node in nodes {
// Check all internal IPs (not just the first one) for IPv6 addresses
for ip in node.internal_ips {
if ip.len > 0 && ip.contains(':') {
master_ips << ip
}
}
}
return master_ips
}
/////////////NORMALLY NO NEED TO TOUCH
pub fn heroscript_loads(heroscript string) !GiteaK8SInstaller {
mut obj := encoderhero.decode[GiteaK8SInstaller](heroscript)!
return obj
}

View File

@@ -0,0 +1,109 @@
apiVersion: v1
kind: Namespace
metadata:
name: @{config_values.namespace}
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: gitea-data
namespace: @{config_values.namespace}
spec:
accessModes: [ "ReadWriteOnce" ]
resources: { requests: { storage: @{config_values.storage_size} } }
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: gitea
namespace: @{config_values.namespace}
spec:
replicas: 1
selector:
matchLabels: { app: gitea }
template:
metadata:
labels: { app: gitea }
spec:
securityContext:
fsGroup: 1000
containers:
- name: gitea
image: gitea/gitea:1.22-rootless
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: @{config_values.http_port}
env:
- name: GITEA__server__ROOT_URL
value: "@{config_values.root_url}"
- name: GITEA__server__PROTOCOL
value: "http"
- name: GITEA__server__HTTP_PORT
value: "@{config_values.http_port}"
- name: GITEA__server__DOMAIN
value: "@{config_values.domain}"
- name: GITEA__server__START_SSH_SERVER
value: "false"
- name: GITEA__database__DB_TYPE
value: "@{config_values.db_type}"
@if config_values.db_type == 'sqlite3'
- name: GITEA__database__PATH
value: "@{config_values.db_path}"
@end
@if config_values.db_type == 'postgres'
- name: GITEA__database__HOST
value: "@{config_values.db_host}"
- name: GITEA__database__NAME
value: "@{config_values.db_name}"
- name: GITEA__database__USER
value: "@{config_values.db_user}"
- name: GITEA__database__PASSWD
value: "@{config_values.db_password}"
@end
- name: GITEA__service__DISABLE_REGISTRATION
value: "@{config_values.disable_registration}"
volumeMounts:
- name: data
mountPath: /data
readinessProbe:
httpGet: { path: /, port: @{config_values.http_port} }
initialDelaySeconds: 20
periodSeconds: 10
volumes:
- name: data
persistentVolumeClaim:
claimName: gitea-data
---
apiVersion: v1
kind: Service
metadata:
name: gitea
namespace: @{config_values.namespace}
spec:
selector: { app: gitea }
ports:
- name: http
port: @{config_values.http_port}
targetPort: @{config_values.http_port}
type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: gitea
namespace: @{config_values.namespace}
spec:
ingressClassName: traefik
rules:
- host: @{config_values.domain}
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: gitea
port:
number: @{config_values.http_port}

View File

@@ -0,0 +1,56 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-data
namespace: @{config_values.namespace}
spec:
accessModes: [ReadWriteOnce]
resources:
requests:
storage: @{config_values.storage_size}
---
apiVersion: v1
kind: Pod
metadata:
name: @{config_values.db_host}
namespace: @{config_values.namespace}
labels:
app: @{config_values.db_host}
spec:
containers:
- name: postgres
image: postgres:16-alpine
env:
- name: POSTGRES_DB
value: @{config_values.db_name}
- name: POSTGRES_USER
value: @{config_values.db_user}
- name: POSTGRES_PASSWORD
value: @{config_values.db_password}
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
ports:
- containerPort: 5432
name: postgres
volumeMounts:
- name: postgres-storage
mountPath: /var/lib/postgresql/data
volumes:
- name: postgres-storage
persistentVolumeClaim:
claimName: postgres-data
---
apiVersion: v1
kind: Service
metadata:
name: @{config_values.db_host}
namespace: @{config_values.namespace}
spec:
selector:
app: @{config_values.db_host}
ports:
- port: 5432
targetPort: 5432
name: postgres
type: ClusterIP

View File

@@ -0,0 +1,15 @@
apiVersion: v1
kind: Namespace
metadata:
name: @{config_values.namespace}
---
apiVersion: ingress.grid.tf/v1
kind: TFGW
metadata:
name: gitea
namespace: @{config_values.namespace}
spec:
hostname: "@{config_values.hostname}"
backends:
@{config_values.backends}