Forgejo server
Considerations about the Forgejo server
The last component to setup in its own Kustomize subproject is the Forgejo server itself. Forgejo is a platform specialized in storing and managing Git repositories, which you can upload to Forgejo through HTTP or SSH connections. In fact, Forgejo is a hard fork of an equivalent platform called Gitea. Internally, some configuration parameters still use Gitea-related values. In particular, this happens with some paths which will be indicated later in this chapter.
Like Gitea, Forgejo comes with a web console and embedded Prometheus-formatted metrics. All of this means that you are going to run in your K3s cluster one Forgejo container with two open ports.
Forgejo server Kustomize project’s folders
Prepare your Forgejo’s Kustomize project folder tree with this mkdir command:
$ mkdir -p $HOME/k8sprjs/forgejo/components/server-forgejo/{configs,resources,secrets}Forgejo server configuration with environment variables
Forgejo can be fully configured either with an app.ini file or with environment variables. This section shows you how to declare the necessary Forgejo parameters as environment variables.
Non-secret Forgejo configuration parameters
See here how to configure as environment variables, and in a separated properties file, the necessary Forgejo parameters that are not secrets (meaning passwords, paths or similar values) with values not injected from somewhere else:
Create an
env.propertiesfiles under theconfigspath:$ touch $HOME/k8sprjs/forgejo/components/server-forgejo/configs/env.propertiesSet the Forgejo parameters as environment variables in the
configs/env.properties:FORGEJO__server__DOMAIN=forgejo.homelab.cloud FORGEJO__server__HTTP_ADDR=0.0.0.0 FORGEJO__server__LFS_START_SERVER=true FORGEJO__metrics__ENABLED=true FORGEJO__database__HOST=db-postgresql.forgejo.svc.homelab.cluster.:5432 FORGEJO__database__DB_TYPE=postgres FORGEJO__database__SSL_MODE=disable FORGEJO__cache__ENABLED=true FORGEJO__cache__ADAPTER=redis FORGEJO__session__PROVIDER=redis FORGEJO__session__COOKIE_NAME=forgejo_cookie FORGEJO__queue__TYPE=redis FORGEJO__queue__QUEUE_NAME=_queue_forgejo FORGEJO__queue__SET_NAME=_uniqueue_forgejoThe environment variables set above mean the following:
FORGEJO__server__DOMAIN
The domain name for the Forgejo server. As in other cases, you have to enable the domain in your network or directly in your client systems using thehostsfile.FORGEJO__server__HTTP_ADDR
On which IP address this server will listen on.FORGEJO__server_LFS_START_SERVER
Enables Forgejo’s support of the Git Large File Storage extension.FORGEJO__metrics__ENABLED
For enabling the Prometheus metrics feature included in the Forgejo server.FORGEJO__database__HOST
The host address and port of the database server this Forgejo server has to connect to. Its value here is the combination of the absolute FQDN with theserverport number of the PostgreSQLServicecreated in the previous part.FORGEJO__database__DB_TYPE
Indicates the type of database Forgejo must use.FORGEJO__database__SSL_MODE
For enabling or disabling encryption in the communication with the database.FORGEJO__cache__ENABLED
For enabling the cache on the Forgejo instance.FORGEJO__cache__ADAPTER
Depending on what caching engine you want to use, you have to set the proper adapter here to connect to that engine. To use Valkey, you have to specifyredishere.FORGEJO__session__PROVIDER
Indicates what session engine provider you want to use.FORGEJO__session__COOKIE_NAME
Name of the cookie used for the session ID.FORGEJO__queue__TYPE
Type of queue server to be used. In this case, since Valkey is also used for this feature, you must set this value toredis.FORGEJO__queue__QUEUE_NAME
Suffix added to the name of default and regular non-unique queues.FORGEJO__queue__SET_NAME
Suffix added specifically to the name of unique queues.
Warning
Careful with the underscore characters
When typing these environment variables, be very careful of not missing or misplacing their underscore characters or the Forgejo server will not be able to read them.The double underscore separates categories.
FORGEJOis the root category, while those likeserver,lfsordatabaseare subcategories (notice these are in lowercase). The third part (always in UPPERCASE) on each environment variable represents the Forgejo configuration parameter itself.
Secret Forgejo configuration parameters
The only secret values to configure are those corresponding to the forgejocache user prepared for Forgejo in the ACL user list of the Valkey server setup:
Create a
valkey_user_env.propertiesfiles in thesecretsfolder:$ touch $HOME/k8sprjs/forgejo/components/server-forgejo/secrets/valkey_user_env.propertiesEnter the values of Forgejo’s Valkey user as environment variables in the
secrets/valkey_user_env.properties:FORGEJO_VALKEY_USERNAME=forgejocache FORGEJO_VALKEY_PASSWORD=pAS2wOrD_f0r_The_F0rgEJ0_Us3RThese two environment variables are just custom non-Forgejo parameters used later in this part when declaring the URI for calling the Valkey server host. They are necessary because it is not possible to reuse the values from Valkey’s ACL file for injecting them somewhere else.
Warning
URL encode any special character found in these values
You will see later how these environment variables are inserted in the connection string for connecting with the Valkey cache server. This forces you to URL-encode any special character you might have either in the username or the password. Otherwise, the connection attempt may fail. You could also consider just using alphanumeric values to avoid such issues.
Forgejo server persistent storage claims
The Forgejo server requires two distinct PersistentVolume resources (to be declared in the final part of this Forgejo deployment procedure), each for a specific purpose:
- One stores Forgejo server’s own data files.
- Other for storing the users’ Git repositories and LFS contents that Forgejo will manage.
Hence you need two PersistentVolumeClaims, one per persistent volume.
Persistent storage claim for Forgejo server’s data
Declare the PersistentVolumeClaim to claim the storage where to put the Forgejo server’s data:
Create a
server-forgejo-data.persistentvolumeclaim.yamlfile under theresourcesfolder:$ touch $HOME/k8sprjs/forgejo/components/server-forgejo/resources/server-forgejo-data.persistentvolumeclaim.yamlDeclare the
server-forgejo-dataclaim inresources/server-forgejo-data.persistentvolumeclaim.yaml:# Forgejo server claim of persistent storage for server data apiVersion: v1 kind: PersistentVolumeClaim metadata: name: server-forgejo-data spec: accessModes: - ReadWriteOnce storageClassName: local-path volumeName: forgejo-ssd-data resources: requests: storage: 1.9G
Persistent storage claim for users’ Git repositories and LFS contents
Declare the PersistentVolumeClaim to claim the storage for keeping the Git repositories and LFS contents of the Forgejo server’s users:
Create a
server-forgejo-git.persistentvolumeclaim.yamlfile under theresourcesfolder:$ touch $HOME/k8sprjs/forgejo/components/server-forgejo/resources/server-forgejo-git.persistentvolumeclaim.yamlDeclare the
server-forgejo-gitclaim inresources/server-forgejo-git.persistentvolumeclaim.yaml:# Forgejo server claim of persistent storage for Forgejo users' Git repositories and LFS contents apiVersion: v1 kind: PersistentVolumeClaim metadata: name: server-forgejo-git spec: accessModes: - ReadWriteOnce storageClassName: local-path volumeName: forgejo-hdd-git resources: requests: storage: 19G
Forgejo server StatefulSet
Since Forgejo is a server that stores data, it is better to deploy it with a StatefulSet resource:
Create a
server-forgejo.statefulset.yamlfile under theresourcespath:$ touch $HOME/k8sprjs/forgejo/components/server-forgejo/resources/server-forgejo.statefulset.yamlDeclare the
StatefulSetfor your Forgejo server inresources/server-forgejo.statefulset.yaml:# Forgejo StatefulSet for a server pod apiVersion: apps/v1 kind: StatefulSet metadata: name: server-forgejo spec: replicas: 1 serviceName: server-forgejo template: spec: securityContext: fsGroup: 1000 fsGroupChangePolicy: OnRootMismatch initContainers: - name: permissions-fix image: docker.io/busybox:stable-musl env: - name: FORGEJO_APP_DATA_PATH value: /var/lib/gitea securityContext: readOnlyRootFilesystem: true allowPrivilegeEscalation: false resources: requests: cpu: 100m memory: 128Mi command: - /bin/sh - '-c' - | set -e chown -Rfv 1000:1000 $FORGEJO_APP_DATA_PATH && echo "chown ok on $FORGEJO_APP_DATA_PATH" || echo "Error changing ownership of $FORGEJO_APP_DATA_PATH directory" chown -Rfv 1000:1000 /tmp/forgejo && echo "chown ok on /tmp/forgejo" || echo "Error changing ownership of /tmp/forgejo directory" export DIRS='git git/custom git/repositories git/lfs' echo 'Check if base dirs exists, if not, create them' echo "Directories to check: $DIRS" for dir in $DIRS; do if [ ! -d $FORGEJO_APP_DATA_PATH/$dir ]; then echo "Creating $FORGEJO_APP_DATA_PATH/$dir directory" mkdir -pv $FORGEJO_APP_DATA_PATH/$dir || echo "Error creating $FORGEJO_APP_DATA_PATH/$dir directory" fi chown -Rfv 1000:1000 $FORGEJO_APP_DATA_PATH/$dir && echo "chown ok on $dir" || echo "Error changing ownership of $FORGEJO_APP_DATA_PATH/$dir directory" done exit 0 volumeMounts: - name: forgejo-data-storage mountPath: /var/lib/gitea readOnly: false - name: forgejo-git-storage mountPath: /var/lib/gitea/git readOnly: false - name: tmp mountPath: /tmp/gitea readOnly: false containers: - name: server image: codeberg.org/forgejo/forgejo:14.0-rootless ports: - containerPort: 3000 name: server - containerPort: 2222 name: ssh readinessProbe: httpGet: path: /api/healthz port: server httpHeaders: - name: X-Forwarded-Proto value: https - name: Host value: forgejo.homelab.cloud initialDelaySeconds: 100 timeoutSeconds: 5 periodSeconds: 10 successThreshold: 1 failureThreshold: 10 livenessProbe: httpGet: path: /api/healthz port: server httpHeaders: - name: X-Forwarded-Proto value: https - name: Host value: forgejo.homelab.cloud initialDelaySeconds: 120 timeoutSeconds: 5 periodSeconds: 10 successThreshold: 1 failureThreshold: 10 envFrom: - configMapRef: name: server-forgejo-env-vars - secretRef: name: server-forgejo-valkey-user env: - name: FORGEJO__database__NAME valueFrom: configMapKeyRef: name: db-postgresql-config key: postgresql-db-name - name: FORGEJO__database__USER valueFrom: configMapKeyRef: name: db-postgresql-config key: forgejo-username - name: FORGEJO__database__PASSWD valueFrom: secretKeyRef: name: db-postgresql-secrets key: forgejo-user-password - name: FORGEJO__database__SCHEMA valueFrom: configMapKeyRef: name: db-postgresql-config key: forgejo-username - name: FORGEJO__cache__HOST value: 'redis://$(FORGEJO_VALKEY_USERNAME):$(FORGEJO_VALKEY_PASSWORD)@cache-valkey.forgejo.svc.homelab.cluster.:6379/0?pool_size=100&idle_timeout=180s&prefix=forgejo%3A' - name: FORGEJO__session__PROVIDER_CONFIG value: $(FORGEJO__cache__HOST) - name: FORGEJO__queue__CONN_STR value: $(FORGEJO__cache__HOST) resources: requests: cpu: 250m memory: 128Mi volumeMounts: - name: forgejo-data-storage mountPath: /var/lib/gitea readOnly: false - name: forgejo-git-storage mountPath: /var/lib/gitea/git readOnly: false - name: tmp mountPath: /tmp/gitea readOnly: false securityContext: readOnlyRootFilesystem: true allowPrivilegeEscalation: false runAsNonRoot: true runAsUser: 1000 runAsGroup: 1000 automountServiceAccountToken: false hostAliases: - ip: "10.7.0.1" hostnames: - "forgejo.homelab.cloud" volumes: - name: forgejo-data-storage persistentVolumeClaim: claimName: server-forgejo-data - name: forgejo-git-storage persistentVolumeClaim: claimName: server-forgejo-git - name: tmp emptyDir: sizeLimit: 64MiThis
StatefulSetfor the Forgejo server is similar to the one declared for the Ghost server, with the following differences:spec.template.spec.securityContext
This section applies security hardening features on all the containers running in the pod produced by thisStatefulSet:The
fsGroupensures that the filesystem of the containers is owned by the group identified by its GID here. The GID1000set in this parameter corresponds to thegitgroup that already exists in the Forgejo rootless container image.The rootless image of Forgejo used in this
StatefulSetis prepared to run under thegituser and group, making necessary to ensure that the filesystem can be managed by that user.The
fsGroupChangePolicyis a feature that can be used to avoid costly changes of ownership on files or folders already existing in the mounted storage volumes. With theOnRootMismatchvalue, this feature ensures that ownership is adjusted only when there is a mismatch between the current filesystem owner and the one set in a file.
spec.template.spec.initContainers.permissions-fix
This block enables onepermissions-fixinit container that runs a script to change the ownership of certain key Forgejo folders to be owned by thegituser and group. This init container also has a security context applied to harden it.spec.template.spec.container.server
There is the only theservercontainer in the pod. Since Forgejo already provides Prometheus metrics, you do not need another sidecar container to run a service providing those metrics.The
imageis for the version14.0-rootlessof Forgejo, built on an Alpine Linux system. Notice that it is therootlessversion of Forgejo’s image, which is prepared to run the Forgejo server with an unnamed non-root user identified by the UID1000.In
portsyou have two ports declared, theserverone to access Forgejo (it listens on the port3000by default) and thesshfor connecting with this Forgejo server through that protocol (the rootless image is configured to use the port2222).The
readinessProbeandlivenessProbeprobes call the/api/healthzendpointpathto check on the Forgejo server status.The
envFromblock invokes theConfigMapandSecretthat will be declared later in the Kustomize manifest for this Forgejo server subproject. Theserver-forgejo-env-varsconfig map loads the environment variables set previously in theconfigs/env.propertiesfile, while theserver-forgejo-valkey-usersecret loads the variables set in thesecrets/valkey_user_env.propertiesfile.The
envsection only declares the environment variables that have values injected from parameters set somewhere else:FORGEJO__database__NAME
The name of the database reserved for Forgejo. This value was set in the configuration of the PostgreSQL deployment subproject.FORGEJO__database__USER
The name of the user assigned to Forgejo in the database server. This value was also set in the configuration of the PostgreSQL deployment subprojectFORGEJO__database__PASSWD
This is the password of the Forgejo user in the database server. This value is one of the passwords declared in the PostgreSQL deployment subproject.FORGEJO__database__SCHEMA
This is a PostgreSQL-specific option that indicates the schema to use with the user specified by theFORGEJO__database__USERenvironment parameter. In this case, the schema has the same name as the Forgejo user (which is the default approach in PostgreSQL).Remember that this schema is created, together with the Forgejo database user itself, by the
initdb.shinitializer shell script declared for the PostgreSQL server configuration.FORGEJO__cache__HOST
This is the URL to connect to the cache server host:Notice that the application layer protocol specified is
redis, nothttp. Here you could also specifyvalkeyinstead ofredis.The values for the user credentials are injected in the URL with the environment variables
FORGEJO_VALKEY_USERNAMEandFORGEJO_VALKEY_PASSWORD.Important
Remember to URL encode any special character you may have in these variables
Otherwise, you may end up being unable to connect your Forgejo server with your Valkey instance.cache-valkey.forgejo.svc.homelab.cluster.:6379specifies the absolute FQDN and theserverport number of the ValkeyService.The
/0specifies which logic database to use in the Valkey instance.The query parameters are options that affect how the client side (Forgejo in this case) connections perform.
Important
Do not forget to URL encode any special character you may enter in the query parameters
For instance, see how the:character included in theforgejo:value of theprefixquery parameter has been encoded as%3A.
FORGEJO__session__PROVIDER_CONFIG
Connection string pointing to the server providing sessions support. Since the session provider is also Valkey in this case, the connection string is the same one specified in theFORGEJO__cache__HOSTvariable.FORGEJO__queue__CONN_STR
Connection string to connect with the server providing queuing support, which is Valkey again.
The
volumeMountsblock links the Forgejo server with three storage resources:The storage for the Forgejo server data, mounted under the
/var/lib/giteapath. Notice here the use of a Gitea-related path, as set in the Forgejo rootless container image’s Dockerfile.The storage for the users’ Git repositories and LFS contents, mounted in the
/var/lib/gitea/gitdirectory. This path is also a remnant from Gitea yet to be changed in Forgejo (at the time of writing this).An ephemeral in-memory storage for Forgejo mounted in
/tmp/gitea, which is the path set as the temporary directory in the rootless Forgejo image.
The
securityContexthardens the container by running it with the non-root user identified by the UID1000, which corresponds to thegituser already existing in the container image. Also protects the root filesystem by making it read-only and disables (up to a point) the possibility of privilege escalation.
The
automountServiceAccountTokenparameter set tofalseblocks the access to the Kubernetes cluster’s control plane from the pod generated by thisStatefulSet.In the
hostAliases, the hostname for the Forgejo server (forgejo.homelab.cloud) is associated with the IP address of Traefik (10.7.0.1). This allows Forgejo to reach itself through the proper IP when necessary.The
volumesblock declares the three storages used in the Forgejoservercontainer:The
forgejo-data-storageitem uses theserver-forgejo-datapersistent volume claim to connect with the LVM meant to store the Forgejo server data.The
forgejo-git-storageitem uses theserver-forgejo-gitpersistent volume claim to connect with the LVM created for storing Forgejo users’ Git repositories and LFS contents.The
tmpentry is an emptyDir that enables the ephemeral in-memory storage for temporary operations happening in the Ghost server.
Forgejo server Service
Your Forgejo server’s StatefulSet needs a Service called server-ghost to work:
Create a file called
server-forgejo.service.yamlunderresources:$ touch $HOME/k8sprjs/forgejo/components/server-forgejo/resources/server-forgejo.service.yamlDeclare the
Servicefor the Ghost server inresources/server-ghost.service.yaml:# Forgejo server headless service apiVersion: v1 kind: Service metadata: name: server-forgejo annotations: prometheus.io/scrape: "true" prometheus.io/path: /metrics prometheus.io/port: "3000" spec: type: ClusterIP clusterIP: None ports: - port: 3000 targetPort: server protocol: TCP name: server - port: 22 targetPort: ssh protocol: TCP name: sshLike the services for the other components, this
Servicefor the Forgejo server does not have an specific IP permanently assigned in the Kubernetes cluster:In the
metadata.annotationssection, there is a newprometheus.io/pathentry you have not seen in the other Kubernetes services you have declared up till now. This parameter is the relative URL to the Prometheus metrics endpoint. By default this path is expected to be located at/metrics, as it is in this case. If the Prometheus metrics had been served by another endpoint, you would have been forced to specify its relative path in this annotation entry.The port
3000is used both for regular access into the Forgejo server and for scraping the server’s Prometheus metrics endpoint.The
sshport declared in thisServiceis the standard SSH22one, but it connects with thessh2222port previously declared in the Forgejo serverStatefulSet.
Forgejo Service’s FQDN
The absolute FQDN for the Forgejo headless service deployed in the forgejo namespace will be:
server-forgejo.forgejo.svc.homelab.cluster.Forgejo Kustomize project
Declare the main kustomization.yaml manifest describing the Forgejo server’s Kustomize subproject:
In the main
server-forgejofolder, create akustomization.yamlfile:$ touch $HOME/k8sprjs/forgejo/components/server-forgejo/kustomization.yamlEnter in the
kustomization.yamlfile theKustomizationdeclaration for deploying the Forgejo server:# Forgejo server setup apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization labels: - pairs: app: server-forgejo includeSelectors: true includeTemplates: true resources: - resources/server-forgejo-data.persistentvolumeclaim.yaml - resources/server-forgejo-git.persistentvolumeclaim.yaml - resources/server-forgejo.service.yaml - resources/server-forgejo.statefulset.yaml replicas: - name: server-forgejo count: 1 images: - name: docker.io/busybox newTag: stable-musl - name: codeberg.org/forgejo/forgejo newTag: 14.0-rootless configMapGenerator: - name: server-forgejo-env-vars envs: - configs/env.properties secretGenerator: - name: server-forgejo-valkey-user envs: - secrets/valkey_user_env.propertiesThis
Kustomizationmanifest is like the others you have created for other components, with just a few particularities to highlight:The two images listed correspond to the containers used in the
StatefulSet, one for the init container and the other for the Forgejo server.In the
resourcesblock are listed the files declaring thePersistentVolumeClaimresources used to enable persistent storage in the Forgejo server, together with the other usual declarations for the correspondingStatefulSetandService.The
configMapGeneratorblock declares theserver-forgejo-env-varsConfigMapobject containing only theconfigs/env.propertiesfile with the specific environment variables that adjust the configuration of the Forgejo server.The
secretGeneratorblock is configured to produce aSecretobject only containing the environment variables with the credentials of the Forgejo server’s Valkey user.
Validating the Kustomize YAML output
At this point, you have completed the Forgejo server Kustomize subproject. It is time to test it out with kubectl:
Execute the
kubectl kustomizecommand on the Forgejo server Kustomize subproject’s root folder, piped toless(or to your preferred text editor) to get the output paginated:$ kubectl kustomize $HOME/k8sprjs/forgejo/components/server-forgejo | lessThe resulting YAML should look like this:
apiVersion: v1 data: FORGEJO__cache__ADAPTER: redis FORGEJO__cache__ENABLED: "true" FORGEJO__database__DB_TYPE: postgres FORGEJO__database__HOST: db-postgresql.forgejo.svc.homelab.cluster.:5432 FORGEJO__database__SSL_MODE: disable FORGEJO__metrics__ENABLED: "true" FORGEJO__queue__QUEUE_NAME: _queue_forgejo FORGEJO__queue__SET_NAME: _uniqueue_forgejo FORGEJO__queue__TYPE: redis FORGEJO__server__DOMAIN: forgejo.homelab.cloud FORGEJO__server__HTTP_ADDR: 0.0.0.0 FORGEJO__server__LFS_START_SERVER: "true" FORGEJO__session__COOKIE_NAME: forgejo_cookie FORGEJO__session__PROVIDER: redis kind: ConfigMap metadata: labels: app: server-forgejo name: server-forgejo-env-vars-bht2m829kt --- apiVersion: v1 data: FORGEJO_VALKEY_PASSWORD: cEFTMndPckRfZjByX1RoZV9GMHJnRUowX1VzM1I= FORGEJO_VALKEY_USERNAME: Zm9yZ2Vqb2NhY2hl kind: Secret metadata: labels: app: server-forgejo name: server-forgejo-valkey-user-5k8kmm9bk4 type: Opaque --- apiVersion: v1 kind: Service metadata: annotations: prometheus.io/path: /metrics prometheus.io/port: "3000" prometheus.io/scrape: "true" labels: app: server-forgejo name: server-forgejo spec: clusterIP: None ports: - name: server port: 3000 protocol: TCP targetPort: server - name: ssh port: 22 protocol: TCP targetPort: ssh selector: app: server-forgejo type: ClusterIP --- apiVersion: v1 kind: PersistentVolumeClaim metadata: labels: app: server-forgejo name: server-forgejo-data spec: accessModes: - ReadWriteOnce resources: requests: storage: 1.9G storageClassName: local-path volumeName: forgejo-ssd-data --- apiVersion: v1 kind: PersistentVolumeClaim metadata: labels: app: server-forgejo name: server-forgejo-git spec: accessModes: - ReadWriteOnce resources: requests: storage: 19G storageClassName: local-path volumeName: forgejo-hdd-git --- apiVersion: apps/v1 kind: StatefulSet metadata: labels: app: server-forgejo name: server-forgejo spec: replicas: 1 selector: matchLabels: app: server-forgejo serviceName: server-forgejo template: metadata: labels: app: server-forgejo spec: automountServiceAccountToken: false containers: - env: - name: FORGEJO__database__NAME valueFrom: configMapKeyRef: key: postgresql-db-name name: db-postgresql-config - name: FORGEJO__database__USER valueFrom: configMapKeyRef: key: forgejo-username name: db-postgresql-config - name: FORGEJO__database__PASSWD valueFrom: secretKeyRef: key: forgejo-user-password name: db-postgresql-secrets - name: FORGEJO__database__SCHEMA valueFrom: configMapKeyRef: key: forgejo-username name: db-postgresql-config - name: FORGEJO__cache__HOST value: redis://$(FORGEJO_VALKEY_USERNAME):$(FORGEJO_VALKEY_PASSWORD)@cache-valkey.forgejo.svc.homelab.cluster.:6379/0?pool_size=100&idle_timeout=180s&prefix=forgejo%3A - name: FORGEJO__session__PROVIDER_CONFIG value: $(FORGEJO__cache__HOST) - name: FORGEJO__queue__CONN_STR value: $(FORGEJO__cache__HOST) envFrom: - configMapRef: name: server-forgejo-env-vars-bht2m829kt - secretRef: name: server-forgejo-valkey-user-5k8kmm9bk4 image: codeberg.org/forgejo/forgejo:14.0-rootless livenessProbe: failureThreshold: 10 httpGet: httpHeaders: - name: X-Forwarded-Proto value: https - name: Host value: forgejo.homelab.cloud path: /api/healthz port: server initialDelaySeconds: 120 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 5 name: server ports: - containerPort: 3000 name: server - containerPort: 2222 name: ssh readinessProbe: failureThreshold: 10 httpGet: httpHeaders: - name: X-Forwarded-Proto value: https - name: Host value: forgejo.homelab.cloud path: /api/healthz port: server initialDelaySeconds: 100 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 5 resources: requests: cpu: 250m memory: 128Mi securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true runAsGroup: 1000 runAsNonRoot: true runAsUser: 1000 volumeMounts: - mountPath: /var/lib/gitea name: forgejo-data-storage readOnly: false - mountPath: /var/lib/gitea/git name: forgejo-git-storage readOnly: false - mountPath: /tmp/gitea name: tmp readOnly: false hostAliases: - hostnames: - forgejo.homelab.cloud ip: 10.7.0.1 initContainers: - command: - /bin/sh - -c - | set -e chown -Rfv 1000:1000 $FORGEJO_APP_DATA_PATH && echo "chown ok on $FORGEJO_APP_DATA_PATH" || echo "Error changing ownership of $FORGEJO_APP_DATA_PATH directory" chown -Rfv 1000:1000 /tmp/forgejo && echo "chown ok on /tmp/forgejo" || echo "Error changing ownership of /tmp/forgejo directory" export DIRS='git git/custom git/repositories git/lfs' echo 'Check if base dirs exists, if not, create them' echo "Directories to check: $DIRS" for dir in $DIRS; do if [ ! -d $FORGEJO_APP_DATA_PATH/$dir ]; then echo "Creating $FORGEJO_APP_DATA_PATH/$dir directory" mkdir -pv $FORGEJO_APP_DATA_PATH/$dir || echo "Error creating $FORGEJO_APP_DATA_PATH/$dir directory" fi chown -Rfv 1000:1000 $FORGEJO_APP_DATA_PATH/$dir && echo "chown ok on $dir" || echo "Error changing ownership of $FORGEJO_APP_DATA_PATH/$dir directory" done exit 0 env: - name: FORGEJO_APP_DATA_PATH value: /var/lib/gitea image: docker.io/busybox:stable-musl name: permissions-fix resources: requests: cpu: 100m memory: 128Mi securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true volumeMounts: - mountPath: /var/lib/gitea name: forgejo-data-storage readOnly: false - mountPath: /var/lib/gitea/git name: forgejo-git-storage readOnly: false - mountPath: /tmp/gitea name: tmp readOnly: false securityContext: fsGroup: 1000 fsGroupChangePolicy: OnRootMismatch volumes: - name: forgejo-data-storage persistentVolumeClaim: claimName: server-forgejo-data - name: forgejo-git-storage persistentVolumeClaim: claimName: server-forgejo-git - emptyDir: sizeLimit: 64Mi name: tmp
Do not deploy this Forgejo server project on its own
This Forgejo server setup is missing two critical element, the persistent volumes it needs to store its working directory data and the users Git repositories and LFS contents. Do not confuse them with the claims you have configured for your Forgejo server. Those persistent volumes and other elements to be declared in the main Kustomize project you will declare in the final part of this Forgejo deployment procedure. Until then, do not deploy this Forgejo server subproject.
Relevant system paths
Folders in kubectl client system
$HOME/k8sprjs/forgejo$HOME/k8sprjs/forgejo/components$HOME/k8sprjs/forgejo/components/server-forgejo$HOME/k8sprjs/forgejo/components/server-forgejo/configs$HOME/k8sprjs/forgejo/components/server-forgejo/resources$HOME/k8sprjs/forgejo/components/server-forgejo/secrets
Files in kubectl client system
$HOME/k8sprjs/forgejo/components/server-forgejo/kustomization.yaml$HOME/k8sprjs/forgejo/components/server-forgejo/configs/env.properties$HOME/k8sprjs/forgejo/components/server-forgejo/resources/server-forgejo-data.persistentvolumeclaim.yaml$HOME/k8sprjs/forgejo/components/server-forgejo/resources/server-forgejo-git.persistentvolumeclaim.yaml$HOME/k8sprjs/forgejo/components/server-forgejo/resources/server-forgejo.service.yaml$HOME/k8sprjs/forgejo/components/server-forgejo/resources/server-forgejo.statefulset.yaml$HOME/k8sprjs/forgejo/components/server-forgejo/secrets/valkey_user_env.properties
References
Forgejo
Gitea
Other Gitea-related contents
Kubernetes
Other Kubernetes-related contents
- StackOverFlow. Kubernetes: how to set VolumeMount user group and file permissions
- StackOverflow. Why do we need a port/containerPort in a Kubernetes deployment/container definition?
- DevOpsCube. How to Setup Prometheus Monitoring On Kubernetes Cluster
- ACA Group. Blog. How to set up auto-discovery of Kubernetes endpoint services in Prometheus