-
Notifications
You must be signed in to change notification settings - Fork 55
Gitea deployment
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.
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
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.
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"]
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
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"
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
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.
To have a completely working example it is necessary to create a MySQL database, and connect it to Gitea.
-> % epinio service create mysql-dev mydb
🚢 Creating Service...
Catalog: mysql-dev
Service: mydb
-> % epinio service bind mydb gitea
🚢 Binding Service...
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.
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.