Skip to content

Commit

Permalink
install an example document db
Browse files Browse the repository at this point in the history
  • Loading branch information
rgl committed May 1, 2024
1 parent d8a45e2 commit 50b04fa
Show file tree
Hide file tree
Showing 13 changed files with 370 additions and 7 deletions.
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"adot",
"awslabs",
"Distro",
"docdb",
"IRSA",
"KUBECONFIG",
"oidc",
Expand Down
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ This will:
* Create a public DNS Zone using [Amazon Route 53](https://aws.amazon.com/route53/).
* Note that you need to configure the parent DNS Zone to delegate to this DNS Zone name servers.
* Use [external-dns](https://github.com/kubernetes-sigs/external-dns) to create the Ingress DNS Resource Records in the DNS Zone.
* Create an [example AWS DocumentDB](stacks/eks/docdb.tf).
* Demonstrate how to automatically deploy the [`kubernetes-hello` workload](stacks/eks-workloads/kubernetes-hello.tf).
* Show its environment variables.
* Show its tokens, secrets, and configs (config maps).
Expand Down Expand Up @@ -47,6 +48,8 @@ This will:
* Use a [`PersistentVolumeClaim` Persistent Volume](https://kubernetes.io/docs/concepts/storage/persistent-volumes/).
* Deploy the [hello-etcd example application](https://github.com/rgl/hello-etcd).
* Use the etcd key-value store.
* Demonstrate how to automatically deploy the [`docdb-example` workload](stacks/eks-workloads/docdb-example.tf).
* Use [the deployed example AWS DocumentDB](stacks/eks/docdb.tf).

The main components are:

Expand All @@ -64,6 +67,7 @@ Install the dependencies:
* [Terraform](https://www.terraform.io/downloads.html).
* [Terramate](https://terramate.io/docs/cli/installation).
* [Crane](https://github.com/google/go-containerregistry/releases).
* [jq](https://github.com/jqlang/jq/releases).
* [Docker](https://docs.docker.com/engine/install/).

Set the AWS Account credentials using SSO:
Expand Down Expand Up @@ -374,6 +378,31 @@ kubectl get pvc,pv
popd
```

Access the `docdb-example` ClusterIP Service from a [kubectl port-forward local port](https://kubernetes.io/docs/tasks/access-application-cluster/port-forward-access-application-cluster/):

```bash
kubectl port-forward service/docdb-example 6789:80 &
sleep 3 && printf '\n\n'
wget -qO- http://localhost:6789
kill %1 && sleep 3
```

Access the `docdb-example` Ingress from the Internet:

```bash
docdb_example_host="$(kubectl get ingress/docdb-example -o jsonpath='{.spec.rules[0].host}')"
docdb_example_url="https://$docdb_example_host"
echo "docdb-example ingress url: $docdb_example_url"
# wait for the host to resolve at the first route 53 name server.
ingress_domain_name_server="$(terramate run -C stacks/eks-aws-load-balancer-controller terraform output -json ingress_domain_name_servers | jq -r '.[0]')"
while [ -z "$(dig +short "$docdb_example_host" "@$ingress_domain_name_server")" ]; do sleep 5; done && dig "$docdb_example_host" "@$ingress_domain_name_server"
# wait for the host to resolve at the public internet (from the viewpoint
# of our local dns resolver).
while [ -z "$(dig +short "$docdb_example_host")" ]; do sleep 5; done && dig "$docdb_example_host"
# finally, access the service.
wget -qO- "$docdb_example_url"
```

List all the used container images:

```bash
Expand Down
14 changes: 14 additions & 0 deletions config.tm.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ globals {
# renovate: datasource=docker depName=ruilopes/kubernetes-hello
tag = "v0.0.202404261745"
}
# see https://github.com/rgl/aws-docdb-example/pkgs/container/aws-docdb-example
# see https://github.com/rgl/aws-docdb-example
docdb-example = {
name = "ghcr.io/rgl/aws-docdb-example"
# renovate: datasource=docker depName=rgl/aws-docdb-example registryUrl=https://ghcr.io
tag = "0.0.1"
}
}
}

Expand Down Expand Up @@ -88,3 +95,10 @@ globals "terraform" "providers" "tls" {
# renovate: datasource=terraform-provider depName=hashicorp/tls
version = "4.0.5"
}

# see https://registry.terraform.io/providers/hashicorp/external
# see https://github.com/hashicorp/terraform-provider-external
globals "terraform" "providers" "external" {
# renovate: datasource=terraform-provider depName=hashicorp/external
version = "2.3.3"
}
4 changes: 4 additions & 0 deletions stacks/ecr/_inputs.auto.tfvars
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

environment = "dev"
images = {
docdb-example = {
name = "ghcr.io/rgl/aws-docdb-example"
tag = "0.0.1"
}
kubernetes-hello = {
name = "docker.io/ruilopes/kubernetes-hello"
tag = "v0.0.202404261745"
Expand Down
20 changes: 20 additions & 0 deletions stacks/eks-workloads/.terraform.lock.hcl

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

4 changes: 4 additions & 0 deletions stacks/eks-workloads/_inputs.auto.tfvars
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ ingress_domain = "example.test"
project = "aws-eks-example"
region = "eu-west-1"
source_images = {
docdb-example = {
name = "ghcr.io/rgl/aws-docdb-example"
tag = "0.0.1"
}
kubernetes-hello = {
name = "docker.io/ruilopes/kubernetes-hello"
tag = "v0.0.202404261745"
Expand Down
4 changes: 4 additions & 0 deletions stacks/eks-workloads/_providers.tf
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ terraform {
source = "hashicorp/aws"
version = "5.47.0"
}
external = {
source = "hashicorp/external"
version = "2.3.3"
}
helm = {
source = "hashicorp/helm"
version = "2.13.1"
Expand Down
13 changes: 13 additions & 0 deletions stacks/eks-workloads/docdb-data.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/bash
set -euo pipefail

eval "$(jq -r '@sh "DOCDB_NAME=\(.name)"')"

DOCDB_ENDPOINT="$(aws docdb describe-db-clusters \
--db-cluster-identifier "$DOCDB_NAME" \
--query 'DBClusters[*].Endpoint' \
| jq -r '.[0]')"

jq -n \
--arg endpoint "$DOCDB_ENDPOINT" \
'{"endpoint":$endpoint}'
203 changes: 203 additions & 0 deletions stacks/eks-workloads/docdb-example.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
locals {
docdb_example_fqdn = "docdb-example.${var.ingress_domain}"
# see Connecting Programmatically to Amazon DocumentDB at https://docs.aws.amazon.com/documentdb/latest/developerguide/
docdb_example_master_connection_string = format(
"mongodb://%s:%s@%s:%d/?tls=true&tlsCAFile=global-bundle.pem&replicaSet=rs0&readPreference=secondaryPreferred&retryWrites=false",
urlencode("master"),
urlencode("Ex0mple!"),
data.external.docdb_example.result.endpoint,
27017
)
}

# see https://registry.terraform.io/providers/hashicorp/external/latest/docs/data-sources/external
data "external" "docdb_example" {
program = ["bash", "${path.module}/docdb-data.sh"]
query = {
name = var.cluster_name
}
}

# TODO re-evaluate replacing aws_acm_certificate/aws_acm_certificate_validation/aws_route53_record
# with acm-controller et al to be alike the cert-manager/external-dns CRDs
# when the following issues are addressed.
# see https://github.com/aws-controllers-k8s/community/issues/1904
# see https://github.com/aws-controllers-k8s/community/issues/482#issuecomment-755922462
# see https://github.com/kubernetes-sigs/aws-load-balancer-controller/issues/2509
# see https://github.com/aws-controllers-k8s/acm-controller/blob/v0.0.14/apis/v1alpha1/certificate.go#L23-L24

# see https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/acm_certificate
resource "aws_acm_certificate" "docdb_example" {
domain_name = local.docdb_example_fqdn
validation_method = "DNS"
key_algorithm = "EC_prime256v1"
lifecycle {
create_before_destroy = true
}
}

# see https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/acm_certificate_validation
resource "aws_acm_certificate_validation" "docdb_example" {
certificate_arn = aws_acm_certificate.docdb_example.arn
validation_record_fqdns = [for record in aws_route53_record.docdb_example_certificate_validation : record.fqdn]
}

# see https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record
resource "aws_route53_record" "docdb_example_certificate_validation" {
for_each = {
for dvo in aws_acm_certificate.docdb_example.domain_validation_options : dvo.domain_name => {
name = dvo.resource_record_name
record = dvo.resource_record_value
type = dvo.resource_record_type
}
}
allow_overwrite = true
type = each.value.type
name = each.value.name
records = [each.value.record]
ttl = 60
zone_id = data.aws_route53_zone.ingress.zone_id
}

# see https://kubernetes.io/docs/concepts/configuration/
# see https://kubernetes.io/docs/concepts/configuration/secret/
# see https://kubernetes.io/docs/concepts/security/secrets-good-practices/
# see https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/secret_v1
resource "kubernetes_secret_v1" "docdb_example_master" {
metadata {
name = "docdb-example-master"
}
data = {
connection_string = local.docdb_example_master_connection_string
}
}

# see https://kubernetes.io/docs/concepts/services-networking/ingress/
# see https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#ingress-v1-networking-k8s-io
# see https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.7/guide/ingress/annotations/
# see https://docs.aws.amazon.com/elasticloadbalancing/latest/application/create-https-listener.html#describe-ssl-policies
# see https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/ingress_v1
resource "kubernetes_ingress_v1" "docdb_example" {
metadata {
name = "docdb-example"
annotations = {
"alb.ingress.kubernetes.io/scheme" = "internet-facing"
"alb.ingress.kubernetes.io/target-type" = "ip"
"alb.ingress.kubernetes.io/group.name" = var.ingress_domain
"alb.ingress.kubernetes.io/listen-ports" = "[{\"HTTP\":80},{\"HTTPS\":443}]"
"alb.ingress.kubernetes.io/ssl-redirect" = "443"
"alb.ingress.kubernetes.io/ssl-policy" = "ELBSecurityPolicy-TLS13-1-2-2021-06"
"alb.ingress.kubernetes.io/healthcheck-path" = "/health/ready"
}
}
spec {
rule {
host = local.docdb_example_fqdn
http {
path {
path = "/"
path_type = "Prefix"
backend {
service {
name = "docdb-example"
port {
name = "web"
}
}
}
}
}
}
}
}

# see https://kubernetes.io/docs/concepts/services-networking/service/
# see https://kubernetes.io/docs/concepts/services-networking/service/#clusterip
# see https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#service-v1-core
# see https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#serviceport-v1-core
# see https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/service_v1
resource "kubernetes_service_v1" "docdb_example" {
metadata {
name = "docdb-example"
}
spec {
type = "ClusterIP"
selector = {
app = "docdb-example"
}
port {
name = "web"
port = 80
protocol = "TCP"
target_port = "web"
}
}
}

# see https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
# see https://kubernetes.io/docs/concepts/storage/projected-volumes/#serviceaccounttoken
# see https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
# see https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#deployment-v1-apps
# see https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#podtemplatespec-v1-core
# see https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#container-v1-core
# see https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#serviceaccounttokenprojection-v1-core
# see https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/deployment_v1
resource "kubernetes_deployment_v1" "docdb_example" {
metadata {
name = "docdb-example"
labels = {
app = "docdb-example"
}
}
spec {
replicas = 1
selector {
match_labels = {
app = "docdb-example"
}
}
template {
metadata {
labels = {
app = "docdb-example"
}
}
spec {
enable_service_links = false
container {
name = "docdb-example"
image = local.docdb_example_image
env {
name = "DOCDB_EXAMPLE_CONNECTION_STRING"
value_from {
secret_key_ref {
name = kubernetes_secret_v1.docdb_example_master.metadata[0].name
key = "connection_string"
}
}
}
port {
name = "web"
container_port = 8000
}
readiness_probe {
http_get {
path = "/health/ready"
port = "web"
}
}
resources {
requests = {
cpu = "0.1"
memory = "24Mi"
}
limits = {
cpu = "0.1"
memory = "24Mi"
}
}
}
}
}
}
}
1 change: 1 addition & 0 deletions stacks/eks-workloads/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ locals {
}
otel_example_image = local.images.otel-example
kubernetes_hello_image = local.images.kubernetes-hello
docdb_example_image = local.images.docdb-example
}
6 changes: 6 additions & 0 deletions stacks/eks-workloads/providers.tm.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ generate_hcl "_providers.tf" {
source = "hashicorp/helm"
version = global.terraform.providers.helm.version
}
# see https://registry.terraform.io/providers/hashicorp/external
# see https://github.com/hashicorp/terraform-provider-external
external = {
source = "hashicorp/external"
version = global.terraform.providers.external.version
}
}
}

Expand Down
Loading

0 comments on commit 50b04fa

Please sign in to comment.