Skip to content

Commit 146c6cb

Browse files
committed
initial commit
1 parent 46174fd commit 146c6cb

File tree

9 files changed

+616
-1
lines changed

9 files changed

+616
-1
lines changed

README.md

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,41 @@
1-
# ftp
1+
# Kubernetes Bootstrap
2+
3+
### Features
4+
5+
- Dynamic name for the product
6+
- Dynamic domain names for ingress and certificates
7+
- Automatic SSL Cert generation
8+
- NodePort LoadBalancer service for deployments
9+
- GCE Ingress tls setup
10+
- Frontend LB HTTP -> HTTPS redirect
11+
12+
### TODO
13+
14+
- Automatic dns record (set A record to new static IP)
15+
16+
### Notes
17+
18+
- You have to update your `ingress_hosts` A records in order to get traffic to your site. And to generate the SSL certificate.
19+
20+
### Usage
21+
22+
- set variables (`terraform.tfvars` for example)
23+
- terraform init
24+
- terraform apply
25+
26+
### Variables
27+
28+
```SHELL
29+
project_id = "project-id"
30+
project_region = "us-central1"
31+
credentials_file_path = "/path/to/sa/creds.json"
32+
sa_email = "terraform-admin@project-id.iam.gserviceaccount.com"
33+
cluster_issuer_private_key_secret_name = "cert-manager-private-key"
34+
ingress_hosts = {
35+
ftp_svc = "some-svc.example.com"
36+
}
37+
cluster_issuer_email = "your.email@gmail.com"
38+
cloudflare_email = "your.email@gmail.com"
39+
name_prefix_kebab = "some-svc"
40+
cloudflare_api_key = "XXX"
41+
```

apis.tf

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
resource "google_project_service" "serviceusage_api" {
2+
project = var.project_id
3+
service = "serviceusage.googleapis.com"
4+
5+
disable_on_destroy = false
6+
}
7+
8+
resource "google_project_service" "certificatemanager" {
9+
project = var.project_id
10+
service = "certificatemanager.googleapis.com"
11+
12+
disable_on_destroy = false
13+
14+
depends_on = [
15+
google_project_service.serviceusage_api
16+
]
17+
}
18+
19+
resource "google_project_service" "servicenetworking_api" {
20+
project = var.project_id
21+
service = "servicenetworking.googleapis.com"
22+
23+
disable_on_destroy = false
24+
25+
depends_on = [
26+
google_project_service.serviceusage_api
27+
]
28+
}

clusters.tf

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Cluster
2+
resource "google_container_cluster" "primary" {
3+
name = "${var.name_prefix_kebab}-gke-cluster"
4+
location = var.project_region
5+
node_locations = ["${var.project_region}-f"]
6+
7+
network = google_compute_network.example.id
8+
9+
10+
remove_default_node_pool = true
11+
initial_node_count = 1
12+
deletion_protection = false
13+
14+
depends_on = [google_project_iam_binding.cluster_admin]
15+
}
16+
17+
# Node Pool
18+
resource "google_container_node_pool" "primary_nodes" {
19+
name = "${var.name_prefix_kebab}-node-pool"
20+
location = google_container_cluster.primary.location
21+
cluster = google_container_cluster.primary.name
22+
node_count = 1
23+
node_locations = ["${var.project_region}-f"]
24+
25+
node_config {
26+
preemptible = false
27+
machine_type = "e2-standard-2"
28+
29+
tags = [var.firewall_allow_http, var.firewall_allow_https]
30+
31+
# Google recommends custom service accounts that have cloud-platform scope and permissions granted via IAM Roles.
32+
service_account = var.sa_email
33+
oauth_scopes = [
34+
"https://www.googleapis.com/auth/cloud-platform"
35+
]
36+
}
37+
38+
lifecycle {
39+
ignore_changes = [node_config]
40+
}
41+
42+
depends_on = [google_project_iam_binding.cluster_admin]
43+
}

