Skip to content

Commit

Permalink
Merge branch 'main' into feature/new-dashboard
Browse files Browse the repository at this point in the history
  • Loading branch information
eyemono-moe committed Nov 17, 2023
2 parents 097ce2f + cd17b3c commit 3cc5d7b
Show file tree
Hide file tree
Showing 51 changed files with 1,092 additions and 552 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci-protoc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
go-version-file: ./go.mod
- uses: arduino/setup-protoc@v2
with:
version: "24.2"
version: "24.4"
- name: Install proto tools
run: make init-protoc-tools
- name: Generate code
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/dashboard-ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
- uses: actions/setup-node@v4
with:
node-version: 18
cache: yarn
Expand All @@ -32,7 +32,7 @@ jobs:
needs: [packages]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
- uses: actions/setup-node@v4
with:
node-version: 18
cache: yarn
Expand All @@ -45,7 +45,7 @@ jobs:
needs: [packages]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
- uses: actions/setup-node@v4
with:
node-version: 18
cache: yarn
Expand All @@ -58,7 +58,7 @@ jobs:
needs: [packages]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
- uses: actions/setup-node@v4
with:
node-version: 18
cache: yarn
Expand Down
8 changes: 6 additions & 2 deletions .github/workflows/preview.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
name: preview

on:
pull_request:
# pull_request_target を使うにあたって https://securitylab.github.com/research/github-actions-preventing-pwn-requests/ の一読を推奨
pull_request_target:

permissions:
packages: write
Expand All @@ -12,9 +13,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Set PR_NUMBER env
run: echo "PR_NUMBER=$(echo $GITHUB_REF | sed -e 's/[^0-9]//g')" >> $GITHUB_ENV
run: echo "PR_NUMBER=${{ github.event.number }}" >> $GITHUB_ENV

- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
persist-credentials: false

- name: Set up QEMU
uses: docker/setup-qemu-action@v3
Expand Down
2 changes: 1 addition & 1 deletion .local-dev/manifest/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# manifest

Manifest files required to deploy NeoShowcase locally
Manifest files required to deploy NeoShowcase locally using k8s backend

## bootstrap

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ spec:
name: socket
- mountPath: /opt/config/ns.yaml
name: config
subPath: confnsig.yaml
subPath: ns.yaml
- mountPath: /keys
name: keys
# - mountPath: /.docker
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ spec:
imagePullPolicy: Never
args:
- --loglevel=debug
- --config=/opt/config/ns-gateway.yaml
- --config=/opt/config/ns.yaml
ports:
- containerPort: 8080
name: http
Expand Down
7 changes: 3 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
PROTOC_VERSION := 24.2
TBLS_VERSION := 1.65.3
SPECTRAL_VERSION := 6.4.0
PROTOC_VERSION := 24.4
TBLS_VERSION := 1.70.2

GO_REPO_ROOT_PACKAGE := "github.com/traPtitech/neoshowcase"
PROTOC_OPTS := -I ./api/proto --go_out=. --go_opt=module=$(GO_REPO_ROOT_PACKAGE) --connect-go_out=. --connect-go_opt=module=$(GO_REPO_ROOT_PACKAGE)
Expand All @@ -26,7 +25,7 @@ init-protoc:
init-protoc-tools: ## Install other protoc tools
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install connectrpc.com/connect/cmd/protoc-gen-connect-go@latest
yarn global add @bufbuild/protoc-gen-connect-es @bufbuild/protoc-gen-es
yarn global add @connectrpc/protoc-gen-connect-es @bufbuild/protoc-gen-es

