The SGS controller (this application) can be divided into two main components:
- Workspace management. It provides a web interface for users to request workspaces, and administrators to manage these requests.
- Resource management. For each active workspace, it manages external resources (such as Kubernetes Namespaces, Harbor registries, etc.) and ensures that all resources remain in sync.
flowchart TD
user((user))
admin((admin))
sgs[sgs controller]
db[database]
harbor[harbor]
cluster
user -->|workspace requests| sgs
admin -->|workspace modifications| sgs
sgs <--> |state management| db
sgs --->|manage workspace resources| cluster
sgs --->|manage registries| harbor
The workspace management component is a straightforward CRUD application with basic access control.
The resource management component maintains a queue, where "worker" invocations
are enqueued whenever a workspace is created, modified, or deleted, as well as
periodically to ensure that all resources are in sync. A worker invocation
executes the deploy/worker-sync.sh
script (controlled
with the SGS_WORKER_COMMAND
environment variable) which does the following:
- Invoke
helm
to generate Kubernetes manifests for the each workspace.- It uses the
deploy/chart
Helm chart to generate the manifests. This chart includes Namespaces, ResourceQuotas, LimitRanges, and RoleBindings.
- It uses the
- Invoke
kubectl
to apply the generated manifests to the cluster.- It uses the
--applyset
feature to prune resources that are no longer required, eg. due to deleted workspaces. - Due to a minor technical limitation, this requires the manifest to be
non-empty at all times, even when there are no workspaces defined. We
include the
ws-empty
Namespace to ensure this.
- It uses the
- Invoke
SGS_DEPLOY_REGHARBOR_PATH
(normally built fromcmd/sgs-register-harbor
) create the Harbor registry, add and remove users, and configure the ImagePullSecret in each workspace Namespace to allow pulling images from the registry.- Note: due to technical limitations, the ImagePullSecret registration is not idempotent. It can only run once per workspace, when it is first approved.
Each workspace can be in one of the following states:
- Pending approval: the workspace has been requested by a user, but has not been approved by an administrator. No resources are created for workspaces in this state.
- Enabled: the workspace has been approved by an administrator. External services (quotas, access control, etc.) will be kept in-sync.
- Disabled: the workspace has been disabled by an administrator. The
Namespace will not be deleted, but it will not have a valid ResourceQuota
or RoleBindings.
- This ensure that workspaces can be re-enabled in the future, keeping any important data intact.
Whenever a non-pending resource has pending changes requested by a user, it will be displayed as "Pending changes" in the workspace list.
- Go: most logic is written in Go.
- NodeJS (tailwind): for generating CSS for styling.
- Templ: server-side HTML rendering.
- PostgreSQL: database.
Use Nix to configure the development environment.
$ # Open a shell with the development environment
$ nix develop
$ # Install npm dependencies
$ npm i
$ # Set up the development / test databases
$ docker-compose up -d
During development, you can use the hot reloader to automatically rebuild and restart the server when you make changes to the code.
$ make hotreload
Run the tests with the following command:
$ # ensure the test database is running
$ docker-compose up -d
$ make check
The user manual is written in markdown and rendered with mdbook. Run the documentation server with the following command:
$ # serve docs locally
$ make serve-docs