deployments.tf

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
# hello world deployment
2+
resource "kubernetes_deployment_v1" "example" {
3+
metadata {
4+
name = "${var.name_prefix_kebab}-deployment"
5+
}
6+
7+
spec {
8+
selector {
9+
match_labels = {
10+
app = "${var.name_prefix_kebab}-deployment"
11+
}
12+
}
13+
14+
template {
15+
metadata {
16+
labels = {
17+
app = "${var.name_prefix_kebab}-deployment"
18+
}
19+
}
20+
21+
spec {
22+
container {
23+
image = "us-docker.pkg.dev/google-samples/containers/gke/hello-app:2.0"
24+
name = "${var.name_prefix_kebab}-container"
25+
26+
port {
27+
container_port = 8080
28+
name = "${var.name_prefix_kebab}-port"
29+
}
30+
31+
liveness_probe {
32+
http_get {
33+
path = "/"
34+
port = "${var.name_prefix_kebab}-port"
35+
}
36+
37+
initial_delay_seconds = 3
38+
period_seconds = 3
39+
}
40+
}
41+
}
42+
}
43+
}
44+
45+
timeouts {
46+
create = "3m"
47+
update = "3m"
48+
}
49+
50+
depends_on = [google_container_node_pool.primary_nodes]
51+
}
52+
53+
54+
# Service - NodePort to pod
55+
resource "kubernetes_service_v1" "example" {
56+
metadata {
57+
name = "${var.name_prefix_kebab}-loadbalancer"
58+
}
59+
60+
spec {
61+
selector = {
62+
app = kubernetes_deployment_v1.example.spec[0].selector[0].match_labels.app
63+
}
64+
65+
# load_balancer_ip = google_compute_address.ftp_svc.address
66+
67+
port {
68+
port = 8443
69+
target_port = kubernetes_deployment_v1.example.spec[0].template[0].spec[0].container[0].port[0].name
70+
protocol = "TCP"
71+
}
72+
73+
type = "NodePort"
74+
}
75+
76+
timeouts {
77+
create = "3m"
78+
}
79+
80+
depends_on = [google_compute_global_address.ingress, module.cert_manager]
81+
}
82+
83+
# GCE ingress with SSL
84+
# Configure your routes here
85+
resource "kubernetes_ingress_v1" "example" {
86+
wait_for_load_balancer = true
87+
metadata {
88+
name = "${var.name_prefix_kebab}-ingress"
89+
90+
91+
annotations = {
92+
"kubernetes.io/ingress.class" = "gce"
93+
"kubernetes.io/ingress.global-static-ip-name" = google_compute_global_address.ingress.name
94+
"cert-manager.io/cluster-issuer" = module.cert_manager.cluster_issuer_name
95+
"networking.gke.io/v1beta1.FrontendConfig" = kubectl_manifest.app_frontend_config.name
96+
}
97+
}
98+
99+
spec {
100+
ingress_class_name = "gce"
101+
tls {
102+
# hosts = [var.ingress_hosts.ftp_svc]
103+
hosts = values(var.ingress_hosts)
104+
secret_name = var.cluster_issuer_private_key_secret_name
105+
}
106+
107+
default_backend {
108+
service {
109+
name = kubernetes_service_v1.example.metadata.0.name
110+
port {
111+
number = kubernetes_service_v1.example.spec[0].port[0].port
112+
}
113+
}
114+
115+
}
116+
117+
rule {
118+
host = var.ingress_hosts.ftp_svc
119+
http {
120+
path {
121+
path = "/*"
122+
backend {
123+
service {
124+
name = kubernetes_service_v1.example.metadata.0.name
125+
port {
126+
number = kubernetes_service_v1.example.spec[0].port[0].port
127+
}
128+
}
129+
}
130+
}
131+
}
132+
}
133+
}
134+
135+
depends_on = [kubernetes_service_v1.example, module.cert_manager]
136+
137+
timeouts {
138+
create = "2m"
139+
}
140+
}
141+
142+
# namespcae for cert manager
143+
resource "kubernetes_namespace_v1" "cert_manager_namespace" {
144+
metadata {
145+
name = "cert-manager"
146+
}
147+
148+
depends_on = [google_container_node_pool.primary_nodes]
149+
}
150+
151+
# cert-manager dns01 secret
152+
resource "kubernetes_secret_v1" "cloudflare_api_token" {
153+
metadata {
154+
name = "cloudflare-token"
155+
namespace = "cert-manager"
156+
}
157+
158+
data = {
159+
api_key = var.cloudflare_api_key
160+
}
161+
162+
depends_on = [kubernetes_namespace_v1.cert_manager_namespace]
163+
}
164+
165+
# cert manager module
166+
# you may need to edit this for your particular needs http01 / dns01 / ...
167+
module "cert_manager" {
168+
source = "terraform-iaac/cert-manager/kubernetes"
169+
170+
cluster_issuer_email = var.cluster_issuer_email
171+
cluster_issuer_private_key_secret_name = var.cluster_issuer_private_key_secret_name
172+
namespace_name = "cert-manager"
173+
create_namespace = "false"
174+
175+
solvers = [
176+
{
177+
dns01 = {
178+
cloudflare = {
179+
email = var.cloudflare_email
180+
apiKeySecretRef = {
181+
name = "cloudflare-token"
182+
key = "api_key"
183+
}
184+
},
185+
},
186+
selector = {
187+
dnsZones = [
188+
var.ingress_hosts.ftp_svc
189+
]
190+
}
191+
},
192+
{
193+
http01 = {
194+
ingress = {
195+
class = "nginx"
196+
}
197+
}
198+
}
199+
]
200+
201+
certificates = {
202+
# "${replace(var.ingress_hosts.ftp_svc, ".", "_")}" = {
203+
"${var.ingress_hosts.ftp_svc}" = {
204+
dns_names = [var.ingress_hosts.ftp_svc]
205+
}
206+
}
207+
208+
depends_on = [google_container_node_pool.primary_nodes, kubernetes_secret_v1.cloudflare_api_token]
209+
}

iam.tf

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# add roles to the terraform admin service account
2+
3+
resource "google_project_iam_binding" "cluster_admin" {
4+
project = var.project_id
5+
role = "roles/container.clusterAdmin"
6+
7+
members = [
8+
"serviceAccount:terraform-admin@chmoder.iam.gserviceaccount.com",
9+
]
10+
}
11+
12+
resource "google_project_iam_binding" "container-admin" {
13+
project = var.project_id
14+
role = "roles/container.admin"
15+
16+
members = [
17+
"serviceAccount:terraform-admin@chmoder.iam.gserviceaccount.com",
18+
]
19+
}
20+
21+
# could also use k8 RBAC
22+
resource "google_project_iam_binding" "sa" {
23+
project = var.project_id
24+
role = "roles/iam.serviceAccountUser"
25+
26+
members = [
27+
"serviceAccount:terraform-admin@chmoder.iam.gserviceaccount.com",
28+
]
29+
}

0 commit comments

Comments
 (0)