Waiting for database connection...
+" + val + "
"); + }); + } + + var handleSubmission = function(e) { + e.preventDefault(); + var entryValue = entryContentElement.val() + if (entryValue.length > 0) { + entriesElement.append("...
"); + $.getJSON("rpush/guestbook/" + entryValue, appendGuestbookEntries); + } + return false; + } + + // colors = purple, blue, red, green, yellow + var colors = ["#549", "#18d", "#d31", "#2a4", "#db1"]; + var randomColor = colors[Math.floor(5 * Math.random())]; + (function setElementsColor(color) { + headerTitleElement.css("color", color); + entryContentElement.css("box-shadow", "inset 0 0 0 2px " + color); + submitElement.css("background-color", color); + })(randomColor); + + submitElement.click(handleSubmission); + formElement.submit(handleSubmission); + hostAddressElement.append(document.URL); + + // Poll every second. + (function fetchGuestbook() { + $.getJSON("lrange/guestbook").done(appendGuestbookEntries).always( + function() { + setTimeout(fetchGuestbook, 1000); + }); + })(); +}); diff --git a/kubernetes/guestbook-go/public/style.css b/kubernetes/guestbook-go/public/style.css new file mode 100644 index 0000000..fd1c393 --- /dev/null +++ b/kubernetes/guestbook-go/public/style.css @@ -0,0 +1,61 @@ +body, input { + color: #123; + font-family: "Gill Sans", sans-serif; +} + +div { + overflow: hidden; + padding: 1em 0; + position: relative; + text-align: center; +} + +h1, h2, p, input, a { + font-weight: 300; + margin: 0; +} + +h1 { + color: #BDB76B; + font-size: 3.5em; +} + +h2 { + color: #999; +} + +form { + margin: 0 auto; + max-width: 50em; + text-align: center; +} + +input { + border: 0; + border-radius: 1000px; + box-shadow: inset 0 0 0 2px #BDB76B; + display: inline; + font-size: 1.5em; + margin-bottom: 1em; + outline: none; + padding: .5em 5%; + width: 55%; +} + +form a { + background: #BDB76B; + border: 0; + border-radius: 1000px; + color: #FFF; + font-size: 1.25em; + font-weight: 400; + padding: .75em 2em; + text-decoration: none; + text-transform: uppercase; + white-space: normal; +} + +p { + font-size: 1.5em; + line-height: 1.5; +} diff --git a/kubernetes/guestbook-go/redis-master-controller.yaml b/kubernetes/guestbook-go/redis-master-controller.yaml new file mode 100644 index 0000000..338c76f --- /dev/null +++ b/kubernetes/guestbook-go/redis-master-controller.yaml @@ -0,0 +1,24 @@ +kind: ReplicationController +apiVersion: v1 +metadata: + name: redis-master + labels: + app: redis + role: master +spec: + replicas: 1 + selector: + app: redis + role: master + template: + metadata: + labels: + app: redis + role: master + spec: + containers: + - name: redis-master + image: redis + ports: + - name: redis-server + containerPort: 6379 diff --git a/kubernetes/guestbook-go/redis-master-service.yaml b/kubernetes/guestbook-go/redis-master-service.yaml new file mode 100644 index 0000000..c69456e --- /dev/null +++ b/kubernetes/guestbook-go/redis-master-service.yaml @@ -0,0 +1,14 @@ +kind: Service +apiVersion: v1 +metadata: + name: redis-master + labels: + app: redis + role: master +spec: + ports: + - port: 6379 + targetPort: redis-server + selector: + app: redis + role: master diff --git a/kubernetes/guestbook-go/redis-replica-controller.yaml b/kubernetes/guestbook-go/redis-replica-controller.yaml new file mode 100644 index 0000000..5e10e7d --- /dev/null +++ b/kubernetes/guestbook-go/redis-replica-controller.yaml @@ -0,0 +1,24 @@ +kind: ReplicationController +apiVersion: v1 +metadata: + name: redis-replica + labels: + app: redis + role: replica +spec: + replicas: 2 + selector: + app: redis + role: replica + template: + metadata: + labels: + app: redis + role: replica + spec: + containers: + - name: redis-replica + image: registry.k8s.io/redis-slave:v2 + ports: + - name: redis-server + containerPort: 6379 diff --git a/kubernetes/guestbook-go/redis-replica-service.yaml b/kubernetes/guestbook-go/redis-replica-service.yaml new file mode 100644 index 0000000..191db0b --- /dev/null +++ b/kubernetes/guestbook-go/redis-replica-service.yaml @@ -0,0 +1,14 @@ +kind: Service +apiVersion: v1 +metadata: + name: redis-replica + labels: + app: redis + role: replica +spec: + ports: + - port: 6379 + targetPort: redis-server + selector: + app: redis + role: replica diff --git a/terraform/README.md b/terraform/README.md new file mode 100644 index 0000000..ffca163 --- /dev/null +++ b/terraform/README.md @@ -0,0 +1,17 @@ +# Terraform +This folder holds all the Terraform scripts for provisioning the VMs. The config is inspired by [this blog](https://olav.ninja/talos-cluster-on-proxmox-with-terraform) + +## Deployment +1. Install dependencies +```bash +brew install terraform tfsec siderolabs/tap/talosctl + +pnpm i +``` +2. Provide env variables: + - `terraform login` + - Create `terraform.tfvars` according the `variables.tf` +3. Deploy +```bash +pnpm dep +``` diff --git a/terraform/package.json b/terraform/package.json index e208402..c91fa47 100644 --- a/terraform/package.json +++ b/terraform/package.json @@ -4,6 +4,6 @@ "format": "terraform fmt --recursive", "lint": "terraform validate && tfsec . --tfvars-file=terraform.tfvars", "plan": "terraform state pull terraform.tfstate && terraform plan", - "dep": "terraform state pull terraform.tfstate && terraform apply -auto-approve && terraform state push terraform.tfstate" + "dep": "terraform state pull terraform.tfstate && terraform apply -auto-approve && terraform state push terraform.tfstate && terraform output -raw kube_config > ~/.kube/config && terraform output -raw talos_config > ~/.talos/config" } } diff --git a/terraform/proxmox.tf b/terraform/proxmox.tf index 4845def..f94b970 100644 --- a/terraform/proxmox.tf +++ b/terraform/proxmox.tf @@ -1,15 +1,3 @@ -variable "proxmox_config" { - description = "Proxmox configuration" - type = object({ - name = string - endpoint = string - username = string - password = string - image_store_id = string - vm_store_id = string - }) -} - provider "proxmox" { endpoint = var.proxmox_config.endpoint username = var.proxmox_config.username diff --git a/terraform/qcow2_images.tf b/terraform/qcow2_images.tf deleted file mode 100644 index 7404eeb..0000000 --- a/terraform/qcow2_images.tf +++ /dev/null @@ -1,29 +0,0 @@ -# talos - with extensions `qemu-guest-agent` + `tailscale` + `glibc` -resource "proxmox_virtual_environment_download_file" "talos_qcow2" { - content_type = "iso" - datastore_id = var.proxmox_config.image_store_id - node_name = var.proxmox_config.name - file_name = "talos.qcow2.img" - url = "https://factory.talos.dev/image/9ee49bb5f44200889652309e9af03195a9ed7a13049dd310180aa00e5ed3a7c2/v1.9.0/nocloud-amd64.qcow2" - overwrite = false -} - -# debian -resource "proxmox_virtual_environment_download_file" "debian_qcow2" { - content_type = "iso" - datastore_id = var.proxmox_config.image_store_id - node_name = var.proxmox_config.name - file_name = "debian.qcow2.img" - url = "https://cdimage.debian.org/images/cloud/bookworm/20241201-1948/debian-12-nocloud-amd64-20241201-1948.qcow2" - overwrite = false -} - -# almalinux -resource "proxmox_virtual_environment_download_file" "almalinux_qcow2" { - content_type = "iso" - datastore_id = var.proxmox_config.image_store_id - node_name = var.proxmox_config.name - file_name = "almalinux.qcow2.img" - url = "https://repo.almalinux.org/almalinux/9/cloud/x86_64/images/AlmaLinux-9-GenericCloud-9.5-20241120.x86_64.qcow2" - overwrite = false -} diff --git a/terraform/talos.tf b/terraform/talos.tf index 54477dc..cff9c38 100644 --- a/terraform/talos.tf +++ b/terraform/talos.tf @@ -1,13 +1,3 @@ -variable "talos_cluster_config" { - description = "Talos cluster configuration" - type = object({ - name = string - gateway = string - control_plane_ip = string - worker_ip = string - }) -} - resource "talos_machine_secrets" "this" {} data "talos_client_configuration" "this" { diff --git a/terraform/talos_image.tf b/terraform/talos_image.tf new file mode 100644 index 0000000..456ab4f --- /dev/null +++ b/terraform/talos_image.tf @@ -0,0 +1,9 @@ +# talos - with extensions `qemu-guest-agent` + `glibc` +resource "proxmox_virtual_environment_download_file" "talos_qcow2" { + content_type = "iso" + datastore_id = var.proxmox_config.image_store_id + node_name = var.proxmox_config.name + file_name = "talos.qcow2.img" + url = "https://factory.talos.dev/image/a98370e8bc36e336e1de99db6bbc23b8a0ae03820a474d8a2e964cfeaece9922/v1.9.0/nocloud-amd64.qcow2" + overwrite = true +} diff --git a/terraform/talos_services.tf b/terraform/talos_services.tf index 73192cc..52985b4 100644 --- a/terraform/talos_services.tf +++ b/terraform/talos_services.tf @@ -1,17 +1,16 @@ -# data "talos_cluster_health" "this" { -# depends_on = [talos_machine_configuration_apply.control_plane_config_apply, talos_machine_configuration_apply.worker_config_apply] -# client_configuration = data.talos_client_configuration.this.client_configuration -# control_plane_nodes = [var.talos_cluster_config.control_plane_ip] -# worker_nodes = [var.talos_cluster_config.worker_ip] -# endpoints = data.talos_client_configuration.this.endpoints -# timeouts = { -# read = "30s" -# } -# } +data "talos_cluster_health" "this" { + depends_on = [talos_machine_configuration_apply.control_plane_config_apply, talos_machine_configuration_apply.worker_config_apply] + client_configuration = data.talos_client_configuration.this.client_configuration + control_plane_nodes = [var.talos_cluster_config.control_plane_ip] + worker_nodes = [var.talos_cluster_config.worker_ip] + endpoints = data.talos_client_configuration.this.endpoints + timeouts = { + read = "10m" + } +} resource "talos_cluster_kubeconfig" "talos_kubeconfig" { - # depends_on = [talos_machine_bootstrap.talos_bootstrap, data.talos_cluster_health.this] - depends_on = [talos_machine_bootstrap.talos_bootstrap] + depends_on = [talos_machine_bootstrap.talos_bootstrap, data.talos_cluster_health.this] client_configuration = talos_machine_secrets.this.client_configuration node = var.talos_cluster_config.control_plane_ip } diff --git a/terraform/talos_vms.tf b/terraform/talos_vms.tf index 174852e..ee153bc 100644 --- a/terraform/talos_vms.tf +++ b/terraform/talos_vms.tf @@ -5,10 +5,13 @@ resource "proxmox_virtual_environment_vm" "talos_control_plane_vm" { node_name = var.proxmox_config.name vm_id = 800 - on_boot = true + bios = "seabios" + machine = "q35" + on_boot = true + stop_on_destroy = true cpu { cores = 4 - type = "x86-64-v2-AES" + type = "host" } memory { dedicated = 4000 @@ -17,14 +20,13 @@ resource "proxmox_virtual_environment_vm" "talos_control_plane_vm" { agent { enabled = true } - stop_on_destroy = true network_device { bridge = "vmbr0" } disk { datastore_id = var.proxmox_config.vm_store_id file_id = proxmox_virtual_environment_download_file.talos_qcow2.id - file_format = "raw" + file_format = "qcow2" interface = "virtio0" size = 10 } @@ -53,26 +55,28 @@ resource "proxmox_virtual_environment_vm" "talos_worker_vm" { node_name = var.proxmox_config.name vm_id = 900 - on_boot = true + bios = "seabios" + machine = "q35" + on_boot = true + stop_on_destroy = true cpu { - cores = 12 - type = "x86-64-v2-AES" + cores = 16 + type = "host" } memory { - dedicated = 64000 - floating = 64000 # enable memory ballooning + dedicated = 32000 + floating = 32000 # enable memory ballooning } agent { enabled = true } - stop_on_destroy = true network_device { bridge = "vmbr0" } disk { datastore_id = var.proxmox_config.vm_store_id file_id = proxmox_virtual_environment_download_file.talos_qcow2.id - file_format = "raw" + file_format = "qcow2" interface = "virtio0" size = 10 } diff --git a/terraform/variables.tf b/terraform/variables.tf new file mode 100644 index 0000000..528ee82 --- /dev/null +++ b/terraform/variables.tf @@ -0,0 +1,21 @@ +variable "proxmox_config" { + description = "Proxmox configuration" + type = object({ + name = string + endpoint = string + username = string + password = string + image_store_id = string + vm_store_id = string + }) +} + +variable "talos_cluster_config" { + description = "Talos cluster configuration" + type = object({ + name = string + gateway = string + control_plane_ip = string + worker_ip = string + }) +}