Skip to content

Gitea deployment

Andreas Kupries edited this page Mar 31, 2023 · 19 revisions

One of our lighthouse goals is the deployment of a "complex" Go application.

The chosen application is Gitea. Its backend is written in Go, and its frontend in Javascript. It further needs a MySQL database to hold its state.

The first attempt was just trying to deploying it without any further intervention. While the build seemed to be fine, the frontend was completely missing.

Checking about this in the Paketo Slack channel it seems that the Go buildpack does not support Javascript frontends.

They were advising to use a set of buildpacks to build the frontend and the backend.

As running a make command is enough to locally build the application, we tried to implement a custom builder with the needed dependencies and an additional custom "Make Gitea" buildpack.

As we saw during our tests that the Gitea application needs the git package at runtime, it was necessary to fork the Paketo Full Stack to add this package to the Run image.

Stack

After adding the git package to the packages section in the run.args block of the stack.toml file the stack can be build with

./scripts/create.sh

This will build two OCI images, that can be extracted, copied and pushed to a registry of our choice.

mkdir build/build && tar -xf build/build.oci -C build/build
skopeo -v copy oci:build/build docker-daemon:ghcr.io/enrichman/bionic-full-stack-build:latest
docker push ghcr.io/enrichman/bionic-full-stack-build:latest

mkdir build/run && tar -xf build/run.oci -C build/run
skopeo -v copy oci:build/run docker-daemon:ghcr.io/enrichman/bionic-full-stack-run:latest
docker push ghcr.io/enrichman/bionic-full-stack-run:latest

Buildpack

A buildpack is composed of a buildpack.toml file with some metadata, and a couple of scripts that

  • determine if the buildpack has to be run during the detect phase, and
  • what actions to take during the build phase.

buildpack.toml

The buildpack.toml file contains basic information about the buildpack itself, and, importantly, on which stacks it can run on. Our buildpack can run on any stack which contains the build-essential package in its build image.

api = "0.7"

[buildpack]
id = "make"
version = "0.0.1"
name = "Make Buildpack"

[[stacks]]
id = "*"
mixins = ["build:build-essential"]

bin/detect

The detect script is called to check if the buildpack participates in the build. It fails if there is no Makefile, because that is the only thing needed.

It also appends the requirements of this specific buildpack (Node and Go) to the build plan.

#!/usr/bin/env bash
set -eo pipefail

# 1. CHECK IF APPLICABLE
if [[ ! -f Makefile ]]; then
    echo Makefile not found
    exit 100
fi

# 1. GET ARGS
plan_path=$2

# 2. DECLARE DEPENDENCIES
cat >> "${plan_path}" <<EOL
# Buildpack requires this dependency
#
# NOTE: Everything aside from 'name' is simply additional information
#       that the providing buildpack can use to resolve the dependency.
#
[[requires]]
name = "node"
# version = "*"

[requires.metadata]
build = true

[[requires]]
name = "go"

[requires.metadata]
build = true
EOL

bin/build

The build script is called to execute the actual build steps. It runs the TAGS="bindata" make build command, and adds the web process to execute to the launch.toml file.

#!/usr/bin/env bash
set -eo pipefail

echo "---> Make buildpack"

# INPUT ARGUMENTS
platform_dir=$2
env_dir=${platform_dir}/env
layers_dir=$1
plan_path=$3


TAGS="bindata" make build

cat >> "${layers_dir}/launch.toml" <<EOL
[[processes]]
type = "web"
command = "./gitea"
default = true
EOL

echo "---> Done"

Builder

A builder defines how the buildpacks are executed, and on which stack.

Note that it was necessary to fork the Paketo Full Stack and keep using the original stack ID in the fork. This is due to some of the buildpacks reused here working only with this stack.

The builder.toml file contains the buildpacks references and their execution order/groups.

