An ultra-lightweight self-hosted CI solution with a dashboard and containerized runners

Overview

Candor Candor

An extremely simple containerized CI server.

Ecosystem

Ecosystem

The Candor ecosystem is straightforward, and entirely containerized.

Docker runs on the host machine(s) of the controller and pipeline runner(s). The controller's panel and API runs as a container. The pipeline runner(s) run(s) as a container. The controller keeps track of the semantics of pipelines, their users and permissions, etc.

When the controller should run the pipeline, it chooses an available runner. It then sends the runner a blueprint of the tasks to perform for this pipeline run. The runner builds the required images for each stage on the host Docker. Next, it creates a volume for the run of the pipeline. With the created images, it runs a container per stage of the pipeline, whereby the working directory is mounted on the shared volume. Optionally, after the pipeline has passed, files can be archived to S3 from the working directory of the last stage. Lastly, all created images, containers, volumes, etc. get destroyed, even in the case of errors.

Pipeline Philosophy.

  • A pipeline may have multiple stages, which will be executed one after another.
  • Pipeline stages all perform work in a single working directory, which gets passed from one stage to the next.
  • If a stage fails, all subsequent stages are skipped and the pipeline fails.
  • If the pipeline or a stage errors, all subsequent stages are skipped as well, and the pipeline also fails.
  • If the pipeline passes, select files from the working directory may be permanently archived.

Components

Candor consists of multiple components, which all play an important role in the ecosystem. Although Candor is in an encosystem, it is entirely possible to pick and choose applicable components. For example, a single pipeline runner can be used without its corresponding controller. Or, custom runners can be used in place of the provided one with the same CI controller.

CI Controller

The CI controller is both a web panel and API. Under the hood, it is a command line tool, capable of modifying the state of the ecosystem. Very minimal information is reflected on the dashboard, in order to keep everything simple and to avoid clutter.

The controller's backend is written in TypeScript, using Express.js, TypeORM and a PostgreSQL database. The controller's frontend is written in Svelte.

Runner

The runner is at the heart of the ecossytem. It exposes a single endpoint that contains a pipeline plan, and the runner's job is to execute this plan. Everything the runner does is containerized.

The runner is written in TypeScript using Express.js.

Plans

A plan describes how the pipeline should function. Plans are at their core written in JSON.

When sending a pipeline request to a runner, the following format is required:

{
    "runId": "12345",
    "tag": "veryrandomtaghere",
    "plan": {}
}

The runId is optional (defaults to a random hex string). If the pipeline is being triggered by a panel or something that has a run ID, this will force the runner to use this ID to make debugging easier. The tag is also optional (defaults to "untagged"), and specifies some grouping of pipelines. Multiple pipeline plans can have the same tag, or they can each have their own.

The following describes the current pipeline plan.

Field Type Nullable Description
stages stage[] No A possibly empty array of pipeline stages.
archive string[] Yes The paths of all the filenames that will be archived.

The following describes the current stage plan.

Field Type Nullable Description
name string No The name of the stage.
image string No The name of the Docker image to use for the stage.
runtime string Yes The runtime for the container. Defaults to the default system runtime.
environment string[] Yes A possibly empty array of KEY=VALUE environment variables.
script string[] Yes A possibly empty array of shell commands to execute in the container.

Archiving

At the end of the pipeline, any file can be archived from the working directory and uploaded to S3 storage.

Archived files will be uploaded to tag/filename in S3, where tag is the pipeline run's tag and filename is the base file name of the file to be archived. Note that when archiving, everything will be flattened: path structures in the working directory are disregarded. For example, foo/bar.txt and baz/bar.txt both resolve to bar.txt and will overwrite eachother. As a workaround, archived files should be renamed before achiving. Furthermore, if folders are specified, these will be skipped and not uploaded to S3.

Container Runtimes

Pipeline containers do not get started with --priveleged nor do they have access to the Docker daemon. In order to provide functionality to e.g. build and publish an image, Docker needs to run inside of Docker. Such functionality is supported using third party runtimes like sysbox.

Candor makes no assumption about runtimes. It is up to the host system to install and configure additional container runtimes if the default runtime does not meet system requirements or expectations.

Bootstrap

The bootstrap/ directory provides a super simple way to spin up a fully functioning Candor CI stack. This create the following.

  • A locally hosted S3 server to handle archives.
  • A single pipeline runner.
  • A web server to serve the dashboard.
  • A database server for the dashboard.

Warning: This exposes the Docker socket to the runner's container. If you believe this is not worth the risk, please run the runner on baremetal instead.

