Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions .github/workflows/bootstrap.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: bootstrap
on:
pull_request:
branches: [ main ]
push:
branches: [ main ]

jobs:
full-apply:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Verify Docker
run: |
docker version || (echo "Docker is required" && exit 1)

- name: Install k3d
run: |
curl -s https://github.com/ghraw/k3d-io/k3d/main/install.sh | bash
k3d version

- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: 1.6.6

- name: Apply k8s stack
working-directory: stacks/k8s
run: |
terraform init -input=false
terraform apply -auto-approve -input=false

- name: Apply system stack (Istio + Argo CD)
working-directory: stacks/system
run: |
terraform init -input=false
terraform apply -auto-approve -input=false

- name: Destroy system stack (PR only)
if: ${{ always() && github.event_name == 'pull_request' }}
working-directory: stacks/system
run: |
terraform init -input=false
terraform destroy -auto-approve -input=false

- name: Destroy k8s stack (PR only)
if: ${{ always() && github.event_name == 'pull_request' }}
working-directory: stacks/k8s
run: |
terraform init -input=false
terraform destroy -auto-approve -input=false
36 changes: 36 additions & 0 deletions stacks/k8s/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

53 changes: 41 additions & 12 deletions stacks/k8s/main.tf
Original file line number Diff line number Diff line change
@@ -1,25 +1,54 @@
locals {
kubeconfig_path = "${path.module}/.kube/${var.cluster_name}-kubeconfig.yaml"
kubeconfig_dir = "${path.module}/.kube"
kubeconfig_path = "${local.kubeconfig_dir}/${var.cluster_name}-kubeconfig.yaml"
}

resource "k3d_cluster" "this" {
name = var.cluster_name
servers = var.servers
agents = var.agents

k3s_version = var.k3s_version
k3s_extra_args = var.k3s_extra_args
image = "rancher/k3s:${var.k3s_version}"

expose_api = var.expose_api
api_port = var.api_port
dynamic "kube_api" {
for_each = var.expose_api ? [true] : []

ports = [
for p in var.ports : {
container_port = p.container_port
host_port = p.host_port
protocol = p.protocol
content {
host = "127.0.0.1"
host_ip = "127.0.0.1"
host_port = var.api_port
}
]
}

kubeconfig_path = local.kubeconfig_path
dynamic "k3s" {
for_each = length(var.k3s_extra_args) > 0 ? [true] : []

content {
dynamic "extra_args" {
for_each = var.k3s_extra_args

content {
arg = extra_args.value
}
}
}
}

dynamic "port" {
for_each = var.ports

content {
host = try(port.value.host, "")
host_port = port.value.host_port
container_port = port.value.container_port
protocol = upper(port.value.protocol)
}
}
}

resource "local_sensitive_file" "kubeconfig" {
filename = local.kubeconfig_path
content = one(k3d_cluster.this.credentials).raw
file_permission = "0600"
directory_permission = "0700"
}
4 changes: 2 additions & 2 deletions stacks/k8s/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ output "cluster_name" {
}

output "kubeconfig_path" {
value = k3d_cluster.this.kubeconfig_path
value = local.kubeconfig_path
description = "Local kubeconfig path"
}

Expand All @@ -19,6 +19,6 @@ output "agents" {
}

output "kube_api_endpoint" {
value = var.expose_api ? "https://127.0.0.1:${var.api_port}" : null
value = var.expose_api ? format("https://127.0.0.1:%d", var.api_port) : null
description = "Local Kubernetes API endpoint (if exposed)"
}
5 changes: 5 additions & 0 deletions stacks/k8s/versions.tf
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ terraform {
source = "agynio/k3d"
version = "~> 0.1.0"
}

local = {
source = "hashicorp/local"
version = "~> 2.5"
}
}
backend "local" {
path = "./state/terraform.tfstate"
Expand Down
42 changes: 42 additions & 0 deletions stacks/system/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

81 changes: 81 additions & 0 deletions stacks/system/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Helm repositories
locals {
istio_repository_url = "https://istio-release.storage.googleapis.com/charts"
argo_repository_url = "https://argoproj.github.io/argo-helm"
}

# Istio base (CRDs)
resource "helm_release" "istio_base" {
name = "istio-base"
repository = local.istio_repository_url
chart = "base"
version = var.istio_chart_version
namespace = kubernetes_namespace.istio_system.metadata[0].name
}

# Istio control plane
resource "helm_release" "istiod" {
name = "istiod"
repository = local.istio_repository_url
chart = "istiod"
version = var.istio_chart_version
namespace = kubernetes_namespace.istio_system.metadata[0].name

depends_on = [helm_release.istio_base]

values = [
yamlencode({
pilot = {
traceSampling = 1.0
}
})
]
}

# Istio gateway (minimal)
resource "helm_release" "istio_gateway" {
name = "istio-gateway"
repository = local.istio_repository_url
chart = "gateway"
version = var.istio_chart_version
namespace = kubernetes_namespace.istio_gateway.metadata[0].name

depends_on = [helm_release.istiod]

values = [
yamlencode({
name = "istio-ingressgateway",
service = {
type = "ClusterIP",
ports = [{
name = "http2",
port = 80,
targetPort = 8080
}, {
name = "https",
port = 443,
targetPort = 8443
}]
}
})
]
}

# Argo CD
resource "helm_release" "argo_cd" {
name = "argo-cd"
repository = local.argo_repository_url
chart = "argo-cd"
version = var.argocd_chart_version
namespace = kubernetes_namespace.argocd.metadata[0].name

values = [
yamlencode({
server = {
service = {
type = "ClusterIP"
}
}
})
]
}
11 changes: 11 additions & 0 deletions stacks/system/namespaces.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
resource "kubernetes_namespace" "istio_system" {
metadata { name = "istio-system" }
}

resource "kubernetes_namespace" "istio_gateway" {
metadata { name = "istio-gateway" }
}

resource "kubernetes_namespace" "argocd" {
metadata { name = "argocd" }
}
18 changes: 18 additions & 0 deletions stacks/system/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
output "installed_namespaces" {
value = [
kubernetes_namespace.istio_system.metadata[0].name,
kubernetes_namespace.istio_gateway.metadata[0].name,
kubernetes_namespace.argocd.metadata[0].name,
]
description = "Installed namespaces"
}

output "releases" {
value = [
helm_release.istio_base.name,
helm_release.istiod.name,
helm_release.istio_gateway.name,
helm_release.argo_cd.name,
]
description = "Installed Helm releases"
}
9 changes: 9 additions & 0 deletions stacks/system/providers.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
provider "kubernetes" {
config_path = var.kubeconfig_path
Comment thread
noa-lucent marked this conversation as resolved.
}

provider "helm" {
kubernetes {
config_path = var.kubeconfig_path
}
}
17 changes: 17 additions & 0 deletions stacks/system/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
variable "kubeconfig_path" {
type = string
description = "Path to kubeconfig for connecting to the cluster"
default = "../k8s/.kube/agyn-local-kubeconfig.yaml"
}

variable "istio_chart_version" {
type = string
description = "Istio chart version"
default = "1.21.0"
}

variable "argocd_chart_version" {
type = string
description = "Argo CD chart version"
default = "5.33.0"
}
16 changes: 16 additions & 0 deletions stacks/system/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
terraform {
required_version = ">= 1.5.0"
required_providers {
Comment thread
noa-lucent marked this conversation as resolved.
kubernetes = {
source = "hashicorp/kubernetes"
version = "~> 2.27"
}
helm = {
source = "hashicorp/helm"
version = "~> 2.13"
}
}
backend "local" {
path = "./state/terraform.tfstate"
}
}