.PHONY: init
init: init-protoc init-protoc-tools ## Install commands
Expand Down
17 changes: 8 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,14 @@ This application is a successor to [kaz/showcase](https://github.com/kaz/showcas

## Development

- `make`: Display Makefile help
- `make up`: Spin up development environment
- `make down`: Tear down development environment
See [development.md](./docs/development.md).

### Workaround
## Architecture

Add following to your `/etc/hosts` before executing `make up`
(workaround to issue #493)
See:
- [architecture.md](./docs/architecture.md) for big picture of the architecture
- [components.md](./docs/components.md) for detailed explanation of components and libraries

```
127.0.0.1 registry.local
```
## Production Deployment

See [deployment.md](./docs/deployment.md).
6 changes: 4 additions & 2 deletions cmd/wire_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

File renamed without changes.
6 changes: 3 additions & 3 deletions dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@
"vite-plugin-solid-svg": "0.6.1"
},
"dependencies": {
"@bufbuild/connect": "0.13.0",
"@bufbuild/connect-web": "0.13.0",
"@bufbuild/protobuf": "1.3.1",
"@bufbuild/protobuf": "1.4.1",
"@connectrpc/connect": "1.1.2",
"@connectrpc/connect-web": "1.1.2",
"@modular-forms/solid": "^0.20.0",
"@solid-primitives/refs": "1.0.5",
"@solidjs/router": "0.8.3",
Expand Down
2 changes: 1 addition & 1 deletion dashboard/src/api/neoshowcase/protobuf/gateway_connect.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// @generated by protoc-gen-connect-es v0.13.0 with parameter "target=ts"
// @generated by protoc-gen-connect-es v1.1.3 with parameter "target=ts"
// @generated from file neoshowcase/protobuf/gateway.proto (package neoshowcase.protobuf, syntax proto3)
/* eslint-disable */
// @ts-nocheck
Expand Down
2 changes: 1 addition & 1 deletion dashboard/src/api/neoshowcase/protobuf/gateway_pb.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// @generated by protoc-gen-es v1.3.1 with parameter "target=ts"
// @generated by protoc-gen-es v1.4.1 with parameter "target=ts"
// @generated from file neoshowcase/protobuf/gateway.proto (package neoshowcase.protobuf, syntax proto3)
/* eslint-disable */
// @ts-nocheck
Expand Down
2 changes: 1 addition & 1 deletion dashboard/src/api/neoshowcase/protobuf/null_pb.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// @generated by protoc-gen-es v1.3.1 with parameter "target=ts"
// @generated by protoc-gen-es v1.4.1 with parameter "target=ts"
// @generated from file neoshowcase/protobuf/null.proto (package neoshowcase.protobuf, syntax proto3)
/* eslint-disable */
// @ts-nocheck
Expand Down
2 changes: 1 addition & 1 deletion dashboard/src/components/templates/BuildLog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { client } from '/@/libs/api'
import { concatBuffers, toUTF8WithAnsi } from '/@/libs/buffers'
import { isScrolledToBottom } from '/@/libs/scroll'
import { sleep } from '/@/libs/sleep'
import { Code, ConnectError } from '@bufbuild/connect'
import { Code, ConnectError } from '@connectrpc/connect'
import { Component, Ref, Show, createEffect, createResource, createSignal, onCleanup } from 'solid-js'
import { LogContainer } from '../UI/LogContainer'

Expand Down
2 changes: 1 addition & 1 deletion dashboard/src/components/templates/ContainerLog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { toWithAnsi } from '/@/libs/buffers'
import { isScrolledToBottom } from '/@/libs/scroll'
import { addTimestamp, lessTimestamp, minTimestamp } from '/@/libs/timestamp'
import { colorVars, vars } from '/@/theme'
import { Code, ConnectError } from '@bufbuild/connect'
import { Code, ConnectError } from '@connectrpc/connect'
import { Timestamp } from '@bufbuild/protobuf'
import { styled } from '@macaron-css/solid'
import { Component, For, Ref, Show, createEffect, createMemo, createResource, createSignal, onCleanup } from 'solid-js'
Expand Down
4 changes: 2 additions & 2 deletions dashboard/src/libs/api.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { APIService } from '/@/api/neoshowcase/protobuf/gateway_connect'
import { createPromiseClient } from '@bufbuild/connect'
import { createConnectTransport } from '@bufbuild/connect-web'
import { createPromiseClient } from '@connectrpc/connect'
import { createConnectTransport } from '@connectrpc/connect-web'
import { createResource } from 'solid-js'
import toast from 'solid-toast'

Expand Down
30 changes: 14 additions & 16 deletions dashboard/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -582,22 +582,20 @@
resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-x64/-/cli-win32-x64-1.2.2.tgz#583e50d8a1a1cc81381200d3cb2f34669c6afd35"
integrity sha512-bfaFJwqJ9ApFga2o88OaROSd3pasYRzRGXHJWAE9VUUKdSNSTYxHOqVrNvV54yYPtL6Kt9xkuZa4HNu9it3TaA==

"@bufbuild/connect-web@0.13.0":
version "0.13.0"
resolved "https://registry.yarnpkg.com/@bufbuild/connect-web/-/connect-web-0.13.0.tgz#87301c92d49d3c3f9acb99729c2f7505d739aa4a"
integrity sha512-Ys9VFDWYktD9yFQSLOlkpsD42LonDNMCysLCfjXFuxlupYuf4f7qg0zkT5bESyTfqk4xtRDSSGR3xygaj/ONIQ==
dependencies:
"@bufbuild/connect" "0.13.0"

"@bufbuild/connect@0.13.0":
version "0.13.0"
resolved "https://registry.yarnpkg.com/@bufbuild/connect/-/connect-0.13.0.tgz#97a84a2cac747c7a52d4421a3382d8d165f61c99"
integrity sha512-eZSMbVLyUFtXiZNORgCEvv580xKZeYQdMOWj2i/nxOcpXQcrEzTMTA7SZzWv4k4gveWCOSRoWmYDeOhfWXJv0g==

"@bufbuild/protobuf@1.3.1":
version "1.3.1"
resolved "https://registry.yarnpkg.com/@bufbuild/protobuf/-/protobuf-1.3.1.tgz#c4de66bacbe7ac97fe054e68314aeba6f45177f9"
integrity sha512-BUyJWutgP2S8K/1NphOJokuwDckXS4qI2T1pGZAlkFdZchWae3jm6fCdkcGbLlM1QLOcNFFePd+7Feo4BYGrJQ==
"@bufbuild/protobuf@1.4.1":
version "1.4.1"
resolved "https://registry.yarnpkg.com/@bufbuild/protobuf/-/protobuf-1.4.1.tgz#2a827da66aebe904edca21f7085724154aa7868d"
integrity sha512-4dthhwBGD9nlpY35ic8dMQC5R0dsND2b2xyeVO3qf+hBk8m7Y9dUs+SmMh6rqO2pGLUTKHefGXLDW+z19hBPdQ==

"@connectrpc/connect-web@1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@connectrpc/connect-web/-/connect-web-1.1.2.tgz#e862a4027406dc772ead3ae179f058c26b1fcf0f"
integrity sha512-6Osvp4d/5Qvf0dsbUmqgzCPFIong9KBm5G24g2gapPW2huAtyVj+KwdG6453EKCirPZ5qZHY0FywLef57op9YQ==

"@connectrpc/connect@1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@connectrpc/connect/-/connect-1.1.2.tgz#d1b5fa1dcec310a8210c1523c99abdc227643f4b"
integrity sha512-oDuKJFRORtzyH4IhZyNgIQ5DKjlDnbP72AH55Aabpc0fwApyus/h4cmYU1KDvahVbqsvUOpd5qUTyMH8IhMmLA==

"@emotion/hash@^0.8.0":
version "0.8.0"
Expand Down
108 changes: 108 additions & 0 deletions docs/architecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# Architecture

## Overview

NeoShowcase is a PaaS (Platform as a Service) that traP members (users) can use.
Here, PaaS refers to a service that runs applications on behalf of users just with the source code of the application and a minimal configuration.
Users manage the source code of their applications on Git and push it to services like GitHub or Gitea.
NeoShowcase automatically detects updates and builds applications according to user settings.

One of the major design principles of NeoShowcase is the "reconciliation loop" (also known as the reconciliation pattern, synchronization, eventual consistency, etc.).
This is heavily influenced by the processing method of Kubernetes controllers (in fact, NeoShowcase can also be considered a Kubernetes controller).
In contrast, there is an "event-driven" design, where internal processes are triggered by user actions or external events, and perform some processing which may fire more events.
However, event-driven designs can become complex when events are lost during communication or when processes triggered by events fail or crash.
In contrast, the "reconciliation loop" periodically monitors the system's state and performs "reconciliation" only when it is not in the desired state.

While the event-driven approach tends to have slightly higher computational overhead, it eliminates the need for complex retry logic.
Each process only needs to bring its responsible state to the desired state, making the logic simpler.

Each component has its own "reconciliation loop."

- controller/repository_fetcher: Every 3 minutes or when an event occurs, it retrieves a list of repositories and applications from the database, fetches the latest commit hash corresponding to the git ref specified by each application, and stores that value in the database.
- This is influenced by the way ArgoCD updates. Argo CD polls Git repositories every three minutes to detect changes to the manifests. https://argo-cd.readthedocs.io/en/stable/operator-manual/webhook/
- controller/continuous_deployment/build_registerer: Every 3 minutes or when an event occurs, it lists applications that have not been built yet (no build information queued in the database) and saves the necessary build information in the database as "queued."
- controller/continuous_deployment/build_starter: Every 3 minutes or when an event occurs, it instructs connected builders to process the next queued build.
- controller/continuous_deployment/build_crash_detector: Every 1 minute, it detects whether the builder crashed or became unresponsive and records the corresponding build as a failure.
- controller/continuous_deployment/deployments_synchronizer: Every 3 minutes or when an event occurs, it checks whether the latest build has completed for each application whose desired state is "running" and, if so, requests synchronization with backend and ssgen.
- controller/backend: It connects to Docker or Kubernetes and manages the actual containers and network. It receives a list of applications whose desired state is "running" and ensures that the actual system state matches it by starting/terminating containers and configuring routing. It also handles routing to the static file server configured by ss-gen.
- ss-gen: Every 3 minutes or when an event occurs, it downloads static site files from storage and arranges them for delivery.

In this way, each component monitors only the state it is responsible for and focuses on bringing it to the desired state, resulting in a system that is robust against failures.

## Components

### traefik-forward-auth

https://github.com/traPtitech/traefik-forward-auth

This component performs user authentication using the forward auth middleware of the traefik proxy.

It is a simple HTTP server that performs the following:

- If authenticated, return 200 OK.
- In the case of "soft" authentication, login is possible at `/_oauth/login`.
- If not authenticated, perform a 307 Temporary Redirect to carry out OAuth/OIDC authentication set in the configuration.
- It first attempts "prompt=none", so the authorization screen should only appear once per root domain.

For detailed behavior, please refer to the README.

### Gateway (ns-gateway)

This is the part where users operate directly from the front-end (dashboard).
It uses [Connect](https://connect.build/) to perform typed communication while using existing proxy authentication on HTTP/1.1.

Normally, "API Gateways" often refer to components that aggregate multiple microservices, NeoShowcase's Gateway handles all API operations by itself since NeoShowcase's API is not that complex.
It reads and writes various necessary information from the Controller, DB, and storage.
It also triggers events to the Controller, and even if these events were to be missed, the system would automatically recover to its desired state through the Controller's internal reconciliation loop.

### Controller (ns-controller)

Core of NeoShowcase

It monitors the state in the database, and each subcomponent brings it to the desired state and eventually deploys the application.

For the functionality of important subcomponents, please refer to the description above.

### Builder (ns-builder)

Receives build instructions from the Controller and performs the build of OCI Images (Docker images).

Currently, there are six types of build methods:

- Runtime (buildpack): It uses [Cloud Native Buildpacks](https://buildpacks.io/) to build runtime applications. It can build most common applications with zero config. It's also used in Heroku.
- Runtime (command): This method directly specifies the base image and the commands (shell scripts) for building and running during build.
- Runtime (dockerfile): This method specifies a Dockerfile for building. It offers higher customization than the previous two methods.
- Runtime (buildpack): It uses [Cloud Native Buildpacks](https://buildpacks.io/) and a specified output path to build static applications.
- Static (command): This method directly specifies the base image, build-time command (shell script), and the path where build artifacts are generated, to build static sites.
- Static (dockerfile): This method specifies a Dockerfile for building static sites. It offers higher customization than the command-based approach.

It performs builds according to each build method and pushes the generated images to the registry.

### Static-Site Generator (ns-ssgen)

It places the build artifacts of static sites and configures them for delivery.

It can be extended to configure settings for static delivery processes like Apache HTTPD, Nginx, Caddy, etc.

### Migrator (ns-migrate)

Performs database migrations.
Migrator consists of a single shell script that executes [sqldef](https://github.com/k0kubun/sqldef).

If possible, you should first define a schema that is compatible with both the old and new versions.
Then, run this migrator to make schema changes.
Afterward, migrate the necessary data manually or from within the code to perform zero-downtime migration.

However, since NeoShowcase's gateway works fine with a short controller downtime, you don't necessarily have to perform migrations that are backward-compatible.

## Compatibility with Various Backends

NeoShowcase is designed to be cloud-agnostic, based on traefik. While it's theoretically possible to adapt it to various cloud's Ingress Controllers, implementing it extensively can become challenging.

| | Docker(traefik) | K8s(traefik) | K8s(Cloud, not implemented) |
|-----------|-------------------------|---------------------------------------|----------------|
| Routing | traefik docker provider | traefik CRD provider | Ingress |
| Certificate Acquisition | traefik Let's encrypt | traefik Let's encrypt or cert-manager | Depends on cloud |
| Member Authentication | traefik middleware | traefik middleware | Depends on cloud |
| Networking | docker network | NetworkPolicy | Depends on cloud |
| Container | docker container | StatefulSet etc. | StatefulSet etc. |
Loading

0 comments on commit 3cc5d7b

Please sign in to comment.