blob: 02229ea0da7464749a737e7b841fd130f5ff4518 [file] [log] [blame]
/*
Deploy a Forgejo instance with PostgreSQL database and additional PV for git data.
Pre-provision the secrets with:
kubectl -n $KUBE_NAMESPACE create secret generic forgejo \
--from-literal=postgres_password=$(pwgen -s 24 1) \
--from-literal=secret_key=$(pwgen -s 128 1) \
--from-literal=admin_password=$(pwgen -s 128 1) \
--from-literal=oauth2_client_id=$SSO_CLIENT_ID \
--from-literal=oauth2_client_secret=$SSO_CLIENT_SECRET \
--from-literal=ldap_bind_dn=$LDAP_BIND_DN \
--from-literal=ldap_bind_password=$LDAP_BIND_PASSWORD \
--from-literal=smtp_password=$SMTP_PASSWORD
Import objectstore secret:
ceph_ns=ceph-waw3; ceph_pool=waw-hdd-redundant-3
kubectl -n $ceph_ns get secrets rook-ceph-object-user-${ceph_pool}-object-codehosting -o json | jq 'del(.metadata.namespace,.metadata.resourceVersion,.metadata.uid) | .metadata.creationTimestamp=null' | kubectl apply -f - -n $KUBE_NAMESPACE
Import oidc auth trigger:
kubectl -n $KUBE_NAMESPACE exec deploy/postgres -i -- psql -U forgejo forgejo < create-oidc-binding.sql
*/
local kube = import "../../kube/kube.libsonnet";
local postgres = import "../../kube/postgres.libsonnet";
{
local forgejo = self,
local cfg = forgejo.cfg,
cfg:: {
namespace: error "namespace must be set",
prefix: "",
image: "codeberg.org/forgejo/forgejo:1.20.5-0",
storageClassName: "waw-hdd-redundant-3",
storageSize: { git: "200Gi" },
admin_username: error "admin_username must be set",
admin_email: error "admin_email must be set",
# Forgejo configuration, roughly representing the structure of app.ini
instanceName: error "instanceName (e.g. 'Warsaw Hackerspace Forgejo') must be set",
runMode: "prod",
altDomains: [],
server: {
domain: error "domain (e.g. git.hackerspace.pl) must be set",
sshDomain: cfg.server.domain,
rootURL: "https://" + cfg.server.domain + "/",
offlineMode: "true",
},
security: {
installLock: "true",
},
service: {
disableRegistration: "false",
allowOnlyExternalRegistration: "true",
},
s3: {
endpoint: "rook-ceph-rgw-waw-hdd-redundant-3-object.ceph-waw3.svc:80", #{ secretKeyRef: {name: "rook-ceph-object-user-waw-hdd-redundant-3-object-codehosting", key: "Endpoint" } },
accessKey: { secretKeyRef: {name: "rook-ceph-object-user-waw-hdd-redundant-3-object-codehosting", key: "AccessKey" } },
secretKey: { secretKeyRef: {name: "rook-ceph-object-user-waw-hdd-redundant-3-object-codehosting", key: "SecretKey" } },
bucket: "codehosting",
},
mailer: {
from: "forgejo@hackerspace.pl",
host: "mail.hackerspace.pl",
port: 465,
user: "forgejo",
password: { secretKeyRef: { name: "forgejo", key: "smtp_password" } },
},
},
name(suffix):: cfg.prefix + suffix,
ns: kube.Namespace(cfg.namespace),
postgres: postgres {
cfg+: {
namespace: cfg.namespace,
appName: "forgejo",
database: "forgejo",
username: "forgejo",
password: { secretKeyRef: { name: "forgejo", key: "postgres_password" } },
storageClassName: cfg.storageClassName,
},
},
configMap: forgejo.ns.Contain(kube.ConfigMap(forgejo.name("forgejo"))) {
data: {
"app.ini.template": importstr 'app.ini.template',
"entrypoint.sh": importstr 'entrypoint.sh',
"bootstrap-auth.sh": importstr 'bootstrap-auth.sh',
},
},
dataVolume: forgejo.ns.Contain(kube.PersistentVolumeClaim(forgejo.name("forgejo"))) {
spec+: {
storageClassName: cfg.storageClassName,
accessModes: [ "ReadWriteOnce" ],
resources: {
requests: {
storage: cfg.storageSize.git,
},
},
},
},
forgejoCustom: forgejo.ns.Contain(kube.ConfigMap(forgejo.name("forgejo-custom"))) {
data: {
"signin_inner.tmpl": importstr 'signin_inner.tmpl',
},
},
statefulSet: forgejo.ns.Contain(kube.StatefulSet(forgejo.name("forgejo"))) {
spec+: {
replicas: 1,
template+: {
spec+: {
securityContext: {
runAsUser: 1000,
runAsGroup: 1000,
fsGroup: 1000,
},
volumes_: {
configmap: kube.ConfigMapVolume(forgejo.configMap),
custom: kube.ConfigMapVolume(forgejo.forgejoCustom),
data: kube.PersistentVolumeClaimVolume(forgejo.dataVolume),
empty: kube.EmptyDirVolume(),
},
containers_: {
server: kube.Container(forgejo.name("forgejo")) {
image: cfg.image,
command: [ "bash", "/usr/bin/entrypoint" ],
ports_: {
server: { containerPort: 3000 },
ssh: { containerPort: 22 },
},
readinessProbe: {
tcpSocket: {
port: "server",
},
initialDelaySeconds: 5,
periodSeconds: 5,
successThreshold: 1,
failureThreshold: 3
},
env_: {
APP_NAME: cfg.instanceName,
RUN_MODE: cfg.runMode,
INSTALL_LOCK: cfg.security.installLock,
SECRET_KEY: { secretKeyRef: { name: "forgejo", key: "secret_key" } },
DB_TYPE: "postgres",
DB_HOST: "postgres:5432",
DB_USER: forgejo.postgres.cfg.username,
DB_PASSWD: forgejo.postgres.cfg.password,
DB_NAME: forgejo.postgres.cfg.appName,
DOMAIN: cfg.server.domain,
SSH_DOMAIN: cfg.server.sshDomain,
SSH_LISTEN_PORT: "2222",
ROOT_URL: forgejo.cfg.server.rootURL,
DISABLE_REGISTRATION: cfg.service.disableRegistration,
ALLOW_ONLY_EXTERNAL_REGISTRATION: cfg.service.allowOnlyExternalRegistration,
OFFLINE_MODE: cfg.server.offlineMode,
USER_UID: "1000",
USER_GID: "1000",
GITEA_CUSTOM: "/custom",
MINIO_ENDPOINT: cfg.s3.endpoint,
MINIO_BUCKET: cfg.s3.bucket,
MINIO_ACCESS_KEY_ID: cfg.s3.accessKey,
MINIO_SECRET_ACCESS_KEY: cfg.s3.secretKey,
MAILER_FROM: cfg.mailer.from,
MAILER_HOST: cfg.mailer.host,
MAILER_PORT: cfg.mailer.port,
MAILER_USER: cfg.mailer.user,
MAILER_PASSWORD: cfg.mailer.password,
},
volumeMounts: [
{ name: "configmap", subPath: "entrypoint.sh", mountPath: "/usr/bin/entrypoint" },
{ name: "configmap", subPath: "app.ini.template", mountPath: "/etc/templates/app.ini" },
{ name: "data", mountPath: "/data" },
{ name: "empty", mountPath: "/custom" },
{ name: "custom", subPath: "signin_inner.tmpl", mountPath: "/custom/templates/user/auth/signin_inner.tmpl" },
],
},
},
initContainers: [
kube.Container(forgejo.name("forgejo-dbmigrate")) {
image: forgejo.statefulSet.spec.template.spec.containers_.server.image,
command: [ "bash", "/usr/bin/entrypoint", "/app/gitea/gitea", "migrate" ],
env_: forgejo.statefulSet.spec.template.spec.containers_.server.env_,
volumeMounts: forgejo.statefulSet.spec.template.spec.containers_.server.volumeMounts,
},
kube.Container(forgejo.name("forgejo-bootstrap-auth")) {
image: forgejo.statefulSet.spec.template.spec.containers_.server.image,
command: [
"bash", "/bootstrap-auth.sh"
],
env_: forgejo.statefulSet.spec.template.spec.containers_.server.env_ + {
ADMIN_PASSWORD: { secretKeyRef: { name: "forgejo", key: "admin_password" } },
SSO_CLIENT_ID: { secretKeyRef: { name: "forgejo", key: "oauth2_client_id" } },
SSO_CLIENT_SECRET: { secretKeyRef: { name: "forgejo", key: "oauth2_client_secret" } },
LDAP_BIND_DN: { secretKeyRef: { name: "forgejo", key: "ldap_bind_dn" } },
LDAP_BIND_PASSWORD: { secretKeyRef: { name: "forgejo", key: "ldap_bind_password" } },
},
volumeMounts: forgejo.statefulSet.spec.template.spec.containers_.server.volumeMounts + [
{ name: "configmap", subPath: "bootstrap-auth.sh", mountPath: "/bootstrap-auth.sh" },
]
},
],
},
},
},
},
svc: forgejo.ns.Contain(kube.Service(forgejo.name("forgejo"))) {
target_pod:: forgejo.statefulSet.spec.template,
spec+: {
ports: [
{ name: "server", port: 80, targetPort: 3000, protocol: "TCP" },
{ name: "ssh", port: 22, targetPort: 2222, protocol: "TCP" },
],
},
},
ingress: forgejo.ns.Contain(kube.Ingress(forgejo.name("forgejo"))) {
metadata+: {
annotations+: {
"kubernetes.io/tls-acme": "true",
"cert-manager.io/cluster-issuer": "letsencrypt-prod",
"nginx.ingress.kubernetes.io/proxy-body-size": "0",
},
},
spec+: {
tls: [
{ hosts: [cfg.server.domain] + cfg.altDomains, secretName: forgejo.name("acme") },
],
rules: [
{
host: domain,
http: {
paths: [
{ path: "/", backend: forgejo.svc.name_port },
],
},
}
for domain in [cfg.server.domain] + cfg.altDomains
],
},
},
}