Add IaC and docs

This commit is contained in:
YYx00xZZ 2025-04-09 14:01:07 +03:00
parent 007d03937b
commit 87b05f2777
13 changed files with 429 additions and 0 deletions

View file

@ -46,6 +46,45 @@ I've provided the same tests reworked to be compatible with Geth.
When running the docker container with Geth, I do not use bind mount and I am making sure that the geth_data dir from previous steps is cleaned so I can be sure that I am working with the contract previously deployed in the container.
### Infrastructure
All Infrastructure as a Code is stored inside `infrastructure` dir. I went with GCP because of the free trial (AWS was exhausted).
Currently, the IaC is ment to be used locally. Later, a pipeline should be create and the state must be stored remotely and securely.
The `secrets` directory is holding all infrastrucutre related sensitive data. It is excluded from source control.
To authenicate the provider, place your service account key JSON file in the `secrets` dir and name it `svc_acc_key.json`.
This is not a requirement and you can change this as you like, but this is the fastest and easiest way to get up and running.
Please name your service account `terraformer` when creating it in the GCP WEB UI for ease of use.
#### Modules
**gcp-apis**
This module is responsible for enabling all APIs that will be needed for the project.
Required inputs:
- `project_id`
!NB There is known issues with enabling APIs through Terraform. Sometimes the backend does not return a response quickly enough which results in the API being enabled really but terraform apply fails. Rerun the pipeline/command.
There are workaround but for the sake of this demo please use the solution described above.
**gcp-networking**
Holds code responsible for setting up all networking resource needed for a k8s cluster to operate - router and a NAT gateway.
Required inputs:
- `project_id`
**gcp-gke-cluster**
The quota for the free trial is being an issue for the demo. I can't raise the quota limit and I am using the min. disk size (10GB).
To overcome this limitation I had to use zonal cluster with only 2 nodes.
Required inputs:
- `project_id`
---
## Go Ethereum
Golang execution layer implementation of the Ethereum protocol.

View file

@ -0,0 +1,41 @@
# This file is maintained automatically by "terraform init".
# Manual edits may be lost in future updates.
provider "registry.terraform.io/hashicorp/google" {
version = "6.29.0"
constraints = "6.29.0"
hashes = [
"h1:U0Ca/+zZMMuea+r80qu9SRzWu8Waxny5aWGZXn+kVhc=",
"zh:01a501df2fb9ecbf0935b27e588bc7b6bcaf4ab0043747f4229c25e4ba47dadb",
"zh:056f8ab2b73755cf5a67228ab4a07882e76265fa25b07f2794d9939288164f48",
"zh:0dbdfa564f7db8a2e6f7e76437a9850b6101450120c08e87cf9846330736c0c6",
"zh:3c3e4ee801de22812bd07cb3d36b227f8057d7825998fb4d97051764a565b89b",
"zh:4e440eb4c60da9cd7d23b3b99be54c869472fd70006c39639a04b9a51248929c",
"zh:659490efd20b3e98e4166b2925baa18549d82e4c16751bc92baed0185d22d108",
"zh:9ae24b98a3a3346b8004c6b87e3b59decba2f64c7407e106263859c275105ef8",
"zh:c64cff9c17e302236bb9e0a6d5eff4c92540ce3947269f3db94e2b9a1b1a3f4e",
"zh:d2fd0aecbbbba463bcb0640f54c8df5e7a63918bdd44236dcd36dff33bb8de09",
"zh:f022316369ea676f5f9d11768b4c621abd3304c1e6d1f0c2361e4e2620c4b65d",
"zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
"zh:feb7d4fdbebdfabac2aaa73376f754736ccf089fa90adf6388701f89801188e6",
]
}
provider "registry.terraform.io/hashicorp/random" {
version = "3.7.1"
hashes = [
"h1:t152MY0tQH4a8fLzTtEWx70ITd3azVOrFDn/pQblbto=",
"zh:3193b89b43bf5805493e290374cdda5132578de6535f8009547c8b5d7a351585",
"zh:3218320de4be943e5812ed3de995946056db86eb8d03aa3f074e0c7316599bef",
"zh:419861805a37fa443e7d63b69fb3279926ccf98a79d256c422d5d82f0f387d1d",
"zh:4df9bd9d839b8fc11a3b8098a604b9b46e2235eb65ef15f4432bde0e175f9ca6",
"zh:5814be3f9c9cc39d2955d6f083bae793050d75c572e70ca11ccceb5517ced6b1",
"zh:63c6548a06de1231c8ee5570e42ca09c4b3db336578ded39b938f2156f06dd2e",
"zh:697e434c6bdee0502cc3deb098263b8dcd63948e8a96d61722811628dce2eba1",
"zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
"zh:a0b8e44927e6327852bbfdc9d408d802569367f1e22a95bcdd7181b1c3b07601",
"zh:b7d3af018683ef22794eea9c218bc72d7c35a2b3ede9233b69653b3c782ee436",
"zh:d63b911d618a6fe446c65bfc21e793a7663e934b2fef833d42d3ccd38dd8d68d",
"zh:fa985cd0b11e6d651f47cff3055f0a9fd085ec190b6dbe99bf5448174434cdea",
]
}