The node-engine buildpack is reused to handle the Node/Javascript dependency. Similarly, the go-dist buildpack is reused to handle the Go dependency. The make buildpack is the custom one created above, handling the specifics of Gitea.

[[buildpacks]]
id = "make"
version = "0.0.1"
uri = "../../buildpacks/make"

[[buildpacks]]
uri = "docker://gcr.io/paketo-buildpacks/node-engine:1.3.0"
version = "1.3.0"

[[buildpacks]]
uri = "docker://gcr.io/paketo-buildpacks/go-dist:2.3.0"
version = "2.3.0"

[[order]]

  [[order.group]]
    id = "paketo-buildpacks/node-engine"
    version = "1.3.0"

  [[order.group]]
    id = "paketo-buildpacks/go-dist"
    version = "2.3.0"

  [[order.group]]
    id = "make"
    version = "0.0.1"

[stack]
id = "io.buildpacks.stacks.bionic"
build-image = "ghcr.io/enrichman/bionic-full-stack-build:latest"
run-image = "ghcr.io/enrichman/bionic-full-stack-run:latest"

Packaging the builder is done with pack:

pack builder create ghcr.io/enrichman/gitea-builder:0.0.1 --config ./test/builders/maker/builder.toml
docker push ghcr.io/enrichman/gitea-builder:0.0.1

Deploy Gitea

With the custom builder in place it is now possible to push the gitea sources as they are.

As the Gitea application listens on the non-standard port 3000 (and cannot be configured to use another) use Epinio 1.8.0+ features (the chart value appListeningPort) to declare this to Epinio as well.

epinio app push -p . --name gitea \
    --builder-image ghcr.io/enrichman/gitea-builder:0.0.2 \
    --chart-value appListeningPort=3000

With the application now available and running it is now the time to provide the proper state database to it.

Database

To have a completely working example it is necessary to create a MySQL database, and connect it to Gitea.

Creation

-> % epinio service create mysql-dev mydb

🚢  Creating Service...
Catalog: mysql-dev
Service: mydb

Binding

-> % epinio service bind mydb gitea

🚢  Binding Service...

Connection

Check the secrets from the generated configuration

-> % epinio configuration show xcca9aa0f19a036fb6389474a7be0-mysql 

🚢  Configuration Details
Name: xcca9aa0f19a036fb6389474a7be0-mysql
Namespace: workspace

🚢  
Created: 2023-03-30 11:08:42 +0200 CEST
User: 
Type: service
Origin: mydb
Used-By: gitea
Siblings: 

⚠️  Attention: Migrate bound apps to new access paths
✔️  
|      PARAMETER      |   VALUE    |               ACCESS PATH                |
|---------------------|------------|------------------------------------------|
| mysql-password      | ikQ5NHqrJR | /configurations/mydb/mysql-password      |
| mysql-root-password | 8OAlnvWQJT | /configurations/mydb/mysql-root-password |

and the endpoint from the service

-> % epinio service show mydb                                     

🚢  Showing Service...

✔️  Details:
|       KEY       |                                     VALUE                                      |
|-----------------|--------------------------------------------------------------------------------|
| Name            | mydb                                                                           |
| Created         | 2023-03-30 11:08:40 +0200 CEST                                                 |
| Catalog Service | mysql-dev                                                                      |
| Version         | 8.0.31                                                                         |
| Status          | deployed                                                                       |
| Used-By         | gitea                                                                          |
| Internal Routes | xcca9aa0f19a036fb6389474a7be0-mysql-headless.workspace.svc.cluster.local:3306, |
|                 | xcca9aa0f19a036fb6389474a7be0-mysql.workspace.svc.cluster.local:3306           |

As sample MySQL server creates a default my_database schema (See https://artifacthub.io/packages/helm/bitnami/mysql?modal=values), providing all these values in the initial Gitea configuration completes the connection.

Issues

During the tests we have faced several issues due to local/remote images, caching, or permissions. To avoid these it is best to always provide the full reference of a public repository.