From f120a8b03f4f1c3902409ccf96e322ea5fd96b1c Mon Sep 17 00:00:00 2001 From: x1unix Date: Sat, 20 Jul 2024 21:39:00 -0400 Subject: [PATCH 1/4] chore: add deployment templates --- README.md | 25 +--- docs/deployment/README.md | 12 ++ docs/deployment/docker/README.md | 54 +++++++++ docs/deployment/docker/compose.yml | 14 +++ docs/deployment/gcloud/.gitignore | 10 ++ docs/deployment/gcloud/README.md | 8 ++ docs/deployment/gcloud/example.tfvars | 9 ++ docs/deployment/gcloud/main.tf | 110 ++++++++++++++++++ docs/deployment/gcloud/variables.tf | 31 +++++ docs/deployment/systemd/README.md | 36 ++++++ .../systemd/better-go-playground.service | 1 + docs/{ => img}/demo.gif | Bin docs/{ => img}/sponsors/gnoland-dark.svg | 0 docs/{ => img}/sponsors/gnoland-light.svg | 0 14 files changed, 290 insertions(+), 20 deletions(-) create mode 100644 docs/deployment/README.md create mode 100644 docs/deployment/docker/README.md create mode 100644 docs/deployment/docker/compose.yml create mode 100644 docs/deployment/gcloud/.gitignore create mode 100644 docs/deployment/gcloud/README.md create mode 100644 docs/deployment/gcloud/example.tfvars create mode 100644 docs/deployment/gcloud/main.tf create mode 100644 docs/deployment/gcloud/variables.tf create mode 100644 docs/deployment/systemd/README.md create mode 120000 docs/deployment/systemd/better-go-playground.service rename docs/{ => img}/demo.gif (100%) rename docs/{ => img}/sponsors/gnoland-dark.svg (100%) rename docs/{ => img}/sponsors/gnoland-light.svg (100%) diff --git a/README.md b/README.md index 39028a27..58724b62 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Improved Go Playground powered by Monaco Editor and React - [https://goplay.tool 🎉 **Check new upcoming features in latest beta at [beta.goplay.tools](https://beta.goplay.tools)** -![alt text](docs/demo.gif) +![alt text](docs/img/demo.gif) ## Features @@ -26,24 +26,9 @@ Improved Go Playground powered by Monaco Editor and React - [https://goplay.tool And more ! -## Installation +## Installation & deployment -### Docker Container (recommended) - -Playground is available as Docker image in [Docker Hub](https://hub.docker.com/r/x1unix/go-playground) and [GitHub Container Registry](https://github.com/x1unix/go-playground/pkgs/container/go-playground%2Fgo-playground). - -See [wiki](https://github.com/x1unix/go-playground/wiki/Docker) for usage info. - -### Building from source - -Service can be built from source (**Go 1.21+** and **Node.js** required): - -```bash -git clone https://github.com/x1unix/go-playground.git -cd go-playground -make -sudo make install -``` +Please check [deployment documentation](./docs/deployment/README.md). ### Third-party credits @@ -59,8 +44,8 @@ Please refer to [CONTRIBUTING.md](CONTRIBUTING.md) and [HACKING.md](HACKING.md) - - Gno.land logo + + Gno.land logo diff --git a/docs/deployment/README.md b/docs/deployment/README.md new file mode 100644 index 00000000..80e0e063 --- /dev/null +++ b/docs/deployment/README.md @@ -0,0 +1,12 @@ +# Deployment + +Here are examples of various application deployment options. + +## Cloud + +* [Google Cloud Run](./gcloud) + +## Bare-metal + +* [Docker](./docker) - Docker container deployment using `docker-compose` +* [systemd](./systemd) - Container-less deployment as systemd unit. diff --git a/docs/deployment/docker/README.md b/docs/deployment/docker/README.md new file mode 100644 index 00000000..a3f2713a --- /dev/null +++ b/docs/deployment/docker/README.md @@ -0,0 +1,54 @@ +# Deployment using docker-compose + +## Using prebuilt image + +Prebuilt Docker image is available on [Docker Hub](https://hub.docker.com/r/x1unix/go-playground) and [GitHub Container Registry](https://github.com/x1unix/go-playground/pkgs/container/go-playground%2Fgo-playground) + +### Starting container + +Download the [compose.yaml](./compose.yaml) file and run `docker-compose` to bootstrap the service: + +```shell +# Create container and start the service. +docker-compose up -d + +# Ensure that service is running. +docker-compose ps +``` + +### Environment variables + +Playground server can be configured using environment variables described below. + +| Environment Variable | Example | Description | +| ---------------------- | ------------------------------ | -------------------------------------------------------------- | +| `GOROOT` | `/usr/local/go` | Go root location. Uses `go env GOROOT` as fallback. | +| `APP_DEBUG` | `false` | Enables debug logging. | +| `APP_PLAYGROUND_URL` | `https://play.golang.org` | Official Go playground service URL. | +| `APP_GOTIP_URL` | `https://gotipplay.golang.org` | GoTip playground service URL. | +| `APP_BUILD_DIR` | `/var/cache/wasm` | Path to store cached WebAssembly builds. | +| `APP_CLEAN_INTERVAL` | `10m` | WebAssembly build files cache cleanup interval. | +| `APP_SKIP_MOD_CLEANUP` | `1` | Disables WASM builds cache cleanup. | +| `APP_PERMIT_ENV_VARS` | `GOSUMDB,GOPROXY` | Restricts list of environment variables passed to Go compiler. | + +## Building custom image + +Use **make** to build Docker image from sources: + +```shell +make docker [...params] +``` + +### Required params + +| Parameter | Description | +| ------------- | -------------------------- | +| `TAG` | Image tag (version) | +| `DOCKER_USER` | Docker repository user | +| `DOCKER_PASS` | Docker repository password | + +### Optional params + +| Parameter | Defaults | Description | +| ------------- | ---------------------- | -------------------------- | +| `IMG_NAME` | `x1unix/go-playground` | Image tag (version) | diff --git a/docs/deployment/docker/compose.yml b/docs/deployment/docker/compose.yml new file mode 100644 index 00000000..b22a4368 --- /dev/null +++ b/docs/deployment/docker/compose.yml @@ -0,0 +1,14 @@ +version: '2' +services: + playground: + # 'latest' used only for example purposes. + # It's strongly recommended to use a specific version (tag). + # + # Also, you can use image from GitHub Container Registry + #image: ghcr.io/x1unix/go-playground/go-playground:latest + image: x1unix/go-playground:latest + restart: unless-stopped + ports: + - 8000:8000 + environment: + APP_CLEAN_INTERVAL: '30m' diff --git a/docs/deployment/gcloud/.gitignore b/docs/deployment/gcloud/.gitignore new file mode 100644 index 00000000..4ac3059e --- /dev/null +++ b/docs/deployment/gcloud/.gitignore @@ -0,0 +1,10 @@ +# Temporary files +.terraform + +# HCL vars except example +*.tfvars +!example.tfvars + +# Temporary plan options +tplan +*.tplan diff --git a/docs/deployment/gcloud/README.md b/docs/deployment/gcloud/README.md new file mode 100644 index 00000000..dff3db9d --- /dev/null +++ b/docs/deployment/gcloud/README.md @@ -0,0 +1,8 @@ +# Google Cloud Run Deployment + +## Prerequisites + +* [OpenTofu](https://opentofu.org) or Terraform +* [Google Cloud](https://cloud.google.com/) project + + diff --git a/docs/deployment/gcloud/example.tfvars b/docs/deployment/gcloud/example.tfvars new file mode 100644 index 00000000..1e249966 --- /dev/null +++ b/docs/deployment/gcloud/example.tfvars @@ -0,0 +1,9 @@ +app_env = "prod" +app_version = "latest" # Deployed app version, replace "latest" with Docker image tag. +project_id = "your gcp project ID" +region = "us-central1" # Desired region for deployment +env_vars = { + # Put here custom environment variables, optional. + # "FOO" = "bar" +} + diff --git a/docs/deployment/gcloud/main.tf b/docs/deployment/gcloud/main.tf new file mode 100644 index 00000000..bb458817 --- /dev/null +++ b/docs/deployment/gcloud/main.tf @@ -0,0 +1,110 @@ +provider "google" { + project = var.project_id + region = var.region +} + +resource "google_cloud_run_v2_service" "default" { + name = "gpg-${var.app_env}" + location = var.region + + template { + scaling { + min_instance_count = 1 + max_instance_count = 5 + } + + volumes { + name = "gpg-build-cache-${var.app_env}" + empty_dir { + medium = "MEMORY" + size_limit = "256Mi" + } + } + + containers { + image = "x1unix/go-playground:${var.app_version}" + ports { + container_port = 8000 + } + + resources = { + cpu_idle = true + startup_cpu_boost = false + limits = { + cpu = "1" + memory = "512Mi" + } + } + + env { + name = "APP_LOG_FORMAT" + value = "console" + } + + env { + name = "APP_SKIP_MOD_CLEANUP" + value = "1" + } + + env { + name = "SENTRY_ENVIRONMENT" + value = var.app_env + } + + env { + name = "SENTRY_RELEASE" + value = "v${var.app_version}" + } + + env { + name = "SENTRY_DSN" + value = var.sentry_dsn + } + + env { + name = "APP_BUILD_DIR" + value = "/var/cache/wasm-builds" + } + + dynamic "env" { + for_each = var.env_vars + content { + key = env.key + value = env.value + } + } + + volume_mounts { + name = "gpg-build-cache-${var.app_env}" + mount_path = "/var/cache/wasm-builds" + } + + startup_probe { + http_get { + path = "/api/version" + port = 8000 + } + initial_delay_seconds = 10 + period_seconds = 10 + timeout_seconds = 5 + success_threshold = 1 + failure_threshold = 3 + } + } + } + + traffic { + percent = 100 + latest_revision = true + } +} + +resource "google_project_iam_member" "run_invoker" { + project = var.project_id + role = "roles/run.invoker" + member = "allUsers" +} + +output "url" { + value = google_cloud_run_v2_service.default.status[0].url +} diff --git a/docs/deployment/gcloud/variables.tf b/docs/deployment/gcloud/variables.tf new file mode 100644 index 00000000..2a3ac240 --- /dev/null +++ b/docs/deployment/gcloud/variables.tf @@ -0,0 +1,31 @@ +variable "project_id" { + description = "GCP Project ID" + type = string +} + +variable "region" { + description = "The region of the GCP project" + type = string +} + +variable "app_env" { + description = "Deployment environment" + type = string +} + +variable "app_version" { + description = "Better Go Playground application version" + type = string +} + +variable "sentry_dsn" { + description = "Sentry DSN" + type = string + default = "" +} + +variable "env_vars" { + description = "key-value pair of custom environment variables." + type = map(string) + default = {} +} diff --git a/docs/deployment/systemd/README.md b/docs/deployment/systemd/README.md new file mode 100644 index 00000000..2229dc4f --- /dev/null +++ b/docs/deployment/systemd/README.md @@ -0,0 +1,36 @@ +# Deployment as systemd unit + +> [!TIP] +> See [HACKING.md](../../../HACKING.md) for development documentation. + +## Prerequisites + +* GNU or BSD Make +* Git +* Go 1.22+ +* [Node Version Manager](https://github.com/nvm-sh/nvm) or Node.js 20 (`lts/iron`) +* [Yarn](https://yarnpkg.com/) package manager. + +## Building + +Close and build this repository: + +```shell +git clone https://github.com/x1unix/go-playground.git +cd go-playground +make +``` + +## Installation + +After building the app, install application and systemd unit: + +```shell +sudo make install +``` + +Check if service is running: + +```shell +systemctl status better-go-playground.service +``` diff --git a/docs/deployment/systemd/better-go-playground.service b/docs/deployment/systemd/better-go-playground.service new file mode 120000 index 00000000..a0cb5374 --- /dev/null +++ b/docs/deployment/systemd/better-go-playground.service @@ -0,0 +1 @@ +../../../build/better-go-playground.service \ No newline at end of file diff --git a/docs/demo.gif b/docs/img/demo.gif similarity index 100% rename from docs/demo.gif rename to docs/img/demo.gif diff --git a/docs/sponsors/gnoland-dark.svg b/docs/img/sponsors/gnoland-dark.svg similarity index 100% rename from docs/sponsors/gnoland-dark.svg rename to docs/img/sponsors/gnoland-dark.svg diff --git a/docs/sponsors/gnoland-light.svg b/docs/img/sponsors/gnoland-light.svg similarity index 100% rename from docs/sponsors/gnoland-light.svg rename to docs/img/sponsors/gnoland-light.svg From e385241e4d53df515d2e35adea931b6d3ce215ce Mon Sep 17 00:00:00 2001 From: x1unix Date: Sat, 20 Jul 2024 22:41:05 -0400 Subject: [PATCH 2/4] chore: add terraform --- docs/deployment/gcloud/.gitignore | 1 + docs/deployment/gcloud/.terraform.lock.hcl | 36 ++++++++++++++++++++++ docs/deployment/gcloud/main.tf | 36 +++++++++++++--------- 3 files changed, 58 insertions(+), 15 deletions(-) create mode 100644 docs/deployment/gcloud/.terraform.lock.hcl diff --git a/docs/deployment/gcloud/.gitignore b/docs/deployment/gcloud/.gitignore index 4ac3059e..a64e2a80 100644 --- a/docs/deployment/gcloud/.gitignore +++ b/docs/deployment/gcloud/.gitignore @@ -7,4 +7,5 @@ # Temporary plan options tplan +tfplan *.tplan diff --git a/docs/deployment/gcloud/.terraform.lock.hcl b/docs/deployment/gcloud/.terraform.lock.hcl new file mode 100644 index 00000000..226b35d2 --- /dev/null +++ b/docs/deployment/gcloud/.terraform.lock.hcl @@ -0,0 +1,36 @@ +# This file is maintained automatically by "tofu init". +# Manual edits may be lost in future updates. + +provider "registry.opentofu.org/hashicorp/google" { + version = "5.38.0" + hashes = [ + "h1:LJk+tFMSa1SBC6UkhJS+iO94uD7/WjxOQfN2mx5POf0=", + "zh:234832f2795dc3cb868e09999dee02caeed62c8069e80ae1249368c4f9edf629", + "zh:2c8e00ddcb9ec498f58c72e925a1c041233d7b3ebac8535902edad8e3ec5b2d8", + "zh:52526913246417d9223879a32cd72bbbf47f4dbfd05e89cffc4f22106feb81ae", + "zh:65172fc8334126ed065fd2a8364436decf07b75d1347395cc8a1f2d4a628ca02", + "zh:781bb362726a51b98b1fb0b8379a9293bf7415adb750c1284e074788465f9cdd", + "zh:8866dc2d5249a1f90a1e26462451e264c1358939d2e8313bd73260f3d407eb3a", + "zh:9a63de80fc8724b9fb9bd0fd88449cadd60ce3081c763a393e0ac0bd1edb9cb2", + "zh:c73a2608be1a78bd02acca450b55ae4de01d29d029504ba92434159672932aea", + "zh:d7b68aab00f5cf9424df9db0cbf8d6d2efde8188206938a22a11b2b569806095", + "zh:e820d998be11b7ea2ff86391733d434f23846386f53237d19253c2af9197edb1", + ] +} + +provider "registry.opentofu.org/hashicorp/google-beta" { + version = "5.38.0" + hashes = [ + "h1:JWAyHY0ZVTidZL8Qz6W6SegbL5mwuUelAEE2SrKVjME=", + "zh:0b11ac74ddbdc3a660bda95c2da5d70f112a6edc1c15bc70278d2f72ca7239c9", + "zh:1ec867c66eb1878efbff59194614348aa57b272fa171685b2f64dd33e0aee748", + "zh:20da165f540779b69a9e8e2aa166118cea598b5cab88fd9b4dd437a21d118214", + "zh:430b90259b04c4694c280c0d64eae2470c67dd94591478903ff12a9ff16530a5", + "zh:58ed45f7d3016e0c16512a41cb38638bfa5e9f23671164bdbb4eef3a3dfea157", + "zh:728405f40bdecd18cf5c9ddb6a1d0ba30c4b10f3a1b852cb8ae61894569f476d", + "zh:b151219dae286eec73f84f84057b3b386ff3fce880a3930b7655b6df3cb365a4", + "zh:db22046d53ecbe02cd8606462c6eca08e799af5f15c2ec4791729ed04d849fae", + "zh:fd7e926ef766e03a7c3ba9c24d8e0c39097deb405f7022df86113113dd5b1634", + "zh:fea7ed94fc9aad4df3756f60b14a5bcb698a95601096f931cf130c2a3b0b0de6", + ] +} diff --git a/docs/deployment/gcloud/main.tf b/docs/deployment/gcloud/main.tf index bb458817..6cce07be 100644 --- a/docs/deployment/gcloud/main.tf +++ b/docs/deployment/gcloud/main.tf @@ -1,11 +1,16 @@ -provider "google" { +# See: https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/cloud_run_v2_service + +# Beta provider is required for "empty_dir" storage type. +provider "google-beta" { project = var.project_id region = var.region } resource "google_cloud_run_v2_service" "default" { + provider = google-beta name = "gpg-${var.app_env}" location = var.region + launch_stage = "BETA" template { scaling { @@ -24,10 +29,11 @@ resource "google_cloud_run_v2_service" "default" { containers { image = "x1unix/go-playground:${var.app_version}" ports { + name = "http1" container_port = 8000 } - resources = { + resources { cpu_idle = true startup_cpu_boost = false limits = { @@ -41,6 +47,7 @@ resource "google_cloud_run_v2_service" "default" { value = "console" } + # Disable cache cleanup for stateless containers. env { name = "APP_SKIP_MOD_CLEANUP" value = "1" @@ -61,19 +68,20 @@ resource "google_cloud_run_v2_service" "default" { value = var.sentry_dsn } - env { - name = "APP_BUILD_DIR" - value = "/var/cache/wasm-builds" - } - dynamic "env" { for_each = var.env_vars content { - key = env.key + name = env.key value = env.value } } + # Use WASM build cache directory. + env { + name = "APP_BUILD_DIR" + value = "/var/cache/wasm-builds" + } + volume_mounts { name = "gpg-build-cache-${var.app_env}" mount_path = "/var/cache/wasm-builds" @@ -85,17 +93,15 @@ resource "google_cloud_run_v2_service" "default" { port = 8000 } initial_delay_seconds = 10 - period_seconds = 10 - timeout_seconds = 5 - success_threshold = 1 - failure_threshold = 3 + period_seconds = 10 + timeout_seconds = 5 + failure_threshold = 3 } } } traffic { - percent = 100 - latest_revision = true + percent = 100 } } @@ -106,5 +112,5 @@ resource "google_project_iam_member" "run_invoker" { } output "url" { - value = google_cloud_run_v2_service.default.status[0].url + value = google_cloud_run_v2_service.default.uri } From fb0d19a1a20d93d95ebe7eb056639ce9f4eb64c9 Mon Sep 17 00:00:00 2001 From: x1unix Date: Sat, 20 Jul 2024 22:47:42 -0400 Subject: [PATCH 3/4] fix: update readme --- docs/deployment/gcloud/README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/deployment/gcloud/README.md b/docs/deployment/gcloud/README.md index dff3db9d..c4dee639 100644 --- a/docs/deployment/gcloud/README.md +++ b/docs/deployment/gcloud/README.md @@ -2,7 +2,6 @@ ## Prerequisites -* [OpenTofu](https://opentofu.org) or Terraform -* [Google Cloud](https://cloud.google.com/) project - - +* [OpenTofu](https://opentofu.org) or Terraform. +* [gcloud](https://cloud.google.com/sdk/docs/install) tool. +* [Google Cloud](https://cloud.google.com/) project. From 8de2045414ba44711ec126b1e5e27d0401b9cc7e Mon Sep 17 00:00:00 2001 From: x1unix Date: Sun, 21 Jul 2024 00:15:37 -0400 Subject: [PATCH 4/4] fix: fix main.tf --- docs/deployment/gcloud/.gitignore | 2 ++ docs/deployment/gcloud/main.tf | 14 ++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/docs/deployment/gcloud/.gitignore b/docs/deployment/gcloud/.gitignore index a64e2a80..357e8026 100644 --- a/docs/deployment/gcloud/.gitignore +++ b/docs/deployment/gcloud/.gitignore @@ -1,5 +1,7 @@ # Temporary files .terraform +*.backup +*.tfstate # HCL vars except example *.tfvars diff --git a/docs/deployment/gcloud/main.tf b/docs/deployment/gcloud/main.tf index 6cce07be..0ca30406 100644 --- a/docs/deployment/gcloud/main.tf +++ b/docs/deployment/gcloud/main.tf @@ -102,13 +102,19 @@ resource "google_cloud_run_v2_service" "default" { traffic { percent = 100 + type = "TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST" } } -resource "google_project_iam_member" "run_invoker" { - project = var.project_id - role = "roles/run.invoker" - member = "allUsers" +# Make service public. +# See: https://cloud.google.com/run/docs/authenticating/public +resource "google_cloud_run_service_iam_binding" "run_invoker" { + location = google_cloud_run_v2_service.default.location + service = google_cloud_run_v2_service.default.name + role = "roles/run.invoker" + members = [ + "allUsers" + ] } output "url" {