diff --git a/.gitignore b/.gitignore index e47b4e9855..f3e894463e 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,8 @@ bin *.o tmp +terraform.tfvars +terraform.tfstate* build/local-includes/* !build/local-includes/README.md /release diff --git a/build/README.md b/build/README.md index d74eacbb8e..9d1d7e8b14 100644 --- a/build/README.md +++ b/build/README.md @@ -379,6 +379,9 @@ The Kubernetes config file used to access the cluster. Defaults to `~/.kube/conf ### CLUSTER_NAME The (gcloud) test cluster that is being worked against. Defaults to `test-cluster` +### GCP_PROJECT +Your GCP project for deploying GKE cluster. + ### IMAGE_PULL_SECRET The name of the secret required to pull the Agones images, if needed. If unset, no pull secret will be used. @@ -542,6 +545,26 @@ Pulls down authentication information for kubectl against a cluster, name can be Creates a short lived access to Google Cloud container repositories, so that you are able to call `docker push` directly. Useful when used in combination with `make push` command. +### Terraform + +Targets used to deploy a cluster with terraform. + +#### `make terraform-init` +Install google and google-beta terraform provider and authorize + +#### `make gcloud-terraform-cluster` +Run next command with your project ID specified: +``` +GCP_PROJECT= GKE_PASSWORD="" make gcloud-terraform-cluster +``` +Where `` should be 16 characters in length. You can omit GKE_PASSWORD and define `password=` string in `build/terraform.tfvars`. Also you change `ports="7000-8000"` setting using tfvars file. + +#### `make gcloud-terraform-destroy-cluster` +Run `terraform destroy` on your cluster. + +#### `make terraform-clean` +Remove .terraform directory with configs + ### Minikube A set of utilities for setting up and running a [Minikube](https://github.com/kubernetes/minikube) instance, diff --git a/build/build-image/Dockerfile b/build/build-image/Dockerfile index d9ecc41948..462bd590f9 100644 --- a/build/build-image/Dockerfile +++ b/build/build-image/Dockerfile @@ -140,6 +140,9 @@ RUN echo "export PATH=/usr/local/go/bin:/go/bin/:\$PATH" >> /root/.bashrc # make nano the editor RUN echo "export EDITOR=nano" >> /root/.bashrc +# install terraform +RUN wget -nv https://releases.hashicorp.com/terraform/0.11.13/terraform_0.11.13_linux_386.zip && unzip ./terraform_0.11.13_linux_386.zip && mv terraform /usr/local/bin/ + # code generation scripts COPY *.sh /root/ RUN chmod +x /root/*.sh diff --git a/build/cluster.tf b/build/cluster.tf new file mode 100644 index 0000000000..6067ed93e4 --- /dev/null +++ b/build/cluster.tf @@ -0,0 +1,182 @@ +# Copyright 2019 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +provider "google-beta" { + zone = "${lookup(var.cluster, "zone")}" +} + + +# Password for the Kubernetes API. +# Could be defined using GKE_PASSWORD env variable +# or by setting `password="somepass"` string in build/terraform.tfvars +variable "password" {default = ""} + +# Ports can be overriden using tfvars file +variable "ports" {default="7000-8000"} + +# Set of GKE cluster parameters which defines its name, zone +# and primary node pool configuration. +# It is crucial to set valid ProjectID for "project". +variable "cluster" { + description = "Set of GKE cluster parameters." + type = "map" + default = { + "zone" = "us-west1-c" + "name" = "test-cluster" + "machineType" = "n1-standard-4" + "initialNodeCount" = "4" + "legacyAbac" = false + "project" = "agones" + } +} + + +# echo command used for debugging purpose +# Run `terraform taint null_resource.test-setting-variables` before second execution +resource "null_resource" "test-setting-variables" { + provisioner "local-exec" { + command = "${"${format("echo Current variables set as following - name: %s, project: %s, machineType: %s, initialNodeCount: %s, zone: %s, legacyAbac: %s", + "${lookup(var.cluster, "name")}", "${lookup(var.cluster, "project")}", + "${lookup(var.cluster, "machineType")}", "${lookup(var.cluster, "initialNodeCount")}", + "${lookup(var.cluster, "zone")}", "${lookup(var.cluster, "legacyAbac")}")}"}" + } +} + +# assert that password has correct length +# before creating the cluster to avoid +# unfinished configurations +resource "null_resource" "check-password-length" { + count = "${length(var.password) >= 16 ? 0 : 1}" + "Password must be more than 16 chars in length" = true +} + +resource "google_container_cluster" "primary" { + name = "${lookup(var.cluster, "name")}" + location = "${lookup(var.cluster, "zone")}" + project = "${lookup(var.cluster, "project")}" + provider = "google-beta" + + master_auth { + username = "admin" + password = "${var.password}" + } + enable_legacy_abac = "${lookup(var.cluster, "legacyAbac")}" + node_pool = [ + { + node_count = "${lookup(var.cluster, "initialNodeCount")}" + node_config { + machine_type = "${lookup(var.cluster, "machineType")}" + oauth_scopes = [ + "https://www.googleapis.com/auth/devstorage.read_only", + "https://www.googleapis.com/auth/logging.write", + "https://www.googleapis.com/auth/monitoring", + "https://www.googleapis.com/auth/service.management.readonly", + "https://www.googleapis.com/auth/servicecontrol", + "https://www.googleapis.com/auth/trace.append", + ] + + tags = ["game-server"] + timeouts { + create = "30m" + update = "40m" + } + } + }, + { + name = "agones-system" + node_count = 1 + node_config { + preemptible = true + machine_type = "n1-standard-4" + + oauth_scopes = [ + "https://www.googleapis.com/auth/devstorage.read_only", + "https://www.googleapis.com/auth/logging.write", + "https://www.googleapis.com/auth/monitoring", + "https://www.googleapis.com/auth/service.management.readonly", + "https://www.googleapis.com/auth/servicecontrol", + "https://www.googleapis.com/auth/trace.append", + ] + labels = { + "stable.agones.dev/agones-system" = "true" + } + taint = { + key = "stable.agones.dev/agones-system" + value = "true" + effect = "NO_EXECUTE" + } + } + }, + { + name = "agones-metrics" + node_count = 1 + + node_config { + preemptible = true + machine_type = "n1-standard-4" + + oauth_scopes = [ + "https://www.googleapis.com/auth/devstorage.read_only", + "https://www.googleapis.com/auth/logging.write", + "https://www.googleapis.com/auth/monitoring", + "https://www.googleapis.com/auth/service.management.readonly", + "https://www.googleapis.com/auth/servicecontrol", + "https://www.googleapis.com/auth/trace.append", + ] + labels = { + "stable.agones.dev/agones-metrics" = "true" + } + taint = { + key = "stable.agones.dev/agones-metrics" + value = "true" + effect = "NO_EXECUTE" + } + } + } + ] +} + +resource "google_compute_firewall" "default" { + name = "game-server-firewall-firewall-${lookup(var.cluster, "name")}" + project = "${lookup(var.cluster, "project")}" + network = "${google_compute_network.default.name}" + + allow { + protocol = "udp" + ports = ["${var.ports}"] + } + + source_tags = ["game-server"] +} + +resource "google_compute_network" "default" { + project = "${lookup(var.cluster, "project")}" + name = "agones-network-${lookup(var.cluster, "name")}" +} + + + +# The following outputs allow authentication and connectivity to the GKE Cluster +# by using certificate-based authentication. +output "client_certificate" { + value = "${google_container_cluster.primary.master_auth.0.client_certificate}" +} + +output "client_key" { + value = "${google_container_cluster.primary.master_auth.0.client_key}" +} + +output "cluster_ca_certificate" { + value = "${google_container_cluster.primary.master_auth.0.cluster_ca_certificate}" +} diff --git a/build/helm.tf b/build/helm.tf new file mode 100644 index 0000000000..5c805370b3 --- /dev/null +++ b/build/helm.tf @@ -0,0 +1,120 @@ +# Copyright 2019 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +resource "kubernetes_service_account" "tiller" { + metadata { + name = "tiller" + namespace = "kube-system" + } + depends_on = ["google_container_cluster.primary"] + + automount_service_account_token = true +} + +resource "kubernetes_cluster_role_binding" "tiller" { + depends_on = ["kubernetes_service_account.tiller"] + metadata { + name = "tiller" + } + + role_ref { + kind = "ClusterRole" + name = "cluster-admin" + api_group = "rbac.authorization.k8s.io" + } + + subject { + kind = "ServiceAccount" + name = "tiller" + + api_group = "" + namespace = "kube-system" + } +} +variable "agones_version" { + default = "0.9.0" +} + +data "google_client_config" "default" {} + +provider "kubernetes" { + load_config_file = false + host = "https://${google_container_cluster.primary.endpoint}" + token = "${data.google_client_config.default.access_token}" + cluster_ca_certificate = "${base64decode(google_container_cluster.primary.master_auth.0.cluster_ca_certificate)}" +} + +provider "helm" { + version = "~> 0.7" + + debug = true + install_tiller = true + service_account = "${kubernetes_service_account.tiller.metadata.0.name}" + tiller_image = "gcr.io/kubernetes-helm/tiller:v2.12.3" + + kubernetes { + load_config_file = false + host = "https://${google_container_cluster.primary.endpoint}" + token = "${data.google_client_config.default.access_token}" + cluster_ca_certificate = "${base64decode(google_container_cluster.primary.master_auth.0.cluster_ca_certificate)}" + + } + +} + +data "google_client_config" "current" {} + + +data "helm_repository" "agones" { + depends_on = ["kubernetes_cluster_role_binding.tiller"] + name = "agones" + url = "https://agones.dev/chart/stable" +} + +resource "helm_release" "agones" { + depends_on = ["null_resource.helm_init", "kubernetes_cluster_role_binding.tiller"] + name = "agones" + force_update = "true" + repository = "${data.helm_repository.agones.metadata.0.name}" + chart = "agones" + values = [ + "${file("../install/helm/agones/values.yaml")}" + ] + + set { + name = "registerServiceAccounts" + value = "true" + } + set { + name = "crds.CleanupOnDelete" + value = "true" + } + set { + name = "agones.image.tag" + value = "${var.agones_version}" + } + version = "${var.agones_version}" + namespace = "agones-system" +} + +# Creates folder with repositories so that helm provider would not fail +resource "null_resource" "helm_init" { + triggers = { + always_run = "${timestamp()}" + } + + provisioner "local-exec" { + command = "helm init --client-only" + } +} diff --git a/build/includes/google-cloud.mk b/build/includes/google-cloud.mk index 3e249720f9..0973f2e391 100644 --- a/build/includes/google-cloud.mk +++ b/build/includes/google-cloud.mk @@ -33,7 +33,34 @@ gcloud-test-cluster: $(ensure-build-image) --properties cluster.zone:$(GCP_CLUSTER_ZONE),cluster.name:$(GCP_CLUSTER_NAME),cluster.nodePool.initialNodeCount:$(GCP_CLUSTER_NODEPOOL_INITIALNODECOUNT),cluster.nodePool.machineType:$(GCP_CLUSTER_NODEPOOL_MACHINETYPE),cluster.legacyAbac:$(GCP_CLUSTER_LEGACYABAC)\ --template=$(mount_path)/build/gke-test-cluster/cluster.yml.jinja $(MAKE) gcloud-auth-cluster - $(MAKE) setup-test-cluster + +terraform-init: + docker run --rm -it $(common_mounts) $(DOCKER_RUN_ARGS) $(build_tag) bash -c '\ + cd $(mount_path)/build && terraform init && gcloud auth application-default login' + +terraform-clean: + rm -r ./.terraform + rm ./terraform.tfstate* + + +gcloud-terraform-cluster: GCP_PROJECT ?= "" +gcloud-terraform-cluster: GCP_CLUSTER_LEGACYABAC ?= false +gcloud-terraform-cluster: GCP_CLUSTER_NODEPOOL_INITIALNODECOUNT ?= 4 +gcloud-terraform-cluster: GCP_CLUSTER_NODEPOOL_MACHINETYPE ?= n1-standard-4 +gcloud-terraform-cluster: $(ensure-build-image) +gcloud-terraform-cluster: + test -n "$(GCP_PROJECT)" # $$GCP_PROJECT is undefined + $(DOCKER_RUN) bash -c 'export TF_VAR_password=$(GKE_PASSWORD) && \ + cd $(mount_path)/build && terraform apply -auto-approve \ + -var "cluster={name=\"$(GCP_CLUSTER_NAME)\", machineType=\"$(GCP_CLUSTER_NODEPOOL_MACHINETYPE)\", \ + zone=\"$(GCP_CLUSTER_ZONE)\", project=\"$(GCP_PROJECT)\", \ + initialNodeCount=\"$(GCP_CLUSTER_NODEPOOL_INITIALNODECOUNT)\", \ + legacyABAC=\"$(GCP_CLUSTER_LEGACYABAC)\"}"' + $(MAKE) gcloud-auth-cluster + +gcloud-terraform-destroy-cluster: + $(DOCKER_RUN) bash -c ' export TF_VAR_password="1234567890123456" && \ + cd $(mount_path)/build && terraform destroy -auto-approve' clean-gcloud-test-cluster: $(ensure-build-image) docker run --rm -it $(common_mounts) $(DOCKER_RUN_ARGS) $(build_tag) gcloud \