32
infrastructure/main.tf Normal file
View file

@ -0,0 +1,32 @@
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = "6.29.0"
}
}
required_version = ">= 1.5.0"
}
provider "google" {
credentials = file("./secrets/svc_acc_key.json")
project = var.project_id
}
module "gcp_apis" {
source = "./modules/gcp-apis"
project_id = var.project_id
}
module "gcp_networking" {
source = "./modules/gcp-networking"
project_id = var.project_id
depends_on = [ module.gcp_apis ]
}
module "gcp_gke_cluster" {
source = "./modules/gcp-gke-cluster"
project_id = var.project_id
depends_on = [ module.gcp_networking ]
}

View file

@ -0,0 +1,7 @@
# API's to enable
resource "google_project_service" "api_services" {
project = var.project_id
for_each = toset(var.api_service)
service = each.key
disable_dependent_services = true
}

View file

@ -0,0 +1,41 @@
variable "project_id" {
description = "The GCP project ID"
type = string
}
variable "api_service" {
description = "List of strings. Contain API services to be enabled."
type = list(string)
default = [
"cloudresourcemanager.googleapis.com",
"servicenetworking.googleapis.com",
"cloudbilling.googleapis.com",
"autoscaling.googleapis.com",
"bigquery.googleapis.com",
"bigquerymigration.googleapis.com",
"bigquerystorage.googleapis.com",
"cloudapis.googleapis.com",
"cloudtrace.googleapis.com",
"compute.googleapis.com",
"container.googleapis.com",
"containerfilesystem.googleapis.com",
"containerregistry.googleapis.com",
"datastore.googleapis.com",
"iam.googleapis.com",
"iamcredentials.googleapis.com",
"logging.googleapis.com",
"monitoring.googleapis.com",
"networkmanagement.googleapis.com",
"osconfig.googleapis.com",
"oslogin.googleapis.com",
"pubsub.googleapis.com",
"secretmanager.googleapis.com",
"servicemanagement.googleapis.com",
"serviceusage.googleapis.com",
"storage-api.googleapis.com",
"storage-component.googleapis.com",
"storage.googleapis.com",
"workloadmanager.googleapis.com",
"networkconnectivity.googleapis.com"
]
}

View file

@ -0,0 +1,160 @@
locals {
# Defining a service account to grant necessary GKE cluster permisisons
service_account_email = "terraformer@${var.project_id}.iam.gserviceaccount.com"
}
resource "random_string" "random_node_pool_suffix" {
lower = true
length = 5
special = false
upper = false
keepers = {
node_pool_machine_type = var.node_pool_machine_type
node_pool_disk_size_gb = var.node_pool_disk_size_gb
}
}
resource "google_container_cluster" "app_cluster" {
project = var.project_id
name = var.cluster_name
location = var.cluster_location
# node_locations = slice(data.google_compute_zones.region_zones.names, 0, 3)
remove_default_node_pool = true
initial_node_count = 1
deletion_protection = false # Change this to true when going to production :)
# Automation section from the UI
maintenance_policy {
recurring_window {
end_time = "2023-10-02T15:00:00Z"
recurrence = "FREQ=WEEKLY;BYDAY=WE,TH"
start_time = "2023-10-02T07:00:00Z"
}
}
notification_config {
pubsub {
enabled = false
}
}
vertical_pod_autoscaling {
enabled = false
}
cluster_autoscaling {
enabled = false
# autoscaling_profile = "BALANCED" # Defaults to BALANCED
}
# Networking
private_cluster_config {
enable_private_nodes = true
enable_private_endpoint = false
master_ipv4_cidr_block = "172.16.0.0/28"
}
network = "projects/${var.project_id}/global/networks/default" # "default"
subnetwork = "default" # "default"
networking_mode = "VPC_NATIVE"
ip_allocation_policy {
cluster_ipv4_cidr_block = "10.16.0.0/14" # The IP address range for the cluster pod IPs
services_ipv4_cidr_block = "10.20.0.0/20" # The IP address range of the services IPs in this cluster
}
default_max_pods_per_node = 110
enable_intranode_visibility = false
addons_config {
dns_cache_config {
enabled = true
}
http_load_balancing {
disabled = false
}
gce_persistent_disk_csi_driver_config {
enabled = true
}
}
# SECURITY TAB FROM THE UI
binary_authorization {
evaluation_mode = "DISABLED"
}
enable_shielded_nodes = true
confidential_nodes {
enabled = false
}
logging_config {
enable_components = ["SYSTEM_COMPONENTS", "WORKLOADS"]
}
monitoring_config {
enable_components = ["SYSTEM_COMPONENTS"]
}
release_channel {
channel = "STABLE"
}
lifecycle {
ignore_changes = [
maintenance_policy
]
}
}
resource "google_container_node_pool" "node_pool" {
name = "pool-${random_string.random_node_pool_suffix.result}"
cluster = google_container_cluster.app_cluster.id
node_count = var.node_pool_node_count
location = var.cluster_location
management {
auto_repair = true
auto_upgrade = true
}
upgrade_settings {
max_surge = 1
max_unavailable = 0
}
node_config {
machine_type = var.node_pool_machine_type
disk_size_gb = var.node_pool_disk_size_gb
disk_type = var.node_pool_disk_type
service_account = local.service_account_email
oauth_scopes = [
# The set of Google API scopes to be made available on all of the node VMs under the "default" service account.
# Use the "https://www.googleapis.com/auth/cloud-platform" scope to grant access to all APIs.
# It is recommended that you set service_account to a non-default service account and grant IAM roles to that service account for only the resources that it needs.
"https://www.googleapis.com/auth/servicecontrol",
"https://www.googleapis.com/auth/service.management.readonly",
"https://www.googleapis.com/auth/logging.write",
"https://www.googleapis.com/auth/monitoring",
"https://www.googleapis.com/auth/devstorage.read_only",
"https://www.googleapis.com/auth/trace.append"
# "https://www.googleapis.com/auth/cloud-platform"
]
metadata = {
"disable-legacy-endpoints" = "true"
}
# kubelet_config - enabled or disabled
# Render this block only if variable app_cluster_kubelet_config is true
dynamic "kubelet_config" {
for_each = var.cluster_kubelet_config == true ? [1] : []
content {
cpu_cfs_quota = false
insecure_kubelet_readonly_port_enabled = "FALSE"
pod_pids_limit = 0
}
}
}
lifecycle {
create_before_destroy = true
}
}

