From 108fb4aaca8e8c084aa83dbd60639536bd3c5dfe Mon Sep 17 00:00:00 2001 From: Mathieu Tortuyaux Date: Thu, 21 Mar 2024 10:36:29 +0100 Subject: [PATCH] scaleway: initial commit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mathieu Tortuyaux Co-authored-by: Kai Lüke --- scaleway/README.md | 63 ++++++++++++++++++++++ scaleway/compute.tf | 53 +++++++++++++++++++ scaleway/core-user.yaml.tmpl | 7 +++ scaleway/outputs.tf | 20 +++++++ scaleway/provider.tf | 28 ++++++++++ scaleway/server-configs/server1.yaml | 25 +++++++++ scaleway/variables.tf | 78 ++++++++++++++++++++++++++++ 7 files changed, 274 insertions(+) create mode 100644 scaleway/README.md create mode 100644 scaleway/compute.tf create mode 100644 scaleway/core-user.yaml.tmpl create mode 100644 scaleway/outputs.tf create mode 100644 scaleway/provider.tf create mode 100644 scaleway/server-configs/server1.yaml create mode 100644 scaleway/variables.tf diff --git a/scaleway/README.md b/scaleway/README.md new file mode 100644 index 0000000..4da3184 --- /dev/null +++ b/scaleway/README.md @@ -0,0 +1,63 @@ +# Flatcar Provisioning Automation for Scaleway + +This repository provides tools to automate Flatcar provisioning on [ScaleWay][scaleway] using [Terraform][terraform]. + +## Features + +- Minimal configuration required (demo deployment works with default settings w/o any customisation, just run `terraform apply`!). +- Deploy one or multiple servers. +- Per-server custom configuration via separate [Butane][butane] configuration. + +## Prerequisites + +1. Scaleway credentials: `access_key`, `secret_key`, `project_id`, `organization_id`, `region` and `zone`. + +## HowTo + +This will create a server in 'fr-par-1' using a small instance size. +See "Customisation" below for advanced settings. + +1. Clone the repo. +2. Add credentials in a `terraform.tfvars` file, expected credentials name can be found in `provider.tf` +3. Run + ```shell + terraform init + ``` +4. Edit [`server1.yaml`][server-1] and provide your own custom provisioning configuration in [Butane][butane] syntax. +5. Plan and apply. + Invoke Terraform: + ```shell + terraform plan + terraform apply + ``` + +Terraform will print server information (name, ipv4 and v6) after deployment concluded. + +_NOTE_: +* Server IP address can be found at any moment after deployment by running `terraform output` +* If you update server configuration(s) in `server-configs` and re-run `terraform apply`, the instance will be **replaced**. +Consider adding [`create_before_destroy`](https://www.terraform.io/docs/configuration/meta-arguments/lifecycle.html#syntax-and-arguments) to the `scaleway_instance_server` resource in [`compute.tf`](compute.tf) to avoid services becoming unavailable during reprovisioning. + +### Customisation + +The provisioning automation can be customised via settings in [`terraform.tfvars`][terraform.tfvars]: + - `cluster_name`: Descriptive name of your cluster, will be used to generate server names. + `flatcar-terraform` by default. + - `machines`: Add more machines to your deployment. + Each machine name must be unique and requires a respective `[NAME].yaml` server configuration in [`server-configs`](server-configs). + An example / default configuration for machine `server1` is provided with [`server1.yaml`](server-configs/server1.yaml). + During provisioning, server names are generated by concatenating the cluster name and the machine name - the defaults above will create a single server named `flatcar-terraform-server1`. + - `ssh_keys`: Additional SSH public keys to add to core user's `authorized_keys`. + Note that during provisioning, a provisioning RSA key pair will be generated and stored in the local directory `.ssh/provisioning_private_key.pem` and `.ssh/provisioning_key.pub`, respectively. + The private key can be used for ssh connections (`core` user) to all provisioned servers. + - `release_channel`: Select one of "lts", "stable", "beta", or "alpha". + Read more about channels [here](https://www.flatcar.org/releases). + - `flatcar_version`: Select the desired Flatcar version for the given channel (default to "current", which is the latest). + - `type`: The spec of the machine, it default to DEV1-S. + - `flatcar_file`: The local Flatcar Scaleway image to upload as a snapshot. + +[butane]: https://www.flatcar.org/docs/latest/provisioning/config-transpiler/configuration/ +[server-1]: server-configs/server1.yaml +[scaleway]: https://www.scaleway.com/ +[terraform]: https://www.terraform.io/ +[terraform-tfvars]: terraform.tfvars diff --git a/scaleway/compute.tf b/scaleway/compute.tf new file mode 100644 index 0000000..d5cc922 --- /dev/null +++ b/scaleway/compute.tf @@ -0,0 +1,53 @@ +resource "scaleway_object_bucket" "bucket" { + name = "snapshot-flatcar-import" +} + +resource "scaleway_object" "qcow" { + bucket = scaleway_object_bucket.bucket.name + key = "flatcar_production_scaleway_image.qcow2" + file = var.flatcar_file +} + +resource "scaleway_instance_snapshot" "snapshot" { + type = "unified" + import { + bucket = scaleway_object.qcow.bucket + key = scaleway_object.qcow.key + } +} + +resource "scaleway_instance_volume" "from_snapshot" { + from_snapshot_id = scaleway_instance_snapshot.snapshot.id + type = "b_ssd" +} + +resource "scaleway_instance_server" "instance" { + for_each = toset(var.machines) + type = var.type + user_data = { + "cloud-init" = data.ct_config.machine-ignitions[each.key].rendered + } + root_volume { + volume_id = scaleway_instance_volume.from_snapshot.id + } + + ip_id = scaleway_instance_ip.public_ip.id +} + +data "ct_config" "machine-ignitions" { + for_each = toset(var.machines) + strict = true + content = file("${path.module}/server-configs/${each.key}.yaml") + snippets = [ + data.template_file.core_user.rendered + ] +} + +data "template_file" "core_user" { + template = file("${path.module}/core-user.yaml.tmpl") + vars = { + ssh_keys = jsonencode(var.ssh_keys) + } +} + +resource "scaleway_instance_ip" "public_ip" {} diff --git a/scaleway/core-user.yaml.tmpl b/scaleway/core-user.yaml.tmpl new file mode 100644 index 0000000..b21c5ef --- /dev/null +++ b/scaleway/core-user.yaml.tmpl @@ -0,0 +1,7 @@ +variant: flatcar +version: 1.0.0 + +passwd: + users: + - name: core + ssh_authorized_keys: ${ssh_keys} diff --git a/scaleway/outputs.tf b/scaleway/outputs.tf new file mode 100644 index 0000000..89c46b0 --- /dev/null +++ b/scaleway/outputs.tf @@ -0,0 +1,20 @@ +output "ipv4" { + value = { + for key in var.machines : + "${var.cluster_name}-${key}" => scaleway_instance_server.instance[key].public_ip + } +} + +output "ipv6" { + value = { + for key in var.machines : + "${var.cluster_name}-${key}" => scaleway_instance_server.instance[key].ipv6_address + } +} + +output "name" { + value = { + for key in var.machines : + "${var.cluster_name}-${key}" => scaleway_instance_server.instance[key].name + } +} diff --git a/scaleway/provider.tf b/scaleway/provider.tf new file mode 100644 index 0000000..afc04d3 --- /dev/null +++ b/scaleway/provider.tf @@ -0,0 +1,28 @@ +terraform { + required_version = ">= 0.14.0" + required_providers { + scaleway = { + source = "scaleway/scaleway" + version = "2.38.2" + } + ct = { + source = "poseidon/ct" + version = "0.11.0" + } + template = { + source = "hashicorp/template" + version = "~> 2.2.0" + } + } +} + +# Configure the ScaleWay Provider +provider "scaleway" { + access_key = var.access_key + secret_key = var.secret_key + project_id = var.project_id + organization_id = var.organization_id + region = var.region + zone = var.zone +} + diff --git a/scaleway/server-configs/server1.yaml b/scaleway/server-configs/server1.yaml new file mode 100644 index 0000000..c3cce4a --- /dev/null +++ b/scaleway/server-configs/server1.yaml @@ -0,0 +1,25 @@ +variant: flatcar +version: 1.0.0 + +# This is a simple NGINX example. +# Replace the below with your own config. +# Refer to https://www.flatcar.org/docs/latest/provisioning/config-transpiler/configuration/ for more information. + +systemd: + units: + - name: nginx.service + enabled: true + contents: | + [Unit] + Description=NGINX example + After=docker.service + Requires=docker.service + [Service] + TimeoutStartSec=0 + ExecStartPre=-/usr/bin/docker rm --force nginx1 + ExecStart=/usr/bin/docker run --name nginx1 --pull always --net host docker.io/nginx:1 + ExecStop=/usr/bin/docker stop nginx1 + Restart=always + RestartSec=5s + [Install] + WantedBy=multi-user.target diff --git a/scaleway/variables.tf b/scaleway/variables.tf new file mode 100644 index 0000000..c9ea6fb --- /dev/null +++ b/scaleway/variables.tf @@ -0,0 +1,78 @@ +variable "machines" { + type = list(string) + description = "Machine names, corresponding to machine-NAME.yaml.tmpl files" + default = ["server1"] +} + +variable "cluster_name" { + type = string + description = "Cluster name used as prefix for the machine names" + default = "terraform-flatcar" +} + +variable "ssh_keys" { + type = list(string) + default = [] + description = "Additional SSH public keys for user 'core'." +} + +variable "release_channel" { + type = string + description = "Release channel" + default = "stable" + + validation { + condition = contains(["lts", "stable", "beta", "alpha"], var.release_channel) + error_message = "release_channel must be lts, stable, beta, or alpha." + } +} + +variable "flatcar_version" { + type = string + description = "The Flatcar version associated to the release channel" + default = "current" +} + +variable "region" { + type = string + description = "Scaleway region" + default = "fr-par" +} + +variable "organization_id" { + type = string + description = "Scaleway organization ID" +} + +variable "project_id" { + type = string + description = "Scaleway project ID" +} + +variable "access_key" { + type = string + description = "Scaleway access key" +} + +variable "secret_key" { + type = string + description = "Scaleway secret key" +} + +variable "zone" { + type = string + description = "Scaleway zone" + default = "fr-par-1" +} + +variable "type" { + type = string + description = "Scaleway instance type" + default = "DEV1-S" +} + +variable "flatcar_file" { + type = string + description = "Path to the Flatcar file" + default = "./flatcar_production_scaleway_image.img" +}