From 2b9bd06264ddb2b086217011ff56957a79be546e Mon Sep 17 00:00:00 2001 From: "kai [they]" Date: Sun, 19 Nov 2023 23:10:02 -0500 Subject: [PATCH] Adds DNS (#8) http://gke-test-2.coilysiren.me/api/healthcheck image --- .../application/.terraform.lock.hcl | 62 +++++++++++++++++++ infrastructure/application/main.tf | 27 ++++++++ infrastructure/application/state.tf | 37 +++++++++++ .../{ => foundation}/.terraform.lock.hcl | 0 infrastructure/{ => foundation}/main.tf | 15 +++-- infrastructure/{ => foundation}/state.tf | 4 +- infrastructure/kubeconfig.yml | 46 ++++++++++++++ tasks.py | 31 ++++++++-- 8 files changed, 209 insertions(+), 13 deletions(-) create mode 100644 infrastructure/application/.terraform.lock.hcl create mode 100644 infrastructure/application/main.tf create mode 100644 infrastructure/application/state.tf rename infrastructure/{ => foundation}/.terraform.lock.hcl (100%) rename infrastructure/{ => foundation}/main.tf (94%) rename infrastructure/{ => foundation}/state.tf (87%) create mode 100644 infrastructure/kubeconfig.yml diff --git a/infrastructure/application/.terraform.lock.hcl b/infrastructure/application/.terraform.lock.hcl new file mode 100644 index 0000000..731ba47 --- /dev/null +++ b/infrastructure/application/.terraform.lock.hcl @@ -0,0 +1,62 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/aws" { + version = "5.26.0" + hashes = [ + "h1:N6Iu1W6tvozB4RsClM9aHPuZhrKD6GCUAjlnl8THcLs=", + "zh:11a4062491e574c8e96b6bc7ced67b5e9338ccfa068223fc9042f9e1e7eda47a", + "zh:4331f85aeb22223ab656d04b48337a033f44f02f685c8def604c4f8f4687d10f", + "zh:915d6c996390736709f7ac7582cd41418463cfc07696218af6fea4a282df744a", + "zh:9306c306dbb2e1597037c54d20b1bd5f22a9cdcdb2b2b7bad657c8230bea2298", + "zh:93371860b9df369243219606711bfd3cfbd263db67838c06d5d5848cf47b6ede", + "zh:98338c17764a7b9322ddb6efd3af84e6890a4a0687f846eefdfb0fa03cec892d", + "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", + "zh:a28c9d77a5be25bac42d99418365757e4eb65a2c7c6788828263772cf2774869", + "zh:bd9c4648a090622d6b8c3c91dad513eec81e54db3dfe940ab6d155e5f37735e5", + "zh:bde63db136cccdeb282489e2ec2b3f9a7566edc9df27911a296352ab00832261", + "zh:ccd33f9490ce3f2d89efab995abf3b30e75579585f6a8a5b1f756246903d3518", + "zh:d73d1c461eb9d22833251f6533fc214cf014bc1d3165c5bfaa8ca29cd295ffb2", + "zh:db4ffb7eec5d0e1d0dbd0d65e1a3eaa6173a3337058105aec41fd0b2af5a2b46", + "zh:eb36b933419e9f6563330f3b7d53d4f1b09e62d27f7786d5dc6c4a2d0f6de182", + "zh:ec85ce1976e43f7d7fa10fa191c0a85e97326a3cb22387c0ed8b74d426ec94fd", + ] +} + +provider "registry.terraform.io/hashicorp/google" { + version = "5.6.0" + hashes = [ + "h1:4ALyLql3FFIU5xtZ1VJVoE9kQgI0PI8wO63sAKEdXT0=", + "zh:102b6a2672fade82114eb14ed46923fb1b74be2aaca3a50b4f35f7057a9a94b9", + "zh:1a56b63175068c67efbe7d130986ba2839a938f5ffc96a14fd450153174dbfa3", + "zh:1ba1c5e0c86e8aaa8037406390846e78c89b63faf9e527c7874641f35d436e1b", + "zh:3f7161b9288b47cbe89d2f9675f78d83b58ad5880c793b01f50a71ee2583844b", + "zh:66912d6e4180dac37185d17424b345a9d4e3c3c791d45e0737b35e32c9536b35", + "zh:6f06f56e9fac2e55b50e74ffac42d9522bb379394e51dca1eddd4c3b7a68545c", + "zh:8741861ebfa13bb1ed74ea7f4865388a0725ca3a781b6d873ce45e6a4630fe41", + "zh:ae89a9c538665fbc30bb83aa3b13acb18d8380e551ccf242e1c0ab4d626089ab", + "zh:c510f8321c7599aa601b1870fdc0c76cbad3054ed5cc70fe8e37a13a8046a71f", + "zh:cf143a53d5a25c6216d09a9c0b115bb473ffcebd5c4c62b2b2594b1ebc13e662", + "zh:de05b957e5dfdbaf92db47cd9b3ef46a0f8d94599eea6d472928f33058856add", + "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", + ] +} + +provider "registry.terraform.io/hashicorp/kubernetes" { + version = "2.23.0" + hashes = [ + "h1:cMs2scNCSgQhGamomGT5Ag4i8ms/mql1AR7NJc2hmbA=", + "zh:10488a12525ed674359585f83e3ee5e74818b5c98e033798351678b21b2f7d89", + "zh:1102ba5ca1a595f880e67102bbf999cc8b60203272a078a5b1e896d173f3f34b", + "zh:1347cf958ed3f3f80b3c7b3e23ddda3d6c6573a81847a8ee92b7df231c238bf6", + "zh:2cb18e9f5156bc1b1ee6bc580a709f7c2737d142722948f4a6c3c8efe757fa8d", + "zh:5506aa6f28dcca2a265ccf8e34478b5ec2cb43b867fe6d93b0158f01590fdadd", + "zh:6217a20686b631b1dcb448ee4bc795747ebc61b56fbe97a1ad51f375ebb0d996", + "zh:8accf916c00579c22806cb771e8909b349ffb7eb29d9c5468d0a3f3166c7a84a", + "zh:9379b0b54a0fa030b19c7b9356708ec8489e194c3b5e978df2d31368563308e5", + "zh:aa99c580890691036c2931841e88e7ee80d59ae52289c8c2c28ea0ac23e31520", + "zh:c57376d169875990ac68664d227fb69cd0037b92d0eba6921d757c3fd1879080", + "zh:e6068e3f94f6943b5586557b73f109debe19d1a75ca9273a681d22d1ce066579", + "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", + ] +} diff --git a/infrastructure/application/main.tf b/infrastructure/application/main.tf new file mode 100644 index 0000000..34d6dc4 --- /dev/null +++ b/infrastructure/application/main.tf @@ -0,0 +1,27 @@ +locals { + name = yamldecode(file("../../config.yml")).name +} + +# https://registry.terraform.io/providers/hashicorp/google/latest/docs/data-sources/client_config +data "google_client_config" "default" {} + +data "kubernetes_service" "service" { + metadata { + name = "application" + } +} + +# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/route53_zone +data "aws_route53_zone" "zone" { + name = "coilysiren.me." + private_zone = false +} + +# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record +resource "aws_route53_record" "record" { + zone_id = data.aws_route53_zone.zone.zone_id + name = "${local.name}.coilysiren.me." + type = "A" + ttl = "300" + records = [data.kubernetes_service.service.status.0.load_balancer.0.ingress.0.ip] +} diff --git a/infrastructure/application/state.tf b/infrastructure/application/state.tf new file mode 100644 index 0000000..d7d1798 --- /dev/null +++ b/infrastructure/application/state.tf @@ -0,0 +1,37 @@ +terraform { + backend "gcs" { + bucket = "coilysiren-k8s-gpc-tfstate-0" + prefix = "terraform/state/application" + } +} + +# https://registry.terraform.io/providers/hashicorp/google/latest/docs +provider "google" { + project = yamldecode(file("../../config.yml")).project + region = yamldecode(file("../../config.yml")).region +} + +# https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs +provider "kubernetes" { + host = "https://${data.terraform_remote_state.foundation.outputs.endpoint}" + token = data.google_client_config.default.access_token + cluster_ca_certificate = base64decode(data.terraform_remote_state.foundation.outputs.ca_certificate) +} + +# https://registry.terraform.io/providers/hashicorp/aws/latest/docs +provider "aws" { + # AWS doesn't have the same regions as GCP, and also doesn't format then in the same way. + # That said, this isn't a huge issue because we are only using AWS for DNS. + region = "us-east-1" +} + +# https://registry.terraform.io/providers/hashicorp/google/latest/docs/data-sources/project +data "google_project" "default" {} + +data "terraform_remote_state" "foundation" { + backend = "gcs" + config = { + bucket = "coilysiren-k8s-gpc-tfstate-0" + prefix = "terraform/state" + } +} diff --git a/infrastructure/.terraform.lock.hcl b/infrastructure/foundation/.terraform.lock.hcl similarity index 100% rename from infrastructure/.terraform.lock.hcl rename to infrastructure/foundation/.terraform.lock.hcl diff --git a/infrastructure/main.tf b/infrastructure/foundation/main.tf similarity index 94% rename from infrastructure/main.tf rename to infrastructure/foundation/main.tf index 7e15962..3313bf7 100644 --- a/infrastructure/main.tf +++ b/infrastructure/foundation/main.tf @@ -1,5 +1,5 @@ locals { - name = yamldecode(file("../config.yml")).name + name = yamldecode(file("../../config.yml")).name } # https://registry.terraform.io/providers/hashicorp/google/latest/docs/data-sources/client_config @@ -159,9 +159,12 @@ resource "google_artifact_registry_repository" "repository" { } } -# https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs -provider "kubernetes" { - host = "https://${module.gke.endpoint}" - token = data.google_client_config.default.access_token - cluster_ca_certificate = base64decode(module.gke.ca_certificate) +output "endpoint" { + value = module.gke.endpoint + sensitive = true +} + +output "ca_certificate" { + value = module.gke.ca_certificate + sensitive = true } diff --git a/infrastructure/state.tf b/infrastructure/foundation/state.tf similarity index 87% rename from infrastructure/state.tf rename to infrastructure/foundation/state.tf index b06bfae..6fe003d 100644 --- a/infrastructure/state.tf +++ b/infrastructure/foundation/state.tf @@ -7,8 +7,8 @@ terraform { # https://registry.terraform.io/providers/hashicorp/google/latest/docs provider "google" { - project = yamldecode(file("../config.yml")).project - region = yamldecode(file("../config.yml")).region + project = yamldecode(file("../../config.yml")).project + region = yamldecode(file("../../config.yml")).region } # https://registry.terraform.io/providers/hashicorp/google/latest/docs/data-sources/project diff --git a/infrastructure/kubeconfig.yml b/infrastructure/kubeconfig.yml new file mode 100644 index 0000000..06f41be --- /dev/null +++ b/infrastructure/kubeconfig.yml @@ -0,0 +1,46 @@ +apiVersion: v1 +items: +- apiVersion: v1 + kind: Service + metadata: + annotations: + cloud.google.com/neg: '{"ingress":true}' + finalizers: + - service.kubernetes.io/load-balancer-cleanup + labels: + app: application + name: application + spec: + allocateLoadBalancerNodePorts: true + externalTrafficPolicy: Cluster + internalTrafficPolicy: Cluster + ports: + - port: 80 + targetPort: 8080 + selector: + app: application + type: LoadBalancer +- apiVersion: apps/v1 + kind: Deployment + metadata: + labels: + app: application + name: application + spec: + replicas: 1 + selector: + matchLabels: + app: application + template: + metadata: + labels: + app: application + spec: + containers: + - image: us-central1-docker.pkg.dev/root-territory-384205/repository/gke-test-2:dns-21c2dd5-kai + name: application + ports: + - containerPort: 8080 +kind: List +metadata: + resourceVersion: '' diff --git a/tasks.py b/tasks.py index c196798..3d20727 100644 --- a/tasks.py +++ b/tasks.py @@ -17,6 +17,7 @@ class Context: version: str docker_repo: str python_version: str + kubeconfig = "./infrastructure/kubeconfig.yml" def __init__(self, ctx) -> None: self.invoke = ctx @@ -61,6 +62,20 @@ def project(self) -> str: """get the project id""" return self.config["project"] + def get_kubeconfig(self) -> str: + with open(self.kubeconfig, "r", encoding="utf-8") as _file: + return yaml.safe_load(_file.read()) + + def update_image(self, kubeconfig: dict, image: str) -> dict: + for item in kubeconfig["items"]: + if item["kind"] == "Deployment": + item["spec"]["template"]["spec"]["containers"][0]["image"] = image + return kubeconfig + + def write_kubeconfig(self, value: str) -> None: + with open(self.kubeconfig, "w", encoding="utf-8") as _file: + yaml.dump(value, _file) + def _repo_name(self) -> str: """get the name of the repository""" return self.stdout("basename -s .git `git config --get remote.origin.url`") @@ -105,8 +120,9 @@ def deploy(ctx: [invoke.Context, Context]): # build docker, get the tag build(ctx.invoke) - # deploy and infrastructure changes - ctx.run("cd infrastructure && terraform apply") + # deploy foundational infrastructure + ctx.run("cd infrastructure/foundation && terraform init") + ctx.run("cd infrastructure/foundation && terraform apply") # set the project ctx.run(f"gcloud config set project {ctx.project}") @@ -133,9 +149,14 @@ def deploy(ctx: [invoke.Context, Context]): ctx.run(f"docker push {ctx.docker_repo}:{ctx.version}") # deploy to k8s cluster - ctx.run(f"kubectl create deployment {ctx.name} --image={ctx.docker_repo}:{ctx.version} --port=8080", warn=True) - ctx.run(f"kubectl set image deployment/{ctx.name} {ctx.name}={ctx.docker_repo}:{ctx.version}") - ctx.run(f"kubectl expose deployment {ctx.name} --type=LoadBalancer --port=80 --target-port=8080", warn=True) + kubeconfig = ctx.get_kubeconfig() + kubeconfig = ctx.update_image(kubeconfig, f"{ctx.docker_repo}:{ctx.version}") + ctx.write_kubeconfig(kubeconfig) + ctx.run(f"kubectl apply -f {ctx.kubeconfig}") + + # deploy application infrastructure + ctx.run("cd infrastructure/application && terraform init") + ctx.run("cd infrastructure/application && terraform apply") @invoke.task