View file

@ -0,0 +1,4 @@
output "random_node_pool_suffix_output" {
description = "The random generated suffix for app cluster's node pool"
value = random_string.random_node_pool_suffix.result
}

View file

@ -0,0 +1,46 @@
variable "project_id" {
description = "The GCP project ID"
type = string
}
variable "node_pool_node_count" {
description = "If it is regional cluster it is nodes per zone. Otherwise number of total nodes"
type = number
default = 2
}
variable "node_pool_machine_type" {
description = "The machine type used for pool-* nodes."
type = string
default = "e2-small"
}
variable "node_pool_disk_size_gb" {
description = "The size of the nodes' disk in GB. Minimum 10G"
type = number
default = 10
}
variable "node_pool_disk_type" {
description = "The disk type used for nodes."
type = string
default = "pd-standard"
}
variable "cluster_kubelet_config" {
description = "Enable or disable cluster node pool kubelet_config"
type = bool
default = false
}
variable "cluster_name" {
description = "The name of the cluster"
type = string
default = "test-cluster"
}
variable "cluster_location" {
description = "the locaion of the cluster; region"
type = string
default = "europe-west1-b" # "europe-west1"
}

View file

@ -0,0 +1,37 @@
data "google_compute_network" "default" {
project = var.project_id
name = "default"
}
# =============================================================================
# === NAT Gateway
# Router
resource "google_compute_router" "default_nat_router" {
name = "router"
network = "default"
region = var.region
}
# NAT addresses
resource "google_compute_address" "nat_1" {
name = "nat-1-address"
address_type = "EXTERNAL"
region = var.region
network_tier = "PREMIUM"
}
# Gateway
resource "google_compute_router_nat" "nat_gateway" {
name = "nat-1"
router = google_compute_router.default_nat_router.name
region = var.region
source_subnetwork_ip_ranges_to_nat = "ALL_SUBNETWORKS_ALL_IP_RANGES"
nat_ip_allocate_option = "MANUAL_ONLY"
nat_ips = google_compute_address.nat_1.*.self_link
enable_dynamic_port_allocation = true
min_ports_per_vm = 1024
max_ports_per_vm = 4096
enable_endpoint_independent_mapping = false
}

View file

@ -0,0 +1,10 @@
variable "project_id" {
description = "The GCP project ID"
type = string
}
variable "region" {
description = "The VPC region"
type = string
default = "europe-west1"
}

View file

@ -0,0 +1,12 @@
variable "project_id" {
description = "The GCP project ID"
type = string
default = "lime-demo-aap"
}
variable "gke_cluster_location" {
description = "the locaion of the cluster; region"
type = string
default = "europe-west1"
}