├── .gitignore ├── README.md ├── cloudinit.tf ├── kubeconfig.tf ├── main.tf ├── network.tf ├── outputs.tf ├── providers.tf ├── sshkey.tf ├── variables.tf └── winInsecureCurl.ps1 /.gitignore: -------------------------------------------------------------------------------- 1 | # Terraform 2 | .terraform* 3 | terraform.tfstate* 4 | 5 | # SSH keys 6 | id_rsa* 7 | 8 | # K8s 9 | kubeconfig -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ampernetacle 2 | 3 | This is a Terraform configuration to deploy a Kubernetes cluster on 4 | [Oracle Cloud Infrastructure][oci]. It creates a few virtual machines 5 | and uses [kubeadm] to install a Kubernetes control plane on the first 6 | machine, and join the other machines as worker nodes. 7 | 8 | By default, it deploys a 4-node cluster using ARM machines. Each machine 9 | has 1 OCPU and 6 GB of RAM, which means that the cluster fits within 10 | Oracle's (pretty generous if you ask me) [free tier][freetier]. 11 | 12 | **It is not meant to run production workloads,** 13 | but it's great if you want to learn Kubernetes with a "real" cluster 14 | (i.e. a cluster with multiple nodes) without breaking the bank, *and* 15 | if you want to develop or test applications on ARM. 16 | 17 | ## Getting started 18 | 19 | 1. Create an Oracle Cloud Infrastructure account (just follow [this link][createaccount]). 20 | 2. Have installed or [install kubernetes](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#installing-kubeadm-kubelet-and-kubectl). 21 | 3. Have installed or [install terraform](https://learn.hashicorp.com/tutorials/terraform/install-cli?in=terraform/oci-get-started). 22 | 4. Have installed or [install OCI CLI ](https://docs.oracle.com/en-us/iaas/Content/API/SDKDocs/cliinstall.htm). 23 | 5. Configure [OCI credentials](https://learn.hashicorp.com/tutorials/terraform/oci-build?in=terraform/oci-get-started). 24 | If you obtain a session token (with `oci session authenticate`), make sure to put the correct region, and when prompted for the profile name, enter `DEFAULT` so that Terraform finds the session token automatically. 25 | 6. Download this project and enter its folder. 26 | 7. `terraform init` 27 | 8. `terraform apply` 28 | 29 | That's it! 30 | 31 | At the end of the `terraform apply`, a `kubeconfig` file is generated 32 | in this directory. To use your new cluster, you can do: 33 | 34 | Linux 35 | ```bash 36 | export KUBECONFIG=$PWD/kubeconfig 37 | kubectl get nodes 38 | ``` 39 | 40 | Windows 41 | ```powershell 42 | $env:KUBECONFIG="$pwd\kubeconfig" 43 | kubectl get nodes 44 | ``` 45 | 46 | The command above should show you 4 nodes, named `node1` to `node4`. 47 | 48 | You can also log into the VMs. At the end of the Terraform output 49 | you should see a command that you can use to SSH into the first VM 50 | (just copy-paste the command). 51 | 52 | ## Windows 53 | 54 | It works with Windows 10/Powershell 5.1. 55 | 56 | It may be necesssary to change the execution policy to unrestricted. 57 | 58 | [PowerShell ExecutionPolicy](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.security/set-executionpolicy?view=powershell-5.1) 59 | 60 | ## Customization 61 | 62 | Check `variables.tf` to see tweakable parameters. You can change the number 63 | of nodes, the size of the nodes, or switch to Intel/AMD instances if you'd 64 | like. Keep in mind that if you switch to Intel/AMD instances, you won't get 65 | advantage of the free tier. 66 | 67 | ## Stopping the cluster 68 | 69 | `terraform destroy` 70 | 71 | ## Implementation details 72 | 73 | This Terraform configuration: 74 | 75 | - generates an OpenSSH keypair and a kubeadm token 76 | - deploys 4 VMs using Ubuntu 20.04 77 | - uses cloud-init to install and configure everything 78 | - installs Docker and Kubernetes packages 79 | - runs `kubeadm init` on the first VM 80 | - runs `kubeadm join` on the other VMs 81 | - installs the Weave CNI plugin 82 | - transfers the `kubeconfig` file generated by `kubeadm` 83 | - patches that file to use the public IP address of the machine 84 | 85 | ## Caveats 86 | 87 | This doesn't install the [OCI cloud controller manager][ccm], 88 | which means that you cannot 89 | create services with `type: LoadBalancer`; or rather, if you create 90 | such services, their `EXTERNAL-IP` will remain ``. 91 | 92 | To expose services, use `NodePort`. 93 | 94 | Likewise, there is no ingress controller and no storage class. 95 | 96 | These might be added in a later iteration of this project. 97 | Meanwhile, if you want to install it manually, you can check 98 | the [OCI cloud controller manager github repository][ccm]. 99 | 100 | ## Remarks 101 | 102 | Oracle Cloud also has a managed Kubernetes service called 103 | [Container Engine for Kubernetes (or OKE)][oke]. That service 104 | doesn't have the caveats mentioned above; however, it's not part 105 | of the free tier. 106 | 107 | ## What does "Ampernetacle" mean? 108 | 109 | It's a *porte-manteau* between Ampere, Kubernetes, and Oracle. 110 | It's probably not the best name in the world but it's the one 111 | we have! If you have an idea for a better name let us know. 😊 112 | 113 | ## Possible errors and how to address them 114 | 115 | ### Authentication problem 116 | 117 | If you configured OCI authentication using a session token 118 | (with `oci session authenticate`), please note that this token 119 | is valid 1 hour by default. If you authenticate, then wait more 120 | than 1 hour, then try to `terraform apply`, you will get 121 | authentication errors. 122 | 123 | #### Symptom 124 | 125 | The following message: 126 | 127 | ``` 128 | Error: 401-NotAuthenticated 129 | │ Service: Identity Compartment 130 | │ Error Message: The required information to complete authentication was not provided or was incorrect. 131 | │ OPC request ID: [...] 132 | │ Suggestion: Please retry or contact support for help with service: Identity Compartment 133 | ``` 134 | 135 | #### Solution 136 | 137 | Authenticate or re-authenticate, for instance with 138 | `oci session authenticate`. 139 | 140 | If prompted for the profile name, make sure to enter `DEFAULT` 141 | so that Terraform automatically uses the session token. 142 | 143 | If you previously used `oci session authenticate`, you 144 | should be able to refresh the session with 145 | `oci session refresh --profile DEFAULT`. 146 | 147 | ### Capacity issue 148 | 149 | #### Symptom 150 | 151 | If you get a message like the following one: 152 | ``` 153 | Error: 500-InternalError 154 | │ ... 155 | │ Service: Core Instance 156 | │ Error Message: Out of host capacity. 157 | ``` 158 | 159 | It means that there isn't enough servers available at the moment 160 | on OCI to create the cluster. 161 | 162 | #### Solution 163 | 164 | One solution is to switch to a different *availability domain*. 165 | This can be done by changing the `availability_domain` input variable. (Thanks @uknbr for the contribution!) 166 | 167 | Note 1: some regions have only one availability domain. In that 168 | case you cannot change the availability domain. 169 | 170 | Note 2: OCI accounts (especially free accounts) are tied to a 171 | single region, so if you get that problem and cannot change the 172 | availability domain, you can [create another account][createaccount]. 173 | 174 | ### Using the wrong region 175 | 176 | #### Symptom 177 | 178 | When doing `terraform apply`, you get this message: 179 | 180 | ``` 181 | oci_identity_compartment._: Creating... 182 | ╷ 183 | │ Error: 404-NotAuthorizedOrNotFound 184 | │ Service: Identity Compartment 185 | │ Error Message: Authorization failed or requested resource not found 186 | │ OPC request ID: [...] 187 | │ Suggestion: Either the resource has been deleted or service Identity Compartment need policy to access this resource. Policy reference: https://docs.oracle.com/en-us/iaas/Content/Identity/Reference/policyreference.htm 188 | │ 189 | │ 190 | │ with oci_identity_compartment._, 191 | │ on main.tf line 1, in resource "oci_identity_compartment" "_": 192 | │ 1: resource "oci_identity_compartment" "_" { 193 | │ 194 | ╵ 195 | ``` 196 | 197 | #### Solution 198 | 199 | Edit `~/.oci/config` and change the `region=` line to put the correct region. 200 | 201 | To know what's the correct region, you can try to log in to 202 | https://cloud.oracle.com/ with your account; after logging in, 203 | you should be redirected to an URL that looks like 204 | https://cloud.oracle.com/?region=us-ashburn-1 and in that 205 | example the region is `us-ashburn-1`. 206 | 207 | ### Troubleshooting cluster creation 208 | 209 | After the VMs are created, you can log into the VMs with the 210 | `ubuntu` user and the SSH key contained in the `id_rsa` file 211 | that was created by Terraform. 212 | 213 | Then you can check the cloud init output file, e.g. like this: 214 | ``` 215 | tail -n 100 -f /var/log/cloud-init-output.log 216 | ``` 217 | 218 | 219 | [ccm]: https://github.com/oracle/oci-cloud-controller-manager 220 | [createaccount]: https://bit.ly/free-oci-dat-k8s-on-arm 221 | [freetier]: https://www.oracle.com/cloud/free/ 222 | [kubeadm]: https://kubernetes.io/docs/reference/setup-tools/kubeadm/ 223 | [oci]: https://www.oracle.com/cloud/compute/ 224 | [oke]: https://www.oracle.com/cloud-native/container-engine-kubernetes/ 225 | -------------------------------------------------------------------------------- /cloudinit.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | packages = [ 3 | "apt-transport-https", 4 | "build-essential", 5 | "ca-certificates", 6 | "containerd.io", 7 | "curl", 8 | "docker-ce", 9 | "gpg", 10 | "jq", 11 | "kubeadm", 12 | "kubectl", 13 | "kubelet", 14 | "lsb-release", 15 | "make", 16 | "prometheus-node-exporter", 17 | "python3-pip", 18 | "software-properties-common", 19 | "tmux", 20 | "tree", 21 | "unzip", 22 | ] 23 | } 24 | 25 | data "cloudinit_config" "_" { 26 | for_each = local.nodes 27 | 28 | part { 29 | filename = "cloud-config.cfg" 30 | content_type = "text/cloud-config" 31 | content = <<-EOF 32 | hostname: ${each.value.node_name} 33 | package_update: true 34 | package_upgrade: false 35 | packages: 36 | ${yamlencode(local.packages)} 37 | apt: 38 | sources: 39 | kubernetes.list: 40 | source: "deb https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /" 41 | key: | 42 | ${indent(8, data.http.kubernetes_repo_key.response_body)} 43 | docker.list: 44 | source: "deb https://download.docker.com/linux/ubuntu jammy stable" 45 | key: | 46 | ${indent(8, data.http.docker_repo_key.response_body)} 47 | users: 48 | - default 49 | - name: k8s 50 | primary_group: k8s 51 | groups: docker 52 | home: /home/k8s 53 | shell: /bin/bash 54 | sudo: ALL=(ALL) NOPASSWD:ALL 55 | ssh_authorized_keys: 56 | - ${tls_private_key.ssh.public_key_openssh} 57 | write_files: 58 | - path: /etc/kubeadm_token 59 | owner: "root:root" 60 | permissions: "0600" 61 | content: ${local.kubeadm_token} 62 | - path: /etc/kubeadm_config.yaml 63 | owner: "root:root" 64 | permissions: "0600" 65 | content: | 66 | kind: InitConfiguration 67 | apiVersion: kubeadm.k8s.io/v1beta3 68 | bootstrapTokens: 69 | - token: ${local.kubeadm_token} 70 | --- 71 | kind: KubeletConfiguration 72 | apiVersion: kubelet.config.k8s.io/v1beta1 73 | cgroupDriver: cgroupfs 74 | --- 75 | kind: ClusterConfiguration 76 | apiVersion: kubeadm.k8s.io/v1beta3 77 | apiServer: 78 | certSANs: 79 | - @@PUBLIC_IP_ADDRESS@@ 80 | - path: /home/k8s/.ssh/id_rsa 81 | defer: true 82 | owner: "k8s:k8s" 83 | permissions: "0600" 84 | content: | 85 | ${indent(4, tls_private_key.ssh.private_key_pem)} 86 | - path: /home/k8s/.ssh/id_rsa.pub 87 | defer: true 88 | owner: "k8s:k8s" 89 | permissions: "0600" 90 | content: | 91 | ${indent(4, tls_private_key.ssh.public_key_openssh)} 92 | EOF 93 | } 94 | 95 | # By default, all inbound traffic is blocked 96 | # (except SSH) so we need to change that. 97 | part { 98 | filename = "1-allow-inbound-traffic.sh" 99 | content_type = "text/x-shellscript" 100 | content = <<-EOF 101 | #!/bin/sh 102 | sed -i "s/-A INPUT -j REJECT --reject-with icmp-host-prohibited//" /etc/iptables/rules.v4 103 | sed -i "s/-A FORWARD -j REJECT --reject-with icmp-host-prohibited//" /etc/iptables/rules.v4 104 | # There appears to be a bug in the netfilter-persistent scripts: 105 | # the "reload" and "restart" actions seem to append the rules files 106 | # to the existing rules (instead of replacing them), perhaps because 107 | # the "stop" action is disabled. So instead, we need to flush the 108 | # rules first before we load the new rule set. 109 | netfilter-persistent flush 110 | netfilter-persistent start 111 | EOF 112 | } 113 | 114 | # Docker's default containerd configuration disables CRI. 115 | # Let's re-enable it. 116 | part { 117 | filename = "2-re-enable-cri.sh" 118 | content_type = "text/x-shellscript" 119 | content = <<-EOF 120 | #!/bin/sh 121 | echo "# Use containerd's default configuration instead of the one shipping with Docker." > /etc/containerd/config.toml 122 | systemctl restart containerd 123 | EOF 124 | } 125 | 126 | dynamic "part" { 127 | for_each = each.value.role == "controlplane" ? ["yes"] : [] 128 | content { 129 | filename = "3-kubeadm-init.sh" 130 | content_type = "text/x-shellscript" 131 | content = <<-EOF 132 | #!/bin/sh 133 | PUBLIC_IP_ADDRESS=$(curl https://icanhazip.com/) 134 | sed -i s/@@PUBLIC_IP_ADDRESS@@/$PUBLIC_IP_ADDRESS/ /etc/kubeadm_config.yaml 135 | kubeadm init --config=/etc/kubeadm_config.yaml --ignore-preflight-errors=NumCPU 136 | export KUBECONFIG=/etc/kubernetes/admin.conf 137 | kubectl apply -f https://github.com/weaveworks/weave/releases/download/v2.8.1/weave-daemonset-k8s-1.11.yaml 138 | mkdir -p /home/k8s/.kube 139 | cp $KUBECONFIG /home/k8s/.kube/config 140 | chown -R k8s:k8s /home/k8s/.kube 141 | EOF 142 | } 143 | } 144 | 145 | dynamic "part" { 146 | for_each = each.value.role == "worker" ? ["yes"] : [] 147 | content { 148 | filename = "3-kubeadm-join.sh" 149 | content_type = "text/x-shellscript" 150 | content = <<-EOF 151 | #!/bin/sh 152 | KUBE_API_SERVER=${local.nodes[1].ip_address}:6443 153 | while ! curl --insecure https://$KUBE_API_SERVER; do 154 | echo "Kubernetes API server ($KUBE_API_SERVER) not responding." 155 | echo "Waiting 10 seconds before we try again." 156 | sleep 10 157 | done 158 | echo "Kubernetes API server ($KUBE_API_SERVER) appears to be up." 159 | echo "Trying to join this node to the cluster." 160 | kubeadm join --discovery-token-unsafe-skip-ca-verification --token ${local.kubeadm_token} $KUBE_API_SERVER 161 | EOF 162 | } 163 | } 164 | } 165 | 166 | data "http" "kubernetes_repo_key" { 167 | url = "https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key" 168 | } 169 | 170 | data "http" "docker_repo_key" { 171 | url = "https://download.docker.com/linux/debian/gpg" 172 | } 173 | 174 | # The kubeadm token must follow a specific format: 175 | # - 6 letters/numbers 176 | # - a dot 177 | # - 16 letters/numbers 178 | 179 | resource "random_string" "token1" { 180 | length = 6 181 | numeric = true 182 | lower = true 183 | special = false 184 | upper = false 185 | } 186 | 187 | resource "random_string" "token2" { 188 | length = 16 189 | numeric = true 190 | lower = true 191 | special = false 192 | upper = false 193 | } 194 | 195 | locals { 196 | kubeadm_token = format( 197 | "%s.%s", 198 | random_string.token1.result, 199 | random_string.token2.result 200 | ) 201 | } 202 | -------------------------------------------------------------------------------- /kubeconfig.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | is_windows = substr(pathexpand("~"), 0, 1) == "/" ? false : true 3 | } 4 | 5 | data "external" "kubeconfig" { 6 | depends_on = [oci_core_instance._[1]] 7 | program = local.is_windows ? [ 8 | "powershell", 9 | </dev/null 18 | echo '{"base64": "'$( 19 | ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \ 20 | -l k8s -i ${local_file.ssh_private_key.filename} \ 21 | ${oci_core_instance._[1].public_ip} \ 22 | 'sudo cat /etc/kubernetes/admin.conf | base64 -w0' 23 | )'"}' 24 | EOT 25 | ] 26 | } 27 | 28 | resource "local_file" "kubeconfig" { 29 | content = base64decode(data.external.kubeconfig.result.base64) 30 | filename = "kubeconfig" 31 | file_permission = "0600" 32 | provisioner "local-exec" { 33 | command = "kubectl --kubeconfig=kubeconfig config set-cluster kubernetes --server=https://${oci_core_instance._[1].public_ip}:6443" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /main.tf: -------------------------------------------------------------------------------- 1 | resource "oci_identity_compartment" "_" { 2 | name = var.name 3 | description = var.name 4 | enable_delete = true 5 | } 6 | 7 | locals { 8 | compartment_id = oci_identity_compartment._.id 9 | } 10 | 11 | data "oci_identity_availability_domains" "_" { 12 | compartment_id = local.compartment_id 13 | } 14 | 15 | data "oci_core_images" "_" { 16 | compartment_id = local.compartment_id 17 | shape = var.shape 18 | operating_system = "Canonical Ubuntu" 19 | operating_system_version = "22.04" 20 | #operating_system = "Oracle Linux" 21 | #operating_system_version = "7.9" 22 | } 23 | 24 | resource "oci_core_instance" "_" { 25 | for_each = local.nodes 26 | display_name = each.value.node_name 27 | availability_domain = data.oci_identity_availability_domains._.availability_domains[var.availability_domain].name 28 | compartment_id = local.compartment_id 29 | shape = var.shape 30 | shape_config { 31 | memory_in_gbs = var.memory_in_gbs_per_node 32 | ocpus = var.ocpus_per_node 33 | } 34 | source_details { 35 | source_id = data.oci_core_images._.images[0].id 36 | source_type = "image" 37 | } 38 | create_vnic_details { 39 | subnet_id = oci_core_subnet._.id 40 | private_ip = each.value.ip_address 41 | } 42 | metadata = { 43 | ssh_authorized_keys = join("\n", local.authorized_keys) 44 | user_data = data.cloudinit_config._[each.key].rendered 45 | } 46 | connection { 47 | host = self.public_ip 48 | user = "ubuntu" 49 | private_key = tls_private_key.ssh.private_key_pem 50 | } 51 | provisioner "remote-exec" { 52 | inline = [ 53 | "tail -f /var/log/cloud-init-output.log &", 54 | "cloud-init status --wait >/dev/null", 55 | ] 56 | } 57 | } 58 | 59 | locals { 60 | nodes = { 61 | for i in range(1, 1 + var.how_many_nodes) : 62 | i => { 63 | node_name = format("node%d", i) 64 | ip_address = format("10.0.0.%d", 10 + i) 65 | role = i == 1 ? "controlplane" : "worker" 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /network.tf: -------------------------------------------------------------------------------- 1 | resource "oci_core_vcn" "_" { 2 | compartment_id = local.compartment_id 3 | cidr_block = "10.0.0.0/16" 4 | } 5 | 6 | resource "oci_core_internet_gateway" "_" { 7 | compartment_id = local.compartment_id 8 | vcn_id = oci_core_vcn._.id 9 | } 10 | 11 | resource "oci_core_default_route_table" "_" { 12 | manage_default_resource_id = oci_core_vcn._.default_route_table_id 13 | route_rules { 14 | destination = "0.0.0.0/0" 15 | destination_type = "CIDR_BLOCK" 16 | network_entity_id = oci_core_internet_gateway._.id 17 | } 18 | } 19 | 20 | resource "oci_core_default_security_list" "_" { 21 | manage_default_resource_id = oci_core_vcn._.default_security_list_id 22 | ingress_security_rules { 23 | protocol = "all" 24 | source = "0.0.0.0/0" 25 | } 26 | egress_security_rules { 27 | protocol = "all" 28 | destination = "0.0.0.0/0" 29 | } 30 | } 31 | 32 | resource "oci_core_subnet" "_" { 33 | compartment_id = local.compartment_id 34 | cidr_block = "10.0.0.0/24" 35 | vcn_id = oci_core_vcn._.id 36 | route_table_id = oci_core_default_route_table._.id 37 | security_list_ids = [oci_core_default_security_list._.id] 38 | } 39 | -------------------------------------------------------------------------------- /outputs.tf: -------------------------------------------------------------------------------- 1 | output "ssh-with-k8s-user" { 2 | value = format( 3 | "\nssh -o StrictHostKeyChecking=no -i %s -l %s %s\n", 4 | local_file.ssh_private_key.filename, 5 | "k8s", 6 | oci_core_instance._[1].public_ip 7 | ) 8 | } 9 | 10 | output "ssh-with-ubuntu-user" { 11 | value = join( 12 | "\n", 13 | [for i in oci_core_instance._ : 14 | format( 15 | "ssh -o StrictHostKeyChecking=no -l ubuntu -p 22 -i %s %s # %s", 16 | local_file.ssh_private_key.filename, 17 | i.public_ip, 18 | i.display_name 19 | ) 20 | ] 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /providers.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | oci = { 4 | source = "oracle/oci" 5 | version = "4.114.0" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /sshkey.tf: -------------------------------------------------------------------------------- 1 | resource "tls_private_key" "ssh" { 2 | algorithm = "RSA" 3 | rsa_bits = "4096" 4 | } 5 | 6 | resource "local_file" "ssh_private_key" { 7 | content = tls_private_key.ssh.private_key_pem 8 | filename = "id_rsa" 9 | file_permission = "0600" 10 | } 11 | 12 | resource "local_file" "ssh_public_key" { 13 | content = tls_private_key.ssh.public_key_openssh 14 | filename = "id_rsa.pub" 15 | file_permission = "0600" 16 | } 17 | 18 | locals { 19 | authorized_keys = [chomp(tls_private_key.ssh.public_key_openssh)] 20 | } 21 | -------------------------------------------------------------------------------- /variables.tf: -------------------------------------------------------------------------------- 1 | variable "name" { 2 | type = string 3 | default = "kubernetes-on-arm-with-oracle" 4 | } 5 | 6 | /* 7 | Available flex shapes: 8 | "VM.Optimized3.Flex" # Intel Ice Lake 9 | "VM.Standard3.Flex" # Intel Ice Lake 10 | "VM.Standard.A1.Flex" # Ampere Altra 11 | "VM.Standard.E3.Flex" # AMD Rome 12 | "VM.Standard.E4.Flex" # AMD Milan 13 | */ 14 | 15 | variable "shape" { 16 | type = string 17 | default = "VM.Standard.A1.Flex" 18 | } 19 | 20 | variable "how_many_nodes" { 21 | type = number 22 | default = 4 23 | } 24 | 25 | variable "availability_domain" { 26 | type = number 27 | default = 0 28 | } 29 | 30 | variable "ocpus_per_node" { 31 | type = number 32 | default = 1 33 | } 34 | 35 | variable "memory_in_gbs_per_node" { 36 | type = number 37 | default = 6 38 | } 39 | -------------------------------------------------------------------------------- /winInsecureCurl.ps1: -------------------------------------------------------------------------------- 1 | param( 2 | [Parameter()] 3 | [String]$address 4 | ) 5 | $url = "https://$($address):6443" 6 | 7 | add-type @" 8 | using System.Net; 9 | using System.Security.Cryptography.X509Certificates; 10 | public class TrustAllCertsPolicy : ICertificatePolicy { 11 | public bool CheckValidationResult( 12 | ServicePoint srvPoint, X509Certificate certificate, 13 | WebRequest request, int certificateProblem) { 14 | return true; 15 | } 16 | } 17 | "@ 18 | [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy 19 | Start-Sleep -Seconds 5 20 | while ( -not (Invoke-WebRequest $url)){ Start-Sleep -Seconds 1 } 21 | Start-Sleep -Seconds 5 --------------------------------------------------------------------------------