Comments
  • [Dashboard] SIGINT and SIGTERM Fix

    [Dashboard] SIGINT and SIGTERM Fix

    Currently ^C does not terminate the process. This is probably because both Express and the CLI are listening and need to support proper exit handlers.

    bug 
    opened by Arraying 3
  • [Global] Auto Build

    [Global] Auto Build

    Automatic Docker image building:

    • [x] When pushing to main, the dashboard and runner should be built, tagged with the short commit hash and published on Docker Hub.
    • [x] When making a release, the dashboard and runner should be built, tagged with the short commit hash, release version and latest. and published on Docker Hub.
    enhancement 
    opened by Arraying 1
  • [Dashboard] Smoother Popups

    [Dashboard] Smoother Popups

    This consists of two components:

    • [x] Modals should have an animation when being opened and closed.
    • [x] Loading a single pipeline's information occurs too fast, either a transition is needed her or faux loading time.

    These changes should be made to aid with usability and not necessarily cosmetics. My eyes hurt at the moment.

    enhancement wontfix 
    opened by Arraying 1
  • [Global] Legal

    [Global] Legal

    Legal things need to be taken care of.

    • [x] The project needs to be licensed under MIT.
    • [x] The dashboard about needs to be written.
    • [x] The dashboard privacy policy needs to be written.
    • [x] The dashboard ToS can go, it is not needed.
    documentation 
    opened by Arraying 1
  • [Dashboard] Runner Setup/Communication

    [Dashboard] Runner Setup/Communication

    Runner should no longer have the hostname and domain saved, instead the base URL should be saved. As such:

    • [x] When creating the runner, ask for the URL.
    • [x] If the healthcheck for the specified runner URL does not pass, don't create it.
    • [x] When running, just use the base URL and don't bother with any protocol.
    enhancement 
    opened by Arraying 1
  • [Dashboard] CLI Overhaul

    [Dashboard] CLI Overhaul

    The CLI needs to be overhauled to see if it still meets standards. Specifically:

    • [x] Decide on usefulness of info subcommands for runners, users and pipelines.
    • [x] Remove pipeline run.
    enhancement 
    opened by Arraying 1
  • [Dashboard] YAML Support

    [Dashboard] YAML Support

    Instead of JSON, the pipeline configuration should be YAML. Both formats are relatively interchangeable so this should not pose a problem. Internally, the config should still be stored as JSON, and the runner will also still receive JSON.

    enhancement 
    opened by Arraying 1
  • [Runner] More Testing

    [Runner] More Testing

    There need to be more tests, specifically:

    • [x] Tests for each component (volume, image, container, archive).
    • [x] Tests for cleanup (i.e. make one of the components fail and assert cleanup of everything occurs).
    enhancement 
    opened by Arraying 1
  • [Runner] Container Timeout

    [Runner] Container Timeout

    There should be an environment variable that specifies how long each stage is permitted to run: RUNNER_CONTAINER_TIMEOUT. The value should be in seconds.

    When the timeout is reached, it will fail the stage and write to the log that the timeout has been exceeded. Then the next steps will, as usual, be skipped.

    enhancement 
    opened by Arraying 1
  • [Runner] Container Configuration

    [Runner] Container Configuration

    There should be the possibility to configure the payload when creating the container.

    A JSON config should be provided that is then deep-merged with the configuration Candor creates. It should be provided as a base64 encoded RUNNER_CONTAINER_CONFIG_B environment variable.

    This will allow resource limits, isolated networking, etc. and add great security benefit.

    enhancement 
    opened by Arraying 1
  • Bump decode-uri-component from 0.2.0 to 0.2.2 in /dashboard/backend

    Bump decode-uri-component from 0.2.0 to 0.2.2 in /dashboard/backend

    Bumps decode-uri-component from 0.2.0 to 0.2.2.

    Release notes

    Sourced from decode-uri-component's releases.

    v0.2.2

    • Prevent overwriting previously decoded tokens 980e0bf

    https://github.com/SamVerschueren/decode-uri-component/compare/v0.2.1...v0.2.2

    v0.2.1

    • Switch to GitHub workflows 76abc93
    • Fix issue where decode throws - fixes #6 746ca5d
    • Update license (#1) 486d7e2
    • Tidelift tasks a650457
    • Meta tweaks 66e1c28

    https://github.com/SamVerschueren/decode-uri-component/compare/v0.2.0...v0.2.1

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the Security Alerts page.
    dependencies 
    opened by dependabot[bot] 0
  • [Dashboard] Suppress NPM Logs

    [Dashboard] Suppress NPM Logs

    When the dashboard starts using the Docker image, it performs migrations. These generate spammy NPM logs which are not desired and should be suppressed. If possible, it would be nice to maintain the migration log as migrations.log in the log directory.

    enhancement help wanted good first issue 
    opened by Arraying 0
  • [Dashboard] Security

    [Dashboard] Security

    The dashboard needs to be secure. The following endpoints need to be verified that they are hardened:

    • [ ] GET /api/pipelines and GET /api/pipelines/:pid must only expose relevant information.
    • [ ] GET /api/pipelines/:pid/config and POST /api/pipelines/:pid/config must only be accessible to assignees.
    • [ ] GET /api/runs/:pid/:rid/log and GET /api/runs/:pid/:rid/archived are accessible only if the pipeline is public or the requester is assigned.
    • [ ] POST /trigger/:token needs to be widely accessible.

    Furthermore, CORS and cookie include needs to be set:

    • [ ] When running in production, only allow same origin for mode and cookies in fetch.
    • [ ] Otherwise, allow cross origin requests.

    Lastly:

    • [x] An instance of the dashboard should be tested against SSLLabs and receive an A+.
    enhancement help wanted 
    opened by Arraying 3
Releases(v1.0.0-RC.1)
Owner
Paul Huebner
Diving into big data, programming languages and DevOps. Software Developer, formally at Minecraft Servers.
Paul Huebner
A self-hosted solution for backing up and viewing backed up mobile photos

Photostore Photostore is a self-hosted, client-server solution for backing up, viewing and downloading photos. How it works The Photostore API (writte

null 38 Oct 25, 2022
A self-hosted solution for creating/managing forms and applications.

Centox - Self-hosted form website It is a self-hosted solution for creating/managing forms and applications. Users can login using their Discord Accou

Simon Maribo 11 Dec 26, 2022
An open source, self-hosted, and entirely free solution to social media management.

An open source, self-hosted, and entirely free solution to social media management. Status ?? In Development ?? Shoutify is currently early in the dev

TechSquidTV 202 Dec 22, 2022
An example T3 app containerized with Docker, Docker Compose, and deployed on Railway

Create T3 App This is an app bootstrapped according to the init.tips stack, also known as the T3-Stack. What's next? How do I make an app with this? W

Anthony Campolo 15 Dec 19, 2022
let's build containerized crawlee - work repository for test.

Crawlee-ing on container project! NodeJS 기반 컨테이너 + Crawlee 오픈소스 테스트용 레포지토리입니다. Crawlee는 크롤링 및 스크래이핑을 빠르게 구축하는 데 필요한 npm package입니다. Features Docker-co

Present_Jay.Dev 6 Nov 2, 2022
🍭 search-buddy ultra lightweight javascript plugin that can help you create instant search and/or facilitate navigation between pages.

?? search-buddy search-buddy is an open‑source ultra lightweight javascript plugin (* <1kb). It can help you create instant search and/or facilitate n

Michael 4 Jun 16, 2022
A self-hosted, customizable and ad-free Google Search experience

Giggle A self-hosted, customizable and ad-free Google Search experience. What does it do? Giggle lets you run Google searches against allow- and block

Dan Lovelace 213 Dec 15, 2022
A self-hosted Thumbnail generator/finder which creates thumbnails based on folder names and google search results.

Thumba A self hosted Thumbnail generator/finder which creates thumbnails based on folder names and google search results. Description This project use

Norbert Takács 20 Dec 15, 2022
An open-source and self-hosted assessment platform for recruitment

This is a Next.js project bootstrapped with create-next-app. Getting Started First, run the development server: npm run dev # or yarn dev Open http://

Kaen 2 Oct 4, 2022
A fancy self-hosted monitoring tool

Uptime Kuma It is a self-hosted monitoring tool like "Uptime Robot". Features Monitoring uptime for HTTP(s) / TCP / Ping. Fancy, Reactive, Fast UI/UX.

Louis Lam 27.4k Jan 3, 2023
Self-hosted environment variable management platform

envplat - environment platform This project is under development. Please contact me for any information or collaboration. Self-hosted environment vari

Environment Platform 4 Apr 25, 2022
A self-hosted file sharing platform.

Pingvin Share Pingvin Share is a self-hosted file sharing platform made for the Appwrite Hackathon. ?? Showcase Demo: https://pingvin-share.dev.eliass

Elias Schneider 354 Jan 7, 2023
⛺️ Tipi is a homeserver for everyone! One command setup, one click installs for your favorites self-hosted apps. ✨

⛺️ Tipi — A personal homeserver for everyone ⚠️ Tipi is still at an early stage of development and issues are to be expected. Feel free to open an iss

Nicolas Meienberger 4.9k Jan 4, 2023
Self-hosted TOTP authenticator PWA with FIDO2 (WebAuthn)

pasu Self-hosted TOTP authenticator PWA with FIDO2 (WebAuthn) Features 2FA secrets stored in your own server instead of your own device Codes are gene

ソ瑠璃(soruly) 11 Nov 2, 2022
A self-hosted eBooks Library for your family or yourself.

What is BookStairs? BookStairs is an open-source personal EPUB library which was highly inspired by talebook, calibre-web and BookBrowser. It's design

BookStairs 5 Dec 29, 2022
SCAchat - A self-hosted chatting application

SCAchat is a self-hosted chatting application similar to AOL Instant Messenger. The chatting application is privacy-respecting and does not store any messages or user-data. Once a session has ended, all messages are gone.

Chadano 4 Jul 18, 2022
Self-hosted Slack bot to run your code snippets

slack-code-runner Self-hosted Slack bot to run your code snippets Prerequisites Docker Usage Create a new Slack app and add it to your workspace. You

Myeonghyeon Kim 5 Sep 14, 2022
A self-hosted streamable alternative

What is Clippy? Clippy is a self-hosted streamable alternative Usage docker-compose (recommended) version: '3' services: clippy: image: samfry13

Samuel Fry 2 Sep 17, 2022
Self-hosted open source social media marketing

OpenSMM Description OpenSMM(Open Social Media Marketing) is a self-hosted social media marketing platform built to assist small businesses manage thei

Vaughn 22 Dec 23, 2022