diff --git a/main.tf b/main.tf index 19f9aeb1..4c84262c 100644 --- a/main.tf +++ b/main.tf @@ -17,6 +17,10 @@ variable "bind_db_viktorbarzin_lan" {} variable "bind_named_conf_options" {} variable "alertmanager_account_password" {} variable "wireguard_wg_0_key" {} +variable "drone_github_client_id" {} +variable "drone_github_client_secret" {} +variable "drone_rpc_secret" {} +# variable "dockerhub_password" {} variable "ansible_prefix" { default = "ANSIBLE_VAULT_PASSWORD_FILE=~/.ansible/vault_pass.txt ansible-playbook -i playbook/hosts.yaml playbook/linux.yml -t linux/initial_setup" @@ -143,9 +147,10 @@ module "k8s_node5" { module "kubernetes_cluster" { source = "./modules/kubernetes" - tls_secret_name = var.tls_secret_name - tls_crt = var.tls_crt - tls_key = var.tls_key + tls_secret_name = var.tls_secret_name + tls_crt = var.tls_crt + tls_key = var.tls_key + # dockerhub_password = var.dockerhub_password client_certificate_secret_name = var.client_certificate_secret_name mailserver_accounts = var.mailserver_accounts mailserver_aliases = var.mailserver_aliases @@ -162,5 +167,10 @@ module "kubernetes_cluster" { alertmanager_account_password = var.alertmanager_account_password - depends_on = [module.k8s_master, module.k8s_node1, module.k8s_node2] # wait until master and at least 2 nodes are up + # Drone + drone_github_client_id = var.drone_github_client_id + drone_github_client_secret = var.drone_github_client_secret + drone_rpc_secret = var.drone_rpc_secret + + # depends_on = [module.k8s_master, module.k8s_node1, module.k8s_node2] # wait until master and at least 2 nodes are up } diff --git a/modules/kubernetes/blog/main.tf b/modules/kubernetes/blog/main.tf index 88062436..583dfde2 100644 --- a/modules/kubernetes/blog/main.tf +++ b/modules/kubernetes/blog/main.tf @@ -1,6 +1,7 @@ variable "tls_secret_name" {} variable "tls_crt" {} variable "tls_key" {} +# variable "dockerhub_password" {} resource "kubernetes_namespace" "website" { metadata { @@ -16,6 +17,12 @@ module "tls_secret" { tls_key = var.tls_key } +# module "dockerhub_creds" { +# source = "../dockerhub_secret" +# namespace = "website" +# password = var.dockerhub_password +# } + resource "kubernetes_deployment" "blog" { metadata { name = "blog" diff --git a/modules/kubernetes/dockerhub_secret/main.tf b/modules/kubernetes/dockerhub_secret/main.tf new file mode 100644 index 00000000..f3672f3e --- /dev/null +++ b/modules/kubernetes/dockerhub_secret/main.tf @@ -0,0 +1,23 @@ +variable namespace {} +variable password {} +variable dockerhub_creds_secret_name { + default = "dockerhub-creds" +} +variable username { + default = "viktorbarzin" +} + +# DO NOT USE until able to store `stringData` +resource "kubernetes_secret" "dockerhub_creds" { + metadata { + name = var.dockerhub_creds_secret_name + namespace = var.namespace + } + + # data is additionally base64 encode, no stringData yet :/ https://github.com/hashicorp/terraform-provider-kubernetes/issues/901 + data = { + "username" = var.username + "password" = var.password + } + type = "kubernetes.io/basic-auth" +} diff --git a/modules/kubernetes/drone/main.tf b/modules/kubernetes/drone/main.tf new file mode 100644 index 00000000..6218bf91 --- /dev/null +++ b/modules/kubernetes/drone/main.tf @@ -0,0 +1,350 @@ +variable "tls_secret_name" {} +variable "tls_crt" {} +variable "tls_key" {} +variable "github_client_id" {} +variable "github_client_secret" {} +variable "rpc_secret" {} +variable "server_host" {} +variable "server_proto" {} +variable "rpc_host" { + default = "drone.drone.svc.cluster.local" +} +variable "allowed_users" { + # comma separated list + default = "viktorbarzin" +} + +resource "kubernetes_namespace" "drone" { + metadata { + name = "drone" + } +} + +module "tls_secret" { + source = "../setup_tls_secret" + namespace = "drone" + tls_secret_name = var.tls_secret_name + tls_crt = var.tls_crt + tls_key = var.tls_key +} + +resource "kubernetes_deployment" "drone_server" { + metadata { + name = "drone-server" + namespace = "drone" + labels = { + app = "drone" + } + } + spec { + strategy { + type = "Recreate" + } + replicas = 1 + selector { + match_labels = { + app = "drone" + } + } + template { + metadata { + labels = { + app = "drone" + } + } + spec { + container { + image = "drone/drone:1" + name = "drone-server" + resources { + limits = { + cpu = "1" + memory = "1Gi" + } + requests = { + cpu = "500m" + memory = "1Gi" + } + } + port { + container_port = 80 + } + volume_mount { + name = "data" + mount_path = "/data" + } + + env { + name = "DRONE_GITHUB_CLIENT_ID" + value = var.github_client_id + } + env { + name = "DRONE_GITHUB_CLIENT_SECRET" + value = var.github_client_secret + } + env { + name = "DRONE_RPC_SECRET" + value = var.rpc_secret + } + env { + name = "DRONE_SERVER_HOST" + value = var.server_host + } + env { + name = "DRONE_SERVER_PROTO" + value = var.server_proto + } + env { + name = "DRONE_USER_FILTER" + value = var.allowed_users + } + + } + volume { + name = "data" + iscsi { + target_portal = "iscsi.viktorbarzin.lan:3260" + fs_type = "ext4" + iqn = "iqn.2020-12.lan.viktorbarzin:storage:drone" + lun = 0 + read_only = false + } + } + } + } + } +} + +resource "kubernetes_service" "drone" { + metadata { + name = "drone" + namespace = "drone" + labels = { + app = "drone" + } + } + + spec { + selector = { + app = "drone" + } + port { + name = "http" + port = "80" + } + } +} + +resource "kubernetes_ingress" "drone" { + metadata { + name = "drone-ingress" + namespace = "drone" + annotations = { + "kubernetes.io/ingress.class" = "nginx" + } + } + + spec { + tls { + hosts = ["drone.viktorbarzin.me"] + secret_name = var.tls_secret_name + } + rule { + host = "drone.viktorbarzin.me" + http { + path { + path = "/" + backend { + service_name = "drone" + service_port = "80" + } + } + } + } + } +} + +# Setup drone runner +resource "kubernetes_cluster_role" "drone" { + metadata { + name = "drone" + } + rule { + api_groups = [""] + resources = ["secrets"] + verbs = ["get", "list", "create", "delete"] + } + rule { + api_groups = [""] + resources = ["pods", "pods/log"] + verbs = ["get", "create", "delete", "list", "watch", "update"] + } + rule { + api_groups = ["apps"] + resources = ["deployments"] + verbs = ["get", "create", "delete", "list", "watch", "update", "patch"] + } +} + +resource "kubernetes_cluster_role_binding" "drone" { + metadata { + name = "drone" + } + subject { + kind = "ServiceAccount" + name = "default" + namespace = "drone" + } + role_ref { + kind = "ClusterRole" + name = "drone" + api_group = "rbac.authorization.k8s.io" + } +} + +resource "kubernetes_deployment" "drone_runner" { + metadata { + name = "drone-runner" + namespace = "drone" + labels = { + app = "drone-runner" + } + } + spec { + strategy { + type = "Recreate" + } + replicas = 1 + selector { + match_labels = { + app = "drone-runner" + } + } + template { + metadata { + labels = { + app = "drone-runner" + } + } + spec { + container { + image = "drone/drone-runner-kube:latest" + name = "drone-runner" + resources { + limits = { + cpu = "1" + memory = "1Gi" + } + requests = { + cpu = "500m" + memory = "1Gi" + } + } + env { + name = "DRONE_RPC_HOST" + value = var.rpc_host + } + env { + name = "DRONE_RPC_PROTO" + value = "http" + } + env { + name = "DRONE_RPC_SECRET" + value = var.rpc_secret + } + env { + name = "DRONE_NAMESPACE_DEFAULT" + value = "drone" + } + env { + name = "SECRET_KEY" + value = var.rpc_secret + } + env { + name = "DRONE_SECRET_PLUGIN_ENDPOINT" + # value = "http://localhost:3000" + value = "http://drone-runner-secret.drone.svc.cluster.local:3000" + } + env { + name = "DRONE_SECRET_PLUGIN_TOKEN" + value = var.rpc_secret + } + env { + name = "DRONE_DEBUG" + value = "true" + } + } + } + } + } +} +resource "kubernetes_deployment" "drone_runner_secret" { + metadata { + name = "drone-runner-secret" + namespace = "drone" + labels = { + app = "drone-runner-secret" + } + } + spec { + strategy { + type = "Recreate" + } + replicas = 1 + selector { + match_labels = { + app = "drone-runner-secret" + } + } + template { + metadata { + labels = { + app = "drone-runner-secret" + } + } + spec { + container { + name = "secret" + image = "drone/kubernetes-secrets:latest" + port { + container_port = 3000 + } + env { + name = "SECRET_KEY" + value = var.rpc_secret + } + env { + name = "DEBUG" + value = "true" + } + env { + name = "KUBERNETES_NAMESPACE" + value = "drone" + } + } + } + } + } +} + + +resource "kubernetes_service" "drone_runner_secret" { + metadata { + name = "drone-runner-secret" + namespace = "drone" + labels = { + app = "drone-runner-secret" + } + } + + spec { + selector = { + app = "drone-runner-secret" + } + port { + name = "http" + port = "3000" + } + } +} + diff --git a/modules/kubernetes/main.tf b/modules/kubernetes/main.tf index e48b2416..3d309ce9 100644 --- a/modules/kubernetes/main.tf +++ b/modules/kubernetes/main.tf @@ -14,6 +14,10 @@ variable "bind_db_viktorbarzin_me" {} variable "bind_db_viktorbarzin_lan" {} variable "bind_named_conf_options" {} variable "alertmanager_account_password" {} +variable "drone_github_client_id" {} +variable "drone_github_client_secret" {} +variable "drone_rpc_secret" {} +# variable "dockerhub_password" {} resource "null_resource" "core_services" { # List all the core modules that must be provisioned first @@ -25,6 +29,7 @@ module "blog" { tls_secret_name = var.tls_secret_name tls_crt = var.tls_crt tls_key = var.tls_key + # dockerhub_password = var.dockerhub_password depends_on = [null_resource.core_services] } @@ -40,6 +45,22 @@ module "dnscrypt" { source = "./dnscrypt" } +# CI/CD +module "drone" { + source = "./drone" + tls_secret_name = var.tls_secret_name + tls_crt = var.tls_crt + tls_key = var.tls_key + + github_client_id = var.drone_github_client_id + github_client_secret = var.drone_github_client_secret + rpc_secret = var.drone_rpc_secret + server_host = "drone.viktorbarzin.me" + server_proto = "https" + + depends_on = [null_resource.core_services] +} + module "f1-stream" { source = "./f1-stream" tls_secret_name = var.tls_secret_name