Compare commits

...

85 Commits

Author SHA1 Message Date
daa5fc4171 Merge remote-tracking branch 'upstream/main' 2024-12-02 11:05:29 +01:00
dghubble-renovate[bot]
17060445f7 Bump mkdocs-material from 9.5.45 to v9.5.46 2024-11-29 08:54:47 -08:00
dghubble-renovate[bot]
10dd385c38 Bump registry.k8s.io/coredns/coredns image from v1.11.4 to v1.12.0 2024-11-29 08:54:38 -08:00
Dalton Hubble
bc59d5153e Update Kubernetes from v1.31.2 to v1.31.3
* https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.31.md#v1313
* Update CoreDNS from v1.11.3 to v1.11.4
* Update Cilium from v1.16.3 to v1.16.4
* Plan to drop support for using Calico CNI, recommend everyone use the Cilium default
2024-11-24 08:43:54 -08:00
dghubble-renovate[bot]
cec2a097d4 Bump quay.io/cilium/cilium image from v1.16.3 to v1.16.4 2024-11-24 08:36:50 -08:00
dghubble-renovate[bot]
afbb55b79e Bump quay.io/cilium/operator-generic image from v1.16.3 to v1.16.4 2024-11-24 08:36:46 -08:00
dghubble-renovate[bot]
5cb48f01bd Bump mkdocs-material from 9.5.44 to v9.5.45 2024-11-24 08:36:42 -08:00
Dalton Hubble
dfb307b1a7 Use consistent resources naming btw Azure Flatcar/FCOS
* Fix Azure Public IP name in the Flatcar Linux configuration
2024-11-23 21:20:00 -08:00
dghubble-renovate[bot]
a908d30821 Bump registry.k8s.io/coredns/coredns image from v1.11.3 to v1.11.4 2024-11-14 13:31:17 -08:00
Raimo Radczewski
2b99ccaa39 nginx/bare-metal: fix selector 2024-11-11 10:00:35 -08:00
Raimo Radczewski
93c6c2fed3 nginx: Add endpointslices.discovery.k8s.io to all rbac documents 2024-11-11 10:00:35 -08:00
dghubble-renovate[bot]
93c52df929 Bump mkdocs-material from 9.5.42 to v9.5.44 2024-11-11 09:53:16 -08:00
dghubble-renovate[bot]
ef740832c9 Bump docker.io/flannel/flannel image from v0.26.0 to v0.26.1 2024-11-11 09:41:02 -08:00
dghubble-renovate[bot]
9b28867ea8 Bump pymdown-extensions from 10.11.2 to v10.12 2024-10-30 20:02:18 -07:00
Dalton Hubble
61ffc0bc19
Update Kubernetes from v1.31.1 to v1.31.2
* https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.31.md#v1312
* Update Cilium from v1.16.1 to v1.16.3
* Update flannel from v0.25.6 to v0.26.0
2024-10-26 08:33:43 -07:00
dghubble-renovate[bot]
e143061bcf Bump mkdocs-material from 9.5.39 to v9.5.42 2024-10-26 08:21:10 -07:00
dghubble-renovate[bot]
c3cb5a3f1b Bump quay.io/cilium/cilium image from v1.16.2 to v1.16.3 2024-10-26 08:20:58 -07:00
dghubble-renovate[bot]
81265483c6 Bump quay.io/cilium/operator-generic image from v1.16.2 to v1.16.3 2024-10-26 08:19:17 -07:00
dghubble-renovate[bot]
a4e0ade8d9 Bump docker.io/flannel/flannel image from v0.25.7 to v0.26.0 2024-10-26 08:18:52 -07:00
dghubble-renovate[bot]
3d4905bb3a Bump pymdown-extensions from 10.9 to v10.11.2 2024-10-08 21:33:42 -07:00
jordanp
5932b651e3 doc: set file_permission 0600 for kubeconfig file
It's only documentation, but kubeconfig file contains sensitive info so it's better to secure it a little
2024-10-08 21:33:31 -07:00
Dalton Hubble
6a5b808b17
Add region to gcp instance template resource
* Configure the regional worker instance templates with the
region of the cluster. This defaults to the provider's region
which isn't always what you want and if left off causes an error
* Close #1512
2024-10-08 21:28:29 -07:00
dghubble-renovate[bot]
e6989514a5 Bump mkdocs-material from 9.5.36 to v9.5.39 2024-10-08 21:07:25 -07:00
dghubble-renovate[bot]
edd9328554 Bump quay.io/cilium/cilium image from v1.16.1 to v1.16.2 2024-10-08 21:07:18 -07:00
dghubble-renovate[bot]
8656a2d75b Bump quay.io/cilium/operator-generic image from v1.16.1 to v1.16.2 2024-10-08 21:07:13 -07:00
dghubble-renovate[bot]
16c26f4384 Bump docker.io/flannel/flannel image from v0.25.6 to v0.25.7 2024-10-08 21:07:05 -07:00
dghubble-renovate[bot]
c87c21c7e2 Bump mkdocs-material from 9.5.35 to v9.5.36 2024-09-21 19:31:03 -07:00
Dalton Hubble
598f707cbd
Update Kubernetes from v1.31.0 to v1.31.1
* https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.31.md#v1311
2024-09-20 14:43:39 -07:00
Jordan Pittier
3f844e3c57
google: Add controller_disk_type and worker_disk_type variables (#1513)
* Add controller_disk_type and worker_disk_type variables
* Properly pass disk_type to worker nodes
2024-09-20 14:31:17 -07:00
dghubble-renovate[bot]
b2fad7771f Bump mkdocs from 1.6.0 to v1.6.1 2024-09-20 14:20:43 -07:00
dghubble-renovate[bot]
3ae8794c6c Bump mkdocs-material from 9.5.34 to v9.5.35 2024-09-20 13:06:40 -07:00
dghubble-renovate[bot]
6878fa9fe6 Bump mkdocs-material from 9.5.33 to v9.5.34 2024-09-09 19:55:42 -07:00
dghubble-renovate[bot]
c72e99834c Bump docker.io/flannel/flannel image from v0.25.5 to v0.25.6 2024-08-28 19:45:28 -07:00
Dalton Hubble
7d2d8e16e5
google: Use regional instance templates for workers
* Use regional instance templates for the worker node regional
managed instance groups. Regional instance templates are kept in
the associated region, whereas the older "global" instance templates
were kept in a particular region (regardless of where the MIG region)
so outages in a region X could affect clusters in a region Y which
is undesired
2024-08-27 21:35:02 -07:00
dghubble-renovate[bot]
be9ba51269 Bump mkdocs-material from 9.5.32 to v9.5.33 2024-08-23 21:51:36 -07:00
Dalton Hubble
9a2448f711 Remove upper bound on azurerm provider version
* Allow folks to start upgrading to azurerm provider v4.0.0,
don't set an upper bound on versions going forward
2024-08-23 21:51:29 -07:00
Dalton Hubble
3412060c3c
Use Cilium kube-proxy replacement when Cilium CNI is used
* When using the Cilium component, disable bootstrapping the
kube-proxy DaemonSet. Instead, configure Cilium to provide its
kube-proxy replacement with BPF
* Update the self-managed Cilium component to use kube-proxy
replacement as well
2024-08-23 12:33:32 -07:00
Dalton Hubble
808b8a948f
aws: Switch EC2 instances to use resource-based hostnames
* Use EC2 resource-based hostnames instead of IP-based hostnames. The Amazon
DNS server can resolve A and AAAA queries to IPv4 and IPv6 node addresses
* For example, nodes used to be named like `ip-10-11-12-13.us-east-1.compute.internal`
but going forward use the instance id `i-0123456789abcdef.us-east-1.compute.internal`
* Tag controller node EBS volumes with a name based on the controller node name
2024-08-22 20:02:53 -07:00
Dalton Hubble
effa13c141
Fix flannel-cni container image
* Close #1496
2024-08-22 19:26:19 -07:00
dghubble-renovate[bot]
b8645f3ec2 Bump mkdocs-material from 9.5.31 to v9.5.32 2024-08-22 10:36:50 -07:00
Dalton Hubble
10be34daa2
Update Kubernetes from v1.30.4 to v1.31.0
* https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.31.md#v1310
2024-08-17 08:32:35 -07:00
dghubble-renovate[bot]
1cb49e1267 Bump quay.io/cilium/cilium image from v1.16.0 to v1.16.1 2024-08-16 08:31:11 -07:00
dghubble-renovate[bot]
d79f94f4f5 Bump quay.io/cilium/operator-generic image from v1.16.0 to v1.16.1 2024-08-16 08:31:01 -07:00
Dalton Hubble
320d76c934
Update Kubernetes from v1.30.3 to v1.30.4
* Update Cilium from v1.16.0 to v1.16.1
2024-08-16 08:27:07 -07:00
Dalton Hubble
2daa23be50
Update default Cilium and CoreDNS components
* Update the CoreDNS and Cilium versons used by default when
folks aren't managing the components themselves
2024-08-05 08:47:06 -07:00
Dalton Hubble
6e2daded02
Remove some seldom used variables and set reasonable
* Set reasonable values and remove some variable clutter
* enable_reporting is only used with Calico and we can just default
to false, I doubt anyone uses Calico and cares much about reporting
metrics to upstream Calico
2024-08-02 20:45:37 -07:00
Dalton Hubble
83f1bd2373
Update ARM64 cluster and hybrid cluster docs
* Typhoon now supports arbitrary combinations of controller, worker,
and worker pool architectures so we can drop the specific details of
full-cluster vs hybrid cluster. Just pick the architecture for each
group of nodes accordingly.
* However, if a custom node taint is set, continue to configure the
cluster's daemonsets accordingly with `daemonset_tolerations`
2024-08-02 20:34:23 -07:00
dghubble-renovate[bot]
67e5ecf6f2 Bump mkdocs-material from 9.5.30 to v9.5.31 2024-08-02 16:46:36 -07:00
Dalton Hubble
0120b9f38d
Remove the cluster_domain_suffix variable
* Drop support for `cluster_domain_suffix` customization and
always use `cluster.local`. Many components in the Kubernetes
ecosystem assume this default suffix and its very rare to be
setting a special value here these days
* Cleanup a few variables that are seldom used
2024-08-02 15:05:25 -07:00
Dalton Hubble
af27661432 Configure controller and worker node architecture separately
* On platforms that support ARM64 instances, configure controller
and worker node host architectures separately
* For example, you can run arm64 controllers and amd64 workers
* Add `controller_arch` and `worker_arch` variables
* Remove `arch` variable
2024-08-02 15:04:57 -07:00
Dalton Hubble
516786d7bb
google: Configure controller and worker disk sizes
* Add `controller_disk_size` and `worker_disk_size` variables
* Remove `disk_size` variable
2024-08-02 13:07:41 -07:00
Dalton Hubble
1104b4bf28 AWS: Add CPU pricing mode and controller/worker disk variables
* Add `controller_disk_type`, `controller_disk_size`, and `controller_disk_iops`
variables
* Add `worker_disk_type`, `worker_disk_size`, and `worker_disk_iops` variables
and fix propagation to worker nodes
* Remove `disk_type`, `disk_size`, and `disk_iops` variables
* Add `controller_cpu_credits` and `worker_cpu_credits` variables to set CPU
pricing mode for burstable instance types
2024-07-31 15:02:28 -07:00
dghubble-renovate[bot]
39b5079bc3 Bump registry.k8s.io/coredns/coredns image from v1.11.1 to v1.11.3 2024-07-31 13:28:30 -07:00
dghubble-renovate[bot]
858d665d9b Bump quay.io/cilium/cilium image from v1.15.7 to v1.16.0 2024-07-28 11:59:07 -07:00
dghubble-renovate[bot]
8cea37cdd9 Bump quay.io/cilium/operator-generic image from v1.15.7 to v1.16.0 2024-07-28 11:58:58 -07:00
dghubble-renovate[bot]
4251ca937a Bump pymdown-extensions from 10.8.1 to v10.9 2024-07-28 11:58:50 -07:00
dghubble-renovate[bot]
329987187b Bump mkdocs-material from 9.5.29 to v9.5.30 2024-07-26 09:37:41 -07:00
Dalton Hubble
d046026511
Fix incorrect terraform-render-bootstrap SHA 2024-07-25 21:41:54 -07:00
Dalton Hubble
0669d44026
Update Kubernetes from v1.30.2 to v1.30.3
* Update builtin Cilium manifests from v1.15.6 to v1.15.7
* Update builtin flannel manifests from v0.25.4 to v0.25.5
2024-07-20 11:04:32 -07:00
Dalton Hubble
672bbad10b
Generate Azure Virtual Network IPv6 ULA space at random
* Private IPv6 address space should be assigned randomly within
an organization per https://datatracker.ietf.org/doc/html/rfc4193
2024-07-20 11:01:50 -07:00
dghubble-renovate[bot]
be0e516974 Bump mkdocs-material from 9.5.28 to v9.5.29 2024-07-20 10:44:04 -07:00
dghubble-renovate[bot]
6a61afcd3b Bump docker.io/flannel/flannel image from v0.25.4 to v0.25.5 2024-07-20 10:36:12 -07:00
dghubble-renovate[bot]
ca1f897b35 Bump quay.io/cilium/cilium image from v1.15.6 to v1.15.7 2024-07-14 13:42:35 -07:00
dghubble-renovate[bot]
d4514db00c Bump quay.io/cilium/operator-generic image from v1.15.6 to v1.15.7 2024-07-14 13:42:26 -07:00
Dalton Hubble
0d10d180f8
Change worker node pools from uniform to flexible orchestration mode
* Use flexible orchestration mode. Azure has started to recommend this
mode because it allows interacting with VMSS instances like regular VMs
via the CLI or via the Azure Portal
* Add options to allow workers nodes to use ephemeral local disks
  * Add `controller_disk_type` and `controller_disk_size` variables
  * Add `worker_disk_type`, `worker_disk_size`, and `worker_ephemeral_disk` variables
2024-07-14 11:58:15 -07:00
Dalton Hubble
a4fab61066
Remove an IPv4 address from Azure clusters
* Consolidate load balancer frontend IPs to just the minimal IPv4
and IPv6 addresses that are needed per load balancer. apiserver and
ingress use separate ports, so there is not a true need for a separate
public IPv4 address just for apiserver
* Some might prefer a separate IP just because it slightly hides the
apiserver, but these are public hosted endpoints that can be discovered
* Reduce the cost of an Azure cluster since IPv4 public IPs are billed
($3.60/mo/cluster)
2024-07-10 22:29:43 -07:00
Dalton Hubble
24b7f31c55
Rename Azure cluster region variable to location
* Rename the region variable to location to align with Azure
platform conventions, where resources are created within an
Azure location, which are themselves part of broader geographical
regions
2024-07-09 07:56:58 -07:00
Dalton Hubble
48d4973957
Add IPv6 support for Typhoon Azure clusters
* Define a dual-stack virtual network with both IPv4 and IPv6 private
address space. Change `host_cidr` variable (string) to a `network_cidr`
variable (object) with "ipv4" and "ipv6" fields that list CIDR strings.
* Define dual-stack controller and worker subnets. Disable Azure
default outbound access (a deprecated fallback mechanism)
* Enable dual-stack load balancing to Kubernetes Ingress by adding
a public IPv6 frontend IP and LB rule to the load balancer.
* Enable worker outbound IPv6 connectivity through load balancer
SNAT by adding an IPv6 frontend IP and outbound rule
* Configure controller nodes with a public IPv6 address to provide
direct outbound IPv6 connectivity
* Add an IPv6 worker backend pool. Azure requires separate IPv4 and
IPv6 backend pools, though the health probe can be shared
* Extend network security group rules for IPv6 source/destinations

Checklist:

Access to controller and worker nodes via IPv6 addresses:

  * SSH access to controller nodes via public IPv6 address
  * SSH access to worker nodes via (private) IPv6 address (via
    controller)

Outbound IPv6 connectivity from controller and worker nodes:

```
nc -6 -zv ipv6.google.com 80
Ncat: Version 7.94 ( https://nmap.org/ncat )
Ncat: Connected to [2607:f8b0:4001:c16::66]:80.
Ncat: 0 bytes sent, 0 bytes received in 0.02 seconds.
```

Serve Ingress traffic via IPv4 or IPv6 just requires setting
up A and AAAA records and running the ingress controller with
`hostNetwork: true` since, hostPort only forwards IPv4 traffic
2024-07-09 07:55:00 -07:00
dghubble-renovate[bot]
3483ed8bd5 Bump mkdocs-material from 9.5.27 to v9.5.28 2024-07-03 22:23:23 -07:00
Dalton Hubble
931d6d18de
Update Kubernetes from v1.30.1 to v1.30.2
* Update CoreDNS from v1.9.4 to v1.11.1
* Update Cilium from v1.15.5 to v1.15.6
* Update flannel from v0.25.1 to v0.25.4
2024-06-17 08:20:03 -07:00
dghubble-renovate[bot]
da99a01f43 Bump mkdocs-material from 9.5.26 to v9.5.27 2024-06-16 16:57:27 -07:00
dghubble-renovate[bot]
5090e60fe0 Bump quay.io/cilium/operator-generic image from v1.15.5 to v1.15.6 2024-06-15 08:01:29 -07:00
dghubble-renovate[bot]
158a681a8b Bump quay.io/cilium/cilium image from v1.15.5 to v1.15.6 2024-06-15 08:00:23 -07:00
dghubble-renovate[bot]
8fd2c95cec Bump docker.io/flannel/flannel image from v0.25.3 to v0.25.4 2024-06-15 07:55:44 -07:00
dghubble-renovate[bot]
9be5250a71 Bump mkdocs-material from 9.5.25 to v9.5.26 2024-06-09 15:58:05 -07:00
dghubble-renovate[bot]
d6e4f49cd9 Bump docker.io/flannel/flannel image from v0.25.2 to v0.25.3 2024-05-31 17:13:30 -07:00
dghubble-renovate[bot]
2d020a2ce3 Bump mkdocs-material from 9.5.24 to v9.5.25 2024-05-27 07:43:40 -07:00
dghubble-renovate[bot]
e942ae9f4a Bump docker.io/flannel/flannel image from v0.25.1 to v0.25.2 2024-05-26 12:45:03 -07:00
dghubble-renovate[bot]
fa8f3d81b4 Bump mkdocs-material from 9.5.23 to v9.5.24 2024-05-26 12:23:13 -07:00
516517fafe Merge remote-tracking branch 'upstream/main' 2023-11-02 11:56:22 +01:00
21f7142464 Merge remote-tracking branch 'upstream/main' 2023-10-20 14:00:37 +02:00
73e7448f53 Merge remote-tracking branch 'upstream/main' 2023-10-11 13:31:16 +02:00
27cecd0f94 fix typo in variable name 2023-08-03 14:26:39 +02:00
634deaf92e Adding install_snippets support.
During the "real" first boot (install boot), we need tu run butane
config to manipulate disks, so we add install_snippets variable to do
so.

This snippets are added to the install.yaml butane configuration
2023-08-03 14:16:24 +02:00
cd699ee1aa Update docs on flatcar-linux bare-metal kubernetes worker module usage. 2023-08-02 12:07:53 +02:00
138 changed files with 2374 additions and 1785 deletions

View File

@ -4,6 +4,147 @@ Notable changes between versions.
## Latest ## Latest
## v1.31.3
* Kubernetes [v1.31.2](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.31.md#v1312)
* Update CoreDNS from v1.11.3 to v1.11.4
* Update Cilium from v1.16.3 to [v1.16.4](https://github.com/cilium/cilium/releases/tag/v1.16.4)
### Deprecations
* Plan to drop support for using Calico CNI, recommend everyone use the Cilium default
## v1.31.2
* Kubernetes [v1.31.2](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.31.md#v1312)
* Update Cilium from v1.16.1 to [v1.16.3](https://github.com/cilium/cilium/releases/tag/v1.16.3)
* Update flannel from v0.25.6 to [v0.26.0](https://github.com/flannel-io/flannel/releases/tag/v0.26.0)
## v1.31.1
* Kubernetes [v1.31.1](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.31.md#v1311)
* Update flannel from v0.25.5 to [v0.25.6](https://github.com/flannel-io/flannel/releases/tag/v0.25.6)
### Google
* Add `controller_disk_type` and `worker_disk_type` variables ([#1513](https://github.com/poseidon/typhoon/pull/1513))
* Add explicit `region` field to regional worker instance templates ([#1524](https://github.com/poseidon/typhoon/pull/1524))
## v1.31.0
* Kubernetes [v1.31.0](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.31.md#v1310)
* Use Cilium kube-proxy replacement mode when `cilium` networking is chosen ([#1501](https://github.com/poseidon/typhoon/pull/1501))
* Fix invalid flannel-cni container image for those using `flannel` networking ([#1497](https://github.com/poseidon/typhoon/pull/1497))
### AWS
* Use EC2 resource-based hostnames instead of IP-based hostnames ([#1499](https://github.com/poseidon/typhoon/pull/1499))
* The Amazon DNS server can resolve A and AAAA queries to IPv4 and IPv6 node addresses
* Tag controller node EBS volumes with a name based on the controller node name
### Google
* Use `google_compute_region_instance_template` instead of `google_compute_instance_template`
* Google's regional instance template metadata is kept in the associated region for greater resiliency. The "global" instance templates were kept in a single region
## v1.30.4
* Kubernetes [v1.30.4](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.30.md#v1304)
* Update Cilium from v1.15.7 to [v1.16.1](https://github.com/cilium/cilium/releases/tag/v1.16.1)
* Update CoreDNS from v1.11.1 to v1.11.3
* Remove `enable_aggregation` variable for Kubernetes Aggregation Layer, always set to true
* Remove `cluster_domain_suffix` variable, always use "cluster.local"
* Remove `enable_reporting` variable for analytics, always set to false
## v1.30.3
* Kubernetes [v1.30.3](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.30.md#v1303)
* Update Cilium from v1.15.6 to [v1.15.7](https://github.com/cilium/cilium/releases/tag/v1.15.7)
* Update flannel from v0.25.4 to [v0.25.5](https://github.com/flannel-io/flannel/releases/tag/v0.25.5)
### AWS
* Configure controller and worker disks ([#1482](https://github.com/poseidon/typhoon/pull/1482))
* Add `controller_disk_type`, `controller_disk_size`, and `controller_disk_iops` variables
* Add `worker_disk_type`, `worker_disk_size`, and `worker_disk_iops` variables
* Remove `disk_type`, `disk_size`, and `disk_iops` variables
* Fix propagating settings to worker disks, previously ignored
* Configure CPU pricing model for burstable instance types ([#1482](https://github.com/poseidon/typhoon/pull/1482))
* Add `controller_cpu_credits` and `worker_cpu_credits` variables (`standard` or `unlimited`)
* Configure controller or worker instance architecture ([#1485](https://github.com/poseidon/typhoon/pull/1485))
* Add `controller_arch` and `worker_arch` variables (`amd64` or `arm64`)
* Remove `arch` variable
```diff
module "cluster" {
...
- arch = "amd64"
- disk_type = "gp3"
- disk_size = 30
- disk_iops = 3000
+ controller_arch = "amd64"
+ controller_disk_size = 15
+ controller_cpu_credits = "standard"
+ worker_arch = "amd64"
+ worker_disk_size = 22
+ worker_cpu_credits = "unlimited"
}
```
### Azure
* Configure the virtual network and subnets with IPv6 private address space
* Change `host_cidr` variable (string) to a `network_cidr` object with `ipv4` and `ipv6` fields that list CIDR strings. Leave the variable unset to use the defaults. (**breaking**)
* Add support for dual-stack Kubernetes Ingress Load Balancing
* Add a public IPv6 frontend, 80/443 rules, and a worker-ipv6 backend pool
* Change the `controller_address_prefixes` output from a list of strings to an object with `ipv4` and `ipv6` fields. Most Azure resources can't accept a mix, so these are split out (**breaking**)
* Change the `worker_address_prefixes` output from a list of strings to an object with `ipv4` and `ipv6` fields. Most Azure resources can't accept a mix, so these are split out (**breaking**)
* Change the `backend_address_pool_id` output (and worker module input) from a string to an object with `ipv4` and `ipv6` fields that list ids (**breaking**)
* Configure nodes to have outbound IPv6 internet connectivity (analogous to IPv4 SNAT)
* Configure controller nodes to have a public IPv6 address
* Configure worker nodes to use outbound rules and the load balancer for SNAT
* Extend network security rules to allow IPv6 traffic, analogous to IPv4
* Rename `region` variable to `location` to align with Azure platform conventions ([#1469](https://github.com/poseidon/typhoon/pull/1469))
* Change worker pools from uniform to flexible orchestration mode ([#1473](https://github.com/poseidon/typhoon/pull/1473))
* Add options to allow workers nodes to use ephemeral local disks ([#1473](https://github.com/poseidon/typhoon/pull/1473))
* Add `controller_disk_type` and `controller_disk_size` variables
* Add `worker_disk_type`, `worker_disk_size`, and `worker_ephemeral_disk` variables
* Reduce the number of public IPv4 addresses needed for the Azure load balancer ([#1470](https://github.com/poseidon/typhoon/pull/1470))
* Configure controller or worker instance architecture for Flatcar Linux ([#1485](https://github.com/poseidon/typhoon/pull/1485))
* Add `controller_arch` and `worker_arch` variables (`amd64` or `arm64`)
* Remove `arch` variable
```diff
module "cluster" {
...
- region = "centralus"
+ location = "centralus"
# optional
- host_cidr = "10.0.0.0/16"
+ network_cidr = {
+ ipv4 = ["10.0.0.0/16"]
+ }
# instances
+ controller_disk_type = "StandardSSD_LRS"
+ worker_ephemeral_disk = true
}
```
### Google Cloud
* Allow configuring controller and worker disks ([#1486](https://github.com/poseidon/typhoon/pull/1486))
* Add `controller_disk_size` and `worker_disk_size` variables
* Remove `disk_size` variable
## v1.30.2
* Kubernetes [v1.30.2](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.30.md#v1302)
* Update CoreDNS from v1.9.4 to v1.11.1
* Update Cilium from v1.15.5 to [v1.15.6](https://github.com/cilium/cilium/releases/tag/v1.15.6)
* Update flannel from v0.25.1 to [v0.25.4](https://github.com/flannel-io/flannel/releases/tag/v0.25.4)
## v1.30.1 ## v1.30.1
* Kubernetes [v1.30.1](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.30.md#v1301) * Kubernetes [v1.30.1](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.30.md#v1301)

View File

@ -18,7 +18,7 @@ Typhoon distributes upstream Kubernetes, architectural conventions, and cluster
## Features <a href="https://www.cncf.io/certification/software-conformance/"><img align="right" src="https://storage.googleapis.com/poseidon/certified-kubernetes.png"></a> ## Features <a href="https://www.cncf.io/certification/software-conformance/"><img align="right" src="https://storage.googleapis.com/poseidon/certified-kubernetes.png"></a>
* Kubernetes v1.30.1 (upstream) * Kubernetes v1.31.3 (upstream)
* Single or multi-master, [Calico](https://www.projectcalico.org/) or [Cilium](https://github.com/cilium/cilium) or [flannel](https://github.com/coreos/flannel) networking * Single or multi-master, [Calico](https://www.projectcalico.org/) or [Cilium](https://github.com/cilium/cilium) or [flannel](https://github.com/coreos/flannel) networking
* On-cluster etcd with TLS, [RBAC](https://kubernetes.io/docs/admin/authorization/rbac/)-enabled, [network policy](https://kubernetes.io/docs/concepts/services-networking/network-policies/), SELinux enforcing * On-cluster etcd with TLS, [RBAC](https://kubernetes.io/docs/admin/authorization/rbac/)-enabled, [network policy](https://kubernetes.io/docs/concepts/services-networking/network-policies/), SELinux enforcing
* Advanced features like [worker pools](https://typhoon.psdn.io/advanced/worker-pools/), [preemptible](https://typhoon.psdn.io/flatcar-linux/google-cloud/#preemption) workers, and [snippets](https://typhoon.psdn.io/advanced/customization/#hosts) customization * Advanced features like [worker pools](https://typhoon.psdn.io/advanced/worker-pools/), [preemptible](https://typhoon.psdn.io/flatcar-linux/google-cloud/#preemption) workers, and [snippets](https://typhoon.psdn.io/advanced/customization/#hosts) customization
@ -78,7 +78,7 @@ Define a Kubernetes cluster by using the Terraform module for your chosen platfo
```tf ```tf
module "yavin" { module "yavin" {
source = "git::https://github.com/poseidon/typhoon//google-cloud/fedora-coreos/kubernetes?ref=v1.30.1" source = "git::https://github.com/poseidon/typhoon//google-cloud/fedora-coreos/kubernetes?ref=v1.31.3"
# Google Cloud # Google Cloud
cluster_name = "yavin" cluster_name = "yavin"
@ -98,6 +98,7 @@ module "yavin" {
resource "local_file" "kubeconfig-yavin" { resource "local_file" "kubeconfig-yavin" {
content = module.yavin.kubeconfig-admin content = module.yavin.kubeconfig-admin
filename = "/home/user/.kube/configs/yavin-config" filename = "/home/user/.kube/configs/yavin-config"
file_permission = "0600"
} }
``` ```
@ -117,9 +118,9 @@ In 4-8 minutes (varies by platform), the cluster will be ready. This Google Clou
$ export KUBECONFIG=/home/user/.kube/configs/yavin-config $ export KUBECONFIG=/home/user/.kube/configs/yavin-config
$ kubectl get nodes $ kubectl get nodes
NAME ROLES STATUS AGE VERSION NAME ROLES STATUS AGE VERSION
yavin-controller-0.c.example-com.internal <none> Ready 6m v1.30.1 yavin-controller-0.c.example-com.internal <none> Ready 6m v1.31.3
yavin-worker-jrbf.c.example-com.internal <none> Ready 5m v1.30.1 yavin-worker-jrbf.c.example-com.internal <none> Ready 5m v1.31.3
yavin-worker-mzdm.c.example-com.internal <none> Ready 5m v1.30.1 yavin-worker-mzdm.c.example-com.internal <none> Ready 5m v1.31.3
``` ```
List the pods. List the pods.
@ -127,9 +128,10 @@ List the pods.
``` ```
$ kubectl get pods --all-namespaces $ kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system calico-node-1cs8z 2/2 Running 0 6m kube-system cilium-1cs8z 1/1 Running 0 6m
kube-system calico-node-d1l5b 2/2 Running 0 6m kube-system cilium-d1l5b 1/1 Running 0 6m
kube-system calico-node-sp9ps 2/2 Running 0 6m kube-system cilium-sp9ps 1/1 Running 0 6m
kube-system cilium-operator-68d778b448-g744f 1/1 Running 0 6m
kube-system coredns-1187388186-zj5dl 1/1 Running 0 6m kube-system coredns-1187388186-zj5dl 1/1 Running 0 6m
kube-system coredns-1187388186-dkh3o 1/1 Running 0 6m kube-system coredns-1187388186-dkh3o 1/1 Running 0 6m
kube-system kube-apiserver-controller-0 1/1 Running 0 6m kube-system kube-apiserver-controller-0 1/1 Running 0 6m

View File

@ -128,8 +128,8 @@ resource "kubernetes_config_map" "cilium" {
enable-bpf-masquerade = "true" enable-bpf-masquerade = "true"
# kube-proxy # kube-proxy
kube-proxy-replacement = "false" kube-proxy-replacement = "true"
kube-proxy-replacement-healthz-bind-address = "" kube-proxy-replacement-healthz-bind-address = ":10256"
enable-session-affinity = "true" enable-session-affinity = "true"
# ClusterIPs from host namespace # ClusterIPs from host namespace

View File

@ -61,7 +61,7 @@ resource "kubernetes_daemonset" "cilium" {
# https://github.com/cilium/cilium/pull/24075 # https://github.com/cilium/cilium/pull/24075
init_container { init_container {
name = "install-cni" name = "install-cni"
image = "quay.io/cilium/cilium:v1.15.5" image = "quay.io/cilium/cilium:v1.16.4"
command = ["/install-plugin.sh"] command = ["/install-plugin.sh"]
security_context { security_context {
allow_privilege_escalation = true allow_privilege_escalation = true
@ -80,7 +80,7 @@ resource "kubernetes_daemonset" "cilium" {
# We use nsenter command with host's cgroup and mount namespaces enabled. # We use nsenter command with host's cgroup and mount namespaces enabled.
init_container { init_container {
name = "mount-cgroup" name = "mount-cgroup"
image = "quay.io/cilium/cilium:v1.15.5" image = "quay.io/cilium/cilium:v1.16.4"
command = [ command = [
"sh", "sh",
"-ec", "-ec",
@ -115,7 +115,7 @@ resource "kubernetes_daemonset" "cilium" {
init_container { init_container {
name = "clean-cilium-state" name = "clean-cilium-state"
image = "quay.io/cilium/cilium:v1.15.5" image = "quay.io/cilium/cilium:v1.16.4"
command = ["/init-container.sh"] command = ["/init-container.sh"]
security_context { security_context {
allow_privilege_escalation = true allow_privilege_escalation = true
@ -139,7 +139,7 @@ resource "kubernetes_daemonset" "cilium" {
container { container {
name = "cilium-agent" name = "cilium-agent"
image = "quay.io/cilium/cilium:v1.15.5" image = "quay.io/cilium/cilium:v1.16.4"
command = ["cilium-agent"] command = ["cilium-agent"]
args = [ args = [
"--config-dir=/tmp/cilium/config-map" "--config-dir=/tmp/cilium/config-map"

View File

@ -58,7 +58,7 @@ resource "kubernetes_deployment" "operator" {
enable_service_links = false enable_service_links = false
container { container {
name = "cilium-operator" name = "cilium-operator"
image = "quay.io/cilium/operator-generic:v1.15.5" image = "quay.io/cilium/operator-generic:v1.16.4"
command = ["cilium-operator-generic"] command = ["cilium-operator-generic"]
args = [ args = [
"--config-dir=/tmp/cilium/config-map", "--config-dir=/tmp/cilium/config-map",

View File

@ -77,7 +77,7 @@ resource "kubernetes_deployment" "coredns" {
} }
container { container {
name = "coredns" name = "coredns"
image = "registry.k8s.io/coredns/coredns:v1.11.1" image = "registry.k8s.io/coredns/coredns:v1.12.0"
args = ["-conf", "/etc/coredns/Corefile"] args = ["-conf", "/etc/coredns/Corefile"]
port { port {
name = "dns" name = "dns"

View File

@ -73,7 +73,7 @@ resource "kubernetes_daemonset" "flannel" {
container { container {
name = "flannel" name = "flannel"
image = "docker.io/flannel/flannel:v0.25.1" image = "docker.io/flannel/flannel:v0.26.1"
command = [ command = [
"/opt/bin/flanneld", "/opt/bin/flanneld",
"--ip-masq", "--ip-masq",

View File

@ -59,4 +59,11 @@ rules:
- get - get
- list - list
- watch - watch
- apiGroups:
- discovery.k8s.io
resources:
- "endpointslices"
verbs:
- get
- list
- watch

View File

@ -59,4 +59,11 @@ rules:
- get - get
- list - list
- watch - watch
- apiGroups:
- discovery.k8s.io
resources:
- "endpointslices"
verbs:
- get
- list
- watch

View File

@ -59,4 +59,11 @@ rules:
- get - get
- list - list
- watch - watch
- apiGroups:
- discovery.k8s.io
resources:
- "endpointslices"
verbs:
- get
- list
- watch

View File

@ -1,7 +1,7 @@
apiVersion: v1 apiVersion: v1
kind: Service kind: Service
metadata: metadata:
name: ingress-controller-public name: nginx-ingress-controller
namespace: ingress namespace: ingress
annotations: annotations:
prometheus.io/scrape: 'true' prometheus.io/scrape: 'true'
@ -10,7 +10,7 @@ spec:
type: ClusterIP type: ClusterIP
clusterIP: 10.3.0.12 clusterIP: 10.3.0.12
selector: selector:
name: ingress-controller-public name: nginx-ingress-controller
phase: prod phase: prod
ports: ports:
- name: http - name: http

View File

@ -59,4 +59,11 @@ rules:
- get - get
- list - list
- watch - watch
- apiGroups:
- discovery.k8s.io
resources:
- "endpointslices"
verbs:
- get
- list
- watch

View File

@ -11,7 +11,7 @@ Typhoon distributes upstream Kubernetes, architectural conventions, and cluster
## Features <a href="https://www.cncf.io/certification/software-conformance/"><img align="right" src="https://storage.googleapis.com/poseidon/certified-kubernetes.png"></a> ## Features <a href="https://www.cncf.io/certification/software-conformance/"><img align="right" src="https://storage.googleapis.com/poseidon/certified-kubernetes.png"></a>
* Kubernetes v1.30.1 (upstream) * Kubernetes v1.31.3 (upstream)
* Single or multi-master, [Calico](https://www.projectcalico.org/) or [Cilium](https://github.com/cilium/cilium) or [flannel](https://github.com/coreos/flannel) networking * Single or multi-master, [Calico](https://www.projectcalico.org/) or [Cilium](https://github.com/cilium/cilium) or [flannel](https://github.com/coreos/flannel) networking
* On-cluster etcd with TLS, [RBAC](https://kubernetes.io/docs/admin/authorization/rbac/)-enabled, [network policy](https://kubernetes.io/docs/concepts/services-networking/network-policies/), SELinux enforcing * On-cluster etcd with TLS, [RBAC](https://kubernetes.io/docs/admin/authorization/rbac/)-enabled, [network policy](https://kubernetes.io/docs/concepts/services-networking/network-policies/), SELinux enforcing
* Advanced features like [worker pools](https://typhoon.psdn.io/advanced/worker-pools/), [spot](https://typhoon.psdn.io/fedora-coreos/aws/#spot) workers, and [snippets](https://typhoon.psdn.io/advanced/customization/#hosts) customization * Advanced features like [worker pools](https://typhoon.psdn.io/advanced/worker-pools/), [spot](https://typhoon.psdn.io/fedora-coreos/aws/#spot) workers, and [snippets](https://typhoon.psdn.io/advanced/customization/#hosts) customization

View File

@ -19,7 +19,7 @@ data "aws_ami" "fedora-coreos" {
} }
data "aws_ami" "fedora-coreos-arm" { data "aws_ami" "fedora-coreos-arm" {
count = var.arch == "arm64" ? 1 : 0 count = var.controller_arch == "arm64" ? 1 : 0
most_recent = true most_recent = true
owners = ["125523088429"] owners = ["125523088429"]

View File

@ -1,6 +1,6 @@
# Kubernetes assets (kubeconfig, manifests) # Kubernetes assets (kubeconfig, manifests)
module "bootstrap" { module "bootstrap" {
source = "git::https://github.com/poseidon/terraform-render-bootstrap.git?ref=e1b1e0c75e77e042cf369f463f0e656297a201a8" source = "git::https://github.com/poseidon/terraform-render-bootstrap.git?ref=e6a1c7bccfc45ab299b5f8149bc3840f99b30b2b"
cluster_name = var.cluster_name cluster_name = var.cluster_name
api_servers = [format("%s.%s", var.cluster_name, var.dns_zone)] api_servers = [format("%s.%s", var.cluster_name, var.dns_zone)]
@ -9,9 +9,6 @@ module "bootstrap" {
network_mtu = var.network_mtu network_mtu = var.network_mtu
pod_cidr = var.pod_cidr pod_cidr = var.pod_cidr
service_cidr = var.service_cidr service_cidr = var.service_cidr
cluster_domain_suffix = var.cluster_domain_suffix
enable_reporting = var.enable_reporting
enable_aggregation = var.enable_aggregation
daemonset_tolerations = var.daemonset_tolerations daemonset_tolerations = var.daemonset_tolerations
components = var.components components = var.components
} }

View File

@ -57,7 +57,7 @@ systemd:
After=afterburn.service After=afterburn.service
Wants=rpc-statd.service Wants=rpc-statd.service
[Service] [Service]
Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.30.1 Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.31.3
EnvironmentFile=/run/metadata/afterburn EnvironmentFile=/run/metadata/afterburn
ExecStartPre=/bin/mkdir -p /etc/cni/net.d ExecStartPre=/bin/mkdir -p /etc/cni/net.d
ExecStartPre=/bin/mkdir -p /etc/kubernetes/manifests ExecStartPre=/bin/mkdir -p /etc/kubernetes/manifests
@ -116,7 +116,7 @@ systemd:
--volume /opt/bootstrap/assets:/assets:ro,Z \ --volume /opt/bootstrap/assets:/assets:ro,Z \
--volume /opt/bootstrap/apply:/apply:ro,Z \ --volume /opt/bootstrap/apply:/apply:ro,Z \
--entrypoint=/apply \ --entrypoint=/apply \
quay.io/poseidon/kubelet:v1.30.1 quay.io/poseidon/kubelet:v1.31.3
ExecStartPost=/bin/touch /opt/bootstrap/bootstrap.done ExecStartPost=/bin/touch /opt/bootstrap/bootstrap.done
ExecStartPost=-/usr/bin/podman stop bootstrap ExecStartPost=-/usr/bin/podman stop bootstrap
storage: storage:
@ -149,7 +149,7 @@ storage:
cgroupDriver: systemd cgroupDriver: systemd
clusterDNS: clusterDNS:
- ${cluster_dns_service_ip} - ${cluster_dns_service_ip}
clusterDomain: ${cluster_domain_suffix} clusterDomain: cluster.local
healthzPort: 0 healthzPort: 0
rotateCertificates: true rotateCertificates: true
shutdownGracePeriod: 45s shutdownGracePeriod: 45s

View File

@ -20,18 +20,18 @@ resource "aws_instance" "controllers" {
tags = { tags = {
Name = "${var.cluster_name}-controller-${count.index}" Name = "${var.cluster_name}-controller-${count.index}"
} }
instance_type = var.controller_type instance_type = var.controller_type
ami = var.arch == "arm64" ? data.aws_ami.fedora-coreos-arm[0].image_id : data.aws_ami.fedora-coreos.image_id ami = var.controller_arch == "arm64" ? data.aws_ami.fedora-coreos-arm[0].image_id : data.aws_ami.fedora-coreos.image_id
user_data = data.ct_config.controllers.*.rendered[count.index]
# storage # storage
root_block_device { root_block_device {
volume_type = var.disk_type volume_type = var.controller_disk_type
volume_size = var.disk_size volume_size = var.controller_disk_size
iops = var.disk_iops iops = var.controller_disk_iops
encrypted = true encrypted = true
tags = {} tags = {
Name = "${var.cluster_name}-controller-${count.index}"
}
} }
# network # network
@ -39,6 +39,14 @@ resource "aws_instance" "controllers" {
subnet_id = element(aws_subnet.public.*.id, count.index) subnet_id = element(aws_subnet.public.*.id, count.index)
vpc_security_group_ids = [aws_security_group.controller.id] vpc_security_group_ids = [aws_security_group.controller.id]
# boot
user_data = data.ct_config.controllers.*.rendered[count.index]
# cost
credit_specification {
cpu_credits = var.controller_cpu_credits
}
lifecycle { lifecycle {
ignore_changes = [ ignore_changes = [
ami, ami,
@ -61,7 +69,6 @@ data "ct_config" "controllers" {
kubeconfig = indent(10, module.bootstrap.kubeconfig-kubelet) kubeconfig = indent(10, module.bootstrap.kubeconfig-kubelet)
ssh_authorized_key = var.ssh_authorized_key ssh_authorized_key = var.ssh_authorized_key
cluster_dns_service_ip = cidrhost(var.service_cidr, 10) cluster_dns_service_ip = cidrhost(var.service_cidr, 10)
cluster_domain_suffix = var.cluster_domain_suffix
}) })
strict = true strict = true
snippets = var.controller_snippets snippets = var.controller_snippets

View File

@ -47,17 +47,25 @@ resource "aws_route" "egress-ipv6" {
resource "aws_subnet" "public" { resource "aws_subnet" "public" {
count = length(data.aws_availability_zones.all.names) count = length(data.aws_availability_zones.all.names)
vpc_id = aws_vpc.network.id
availability_zone = data.aws_availability_zones.all.names[count.index]
cidr_block = cidrsubnet(var.host_cidr, 4, count.index)
ipv6_cidr_block = cidrsubnet(aws_vpc.network.ipv6_cidr_block, 8, count.index)
map_public_ip_on_launch = true
assign_ipv6_address_on_creation = true
tags = { tags = {
"Name" = "${var.cluster_name}-public-${count.index}" "Name" = "${var.cluster_name}-public-${count.index}"
} }
vpc_id = aws_vpc.network.id
availability_zone = data.aws_availability_zones.all.names[count.index]
# IPv4 and IPv6 CIDR blocks
cidr_block = cidrsubnet(var.host_cidr, 4, count.index)
ipv6_cidr_block = cidrsubnet(aws_vpc.network.ipv6_cidr_block, 8, count.index)
# Assign IPv4 and IPv6 addresses to instances
map_public_ip_on_launch = true
assign_ipv6_address_on_creation = true
# Hostnames assigned to instances
# resource-name: <ec2-instance-id>.region.compute.internal
private_dns_hostname_type_on_launch = "resource-name"
enable_resource_name_dns_a_record_on_launch = true
enable_resource_name_dns_aaaa_record_on_launch = true
} }
resource "aws_route_table_association" "public" { resource "aws_route_table_association" "public" {

View File

@ -17,30 +17,6 @@ variable "dns_zone_id" {
# instances # instances
variable "controller_count" {
type = number
description = "Number of controllers (i.e. masters)"
default = 1
}
variable "worker_count" {
type = number
description = "Number of workers"
default = 1
}
variable "controller_type" {
type = string
description = "EC2 instance type for controllers"
default = "t3.small"
}
variable "worker_type" {
type = string
description = "EC2 instance type for workers"
default = "t3.small"
}
variable "os_stream" { variable "os_stream" {
type = string type = string
description = "Fedora CoreOS image stream for instances (e.g. stable, testing, next)" description = "Fedora CoreOS image stream for instances (e.g. stable, testing, next)"
@ -52,24 +28,78 @@ variable "os_stream" {
} }
} }
variable "disk_size" { variable "controller_count" {
type = number
description = "Number of controllers (i.e. masters)"
default = 1
}
variable "controller_type" {
type = string
description = "EC2 instance type for controllers"
default = "t3.small"
}
variable "controller_disk_size" {
type = number type = number
description = "Size of the EBS volume in GB" description = "Size of the EBS volume in GB"
default = 30 default = 30
} }
variable "disk_type" { variable "controller_disk_type" {
type = string type = string
description = "Type of the EBS volume (e.g. standard, gp2, gp3, io1)" description = "Type of the EBS volume (e.g. standard, gp2, gp3, io1)"
default = "gp3" default = "gp3"
} }
variable "disk_iops" { variable "controller_disk_iops" {
type = number type = number
description = "IOPS of the EBS volume (e.g. 3000)" description = "IOPS of the EBS volume (e.g. 3000)"
default = 3000 default = 3000
} }
variable "controller_cpu_credits" {
type = string
description = "CPU credits mode (if using a burstable instance type)"
default = null
}
variable "worker_count" {
type = number
description = "Number of workers"
default = 1
}
variable "worker_type" {
type = string
description = "EC2 instance type for workers"
default = "t3.small"
}
variable "worker_disk_size" {
type = number
description = "Size of the EBS volume in GB"
default = 30
}
variable "worker_disk_type" {
type = string
description = "Type of the EBS volume (e.g. standard, gp2, gp3, io1)"
default = "gp3"
}
variable "worker_disk_iops" {
type = number
description = "IOPS of the EBS volume (e.g. 3000)"
default = 3000
}
variable "worker_cpu_credits" {
type = string
description = "CPU credits mode (if using a burstable instance type)"
default = null
}
variable "worker_price" { variable "worker_price" {
type = number type = number
description = "Spot price in USD for worker instances or 0 to use on-demand instances" description = "Spot price in USD for worker instances or 0 to use on-demand instances"
@ -134,40 +164,31 @@ EOD
default = "10.3.0.0/16" default = "10.3.0.0/16"
} }
variable "enable_reporting" {
type = bool
description = "Enable usage or analytics reporting to upstreams (Calico)"
default = false
}
variable "enable_aggregation" {
type = bool
description = "Enable the Kubernetes Aggregation Layer"
default = true
}
variable "worker_node_labels" { variable "worker_node_labels" {
type = list(string) type = list(string)
description = "List of initial worker node labels" description = "List of initial worker node labels"
default = [] default = []
} }
# unofficial, undocumented, unsupported # advanced
variable "cluster_domain_suffix" { variable "controller_arch" {
type = string type = string
description = "Queries for domains with the suffix will be answered by CoreDNS. Default is cluster.local (e.g. foo.default.svc.cluster.local)" description = "Controller node(s) architecture (amd64 or arm64)"
default = "cluster.local" default = "amd64"
validation {
condition = contains(["amd64", "arm64"], var.controller_arch)
error_message = "The controller_arch must be amd64 or arm64."
}
} }
variable "arch" { variable "worker_arch" {
type = string type = string
description = "Container architecture (amd64 or arm64)" description = "Worker node(s) architecture (amd64 or arm64)"
default = "amd64" default = "amd64"
validation { validation {
condition = var.arch == "amd64" || var.arch == "arm64" condition = contains(["amd64", "arm64"], var.worker_arch)
error_message = "The arch must be amd64 or arm64." error_message = "The worker_arch must be amd64 or arm64."
} }
} }

View File

@ -6,11 +6,16 @@ module "workers" {
vpc_id = aws_vpc.network.id vpc_id = aws_vpc.network.id
subnet_ids = aws_subnet.public.*.id subnet_ids = aws_subnet.public.*.id
security_groups = [aws_security_group.worker.id] security_groups = [aws_security_group.worker.id]
# instances
os_stream = var.os_stream
worker_count = var.worker_count worker_count = var.worker_count
instance_type = var.worker_type instance_type = var.worker_type
os_stream = var.os_stream arch = var.worker_arch
arch = var.arch disk_type = var.worker_disk_type
disk_size = var.disk_size disk_size = var.worker_disk_size
disk_iops = var.worker_disk_iops
cpu_credits = var.worker_cpu_credits
spot_price = var.worker_price spot_price = var.worker_price
target_groups = var.worker_target_groups target_groups = var.worker_target_groups
@ -18,7 +23,6 @@ module "workers" {
kubeconfig = module.bootstrap.kubeconfig-kubelet kubeconfig = module.bootstrap.kubeconfig-kubelet
ssh_authorized_key = var.ssh_authorized_key ssh_authorized_key = var.ssh_authorized_key
service_cidr = var.service_cidr service_cidr = var.service_cidr
cluster_domain_suffix = var.cluster_domain_suffix
snippets = var.worker_snippets snippets = var.worker_snippets
node_labels = var.worker_node_labels node_labels = var.worker_node_labels
} }

View File

@ -29,7 +29,7 @@ systemd:
After=afterburn.service After=afterburn.service
Wants=rpc-statd.service Wants=rpc-statd.service
[Service] [Service]
Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.30.1 Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.31.3
EnvironmentFile=/run/metadata/afterburn EnvironmentFile=/run/metadata/afterburn
ExecStartPre=/bin/mkdir -p /etc/cni/net.d ExecStartPre=/bin/mkdir -p /etc/cni/net.d
ExecStartPre=/bin/mkdir -p /etc/kubernetes/manifests ExecStartPre=/bin/mkdir -p /etc/kubernetes/manifests
@ -104,7 +104,7 @@ storage:
cgroupDriver: systemd cgroupDriver: systemd
clusterDNS: clusterDNS:
- ${cluster_dns_service_ip} - ${cluster_dns_service_ip}
clusterDomain: ${cluster_domain_suffix} clusterDomain: cluster.local
healthzPort: 0 healthzPort: 0
rotateCertificates: true rotateCertificates: true
shutdownGracePeriod: 45s shutdownGracePeriod: 45s

View File

@ -69,6 +69,12 @@ variable "spot_price" {
default = 0 default = 0
} }
variable "cpu_credits" {
type = string
description = "CPU burst credits mode (if applicable)"
default = null
}
variable "target_groups" { variable "target_groups" {
type = list(string) type = list(string)
description = "Additional target group ARNs to which instances should be added" description = "Additional target group ARNs to which instances should be added"
@ -102,12 +108,6 @@ EOD
default = "10.3.0.0/16" default = "10.3.0.0/16"
} }
variable "cluster_domain_suffix" {
type = string
description = "Queries for domains with the suffix will be answered by coredns. Default is cluster.local (e.g. foo.default.svc.cluster.local) "
default = "cluster.local"
}
variable "node_labels" { variable "node_labels" {
type = list(string) type = list(string)
description = "List of initial node labels" description = "List of initial node labels"
@ -120,15 +120,14 @@ variable "node_taints" {
default = [] default = []
} }
# unofficial, undocumented, unsupported # advanced
variable "arch" { variable "arch" {
type = string type = string
description = "Container architecture (amd64 or arm64)" description = "Container architecture (amd64 or arm64)"
default = "amd64" default = "amd64"
validation { validation {
condition = var.arch == "amd64" || var.arch == "arm64" condition = contains(["amd64", "arm64"], var.arch)
error_message = "The arch must be amd64 or arm64." error_message = "The arch must be amd64 or arm64."
} }
} }

View File

@ -6,13 +6,11 @@ resource "aws_autoscaling_group" "workers" {
desired_capacity = var.worker_count desired_capacity = var.worker_count
min_size = var.worker_count min_size = var.worker_count
max_size = var.worker_count + 2 max_size = var.worker_count + 2
default_cooldown = 30
health_check_grace_period = 30
# network # network
vpc_zone_identifier = var.subnet_ids vpc_zone_identifier = var.subnet_ids
# template # instance template
launch_template { launch_template {
id = aws_launch_template.worker.id id = aws_launch_template.worker.id
version = aws_launch_template.worker.latest_version version = aws_launch_template.worker.latest_version
@ -32,6 +30,11 @@ resource "aws_autoscaling_group" "workers" {
min_healthy_percentage = 90 min_healthy_percentage = 90
} }
} }
# Grace period before checking new instance's health
health_check_grace_period = 30
# Cooldown period between scaling activities
default_cooldown = 30
lifecycle { lifecycle {
# override the default destroy and replace update behavior # override the default destroy and replace update behavior
@ -56,11 +59,6 @@ resource "aws_launch_template" "worker" {
name_prefix = "${var.name}-worker" name_prefix = "${var.name}-worker"
image_id = local.ami_id image_id = local.ami_id
instance_type = var.instance_type instance_type = var.instance_type
monitoring {
enabled = false
}
user_data = sensitive(base64encode(data.ct_config.worker.rendered))
# storage # storage
ebs_optimized = true ebs_optimized = true
@ -76,14 +74,26 @@ resource "aws_launch_template" "worker" {
} }
# network # network
vpc_security_group_ids = var.security_groups network_interfaces {
associate_public_ip_address = true
security_groups = var.security_groups
}
# boot
user_data = sensitive(base64encode(data.ct_config.worker.rendered))
# metadata # metadata
metadata_options { metadata_options {
http_tokens = "optional" http_tokens = "optional"
} }
monitoring {
enabled = false
}
# spot # cost
credit_specification {
cpu_credits = var.cpu_credits
}
dynamic "instance_market_options" { dynamic "instance_market_options" {
for_each = var.spot_price > 0 ? [1] : [] for_each = var.spot_price > 0 ? [1] : []
content { content {
@ -107,7 +117,6 @@ data "ct_config" "worker" {
kubeconfig = indent(10, var.kubeconfig) kubeconfig = indent(10, var.kubeconfig)
ssh_authorized_key = var.ssh_authorized_key ssh_authorized_key = var.ssh_authorized_key
cluster_dns_service_ip = cidrhost(var.service_cidr, 10) cluster_dns_service_ip = cidrhost(var.service_cidr, 10)
cluster_domain_suffix = var.cluster_domain_suffix
node_labels = join(",", var.node_labels) node_labels = join(",", var.node_labels)
node_taints = join(",", var.node_taints) node_taints = join(",", var.node_taints)
}) })

View File

@ -11,7 +11,7 @@ Typhoon distributes upstream Kubernetes, architectural conventions, and cluster
## Features <a href="https://www.cncf.io/certification/software-conformance/"><img align="right" src="https://storage.googleapis.com/poseidon/certified-kubernetes.png"></a> ## Features <a href="https://www.cncf.io/certification/software-conformance/"><img align="right" src="https://storage.googleapis.com/poseidon/certified-kubernetes.png"></a>
* Kubernetes v1.30.1 (upstream) * Kubernetes v1.31.3 (upstream)
* Single or multi-master, [Calico](https://www.projectcalico.org/) or [Cilium](https://github.com/cilium/cilium) or [flannel](https://github.com/coreos/flannel) networking * Single or multi-master, [Calico](https://www.projectcalico.org/) or [Cilium](https://github.com/cilium/cilium) or [flannel](https://github.com/coreos/flannel) networking
* On-cluster etcd with TLS, [RBAC](https://kubernetes.io/docs/admin/authorization/rbac/)-enabled, [network policy](https://kubernetes.io/docs/concepts/services-networking/network-policies/) * On-cluster etcd with TLS, [RBAC](https://kubernetes.io/docs/admin/authorization/rbac/)-enabled, [network policy](https://kubernetes.io/docs/concepts/services-networking/network-policies/)
* Advanced features like [worker pools](https://typhoon.psdn.io/advanced/worker-pools/), [spot](https://typhoon.psdn.io/flatcar-linux/aws/#spot) workers, and [snippets](https://typhoon.psdn.io/advanced/customization/#hosts) customization * Advanced features like [worker pools](https://typhoon.psdn.io/advanced/worker-pools/), [spot](https://typhoon.psdn.io/flatcar-linux/aws/#spot) workers, and [snippets](https://typhoon.psdn.io/advanced/customization/#hosts) customization

View File

@ -1,7 +1,7 @@
locals { locals {
# Pick a Flatcar Linux AMI # Pick a Flatcar Linux AMI
# flatcar-stable -> Flatcar Linux AMI # flatcar-stable -> Flatcar Linux AMI
ami_id = var.arch == "arm64" ? data.aws_ami.flatcar-arm64[0].image_id : data.aws_ami.flatcar.image_id ami_id = var.controller_arch == "arm64" ? data.aws_ami.flatcar-arm64[0].image_id : data.aws_ami.flatcar.image_id
channel = split("-", var.os_image)[1] channel = split("-", var.os_image)[1]
} }
@ -26,7 +26,7 @@ data "aws_ami" "flatcar" {
} }
data "aws_ami" "flatcar-arm64" { data "aws_ami" "flatcar-arm64" {
count = var.arch == "arm64" ? 1 : 0 count = var.controller_arch == "arm64" ? 1 : 0
most_recent = true most_recent = true
owners = ["075585003325"] owners = ["075585003325"]

View File

@ -1,6 +1,6 @@
# Kubernetes assets (kubeconfig, manifests) # Kubernetes assets (kubeconfig, manifests)
module "bootstrap" { module "bootstrap" {
source = "git::https://github.com/poseidon/terraform-render-bootstrap.git?ref=e1b1e0c75e77e042cf369f463f0e656297a201a8" source = "git::https://github.com/poseidon/terraform-render-bootstrap.git?ref=e6a1c7bccfc45ab299b5f8149bc3840f99b30b2b"
cluster_name = var.cluster_name cluster_name = var.cluster_name
api_servers = [format("%s.%s", var.cluster_name, var.dns_zone)] api_servers = [format("%s.%s", var.cluster_name, var.dns_zone)]
@ -9,9 +9,6 @@ module "bootstrap" {
network_mtu = var.network_mtu network_mtu = var.network_mtu
pod_cidr = var.pod_cidr pod_cidr = var.pod_cidr
service_cidr = var.service_cidr service_cidr = var.service_cidr
cluster_domain_suffix = var.cluster_domain_suffix
enable_reporting = var.enable_reporting
enable_aggregation = var.enable_aggregation
daemonset_tolerations = var.daemonset_tolerations daemonset_tolerations = var.daemonset_tolerations
components = var.components components = var.components
} }

View File

@ -58,7 +58,7 @@ systemd:
After=coreos-metadata.service After=coreos-metadata.service
Wants=rpc-statd.service Wants=rpc-statd.service
[Service] [Service]
Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.30.1 Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.31.3
EnvironmentFile=/run/metadata/coreos EnvironmentFile=/run/metadata/coreos
ExecStartPre=/bin/mkdir -p /etc/cni/net.d ExecStartPre=/bin/mkdir -p /etc/cni/net.d
ExecStartPre=/bin/mkdir -p /etc/kubernetes/manifests ExecStartPre=/bin/mkdir -p /etc/kubernetes/manifests
@ -109,7 +109,7 @@ systemd:
Type=oneshot Type=oneshot
RemainAfterExit=true RemainAfterExit=true
WorkingDirectory=/opt/bootstrap WorkingDirectory=/opt/bootstrap
Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.30.1 Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.31.3
ExecStart=/usr/bin/docker run \ ExecStart=/usr/bin/docker run \
-v /etc/kubernetes/pki:/etc/kubernetes/pki:ro \ -v /etc/kubernetes/pki:/etc/kubernetes/pki:ro \
-v /opt/bootstrap/assets:/assets:ro \ -v /opt/bootstrap/assets:/assets:ro \
@ -148,7 +148,7 @@ storage:
cgroupDriver: systemd cgroupDriver: systemd
clusterDNS: clusterDNS:
- ${cluster_dns_service_ip} - ${cluster_dns_service_ip}
clusterDomain: ${cluster_domain_suffix} clusterDomain: cluster.local
healthzPort: 0 healthzPort: 0
rotateCertificates: true rotateCertificates: true
shutdownGracePeriod: 45s shutdownGracePeriod: 45s

View File

@ -20,19 +20,18 @@ resource "aws_instance" "controllers" {
tags = { tags = {
Name = "${var.cluster_name}-controller-${count.index}" Name = "${var.cluster_name}-controller-${count.index}"
} }
instance_type = var.controller_type instance_type = var.controller_type
ami = local.ami_id ami = local.ami_id
user_data = data.ct_config.controllers.*.rendered[count.index]
# storage # storage
root_block_device { root_block_device {
volume_type = var.disk_type volume_type = var.controller_disk_type
volume_size = var.disk_size volume_size = var.controller_disk_size
iops = var.disk_iops iops = var.controller_disk_iops
encrypted = true encrypted = true
tags = {} tags = {
Name = "${var.cluster_name}-controller-${count.index}"
}
} }
# network # network
@ -40,6 +39,14 @@ resource "aws_instance" "controllers" {
subnet_id = element(aws_subnet.public.*.id, count.index) subnet_id = element(aws_subnet.public.*.id, count.index)
vpc_security_group_ids = [aws_security_group.controller.id] vpc_security_group_ids = [aws_security_group.controller.id]
# boot
user_data = data.ct_config.controllers.*.rendered[count.index]
# cost
credit_specification {
cpu_credits = var.controller_cpu_credits
}
lifecycle { lifecycle {
ignore_changes = [ ignore_changes = [
ami, ami,
@ -62,7 +69,6 @@ data "ct_config" "controllers" {
kubeconfig = indent(10, module.bootstrap.kubeconfig-kubelet) kubeconfig = indent(10, module.bootstrap.kubeconfig-kubelet)
ssh_authorized_key = var.ssh_authorized_key ssh_authorized_key = var.ssh_authorized_key
cluster_dns_service_ip = cidrhost(var.service_cidr, 10) cluster_dns_service_ip = cidrhost(var.service_cidr, 10)
cluster_domain_suffix = var.cluster_domain_suffix
}) })
strict = true strict = true
snippets = var.controller_snippets snippets = var.controller_snippets

View File

@ -47,17 +47,25 @@ resource "aws_route" "egress-ipv6" {
resource "aws_subnet" "public" { resource "aws_subnet" "public" {
count = length(data.aws_availability_zones.all.names) count = length(data.aws_availability_zones.all.names)
vpc_id = aws_vpc.network.id
availability_zone = data.aws_availability_zones.all.names[count.index]
cidr_block = cidrsubnet(var.host_cidr, 4, count.index)
ipv6_cidr_block = cidrsubnet(aws_vpc.network.ipv6_cidr_block, 8, count.index)
map_public_ip_on_launch = true
assign_ipv6_address_on_creation = true
tags = { tags = {
"Name" = "${var.cluster_name}-public-${count.index}" "Name" = "${var.cluster_name}-public-${count.index}"
} }
vpc_id = aws_vpc.network.id
availability_zone = data.aws_availability_zones.all.names[count.index]
# IPv4 and IPv6 CIDR blocks
cidr_block = cidrsubnet(var.host_cidr, 4, count.index)
ipv6_cidr_block = cidrsubnet(aws_vpc.network.ipv6_cidr_block, 8, count.index)
# Assign IPv4 and IPv6 addresses to instances
map_public_ip_on_launch = true
assign_ipv6_address_on_creation = true
# Hostnames assigned to instances
# resource-name: <ec2-instance-id>.region.compute.internal
private_dns_hostname_type_on_launch = "resource-name"
enable_resource_name_dns_a_record_on_launch = true
enable_resource_name_dns_aaaa_record_on_launch = true
} }
resource "aws_route_table_association" "public" { resource "aws_route_table_association" "public" {

View File

@ -17,30 +17,6 @@ variable "dns_zone_id" {
# instances # instances
variable "controller_count" {
type = number
description = "Number of controllers (i.e. masters)"
default = 1
}
variable "worker_count" {
type = number
description = "Number of workers"
default = 1
}
variable "controller_type" {
type = string
description = "EC2 instance type for controllers"
default = "t3.small"
}
variable "worker_type" {
type = string
description = "EC2 instance type for workers"
default = "t3.small"
}
variable "os_image" { variable "os_image" {
type = string type = string
description = "AMI channel for a Container Linux derivative (flatcar-stable, flatcar-beta, flatcar-alpha)" description = "AMI channel for a Container Linux derivative (flatcar-stable, flatcar-beta, flatcar-alpha)"
@ -52,24 +28,78 @@ variable "os_image" {
} }
} }
variable "disk_size" { variable "controller_count" {
type = number
description = "Number of controllers (i.e. masters)"
default = 1
}
variable "controller_type" {
type = string
description = "EC2 instance type for controllers"
default = "t3.small"
}
variable "controller_disk_size" {
type = number type = number
description = "Size of the EBS volume in GB" description = "Size of the EBS volume in GB"
default = 30 default = 30
} }
variable "disk_type" { variable "controller_disk_type" {
type = string type = string
description = "Type of the EBS volume (e.g. standard, gp2, gp3, io1)" description = "Type of the EBS volume (e.g. standard, gp2, gp3, io1)"
default = "gp3" default = "gp3"
} }
variable "disk_iops" { variable "controller_disk_iops" {
type = number type = number
description = "IOPS of the EBS volume (e.g. 3000)" description = "IOPS of the EBS volume (e.g. 3000)"
default = 3000 default = 3000
} }
variable "controller_cpu_credits" {
type = string
description = "CPU credits mode (if using a burstable instance type)"
default = null
}
variable "worker_count" {
type = number
description = "Number of workers"
default = 1
}
variable "worker_type" {
type = string
description = "EC2 instance type for workers"
default = "t3.small"
}
variable "worker_disk_size" {
type = number
description = "Size of the EBS volume in GB"
default = 30
}
variable "worker_disk_type" {
type = string
description = "Type of the EBS volume (e.g. standard, gp2, gp3, io1)"
default = "gp3"
}
variable "worker_disk_iops" {
type = number
description = "IOPS of the EBS volume (e.g. 3000)"
default = 3000
}
variable "worker_cpu_credits" {
type = string
description = "CPU credits mode (if using a burstable instance type)"
default = null
}
variable "worker_price" { variable "worker_price" {
type = number type = number
description = "Spot price in USD for worker instances or 0 to use on-demand instances" description = "Spot price in USD for worker instances or 0 to use on-demand instances"
@ -134,40 +164,31 @@ EOD
default = "10.3.0.0/16" default = "10.3.0.0/16"
} }
variable "enable_reporting" {
type = bool
description = "Enable usage or analytics reporting to upstreams (Calico)"
default = false
}
variable "enable_aggregation" {
type = bool
description = "Enable the Kubernetes Aggregation Layer"
default = true
}
variable "worker_node_labels" { variable "worker_node_labels" {
type = list(string) type = list(string)
description = "List of initial worker node labels" description = "List of initial worker node labels"
default = [] default = []
} }
# unofficial, undocumented, unsupported # advanced
variable "cluster_domain_suffix" { variable "controller_arch" {
type = string type = string
description = "Queries for domains with the suffix will be answered by CoreDNS. Default is cluster.local (e.g. foo.default.svc.cluster.local)" description = "Controller node(s) architecture (amd64 or arm64)"
default = "cluster.local" default = "amd64"
validation {
condition = contains(["amd64", "arm64"], var.controller_arch)
error_message = "The controller_arch must be amd64 or arm64."
}
} }
variable "arch" { variable "worker_arch" {
type = string type = string
description = "Container architecture (amd64 or arm64)" description = "Worker node(s) architecture (amd64 or arm64)"
default = "amd64" default = "amd64"
validation { validation {
condition = var.arch == "amd64" || var.arch == "arm64" condition = contains(["amd64", "arm64"], var.worker_arch)
error_message = "The arch must be amd64 or arm64." error_message = "The worker_arch must be amd64 or arm64."
} }
} }

View File

@ -6,11 +6,15 @@ module "workers" {
vpc_id = aws_vpc.network.id vpc_id = aws_vpc.network.id
subnet_ids = aws_subnet.public.*.id subnet_ids = aws_subnet.public.*.id
security_groups = [aws_security_group.worker.id] security_groups = [aws_security_group.worker.id]
# instances
os_image = var.os_image
worker_count = var.worker_count worker_count = var.worker_count
instance_type = var.worker_type instance_type = var.worker_type
os_image = var.os_image arch = var.worker_arch
arch = var.arch disk_type = var.worker_disk_type
disk_size = var.disk_size disk_size = var.worker_disk_size
disk_iops = var.worker_disk_iops
spot_price = var.worker_price spot_price = var.worker_price
target_groups = var.worker_target_groups target_groups = var.worker_target_groups
@ -18,7 +22,6 @@ module "workers" {
kubeconfig = module.bootstrap.kubeconfig-kubelet kubeconfig = module.bootstrap.kubeconfig-kubelet
ssh_authorized_key = var.ssh_authorized_key ssh_authorized_key = var.ssh_authorized_key
service_cidr = var.service_cidr service_cidr = var.service_cidr
cluster_domain_suffix = var.cluster_domain_suffix
snippets = var.worker_snippets snippets = var.worker_snippets
node_labels = var.worker_node_labels node_labels = var.worker_node_labels
} }

View File

@ -30,7 +30,7 @@ systemd:
After=coreos-metadata.service After=coreos-metadata.service
Wants=rpc-statd.service Wants=rpc-statd.service
[Service] [Service]
Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.30.1 Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.31.3
EnvironmentFile=/run/metadata/coreos EnvironmentFile=/run/metadata/coreos
ExecStartPre=/bin/mkdir -p /etc/cni/net.d ExecStartPre=/bin/mkdir -p /etc/cni/net.d
ExecStartPre=/bin/mkdir -p /etc/kubernetes/manifests ExecStartPre=/bin/mkdir -p /etc/kubernetes/manifests
@ -103,7 +103,7 @@ storage:
cgroupDriver: systemd cgroupDriver: systemd
clusterDNS: clusterDNS:
- ${cluster_dns_service_ip} - ${cluster_dns_service_ip}
clusterDomain: ${cluster_domain_suffix} clusterDomain: cluster.local
healthzPort: 0 healthzPort: 0
rotateCertificates: true rotateCertificates: true
shutdownGracePeriod: 45s shutdownGracePeriod: 45s

View File

@ -69,6 +69,12 @@ variable "spot_price" {
default = 0 default = 0
} }
variable "cpu_credits" {
type = string
description = "CPU burst credits mode (if applicable)"
default = null
}
variable "target_groups" { variable "target_groups" {
type = list(string) type = list(string)
description = "Additional target group ARNs to which instances should be added" description = "Additional target group ARNs to which instances should be added"
@ -102,12 +108,6 @@ EOD
default = "10.3.0.0/16" default = "10.3.0.0/16"
} }
variable "cluster_domain_suffix" {
type = string
description = "Queries for domains with the suffix will be answered by coredns. Default is cluster.local (e.g. foo.default.svc.cluster.local) "
default = "cluster.local"
}
variable "node_labels" { variable "node_labels" {
type = list(string) type = list(string)
description = "List of initial node labels" description = "List of initial node labels"
@ -128,7 +128,7 @@ variable "arch" {
default = "amd64" default = "amd64"
validation { validation {
condition = var.arch == "amd64" || var.arch == "arm64" condition = contains(["amd64", "arm64"], var.arch)
error_message = "The arch must be amd64 or arm64." error_message = "The arch must be amd64 or arm64."
} }
} }

View File

@ -6,13 +6,11 @@ resource "aws_autoscaling_group" "workers" {
desired_capacity = var.worker_count desired_capacity = var.worker_count
min_size = var.worker_count min_size = var.worker_count
max_size = var.worker_count + 2 max_size = var.worker_count + 2
default_cooldown = 30
health_check_grace_period = 30
# network # network
vpc_zone_identifier = var.subnet_ids vpc_zone_identifier = var.subnet_ids
# template # instance template
launch_template { launch_template {
id = aws_launch_template.worker.id id = aws_launch_template.worker.id
version = aws_launch_template.worker.latest_version version = aws_launch_template.worker.latest_version
@ -32,6 +30,10 @@ resource "aws_autoscaling_group" "workers" {
min_healthy_percentage = 90 min_healthy_percentage = 90
} }
} }
# Grace period before checking new instance's health
health_check_grace_period = 30
# Cooldown period between scaling activities
default_cooldown = 30
lifecycle { lifecycle {
# override the default destroy and replace update behavior # override the default destroy and replace update behavior
@ -56,11 +58,6 @@ resource "aws_launch_template" "worker" {
name_prefix = "${var.name}-worker" name_prefix = "${var.name}-worker"
image_id = local.ami_id image_id = local.ami_id
instance_type = var.instance_type instance_type = var.instance_type
monitoring {
enabled = false
}
user_data = sensitive(base64encode(data.ct_config.worker.rendered))
# storage # storage
ebs_optimized = true ebs_optimized = true
@ -76,14 +73,26 @@ resource "aws_launch_template" "worker" {
} }
# network # network
vpc_security_group_ids = var.security_groups network_interfaces {
associate_public_ip_address = true
security_groups = var.security_groups
}
# boot
user_data = sensitive(base64encode(data.ct_config.worker.rendered))
# metadata # metadata
metadata_options { metadata_options {
http_tokens = "optional" http_tokens = "optional"
} }
monitoring {
enabled = false
}
# spot # cost
credit_specification {
cpu_credits = var.cpu_credits
}
dynamic "instance_market_options" { dynamic "instance_market_options" {
for_each = var.spot_price > 0 ? [1] : [] for_each = var.spot_price > 0 ? [1] : []
content { content {
@ -107,7 +116,6 @@ data "ct_config" "worker" {
kubeconfig = indent(10, var.kubeconfig) kubeconfig = indent(10, var.kubeconfig)
ssh_authorized_key = var.ssh_authorized_key ssh_authorized_key = var.ssh_authorized_key
cluster_dns_service_ip = cidrhost(var.service_cidr, 10) cluster_dns_service_ip = cidrhost(var.service_cidr, 10)
cluster_domain_suffix = var.cluster_domain_suffix
node_labels = join(",", var.node_labels) node_labels = join(",", var.node_labels)
node_taints = join(",", var.node_taints) node_taints = join(",", var.node_taints)
}) })

View File

@ -11,7 +11,7 @@ Typhoon distributes upstream Kubernetes, architectural conventions, and cluster
## Features <a href="https://www.cncf.io/certification/software-conformance/"><img align="right" src="https://storage.googleapis.com/poseidon/certified-kubernetes.png"></a> ## Features <a href="https://www.cncf.io/certification/software-conformance/"><img align="right" src="https://storage.googleapis.com/poseidon/certified-kubernetes.png"></a>
* Kubernetes v1.30.1 (upstream) * Kubernetes v1.31.3 (upstream)
* Single or multi-master, [Calico](https://www.projectcalico.org/) or [Cilium](https://github.com/cilium/cilium) or [flannel](https://github.com/coreos/flannel) networking * Single or multi-master, [Calico](https://www.projectcalico.org/) or [Cilium](https://github.com/cilium/cilium) or [flannel](https://github.com/coreos/flannel) networking
* On-cluster etcd with TLS, [RBAC](https://kubernetes.io/docs/admin/authorization/rbac/)-enabled, [network policy](https://kubernetes.io/docs/concepts/services-networking/network-policies/), SELinux enforcing * On-cluster etcd with TLS, [RBAC](https://kubernetes.io/docs/admin/authorization/rbac/)-enabled, [network policy](https://kubernetes.io/docs/concepts/services-networking/network-policies/), SELinux enforcing
* Advanced features like [worker pools](https://typhoon.psdn.io/advanced/worker-pools/), [spot priority](https://typhoon.psdn.io/fedora-coreos/azure/#low-priority) workers, and [snippets](https://typhoon.psdn.io/advanced/customization/#hosts) customization * Advanced features like [worker pools](https://typhoon.psdn.io/advanced/worker-pools/), [spot priority](https://typhoon.psdn.io/fedora-coreos/azure/#low-priority) workers, and [snippets](https://typhoon.psdn.io/advanced/customization/#hosts) customization

View File

@ -1,6 +1,6 @@
# Kubernetes assets (kubeconfig, manifests) # Kubernetes assets (kubeconfig, manifests)
module "bootstrap" { module "bootstrap" {
source = "git::https://github.com/poseidon/terraform-render-bootstrap.git?ref=e1b1e0c75e77e042cf369f463f0e656297a201a8" source = "git::https://github.com/poseidon/terraform-render-bootstrap.git?ref=e6a1c7bccfc45ab299b5f8149bc3840f99b30b2b"
cluster_name = var.cluster_name cluster_name = var.cluster_name
api_servers = [format("%s.%s", var.cluster_name, var.dns_zone)] api_servers = [format("%s.%s", var.cluster_name, var.dns_zone)]
@ -14,9 +14,6 @@ module "bootstrap" {
pod_cidr = var.pod_cidr pod_cidr = var.pod_cidr
service_cidr = var.service_cidr service_cidr = var.service_cidr
cluster_domain_suffix = var.cluster_domain_suffix
enable_reporting = var.enable_reporting
enable_aggregation = var.enable_aggregation
daemonset_tolerations = var.daemonset_tolerations daemonset_tolerations = var.daemonset_tolerations
components = var.components components = var.components
} }

View File

@ -54,7 +54,7 @@ systemd:
Description=Kubelet (System Container) Description=Kubelet (System Container)
Wants=rpc-statd.service Wants=rpc-statd.service
[Service] [Service]
Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.30.1 Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.31.3
ExecStartPre=/bin/mkdir -p /etc/cni/net.d ExecStartPre=/bin/mkdir -p /etc/cni/net.d
ExecStartPre=/bin/mkdir -p /etc/kubernetes/manifests ExecStartPre=/bin/mkdir -p /etc/kubernetes/manifests
ExecStartPre=/bin/mkdir -p /opt/cni/bin ExecStartPre=/bin/mkdir -p /opt/cni/bin
@ -111,7 +111,7 @@ systemd:
--volume /opt/bootstrap/assets:/assets:ro,Z \ --volume /opt/bootstrap/assets:/assets:ro,Z \
--volume /opt/bootstrap/apply:/apply:ro,Z \ --volume /opt/bootstrap/apply:/apply:ro,Z \
--entrypoint=/apply \ --entrypoint=/apply \
quay.io/poseidon/kubelet:v1.30.1 quay.io/poseidon/kubelet:v1.31.3
ExecStartPost=/bin/touch /opt/bootstrap/bootstrap.done ExecStartPost=/bin/touch /opt/bootstrap/bootstrap.done
ExecStartPost=-/usr/bin/podman stop bootstrap ExecStartPost=-/usr/bin/podman stop bootstrap
storage: storage:
@ -144,7 +144,7 @@ storage:
cgroupDriver: systemd cgroupDriver: systemd
clusterDNS: clusterDNS:
- ${cluster_dns_service_ip} - ${cluster_dns_service_ip}
clusterDomain: ${cluster_domain_suffix} clusterDomain: cluster.local
healthzPort: 0 healthzPort: 0
rotateCertificates: true rotateCertificates: true
shutdownGracePeriod: 45s shutdownGracePeriod: 45s

View File

@ -9,25 +9,22 @@ locals {
# Discrete DNS records for each controller's private IPv4 for etcd usage # Discrete DNS records for each controller's private IPv4 for etcd usage
resource "azurerm_dns_a_record" "etcds" { resource "azurerm_dns_a_record" "etcds" {
count = var.controller_count count = var.controller_count
resource_group_name = var.dns_zone_group
# DNS Zone name where record should be created # DNS Zone name where record should be created
zone_name = var.dns_zone zone_name = var.dns_zone
resource_group_name = var.dns_zone_group
# DNS record # DNS record
name = format("%s-etcd%d", var.cluster_name, count.index) name = format("%s-etcd%d", var.cluster_name, count.index)
ttl = 300 ttl = 300
# private IPv4 address for etcd # private IPv4 address for etcd
records = [azurerm_network_interface.controllers.*.private_ip_address[count.index]] records = [azurerm_network_interface.controllers[count.index].private_ip_address]
} }
# Controller availability set to spread controllers # Controller availability set to spread controllers
resource "azurerm_availability_set" "controllers" { resource "azurerm_availability_set" "controllers" {
resource_group_name = azurerm_resource_group.cluster.name
name = "${var.cluster_name}-controllers" name = "${var.cluster_name}-controllers"
location = var.region resource_group_name = azurerm_resource_group.cluster.name
location = var.location
platform_fault_domain_count = 2 platform_fault_domain_count = 2
platform_update_domain_count = 4 platform_update_domain_count = 4
managed = true managed = true
@ -36,30 +33,34 @@ resource "azurerm_availability_set" "controllers" {
# Controller instances # Controller instances
resource "azurerm_linux_virtual_machine" "controllers" { resource "azurerm_linux_virtual_machine" "controllers" {
count = var.controller_count count = var.controller_count
resource_group_name = azurerm_resource_group.cluster.name
name = "${var.cluster_name}-controller-${count.index}" name = "${var.cluster_name}-controller-${count.index}"
location = var.region resource_group_name = azurerm_resource_group.cluster.name
location = var.location
availability_set_id = azurerm_availability_set.controllers.id availability_set_id = azurerm_availability_set.controllers.id
size = var.controller_type size = var.controller_type
custom_data = base64encode(data.ct_config.controllers.*.rendered[count.index])
# storage # storage
source_image_id = var.os_image source_image_id = var.os_image
os_disk { os_disk {
name = "${var.cluster_name}-controller-${count.index}" name = "${var.cluster_name}-controller-${count.index}"
storage_account_type = var.controller_disk_type
disk_size_gb = var.controller_disk_size
caching = "None" caching = "None"
disk_size_gb = var.disk_size
storage_account_type = "Premium_LRS"
} }
# network # network
network_interface_ids = [ network_interface_ids = [
azurerm_network_interface.controllers.*.id[count.index] azurerm_network_interface.controllers[count.index].id
] ]
# Azure requires setting admin_ssh_key, though Ignition custom_data handles it too # boot
custom_data = base64encode(data.ct_config.controllers[count.index].rendered)
boot_diagnostics {
# defaults to a managed storage account
}
# Azure requires an RSA admin_ssh_key
admin_username = "core" admin_username = "core"
admin_ssh_key { admin_ssh_key {
username = "core" username = "core"
@ -74,31 +75,52 @@ resource "azurerm_linux_virtual_machine" "controllers" {
} }
} }
# Controller public IPv4 addresses # Controller node public IPv4 addresses
resource "azurerm_public_ip" "controllers" { resource "azurerm_public_ip" "controllers-ipv4" {
count = var.controller_count count = var.controller_count
resource_group_name = azurerm_resource_group.cluster.name
name = "${var.cluster_name}-controller-${count.index}" name = "${var.cluster_name}-controller-${count.index}-ipv4"
resource_group_name = azurerm_resource_group.cluster.name
location = azurerm_resource_group.cluster.location location = azurerm_resource_group.cluster.location
ip_version = "IPv4"
sku = "Standard" sku = "Standard"
allocation_method = "Static" allocation_method = "Static"
} }
# Controller NICs with public and private IPv4 # Controller node public IPv6 addresses
resource "azurerm_public_ip" "controllers-ipv6" {
count = var.controller_count
name = "${var.cluster_name}-controller-${count.index}-ipv6"
resource_group_name = azurerm_resource_group.cluster.name
location = azurerm_resource_group.cluster.location
ip_version = "IPv6"
sku = "Standard"
allocation_method = "Static"
}
# Controllers' network interfaces
resource "azurerm_network_interface" "controllers" { resource "azurerm_network_interface" "controllers" {
count = var.controller_count count = var.controller_count
resource_group_name = azurerm_resource_group.cluster.name
name = "${var.cluster_name}-controller-${count.index}" name = "${var.cluster_name}-controller-${count.index}"
resource_group_name = azurerm_resource_group.cluster.name
location = azurerm_resource_group.cluster.location location = azurerm_resource_group.cluster.location
ip_configuration { ip_configuration {
name = "ip0" name = "ipv4"
primary = true
subnet_id = azurerm_subnet.controller.id subnet_id = azurerm_subnet.controller.id
private_ip_address_allocation = "Dynamic" private_ip_address_allocation = "Dynamic"
# instance public IPv4 private_ip_address_version = "IPv4"
public_ip_address_id = azurerm_public_ip.controllers.*.id[count.index] public_ip_address_id = azurerm_public_ip.controllers-ipv4[count.index].id
}
ip_configuration {
name = "ipv6"
subnet_id = azurerm_subnet.controller.id
private_ip_address_allocation = "Dynamic"
private_ip_address_version = "IPv6"
public_ip_address_id = azurerm_public_ip.controllers-ipv6[count.index].id
} }
} }
@ -111,12 +133,20 @@ resource "azurerm_network_interface_security_group_association" "controllers" {
} }
# Associate controller network interface with controller backend address pool # Associate controller network interface with controller backend address pool
resource "azurerm_network_interface_backend_address_pool_association" "controllers" { resource "azurerm_network_interface_backend_address_pool_association" "controllers-ipv4" {
count = var.controller_count count = var.controller_count
network_interface_id = azurerm_network_interface.controllers[count.index].id network_interface_id = azurerm_network_interface.controllers[count.index].id
ip_configuration_name = "ip0" ip_configuration_name = "ipv4"
backend_address_pool_id = azurerm_lb_backend_address_pool.controller.id backend_address_pool_id = azurerm_lb_backend_address_pool.controller-ipv4.id
}
resource "azurerm_network_interface_backend_address_pool_association" "controllers-ipv6" {
count = var.controller_count
network_interface_id = azurerm_network_interface.controllers[count.index].id
ip_configuration_name = "ipv6"
backend_address_pool_id = azurerm_lb_backend_address_pool.controller-ipv6.id
} }
# Fedora CoreOS controllers # Fedora CoreOS controllers
@ -133,7 +163,6 @@ data "ct_config" "controllers" {
kubeconfig = indent(10, module.bootstrap.kubeconfig-kubelet) kubeconfig = indent(10, module.bootstrap.kubeconfig-kubelet)
ssh_authorized_key = var.ssh_authorized_key ssh_authorized_key = var.ssh_authorized_key
cluster_dns_service_ip = cidrhost(var.service_cidr, 10) cluster_dns_service_ip = cidrhost(var.service_cidr, 10)
cluster_domain_suffix = var.cluster_domain_suffix
}) })
strict = true strict = true
snippets = var.controller_snippets snippets = var.controller_snippets

View File

@ -1,116 +1,164 @@
# DNS record for the apiserver load balancer # DNS A record for the apiserver load balancer
resource "azurerm_dns_a_record" "apiserver" { resource "azurerm_dns_a_record" "apiserver" {
resource_group_name = var.dns_zone_group
# DNS Zone name where record should be created # DNS Zone name where record should be created
zone_name = var.dns_zone zone_name = var.dns_zone
resource_group_name = var.dns_zone_group
# DNS record # DNS record
name = var.cluster_name name = var.cluster_name
ttl = 300 ttl = 300
# IPv4 address of apiserver load balancer # IPv4 address of apiserver load balancer
records = [azurerm_public_ip.apiserver-ipv4.ip_address] records = [azurerm_public_ip.frontend-ipv4.ip_address]
} }
# Static IPv4 address for the apiserver frontend # DNS AAAA record for the apiserver load balancer
resource "azurerm_public_ip" "apiserver-ipv4" { resource "azurerm_dns_aaaa_record" "apiserver" {
resource_group_name = azurerm_resource_group.cluster.name # DNS Zone name where record should be created
zone_name = var.dns_zone
resource_group_name = var.dns_zone_group
# DNS record
name = var.cluster_name
ttl = 300
# IPv4 address of apiserver load balancer
records = [azurerm_public_ip.frontend-ipv6.ip_address]
}
name = "${var.cluster_name}-apiserver-ipv4" # Static IPv4 address for the load balancer
location = var.region resource "azurerm_public_ip" "frontend-ipv4" {
name = "${var.cluster_name}-frontend-ipv4"
resource_group_name = azurerm_resource_group.cluster.name
location = var.location
ip_version = "IPv4"
sku = "Standard" sku = "Standard"
allocation_method = "Static" allocation_method = "Static"
} }
# Static IPv4 address for the ingress frontend # Static IPv6 address for the load balancer
resource "azurerm_public_ip" "ingress-ipv4" { resource "azurerm_public_ip" "frontend-ipv6" {
name = "${var.cluster_name}-frontend-ipv6"
resource_group_name = azurerm_resource_group.cluster.name resource_group_name = azurerm_resource_group.cluster.name
location = var.location
name = "${var.cluster_name}-ingress-ipv4" ip_version = "IPv6"
location = var.region
sku = "Standard" sku = "Standard"
allocation_method = "Static" allocation_method = "Static"
} }
# Network Load Balancer for apiservers and ingress # Network Load Balancer for apiservers and ingress
resource "azurerm_lb" "cluster" { resource "azurerm_lb" "cluster" {
resource_group_name = azurerm_resource_group.cluster.name
name = var.cluster_name name = var.cluster_name
location = var.region resource_group_name = azurerm_resource_group.cluster.name
location = var.location
sku = "Standard" sku = "Standard"
frontend_ip_configuration { frontend_ip_configuration {
name = "apiserver" name = "frontend-ipv4"
public_ip_address_id = azurerm_public_ip.apiserver-ipv4.id public_ip_address_id = azurerm_public_ip.frontend-ipv4.id
} }
frontend_ip_configuration { frontend_ip_configuration {
name = "ingress" name = "frontend-ipv6"
public_ip_address_id = azurerm_public_ip.ingress-ipv4.id public_ip_address_id = azurerm_public_ip.frontend-ipv6.id
} }
} }
resource "azurerm_lb_rule" "apiserver" { resource "azurerm_lb_rule" "apiserver-ipv4" {
name = "apiserver" name = "apiserver-ipv4"
loadbalancer_id = azurerm_lb.cluster.id loadbalancer_id = azurerm_lb.cluster.id
frontend_ip_configuration_name = "apiserver" frontend_ip_configuration_name = "frontend-ipv4"
disable_outbound_snat = true
protocol = "Tcp" protocol = "Tcp"
frontend_port = 6443 frontend_port = 6443
backend_port = 6443 backend_port = 6443
backend_address_pool_ids = [azurerm_lb_backend_address_pool.controller.id] backend_address_pool_ids = [azurerm_lb_backend_address_pool.controller-ipv4.id]
probe_id = azurerm_lb_probe.apiserver.id probe_id = azurerm_lb_probe.apiserver.id
} }
resource "azurerm_lb_rule" "ingress-http" { resource "azurerm_lb_rule" "apiserver-ipv6" {
name = "ingress-http" name = "apiserver-ipv6"
loadbalancer_id = azurerm_lb.cluster.id loadbalancer_id = azurerm_lb.cluster.id
frontend_ip_configuration_name = "ingress" frontend_ip_configuration_name = "frontend-ipv6"
disable_outbound_snat = true
protocol = "Tcp"
frontend_port = 6443
backend_port = 6443
backend_address_pool_ids = [azurerm_lb_backend_address_pool.controller-ipv6.id]
probe_id = azurerm_lb_probe.apiserver.id
}
resource "azurerm_lb_rule" "ingress-http-ipv4" {
name = "ingress-http-ipv4"
loadbalancer_id = azurerm_lb.cluster.id
frontend_ip_configuration_name = "frontend-ipv4"
disable_outbound_snat = true disable_outbound_snat = true
protocol = "Tcp" protocol = "Tcp"
frontend_port = 80 frontend_port = 80
backend_port = 80 backend_port = 80
backend_address_pool_ids = [azurerm_lb_backend_address_pool.worker.id] backend_address_pool_ids = [azurerm_lb_backend_address_pool.worker-ipv4.id]
probe_id = azurerm_lb_probe.ingress.id probe_id = azurerm_lb_probe.ingress.id
} }
resource "azurerm_lb_rule" "ingress-https" { resource "azurerm_lb_rule" "ingress-https-ipv4" {
name = "ingress-https" name = "ingress-https-ipv4"
loadbalancer_id = azurerm_lb.cluster.id loadbalancer_id = azurerm_lb.cluster.id
frontend_ip_configuration_name = "ingress" frontend_ip_configuration_name = "frontend-ipv4"
disable_outbound_snat = true disable_outbound_snat = true
protocol = "Tcp" protocol = "Tcp"
frontend_port = 443 frontend_port = 443
backend_port = 443 backend_port = 443
backend_address_pool_ids = [azurerm_lb_backend_address_pool.worker.id] backend_address_pool_ids = [azurerm_lb_backend_address_pool.worker-ipv4.id]
probe_id = azurerm_lb_probe.ingress.id probe_id = azurerm_lb_probe.ingress.id
} }
# Worker outbound TCP/UDP SNAT resource "azurerm_lb_rule" "ingress-http-ipv6" {
resource "azurerm_lb_outbound_rule" "worker-outbound" { name = "ingress-http-ipv6"
name = "worker"
loadbalancer_id = azurerm_lb.cluster.id loadbalancer_id = azurerm_lb.cluster.id
frontend_ip_configuration { frontend_ip_configuration_name = "frontend-ipv6"
name = "ingress" disable_outbound_snat = true
protocol = "Tcp"
frontend_port = 80
backend_port = 80
backend_address_pool_ids = [azurerm_lb_backend_address_pool.worker-ipv6.id]
probe_id = azurerm_lb_probe.ingress.id
} }
protocol = "All" resource "azurerm_lb_rule" "ingress-https-ipv6" {
backend_address_pool_id = azurerm_lb_backend_address_pool.worker.id name = "ingress-https-ipv6"
loadbalancer_id = azurerm_lb.cluster.id
frontend_ip_configuration_name = "frontend-ipv6"
disable_outbound_snat = true
protocol = "Tcp"
frontend_port = 443
backend_port = 443
backend_address_pool_ids = [azurerm_lb_backend_address_pool.worker-ipv6.id]
probe_id = azurerm_lb_probe.ingress.id
} }
# Backend Address Pools
# Address pool of controllers # Address pool of controllers
resource "azurerm_lb_backend_address_pool" "controller" { resource "azurerm_lb_backend_address_pool" "controller-ipv4" {
name = "controller" name = "controller-ipv4"
loadbalancer_id = azurerm_lb.cluster.id
}
resource "azurerm_lb_backend_address_pool" "controller-ipv6" {
name = "controller-ipv6"
loadbalancer_id = azurerm_lb.cluster.id loadbalancer_id = azurerm_lb.cluster.id
} }
# Address pool of workers # Address pool of workers
resource "azurerm_lb_backend_address_pool" "worker" { resource "azurerm_lb_backend_address_pool" "worker-ipv4" {
name = "worker" name = "worker-ipv4"
loadbalancer_id = azurerm_lb.cluster.id
}
resource "azurerm_lb_backend_address_pool" "worker-ipv6" {
name = "worker-ipv6"
loadbalancer_id = azurerm_lb.cluster.id loadbalancer_id = azurerm_lb.cluster.id
} }
@ -122,10 +170,8 @@ resource "azurerm_lb_probe" "apiserver" {
loadbalancer_id = azurerm_lb.cluster.id loadbalancer_id = azurerm_lb.cluster.id
protocol = "Tcp" protocol = "Tcp"
port = 6443 port = 6443
# unhealthy threshold # unhealthy threshold
number_of_probes = 3 number_of_probes = 3
interval_in_seconds = 5 interval_in_seconds = 5
} }
@ -136,10 +182,29 @@ resource "azurerm_lb_probe" "ingress" {
protocol = "Http" protocol = "Http"
port = 10254 port = 10254
request_path = "/healthz" request_path = "/healthz"
# unhealthy threshold # unhealthy threshold
number_of_probes = 3 number_of_probes = 3
interval_in_seconds = 5 interval_in_seconds = 5
} }
# Outbound SNAT
resource "azurerm_lb_outbound_rule" "outbound-ipv4" {
name = "outbound-ipv4"
protocol = "All"
loadbalancer_id = azurerm_lb.cluster.id
backend_address_pool_id = azurerm_lb_backend_address_pool.worker-ipv4.id
frontend_ip_configuration {
name = "frontend-ipv4"
}
}
resource "azurerm_lb_outbound_rule" "outbound-ipv6" {
name = "outbound-ipv6"
protocol = "All"
loadbalancer_id = azurerm_lb.cluster.id
backend_address_pool_id = azurerm_lb_backend_address_pool.worker-ipv6.id
frontend_ip_configuration {
name = "frontend-ipv6"
}
}

View File

@ -0,0 +1,6 @@
locals {
backend_address_pool_ids = {
ipv4 = [azurerm_lb_backend_address_pool.worker-ipv4.id]
ipv6 = [azurerm_lb_backend_address_pool.worker-ipv6.id]
}
}

View File

@ -1,27 +1,64 @@
# Choose an IPv6 ULA subnet at random
# https://datatracker.ietf.org/doc/html/rfc4193
resource "random_id" "ula-netnum" {
byte_length = 5 # 40 bits
}
locals {
# fd00::/8 -> shift 40 -> 2^40 possible /48 subnets
ula-range = cidrsubnet("fd00::/8", 40, random_id.ula-netnum.dec)
network_cidr = {
ipv4 = var.network_cidr.ipv4
ipv6 = length(var.network_cidr.ipv6) > 0 ? var.network_cidr.ipv6 : [local.ula-range]
}
# Subdivide the virtual network into subnets
# - controllers use netnum 0
# - workers use netnum 1
controller_subnets = {
ipv4 = [for i, cidr in local.network_cidr.ipv4 : cidrsubnet(cidr, 1, 0)]
ipv6 = [for i, cidr in local.network_cidr.ipv6 : cidrsubnet(cidr, 16, 0)]
}
worker_subnets = {
ipv4 = [for i, cidr in local.network_cidr.ipv4 : cidrsubnet(cidr, 1, 1)]
ipv6 = [for i, cidr in local.network_cidr.ipv6 : cidrsubnet(cidr, 16, 1)]
}
cluster_subnets = {
ipv4 = concat(local.controller_subnets.ipv4, local.worker_subnets.ipv4)
ipv6 = concat(local.controller_subnets.ipv6, local.worker_subnets.ipv6)
}
}
# Organize cluster into a resource group # Organize cluster into a resource group
resource "azurerm_resource_group" "cluster" { resource "azurerm_resource_group" "cluster" {
name = var.cluster_name name = var.cluster_name
location = var.region location = var.location
} }
resource "azurerm_virtual_network" "network" { resource "azurerm_virtual_network" "network" {
resource_group_name = azurerm_resource_group.cluster.name
name = var.cluster_name name = var.cluster_name
resource_group_name = azurerm_resource_group.cluster.name
location = azurerm_resource_group.cluster.location location = azurerm_resource_group.cluster.location
address_space = [var.host_cidr] address_space = concat(
local.network_cidr.ipv4,
local.network_cidr.ipv6
)
} }
# Subnets - separate subnets for controller and workers because Azure # Subnets - separate subnets for controllers and workers because Azure
# network security groups are based on IPv4 CIDR rather than instance # network security groups are oriented around address prefixes rather
# tags like GCP or security group membership like AWS # than instance tags (GCP) or security group membership (AWS)
resource "azurerm_subnet" "controller" { resource "azurerm_subnet" "controller" {
resource_group_name = azurerm_resource_group.cluster.name
name = "controller" name = "controller"
resource_group_name = azurerm_resource_group.cluster.name
virtual_network_name = azurerm_virtual_network.network.name virtual_network_name = azurerm_virtual_network.network.name
address_prefixes = [cidrsubnet(var.host_cidr, 1, 0)] address_prefixes = concat(
local.controller_subnets.ipv4,
local.controller_subnets.ipv6,
)
default_outbound_access_enabled = false
} }
resource "azurerm_subnet_network_security_group_association" "controller" { resource "azurerm_subnet_network_security_group_association" "controller" {
@ -30,11 +67,14 @@ resource "azurerm_subnet_network_security_group_association" "controller" {
} }
resource "azurerm_subnet" "worker" { resource "azurerm_subnet" "worker" {
resource_group_name = azurerm_resource_group.cluster.name
name = "worker" name = "worker"
resource_group_name = azurerm_resource_group.cluster.name
virtual_network_name = azurerm_virtual_network.network.name virtual_network_name = azurerm_virtual_network.network.name
address_prefixes = [cidrsubnet(var.host_cidr, 1, 1)] address_prefixes = concat(
local.worker_subnets.ipv4,
local.worker_subnets.ipv6,
)
default_outbound_access_enabled = false
} }
resource "azurerm_subnet_network_security_group_association" "worker" { resource "azurerm_subnet_network_security_group_association" "worker" {

View File

@ -6,13 +6,18 @@ output "kubeconfig-admin" {
# Outputs for Kubernetes Ingress # Outputs for Kubernetes Ingress
output "ingress_static_ipv4" { output "ingress_static_ipv4" {
value = azurerm_public_ip.ingress-ipv4.ip_address value = azurerm_public_ip.frontend-ipv4.ip_address
description = "IPv4 address of the load balancer for distributing traffic to Ingress controllers" description = "IPv4 address of the load balancer for distributing traffic to Ingress controllers"
} }
output "ingress_static_ipv6" {
value = azurerm_public_ip.frontend-ipv6.ip_address
description = "IPv6 address of the load balancer for distributing traffic to Ingress controllers"
}
# Outputs for worker pools # Outputs for worker pools
output "region" { output "location" {
value = azurerm_resource_group.cluster.location value = azurerm_resource_group.cluster.location
} }
@ -51,12 +56,12 @@ output "worker_security_group_name" {
output "controller_address_prefixes" { output "controller_address_prefixes" {
description = "Controller network subnet CIDR addresses (for source/destination)" description = "Controller network subnet CIDR addresses (for source/destination)"
value = azurerm_subnet.controller.address_prefixes value = local.controller_subnets
} }
output "worker_address_prefixes" { output "worker_address_prefixes" {
description = "Worker network subnet CIDR addresses (for source/destination)" description = "Worker network subnet CIDR addresses (for source/destination)"
value = azurerm_subnet.worker.address_prefixes value = local.worker_subnets
} }
# Outputs for custom load balancing # Outputs for custom load balancing
@ -66,9 +71,12 @@ output "loadbalancer_id" {
value = azurerm_lb.cluster.id value = azurerm_lb.cluster.id
} }
output "backend_address_pool_id" { output "backend_address_pool_ids" {
description = "ID of the worker backend address pool" description = "IDs of the worker backend address pools"
value = azurerm_lb_backend_address_pool.worker.id value = {
ipv4 = [azurerm_lb_backend_address_pool.worker-ipv4.id]
ipv6 = [azurerm_lb_backend_address_pool.worker-ipv6.id]
}
} }
# Outputs for debug # Outputs for debug

View File

@ -1,214 +1,223 @@
# Controller security group # Controller security group
resource "azurerm_network_security_group" "controller" { resource "azurerm_network_security_group" "controller" {
resource_group_name = azurerm_resource_group.cluster.name
name = "${var.cluster_name}-controller" name = "${var.cluster_name}-controller"
resource_group_name = azurerm_resource_group.cluster.name
location = azurerm_resource_group.cluster.location location = azurerm_resource_group.cluster.location
} }
resource "azurerm_network_security_rule" "controller-icmp" { resource "azurerm_network_security_rule" "controller-icmp" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.controller_subnets
name = "allow-icmp" name = "allow-icmp-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.controller.name network_security_group_name = azurerm_network_security_group.controller.name
priority = "1995" priority = 1995 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Icmp" protocol = "Icmp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "*" destination_port_range = "*"
source_address_prefixes = concat(azurerm_subnet.controller.address_prefixes, azurerm_subnet.worker.address_prefixes) source_address_prefixes = local.cluster_subnets[each.key]
destination_address_prefixes = azurerm_subnet.controller.address_prefixes destination_address_prefixes = local.controller_subnets[each.key]
} }
resource "azurerm_network_security_rule" "controller-ssh" { resource "azurerm_network_security_rule" "controller-ssh" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.controller_subnets
name = "allow-ssh" name = "allow-ssh-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.controller.name network_security_group_name = azurerm_network_security_group.controller.name
priority = "2000" priority = 2000 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "22" destination_port_range = "22"
source_address_prefix = "*" source_address_prefix = "*"
destination_address_prefixes = azurerm_subnet.controller.address_prefixes destination_address_prefixes = local.controller_subnets[each.key]
} }
resource "azurerm_network_security_rule" "controller-etcd" { resource "azurerm_network_security_rule" "controller-etcd" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.controller_subnets
name = "allow-etcd" name = "allow-etcd-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.controller.name network_security_group_name = azurerm_network_security_group.controller.name
priority = "2005" priority = 2005 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "2379-2380" destination_port_range = "2379-2380"
source_address_prefixes = azurerm_subnet.controller.address_prefixes source_address_prefixes = local.controller_subnets[each.key]
destination_address_prefixes = azurerm_subnet.controller.address_prefixes destination_address_prefixes = local.controller_subnets[each.key]
} }
# Allow Prometheus to scrape etcd metrics # Allow Prometheus to scrape etcd metrics
resource "azurerm_network_security_rule" "controller-etcd-metrics" { resource "azurerm_network_security_rule" "controller-etcd-metrics" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.controller_subnets
name = "allow-etcd-metrics" name = "allow-etcd-metrics-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.controller.name network_security_group_name = azurerm_network_security_group.controller.name
priority = "2010" priority = 2010 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "2381" destination_port_range = "2381"
source_address_prefixes = azurerm_subnet.worker.address_prefixes source_address_prefixes = local.worker_subnets[each.key]
destination_address_prefixes = azurerm_subnet.controller.address_prefixes destination_address_prefixes = local.controller_subnets[each.key]
} }
# Allow Prometheus to scrape kube-proxy metrics # Allow Prometheus to scrape kube-proxy metrics
resource "azurerm_network_security_rule" "controller-kube-proxy" { resource "azurerm_network_security_rule" "controller-kube-proxy" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.controller_subnets
name = "allow-kube-proxy-metrics" name = "allow-kube-proxy-metrics-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.controller.name network_security_group_name = azurerm_network_security_group.controller.name
priority = "2011" priority = 2012 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "10249" destination_port_range = "10249"
source_address_prefixes = azurerm_subnet.worker.address_prefixes source_address_prefixes = local.worker_subnets[each.key]
destination_address_prefixes = azurerm_subnet.controller.address_prefixes destination_address_prefixes = local.controller_subnets[each.key]
} }
# Allow Prometheus to scrape kube-scheduler and kube-controller-manager metrics # Allow Prometheus to scrape kube-scheduler and kube-controller-manager metrics
resource "azurerm_network_security_rule" "controller-kube-metrics" { resource "azurerm_network_security_rule" "controller-kube-metrics" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.controller_subnets
name = "allow-kube-metrics" name = "allow-kube-metrics-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.controller.name network_security_group_name = azurerm_network_security_group.controller.name
priority = "2012" priority = 2014 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "10257-10259" destination_port_range = "10257-10259"
source_address_prefixes = azurerm_subnet.worker.address_prefixes source_address_prefixes = local.worker_subnets[each.key]
destination_address_prefixes = azurerm_subnet.controller.address_prefixes destination_address_prefixes = local.controller_subnets[each.key]
} }
resource "azurerm_network_security_rule" "controller-apiserver" { resource "azurerm_network_security_rule" "controller-apiserver" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.controller_subnets
name = "allow-apiserver" name = "allow-apiserver-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.controller.name network_security_group_name = azurerm_network_security_group.controller.name
priority = "2015" priority = 2016 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "6443" destination_port_range = "6443"
source_address_prefix = "*" source_address_prefix = "*"
destination_address_prefixes = azurerm_subnet.controller.address_prefixes destination_address_prefixes = local.controller_subnets[each.key]
} }
resource "azurerm_network_security_rule" "controller-cilium-health" { resource "azurerm_network_security_rule" "controller-cilium-health" {
resource_group_name = azurerm_resource_group.cluster.name for_each = var.networking == "cilium" ? local.controller_subnets : {}
count = var.networking == "cilium" ? 1 : 0
name = "allow-cilium-health" name = "allow-cilium-health-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.controller.name network_security_group_name = azurerm_network_security_group.controller.name
priority = "2018" priority = 2018 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "4240" destination_port_range = "4240"
source_address_prefixes = concat(azurerm_subnet.controller.address_prefixes, azurerm_subnet.worker.address_prefixes) source_address_prefixes = local.cluster_subnets[each.key]
destination_address_prefixes = azurerm_subnet.controller.address_prefixes destination_address_prefixes = local.controller_subnets[each.key]
} }
resource "azurerm_network_security_rule" "controller-cilium-metrics" { resource "azurerm_network_security_rule" "controller-cilium-metrics" {
resource_group_name = azurerm_resource_group.cluster.name for_each = var.networking == "cilium" ? local.controller_subnets : {}
count = var.networking == "cilium" ? 1 : 0
name = "allow-cilium-metrics" name = "allow-cilium-metrics-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.controller.name network_security_group_name = azurerm_network_security_group.controller.name
priority = "2019" priority = 2035 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "9962-9965" destination_port_range = "9962-9965"
source_address_prefixes = concat(azurerm_subnet.controller.address_prefixes, azurerm_subnet.worker.address_prefixes) source_address_prefixes = local.cluster_subnets[each.key]
destination_address_prefixes = azurerm_subnet.controller.address_prefixes destination_address_prefixes = local.controller_subnets[each.key]
} }
resource "azurerm_network_security_rule" "controller-vxlan" { resource "azurerm_network_security_rule" "controller-vxlan" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.controller_subnets
name = "allow-vxlan" name = "allow-vxlan-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.controller.name network_security_group_name = azurerm_network_security_group.controller.name
priority = "2020" priority = 2020 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Udp" protocol = "Udp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "4789" destination_port_range = "4789"
source_address_prefixes = concat(azurerm_subnet.controller.address_prefixes, azurerm_subnet.worker.address_prefixes) source_address_prefixes = local.cluster_subnets[each.key]
destination_address_prefixes = azurerm_subnet.controller.address_prefixes destination_address_prefixes = local.controller_subnets[each.key]
} }
resource "azurerm_network_security_rule" "controller-linux-vxlan" { resource "azurerm_network_security_rule" "controller-linux-vxlan" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.controller_subnets
name = "allow-linux-vxlan" name = "allow-linux-vxlan-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.controller.name network_security_group_name = azurerm_network_security_group.controller.name
priority = "2021" priority = 2022 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Udp" protocol = "Udp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "8472" destination_port_range = "8472"
source_address_prefixes = concat(azurerm_subnet.controller.address_prefixes, azurerm_subnet.worker.address_prefixes) source_address_prefixes = local.cluster_subnets[each.key]
destination_address_prefixes = azurerm_subnet.controller.address_prefixes destination_address_prefixes = local.controller_subnets[each.key]
} }
# Allow Prometheus to scrape node-exporter daemonset # Allow Prometheus to scrape node-exporter daemonset
resource "azurerm_network_security_rule" "controller-node-exporter" { resource "azurerm_network_security_rule" "controller-node-exporter" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.controller_subnets
name = "allow-node-exporter" name = "allow-node-exporter-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.controller.name network_security_group_name = azurerm_network_security_group.controller.name
priority = "2025" priority = 2025 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "9100" destination_port_range = "9100"
source_address_prefixes = azurerm_subnet.worker.address_prefixes source_address_prefixes = local.worker_subnets[each.key]
destination_address_prefixes = azurerm_subnet.controller.address_prefixes destination_address_prefixes = local.controller_subnets[each.key]
} }
# Allow apiserver to access kubelet's for exec, log, port-forward # Allow apiserver to access kubelet's for exec, log, port-forward
resource "azurerm_network_security_rule" "controller-kubelet" { resource "azurerm_network_security_rule" "controller-kubelet" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.controller_subnets
name = "allow-kubelet" name = "allow-kubelet-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.controller.name network_security_group_name = azurerm_network_security_group.controller.name
priority = "2030" priority = 2030 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "10250" destination_port_range = "10250"
# allow Prometheus to scrape kubelet metrics too # allow Prometheus to scrape kubelet metrics too
source_address_prefixes = concat(azurerm_subnet.controller.address_prefixes, azurerm_subnet.worker.address_prefixes) source_address_prefixes = local.cluster_subnets[each.key]
destination_address_prefixes = azurerm_subnet.controller.address_prefixes destination_address_prefixes = local.controller_subnets[each.key]
} }
# Override Azure AllowVNetInBound and AllowAzureLoadBalancerInBound # Override Azure AllowVNetInBound and AllowAzureLoadBalancerInBound
@ -247,182 +256,189 @@ resource "azurerm_network_security_rule" "controller-deny-all" {
# Worker security group # Worker security group
resource "azurerm_network_security_group" "worker" { resource "azurerm_network_security_group" "worker" {
resource_group_name = azurerm_resource_group.cluster.name
name = "${var.cluster_name}-worker" name = "${var.cluster_name}-worker"
resource_group_name = azurerm_resource_group.cluster.name
location = azurerm_resource_group.cluster.location location = azurerm_resource_group.cluster.location
} }
resource "azurerm_network_security_rule" "worker-icmp" { resource "azurerm_network_security_rule" "worker-icmp" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.worker_subnets
name = "allow-icmp" name = "allow-icmp-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.worker.name network_security_group_name = azurerm_network_security_group.worker.name
priority = "1995" priority = 1995 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Icmp" protocol = "Icmp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "*" destination_port_range = "*"
source_address_prefixes = concat(azurerm_subnet.controller.address_prefixes, azurerm_subnet.worker.address_prefixes) source_address_prefixes = local.cluster_subnets[each.key]
destination_address_prefixes = azurerm_subnet.worker.address_prefixes destination_address_prefixes = local.worker_subnets[each.key]
} }
resource "azurerm_network_security_rule" "worker-ssh" { resource "azurerm_network_security_rule" "worker-ssh" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.worker_subnets
name = "allow-ssh" name = "allow-ssh-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.worker.name network_security_group_name = azurerm_network_security_group.worker.name
priority = "2000" priority = 2000 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "22" destination_port_range = "22"
source_address_prefixes = azurerm_subnet.controller.address_prefixes source_address_prefixes = local.controller_subnets[each.key]
destination_address_prefixes = azurerm_subnet.worker.address_prefixes destination_address_prefixes = local.worker_subnets[each.key]
} }
resource "azurerm_network_security_rule" "worker-http" { resource "azurerm_network_security_rule" "worker-http" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.worker_subnets
name = "allow-http" name = "allow-http-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.worker.name network_security_group_name = azurerm_network_security_group.worker.name
priority = "2005" priority = 2005 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "80" destination_port_range = "80"
source_address_prefix = "*" source_address_prefix = "*"
destination_address_prefixes = azurerm_subnet.worker.address_prefixes destination_address_prefixes = local.worker_subnets[each.key]
} }
resource "azurerm_network_security_rule" "worker-https" { resource "azurerm_network_security_rule" "worker-https" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.worker_subnets
name = "allow-https" name = "allow-https-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.worker.name network_security_group_name = azurerm_network_security_group.worker.name
priority = "2010" priority = 2010 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "443" destination_port_range = "443"
source_address_prefix = "*" source_address_prefix = "*"
destination_address_prefixes = azurerm_subnet.worker.address_prefixes destination_address_prefixes = local.worker_subnets[each.key]
} }
resource "azurerm_network_security_rule" "worker-cilium-health" { resource "azurerm_network_security_rule" "worker-cilium-health" {
resource_group_name = azurerm_resource_group.cluster.name for_each = var.networking == "cilium" ? local.worker_subnets : {}
count = var.networking == "cilium" ? 1 : 0
name = "allow-cilium-health" name = "allow-cilium-health-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.worker.name network_security_group_name = azurerm_network_security_group.worker.name
priority = "2013" priority = 2012 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "4240" destination_port_range = "4240"
source_address_prefixes = concat(azurerm_subnet.controller.address_prefixes, azurerm_subnet.worker.address_prefixes) source_address_prefixes = local.cluster_subnets[each.key]
destination_address_prefixes = azurerm_subnet.worker.address_prefixes destination_address_prefixes = local.worker_subnets[each.key]
} }
resource "azurerm_network_security_rule" "worker-cilium-metrics" { resource "azurerm_network_security_rule" "worker-cilium-metrics" {
resource_group_name = azurerm_resource_group.cluster.name for_each = var.networking == "cilium" ? local.worker_subnets : {}
count = var.networking == "cilium" ? 1 : 0
name = "allow-cilium-metrics" name = "allow-cilium-metrics-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.worker.name network_security_group_name = azurerm_network_security_group.worker.name
priority = "2014" priority = 2014 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "9962-9965" destination_port_range = "9962-9965"
source_address_prefixes = concat(azurerm_subnet.controller.address_prefixes, azurerm_subnet.worker.address_prefixes) source_address_prefixes = local.cluster_subnets[each.key]
destination_address_prefixes = azurerm_subnet.worker.address_prefixes destination_address_prefixes = local.worker_subnets[each.key]
} }
resource "azurerm_network_security_rule" "worker-vxlan" { resource "azurerm_network_security_rule" "worker-vxlan" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.worker_subnets
name = "allow-vxlan" name = "allow-vxlan-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.worker.name network_security_group_name = azurerm_network_security_group.worker.name
priority = "2015" priority = 2016 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Udp" protocol = "Udp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "4789" destination_port_range = "4789"
source_address_prefixes = concat(azurerm_subnet.controller.address_prefixes, azurerm_subnet.worker.address_prefixes) source_address_prefixes = local.cluster_subnets[each.key]
destination_address_prefixes = azurerm_subnet.worker.address_prefixes destination_address_prefixes = local.worker_subnets[each.key]
} }
resource "azurerm_network_security_rule" "worker-linux-vxlan" { resource "azurerm_network_security_rule" "worker-linux-vxlan" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.worker_subnets
name = "allow-linux-vxlan" name = "allow-linux-vxlan-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.worker.name network_security_group_name = azurerm_network_security_group.worker.name
priority = "2016" priority = 2018 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Udp" protocol = "Udp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "8472" destination_port_range = "8472"
source_address_prefixes = concat(azurerm_subnet.controller.address_prefixes, azurerm_subnet.worker.address_prefixes) source_address_prefixes = local.cluster_subnets[each.key]
destination_address_prefixes = azurerm_subnet.worker.address_prefixes destination_address_prefixes = local.worker_subnets[each.key]
} }
# Allow Prometheus to scrape node-exporter daemonset # Allow Prometheus to scrape node-exporter daemonset
resource "azurerm_network_security_rule" "worker-node-exporter" { resource "azurerm_network_security_rule" "worker-node-exporter" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.worker_subnets
name = "allow-node-exporter" name = "allow-node-exporter-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.worker.name network_security_group_name = azurerm_network_security_group.worker.name
priority = "2020" priority = 2020 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "9100" destination_port_range = "9100"
source_address_prefixes = azurerm_subnet.worker.address_prefixes source_address_prefixes = local.worker_subnets[each.key]
destination_address_prefixes = azurerm_subnet.worker.address_prefixes destination_address_prefixes = local.worker_subnets[each.key]
} }
# Allow Prometheus to scrape kube-proxy # Allow Prometheus to scrape kube-proxy
resource "azurerm_network_security_rule" "worker-kube-proxy" { resource "azurerm_network_security_rule" "worker-kube-proxy" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.worker_subnets
name = "allow-kube-proxy" name = "allow-kube-proxy-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.worker.name network_security_group_name = azurerm_network_security_group.worker.name
priority = "2024" priority = 2024 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "10249" destination_port_range = "10249"
source_address_prefixes = azurerm_subnet.worker.address_prefixes source_address_prefixes = local.worker_subnets[each.key]
destination_address_prefixes = azurerm_subnet.worker.address_prefixes destination_address_prefixes = local.worker_subnets[each.key]
} }
# Allow apiserver to access kubelet's for exec, log, port-forward # Allow apiserver to access kubelet's for exec, log, port-forward
resource "azurerm_network_security_rule" "worker-kubelet" { resource "azurerm_network_security_rule" "worker-kubelet" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.worker_subnets
name = "allow-kubelet" name = "allow-kubelet-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.worker.name network_security_group_name = azurerm_network_security_group.worker.name
priority = "2025" priority = 2026 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "10250" destination_port_range = "10250"
# allow Prometheus to scrape kubelet metrics too # allow Prometheus to scrape kubelet metrics too
source_address_prefixes = concat(azurerm_subnet.controller.address_prefixes, azurerm_subnet.worker.address_prefixes) source_address_prefixes = local.cluster_subnets[each.key]
destination_address_prefixes = azurerm_subnet.worker.address_prefixes destination_address_prefixes = local.worker_subnets[each.key]
} }
# Override Azure AllowVNetInBound and AllowAzureLoadBalancerInBound # Override Azure AllowVNetInBound and AllowAzureLoadBalancerInBound

View File

@ -18,7 +18,7 @@ resource "null_resource" "copy-controller-secrets" {
connection { connection {
type = "ssh" type = "ssh"
host = azurerm_public_ip.controllers.*.ip_address[count.index] host = azurerm_public_ip.controllers-ipv4[count.index].ip_address
user = "core" user = "core"
timeout = "15m" timeout = "15m"
} }
@ -45,7 +45,7 @@ resource "null_resource" "bootstrap" {
connection { connection {
type = "ssh" type = "ssh"
host = azurerm_public_ip.controllers.*.ip_address[0] host = azurerm_public_ip.controllers-ipv4[0].ip_address
user = "core" user = "core"
timeout = "15m" timeout = "15m"
} }

View File

@ -5,9 +5,9 @@ variable "cluster_name" {
# Azure # Azure
variable "region" { variable "location" {
type = string type = string
description = "Azure Region (e.g. centralus , see `az account list-locations --output table`)" description = "Azure location (e.g. centralus , see `az account list-locations --output table`)"
} }
variable "dns_zone" { variable "dns_zone" {
@ -22,41 +22,65 @@ variable "dns_zone_group" {
# instances # instances
variable "os_image" {
type = string
description = "Fedora CoreOS image for instances"
}
variable "controller_count" { variable "controller_count" {
type = number type = number
description = "Number of controllers (i.e. masters)" description = "Number of controllers (i.e. masters)"
default = 1 default = 1
} }
variable "worker_count" {
type = number
description = "Number of workers"
default = 1
}
variable "controller_type" { variable "controller_type" {
type = string type = string
description = "Machine type for controllers (see `az vm list-skus --location centralus`)" description = "Machine type for controllers (see `az vm list-skus --location centralus`)"
default = "Standard_B2s" default = "Standard_B2s"
} }
variable "controller_disk_type" {
type = string
description = "Type of managed disk for controller node(s)"
default = "Premium_LRS"
}
variable "controller_disk_size" {
type = number
description = "Size of the managed disk in GB for controller node(s)"
default = 30
}
variable "worker_count" {
type = number
description = "Number of workers"
default = 1
}
variable "worker_type" { variable "worker_type" {
type = string type = string
description = "Machine type for workers (see `az vm list-skus --location centralus`)" description = "Machine type for workers (see `az vm list-skus --location centralus`)"
default = "Standard_D2as_v5" default = "Standard_D2as_v5"
} }
variable "os_image" { variable "worker_disk_type" {
type = string type = string
description = "Fedora CoreOS image for instances" description = "Type of managed disk for worker nodes"
default = "Standard_LRS"
} }
variable "disk_size" { variable "worker_disk_size" {
type = number type = number
description = "Size of the disk in GB" description = "Size of the managed disk in GB for worker nodes"
default = 30 default = 30
} }
variable "worker_ephemeral_disk" {
type = bool
description = "Use ephemeral local disk instead of managed disk (requires vm_type with local storage)"
default = false
}
variable "worker_priority" { variable "worker_priority" {
type = string type = string
description = "Set worker priority to Spot to use reduced cost surplus capacity, with the tradeoff that instances can be deallocated at any time." description = "Set worker priority to Spot to use reduced cost surplus capacity, with the tradeoff that instances can be deallocated at any time."
@ -94,10 +118,15 @@ variable "networking" {
default = "cilium" default = "cilium"
} }
variable "host_cidr" { variable "network_cidr" {
type = string type = object({
description = "CIDR IPv4 range to assign to instances" ipv4 = list(string)
default = "10.0.0.0/16" ipv6 = optional(list(string), [])
})
description = "Virtual network CIDR ranges"
default = {
ipv4 = ["10.0.0.0/16"]
}
} }
variable "pod_cidr" { variable "pod_cidr" {
@ -115,31 +144,13 @@ EOD
default = "10.3.0.0/16" default = "10.3.0.0/16"
} }
variable "enable_reporting" {
type = bool
description = "Enable usage or analytics reporting to upstreams (Calico)"
default = false
}
variable "enable_aggregation" {
type = bool
description = "Enable the Kubernetes Aggregation Layer"
default = true
}
variable "worker_node_labels" { variable "worker_node_labels" {
type = list(string) type = list(string)
description = "List of initial worker node labels" description = "List of initial worker node labels"
default = [] default = []
} }
# unofficial, undocumented, unsupported # advanced
variable "cluster_domain_suffix" {
type = string
description = "Queries for domains with the suffix will be answered by coredns. Default is cluster.local (e.g. foo.default.svc.cluster.local) "
default = "cluster.local"
}
variable "daemonset_tolerations" { variable "daemonset_tolerations" {
type = list(string) type = list(string)

View File

@ -3,7 +3,7 @@
terraform { terraform {
required_version = ">= 0.13.0, < 2.0.0" required_version = ">= 0.13.0, < 2.0.0"
required_providers { required_providers {
azurerm = ">= 2.8, < 4.0" azurerm = ">= 2.8"
null = ">= 2.1" null = ">= 2.1"
ct = { ct = {
source = "poseidon/ct" source = "poseidon/ct"

View File

@ -4,14 +4,18 @@ module "workers" {
# Azure # Azure
resource_group_name = azurerm_resource_group.cluster.name resource_group_name = azurerm_resource_group.cluster.name
region = azurerm_resource_group.cluster.location location = azurerm_resource_group.cluster.location
subnet_id = azurerm_subnet.worker.id subnet_id = azurerm_subnet.worker.id
security_group_id = azurerm_network_security_group.worker.id security_group_id = azurerm_network_security_group.worker.id
backend_address_pool_id = azurerm_lb_backend_address_pool.worker.id backend_address_pool_ids = local.backend_address_pool_ids
# instances
os_image = var.os_image
worker_count = var.worker_count worker_count = var.worker_count
vm_type = var.worker_type vm_type = var.worker_type
os_image = var.os_image disk_type = var.worker_disk_type
disk_size = var.worker_disk_size
ephemeral_disk = var.worker_ephemeral_disk
priority = var.worker_priority priority = var.worker_priority
# configuration # configuration
@ -19,7 +23,6 @@ module "workers" {
ssh_authorized_key = var.ssh_authorized_key ssh_authorized_key = var.ssh_authorized_key
azure_authorized_key = var.azure_authorized_key azure_authorized_key = var.azure_authorized_key
service_cidr = var.service_cidr service_cidr = var.service_cidr
cluster_domain_suffix = var.cluster_domain_suffix
snippets = var.worker_snippets snippets = var.worker_snippets
node_labels = var.worker_node_labels node_labels = var.worker_node_labels
} }

View File

@ -26,7 +26,7 @@ systemd:
Description=Kubelet (System Container) Description=Kubelet (System Container)
Wants=rpc-statd.service Wants=rpc-statd.service
[Service] [Service]
Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.30.1 Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.31.3
ExecStartPre=/bin/mkdir -p /etc/cni/net.d ExecStartPre=/bin/mkdir -p /etc/cni/net.d
ExecStartPre=/bin/mkdir -p /etc/kubernetes/manifests ExecStartPre=/bin/mkdir -p /etc/kubernetes/manifests
ExecStartPre=/bin/mkdir -p /opt/cni/bin ExecStartPre=/bin/mkdir -p /opt/cni/bin
@ -99,7 +99,7 @@ storage:
cgroupDriver: systemd cgroupDriver: systemd
clusterDNS: clusterDNS:
- ${cluster_dns_service_ip} - ${cluster_dns_service_ip}
clusterDomain: ${cluster_domain_suffix} clusterDomain: cluster.local
healthzPort: 0 healthzPort: 0
rotateCertificates: true rotateCertificates: true
shutdownGracePeriod: 45s shutdownGracePeriod: 45s

View File

@ -5,9 +5,9 @@ variable "name" {
# Azure # Azure
variable "region" { variable "location" {
type = string type = string
description = "Must be set to the Azure Region of cluster" description = "Must be set to the Azure location of cluster"
} }
variable "resource_group_name" { variable "resource_group_name" {
@ -25,9 +25,12 @@ variable "security_group_id" {
description = "Must be set to the `worker_security_group_id` output by cluster" description = "Must be set to the `worker_security_group_id` output by cluster"
} }
variable "backend_address_pool_id" { variable "backend_address_pool_ids" {
type = string type = object({
description = "Must be set to the `worker_backend_address_pool_id` output by cluster" ipv4 = list(string)
ipv6 = list(string)
})
description = "Must be set to the `backend_address_pool_ids` output by cluster"
} }
# instances # instances
@ -49,6 +52,24 @@ variable "os_image" {
description = "Fedora CoreOS image for instances" description = "Fedora CoreOS image for instances"
} }
variable "disk_type" {
type = string
description = "Type of managed disk"
default = "Standard_LRS"
}
variable "disk_size" {
type = number
description = "Size of the managed disk in GB"
default = 30
}
variable "ephemeral_disk" {
type = bool
description = "Use ephemeral local disk instead of managed disk (requires vm_type with local storage)"
default = false
}
variable "priority" { variable "priority" {
type = string type = string
description = "Set priority to Spot to use reduced cost surplus capacity, with the tradeoff that instances can be evicted at any time." description = "Set priority to Spot to use reduced cost surplus capacity, with the tradeoff that instances can be evicted at any time."
@ -99,12 +120,3 @@ variable "node_taints" {
description = "List of initial node taints" description = "List of initial node taints"
default = [] default = []
} }
# unofficial, undocumented, unsupported
variable "cluster_domain_suffix" {
description = "Queries for domains with the suffix will be answered by coredns. Default is cluster.local (e.g. foo.default.svc.cluster.local) "
type = string
default = "cluster.local"
}

View File

@ -3,7 +3,7 @@
terraform { terraform {
required_version = ">= 0.13.0, < 2.0.0" required_version = ">= 0.13.0, < 2.0.0"
required_providers { required_providers {
azurerm = ">= 2.8, < 4.0" azurerm = ">= 2.8"
ct = { ct = {
source = "poseidon/ct" source = "poseidon/ct"
version = "~> 0.13" version = "~> 0.13"

View File

@ -3,30 +3,29 @@ locals {
} }
# Workers scale set # Workers scale set
resource "azurerm_linux_virtual_machine_scale_set" "workers" { resource "azurerm_orchestrated_virtual_machine_scale_set" "workers" {
resource_group_name = var.resource_group_name
name = "${var.name}-worker" name = "${var.name}-worker"
location = var.region resource_group_name = var.resource_group_name
sku = var.vm_type location = var.location
platform_fault_domain_count = 1
sku_name = var.vm_type
instances = var.worker_count instances = var.worker_count
# instance name prefix for instances in the set
computer_name_prefix = "${var.name}-worker"
single_placement_group = false
custom_data = base64encode(data.ct_config.worker.rendered)
# storage # storage
encryption_at_host_enabled = true
source_image_id = var.os_image source_image_id = var.os_image
os_disk { os_disk {
storage_account_type = "Standard_LRS" storage_account_type = var.disk_type
caching = "ReadWrite" disk_size_gb = var.disk_size
caching = "ReadOnly"
# Optionally, use the ephemeral disk of the instance type (support varies)
dynamic "diff_disk_settings" {
for_each = var.ephemeral_disk ? [1] : []
content {
option = "Local"
placement = "ResourceDisk"
}
} }
# Azure requires setting admin_ssh_key, though Ignition custom_data handles it too
admin_username = "core"
admin_ssh_key {
username = "core"
public_key = var.azure_authorized_key
} }
# network # network
@ -36,41 +35,46 @@ resource "azurerm_linux_virtual_machine_scale_set" "workers" {
network_security_group_id = var.security_group_id network_security_group_id = var.security_group_id
ip_configuration { ip_configuration {
name = "ip0" name = "ipv4"
version = "IPv4"
primary = true primary = true
subnet_id = var.subnet_id subnet_id = var.subnet_id
# backend address pool to which the NIC should be added # backend address pool to which the NIC should be added
load_balancer_backend_address_pool_ids = [var.backend_address_pool_id] load_balancer_backend_address_pool_ids = var.backend_address_pool_ids.ipv4
}
ip_configuration {
name = "ipv6"
version = "IPv6"
subnet_id = var.subnet_id
# backend address pool to which the NIC should be added
load_balancer_backend_address_pool_ids = var.backend_address_pool_ids.ipv6
}
}
# boot
user_data_base64 = base64encode(data.ct_config.worker.rendered)
boot_diagnostics {
# defaults to a managed storage account
}
# Azure requires an RSA admin_ssh_key
os_profile {
linux_configuration {
admin_username = "core"
admin_ssh_key {
username = "core"
public_key = local.azure_authorized_key
}
computer_name_prefix = "${var.name}-worker"
} }
} }
# lifecycle # lifecycle
upgrade_mode = "Manual"
# eviction policy may only be set when priority is Spot # eviction policy may only be set when priority is Spot
priority = var.priority priority = var.priority
eviction_policy = var.priority == "Spot" ? "Delete" : null eviction_policy = var.priority == "Spot" ? "Delete" : null
} termination_notification {
# Scale up or down to maintain desired number, tolerating deallocations.
resource "azurerm_monitor_autoscale_setting" "workers" {
resource_group_name = var.resource_group_name
name = "${var.name}-maintain-desired"
location = var.region
# autoscale
enabled = true enabled = true
target_resource_id = azurerm_linux_virtual_machine_scale_set.workers.id
profile {
name = "default"
capacity {
minimum = var.worker_count
default = var.worker_count
maximum = var.worker_count
}
} }
} }
@ -80,7 +84,6 @@ data "ct_config" "worker" {
kubeconfig = indent(10, var.kubeconfig) kubeconfig = indent(10, var.kubeconfig)
ssh_authorized_key = var.ssh_authorized_key ssh_authorized_key = var.ssh_authorized_key
cluster_dns_service_ip = cidrhost(var.service_cidr, 10) cluster_dns_service_ip = cidrhost(var.service_cidr, 10)
cluster_domain_suffix = var.cluster_domain_suffix
node_labels = join(",", var.node_labels) node_labels = join(",", var.node_labels)
node_taints = join(",", var.node_taints) node_taints = join(",", var.node_taints)
}) })

View File

@ -11,7 +11,7 @@ Typhoon distributes upstream Kubernetes, architectural conventions, and cluster
## Features <a href="https://www.cncf.io/certification/software-conformance/"><img align="right" src="https://storage.googleapis.com/poseidon/certified-kubernetes.png"></a> ## Features <a href="https://www.cncf.io/certification/software-conformance/"><img align="right" src="https://storage.googleapis.com/poseidon/certified-kubernetes.png"></a>
* Kubernetes v1.30.1 (upstream) * Kubernetes v1.31.3 (upstream)
* Single or multi-master, [Calico](https://www.projectcalico.org/) or [Cilium](https://github.com/cilium/cilium) or [flannel](https://github.com/coreos/flannel) networking * Single or multi-master, [Calico](https://www.projectcalico.org/) or [Cilium](https://github.com/cilium/cilium) or [flannel](https://github.com/coreos/flannel) networking
* On-cluster etcd with TLS, [RBAC](https://kubernetes.io/docs/admin/authorization/rbac/)-enabled, [network policy](https://kubernetes.io/docs/concepts/services-networking/network-policies/) * On-cluster etcd with TLS, [RBAC](https://kubernetes.io/docs/admin/authorization/rbac/)-enabled, [network policy](https://kubernetes.io/docs/concepts/services-networking/network-policies/)
* Advanced features like [worker pools](https://typhoon.psdn.io/advanced/worker-pools/), [low-priority](https://typhoon.psdn.io/flatcar-linux/azure/#low-priority) workers, and [snippets](https://typhoon.psdn.io/advanced/customization/#hosts) customization * Advanced features like [worker pools](https://typhoon.psdn.io/advanced/worker-pools/), [low-priority](https://typhoon.psdn.io/flatcar-linux/azure/#low-priority) workers, and [snippets](https://typhoon.psdn.io/advanced/customization/#hosts) customization

View File

@ -1,6 +1,6 @@
# Kubernetes assets (kubeconfig, manifests) # Kubernetes assets (kubeconfig, manifests)
module "bootstrap" { module "bootstrap" {
source = "git::https://github.com/poseidon/terraform-render-bootstrap.git?ref=e1b1e0c75e77e042cf369f463f0e656297a201a8" source = "git::https://github.com/poseidon/terraform-render-bootstrap.git?ref=e6a1c7bccfc45ab299b5f8149bc3840f99b30b2b"
cluster_name = var.cluster_name cluster_name = var.cluster_name
api_servers = [format("%s.%s", var.cluster_name, var.dns_zone)] api_servers = [format("%s.%s", var.cluster_name, var.dns_zone)]
@ -14,9 +14,6 @@ module "bootstrap" {
pod_cidr = var.pod_cidr pod_cidr = var.pod_cidr
service_cidr = var.service_cidr service_cidr = var.service_cidr
cluster_domain_suffix = var.cluster_domain_suffix
enable_reporting = var.enable_reporting
enable_aggregation = var.enable_aggregation
daemonset_tolerations = var.daemonset_tolerations daemonset_tolerations = var.daemonset_tolerations
components = var.components components = var.components
} }

View File

@ -56,7 +56,7 @@ systemd:
After=docker.service After=docker.service
Wants=rpc-statd.service Wants=rpc-statd.service
[Service] [Service]
Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.30.1 Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.31.3
ExecStartPre=/bin/mkdir -p /etc/cni/net.d ExecStartPre=/bin/mkdir -p /etc/cni/net.d
ExecStartPre=/bin/mkdir -p /etc/kubernetes/manifests ExecStartPre=/bin/mkdir -p /etc/kubernetes/manifests
ExecStartPre=/bin/mkdir -p /opt/cni/bin ExecStartPre=/bin/mkdir -p /opt/cni/bin
@ -105,7 +105,7 @@ systemd:
Type=oneshot Type=oneshot
RemainAfterExit=true RemainAfterExit=true
WorkingDirectory=/opt/bootstrap WorkingDirectory=/opt/bootstrap
Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.30.1 Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.31.3
ExecStart=/usr/bin/docker run \ ExecStart=/usr/bin/docker run \
-v /etc/kubernetes/pki:/etc/kubernetes/pki:ro \ -v /etc/kubernetes/pki:/etc/kubernetes/pki:ro \
-v /opt/bootstrap/assets:/assets:ro \ -v /opt/bootstrap/assets:/assets:ro \
@ -144,7 +144,7 @@ storage:
cgroupDriver: systemd cgroupDriver: systemd
clusterDNS: clusterDNS:
- ${cluster_dns_service_ip} - ${cluster_dns_service_ip}
clusterDomain: ${cluster_domain_suffix} clusterDomain: cluster.local
healthzPort: 0 healthzPort: 0
rotateCertificates: true rotateCertificates: true
shutdownGracePeriod: 45s shutdownGracePeriod: 45s

View File

@ -1,25 +1,9 @@
# Discrete DNS records for each controller's private IPv4 for etcd usage
resource "azurerm_dns_a_record" "etcds" {
count = var.controller_count
resource_group_name = var.dns_zone_group
# DNS Zone name where record should be created
zone_name = var.dns_zone
# DNS record
name = format("%s-etcd%d", var.cluster_name, count.index)
ttl = 300
# private IPv4 address for etcd
records = [azurerm_network_interface.controllers.*.private_ip_address[count.index]]
}
locals { locals {
# Container Linux derivative # Container Linux derivative
# flatcar-stable -> Flatcar Linux Stable # flatcar-stable -> Flatcar Linux Stable
channel = split("-", var.os_image)[1] channel = split("-", var.os_image)[1]
offer_suffix = var.arch == "arm64" ? "corevm" : "free" offer_suffix = var.controller_arch == "arm64" ? "corevm" : "free"
urn = var.arch == "arm64" ? local.channel : "${local.channel}-gen2" urn = var.controller_arch == "arm64" ? local.channel : "${local.channel}-gen2"
# Typhoon ssh_authorized_key supports RSA or a newer formats (e.g. ed25519). # Typhoon ssh_authorized_key supports RSA or a newer formats (e.g. ed25519).
# However, Azure requires an older RSA key to pass validations. To use a # However, Azure requires an older RSA key to pass validations. To use a
@ -28,12 +12,25 @@ locals {
azure_authorized_key = var.azure_authorized_key == "" ? var.ssh_authorized_key : var.azure_authorized_key azure_authorized_key = var.azure_authorized_key == "" ? var.ssh_authorized_key : var.azure_authorized_key
} }
# Discrete DNS records for each controller's private IPv4 for etcd usage
resource "azurerm_dns_a_record" "etcds" {
count = var.controller_count
# DNS Zone name where record should be created
zone_name = var.dns_zone
resource_group_name = var.dns_zone_group
# DNS record
name = format("%s-etcd%d", var.cluster_name, count.index)
ttl = 300
# private IPv4 address for etcd
records = [azurerm_network_interface.controllers[count.index].private_ip_address]
}
# Controller availability set to spread controllers # Controller availability set to spread controllers
resource "azurerm_availability_set" "controllers" { resource "azurerm_availability_set" "controllers" {
resource_group_name = azurerm_resource_group.cluster.name
name = "${var.cluster_name}-controllers" name = "${var.cluster_name}-controllers"
location = var.region resource_group_name = azurerm_resource_group.cluster.name
location = var.location
platform_fault_domain_count = 2 platform_fault_domain_count = 2
platform_update_domain_count = 4 platform_update_domain_count = 4
managed = true managed = true
@ -42,24 +39,19 @@ resource "azurerm_availability_set" "controllers" {
# Controller instances # Controller instances
resource "azurerm_linux_virtual_machine" "controllers" { resource "azurerm_linux_virtual_machine" "controllers" {
count = var.controller_count count = var.controller_count
resource_group_name = azurerm_resource_group.cluster.name
name = "${var.cluster_name}-controller-${count.index}" name = "${var.cluster_name}-controller-${count.index}"
location = var.region resource_group_name = azurerm_resource_group.cluster.name
location = var.location
availability_set_id = azurerm_availability_set.controllers.id availability_set_id = azurerm_availability_set.controllers.id
size = var.controller_type size = var.controller_type
custom_data = base64encode(data.ct_config.controllers.*.rendered[count.index])
boot_diagnostics {
# defaults to a managed storage account
}
# storage # storage
os_disk { os_disk {
name = "${var.cluster_name}-controller-${count.index}" name = "${var.cluster_name}-controller-${count.index}"
storage_account_type = var.controller_disk_type
disk_size_gb = var.controller_disk_size
caching = "None" caching = "None"
disk_size_gb = var.disk_size
storage_account_type = "Premium_LRS"
} }
# Flatcar Container Linux # Flatcar Container Linux
@ -71,7 +63,7 @@ resource "azurerm_linux_virtual_machine" "controllers" {
} }
dynamic "plan" { dynamic "plan" {
for_each = var.arch == "arm64" ? [] : [1] for_each = var.controller_arch == "arm64" ? [] : [1]
content { content {
publisher = "kinvolk" publisher = "kinvolk"
product = "flatcar-container-linux-${local.offer_suffix}" product = "flatcar-container-linux-${local.offer_suffix}"
@ -84,7 +76,13 @@ resource "azurerm_linux_virtual_machine" "controllers" {
azurerm_network_interface.controllers[count.index].id azurerm_network_interface.controllers[count.index].id
] ]
# Azure requires setting admin_ssh_key, though Ignition custom_data handles it too # boot
custom_data = base64encode(data.ct_config.controllers[count.index].rendered)
boot_diagnostics {
# defaults to a managed storage account
}
# Azure requires an RSA admin_ssh_key
admin_username = "core" admin_username = "core"
admin_ssh_key { admin_ssh_key {
username = "core" username = "core"
@ -99,31 +97,52 @@ resource "azurerm_linux_virtual_machine" "controllers" {
} }
} }
# Controller public IPv4 addresses # Controller node public IPv4 addresses
resource "azurerm_public_ip" "controllers" { resource "azurerm_public_ip" "controllers-ipv4" {
count = var.controller_count count = var.controller_count
resource_group_name = azurerm_resource_group.cluster.name
name = "${var.cluster_name}-controller-${count.index}" name = "${var.cluster_name}-controller-${count.index}-ipv4"
resource_group_name = azurerm_resource_group.cluster.name
location = azurerm_resource_group.cluster.location location = azurerm_resource_group.cluster.location
ip_version = "IPv4"
sku = "Standard" sku = "Standard"
allocation_method = "Static" allocation_method = "Static"
} }
# Controller NICs with public and private IPv4 # Controller node public IPv6 addresses
resource "azurerm_public_ip" "controllers-ipv6" {
count = var.controller_count
name = "${var.cluster_name}-controller-${count.index}-ipv6"
resource_group_name = azurerm_resource_group.cluster.name
location = azurerm_resource_group.cluster.location
ip_version = "IPv6"
sku = "Standard"
allocation_method = "Static"
}
# Controllers' network interfaces
resource "azurerm_network_interface" "controllers" { resource "azurerm_network_interface" "controllers" {
count = var.controller_count count = var.controller_count
resource_group_name = azurerm_resource_group.cluster.name
name = "${var.cluster_name}-controller-${count.index}" name = "${var.cluster_name}-controller-${count.index}"
resource_group_name = azurerm_resource_group.cluster.name
location = azurerm_resource_group.cluster.location location = azurerm_resource_group.cluster.location
ip_configuration { ip_configuration {
name = "ip0" name = "ipv4"
primary = true
subnet_id = azurerm_subnet.controller.id subnet_id = azurerm_subnet.controller.id
private_ip_address_allocation = "Dynamic" private_ip_address_allocation = "Dynamic"
# instance public IPv4 private_ip_address_version = "IPv4"
public_ip_address_id = azurerm_public_ip.controllers.*.id[count.index] public_ip_address_id = azurerm_public_ip.controllers-ipv4[count.index].id
}
ip_configuration {
name = "ipv6"
subnet_id = azurerm_subnet.controller.id
private_ip_address_allocation = "Dynamic"
private_ip_address_version = "IPv6"
public_ip_address_id = azurerm_public_ip.controllers-ipv6[count.index].id
} }
} }
@ -135,13 +154,21 @@ resource "azurerm_network_interface_security_group_association" "controllers" {
network_security_group_id = azurerm_network_security_group.controller.id network_security_group_id = azurerm_network_security_group.controller.id
} }
# Associate controller network interface with controller backend address pool # Associate controller network interface with controller backend address pools
resource "azurerm_network_interface_backend_address_pool_association" "controllers" { resource "azurerm_network_interface_backend_address_pool_association" "controllers-ipv4" {
count = var.controller_count count = var.controller_count
network_interface_id = azurerm_network_interface.controllers[count.index].id network_interface_id = azurerm_network_interface.controllers[count.index].id
ip_configuration_name = "ip0" ip_configuration_name = "ipv4"
backend_address_pool_id = azurerm_lb_backend_address_pool.controller.id backend_address_pool_id = azurerm_lb_backend_address_pool.controller-ipv4.id
}
resource "azurerm_network_interface_backend_address_pool_association" "controllers-ipv6" {
count = var.controller_count
network_interface_id = azurerm_network_interface.controllers[count.index].id
ip_configuration_name = "ipv6"
backend_address_pool_id = azurerm_lb_backend_address_pool.controller-ipv6.id
} }
# Flatcar Linux controllers # Flatcar Linux controllers
@ -158,7 +185,6 @@ data "ct_config" "controllers" {
kubeconfig = indent(10, module.bootstrap.kubeconfig-kubelet) kubeconfig = indent(10, module.bootstrap.kubeconfig-kubelet)
ssh_authorized_key = var.ssh_authorized_key ssh_authorized_key = var.ssh_authorized_key
cluster_dns_service_ip = cidrhost(var.service_cidr, 10) cluster_dns_service_ip = cidrhost(var.service_cidr, 10)
cluster_domain_suffix = var.cluster_domain_suffix
}) })
strict = true strict = true
snippets = var.controller_snippets snippets = var.controller_snippets

View File

@ -1,116 +1,164 @@
# DNS record for the apiserver load balancer # DNS A record for the apiserver load balancer
resource "azurerm_dns_a_record" "apiserver" { resource "azurerm_dns_a_record" "apiserver" {
resource_group_name = var.dns_zone_group
# DNS Zone name where record should be created # DNS Zone name where record should be created
zone_name = var.dns_zone zone_name = var.dns_zone
resource_group_name = var.dns_zone_group
# DNS record # DNS record
name = var.cluster_name name = var.cluster_name
ttl = 300 ttl = 300
# IPv4 address of apiserver load balancer # IPv4 address of apiserver load balancer
records = [azurerm_public_ip.apiserver-ipv4.ip_address] records = [azurerm_public_ip.frontend-ipv4.ip_address]
} }
# Static IPv4 address for the apiserver frontend # DNS AAAA record for the apiserver load balancer
resource "azurerm_public_ip" "apiserver-ipv4" { resource "azurerm_dns_aaaa_record" "apiserver" {
resource_group_name = azurerm_resource_group.cluster.name # DNS Zone name where record should be created
zone_name = var.dns_zone
resource_group_name = var.dns_zone_group
# DNS record
name = var.cluster_name
ttl = 300
# IPv6 address of apiserver load balancer
records = [azurerm_public_ip.frontend-ipv6.ip_address]
}
name = "${var.cluster_name}-apiserver-ipv4" # Static IPv4 address for the load balancer
location = var.region resource "azurerm_public_ip" "frontend-ipv4" {
name = "${var.cluster_name}-frontend-ipv4"
resource_group_name = azurerm_resource_group.cluster.name
location = var.location
ip_version = "IPv4"
sku = "Standard" sku = "Standard"
allocation_method = "Static" allocation_method = "Static"
} }
# Static IPv4 address for the ingress frontend # Static IPv6 address for the load balancer
resource "azurerm_public_ip" "ingress-ipv4" { resource "azurerm_public_ip" "frontend-ipv6" {
name = "${var.cluster_name}-frontend-ipv6"
resource_group_name = azurerm_resource_group.cluster.name resource_group_name = azurerm_resource_group.cluster.name
location = var.location
name = "${var.cluster_name}-ingress-ipv4" ip_version = "IPv6"
location = var.region
sku = "Standard" sku = "Standard"
allocation_method = "Static" allocation_method = "Static"
} }
# Network Load Balancer for apiservers and ingress # Network Load Balancer for apiservers and ingress
resource "azurerm_lb" "cluster" { resource "azurerm_lb" "cluster" {
resource_group_name = azurerm_resource_group.cluster.name
name = var.cluster_name name = var.cluster_name
location = var.region resource_group_name = azurerm_resource_group.cluster.name
location = var.location
sku = "Standard" sku = "Standard"
frontend_ip_configuration { frontend_ip_configuration {
name = "apiserver" name = "frontend-ipv4"
public_ip_address_id = azurerm_public_ip.apiserver-ipv4.id public_ip_address_id = azurerm_public_ip.frontend-ipv4.id
} }
frontend_ip_configuration { frontend_ip_configuration {
name = "ingress" name = "frontend-ipv6"
public_ip_address_id = azurerm_public_ip.ingress-ipv4.id public_ip_address_id = azurerm_public_ip.frontend-ipv6.id
} }
} }
resource "azurerm_lb_rule" "apiserver" { resource "azurerm_lb_rule" "apiserver-ipv4" {
name = "apiserver" name = "apiserver-ipv4"
loadbalancer_id = azurerm_lb.cluster.id loadbalancer_id = azurerm_lb.cluster.id
frontend_ip_configuration_name = "apiserver" frontend_ip_configuration_name = "frontend-ipv4"
disable_outbound_snat = true
protocol = "Tcp" protocol = "Tcp"
frontend_port = 6443 frontend_port = 6443
backend_port = 6443 backend_port = 6443
backend_address_pool_ids = [azurerm_lb_backend_address_pool.controller.id] backend_address_pool_ids = [azurerm_lb_backend_address_pool.controller-ipv4.id]
probe_id = azurerm_lb_probe.apiserver.id probe_id = azurerm_lb_probe.apiserver.id
} }
resource "azurerm_lb_rule" "ingress-http" { resource "azurerm_lb_rule" "apiserver-ipv6" {
name = "ingress-http" name = "apiserver-ipv6"
loadbalancer_id = azurerm_lb.cluster.id loadbalancer_id = azurerm_lb.cluster.id
frontend_ip_configuration_name = "ingress" frontend_ip_configuration_name = "frontend-ipv6"
disable_outbound_snat = true
protocol = "Tcp"
frontend_port = 6443
backend_port = 6443
backend_address_pool_ids = [azurerm_lb_backend_address_pool.controller-ipv6.id]
probe_id = azurerm_lb_probe.apiserver.id
}
resource "azurerm_lb_rule" "ingress-http-ipv4" {
name = "ingress-http-ipv4"
loadbalancer_id = azurerm_lb.cluster.id
frontend_ip_configuration_name = "frontend-ipv4"
disable_outbound_snat = true disable_outbound_snat = true
protocol = "Tcp" protocol = "Tcp"
frontend_port = 80 frontend_port = 80
backend_port = 80 backend_port = 80
backend_address_pool_ids = [azurerm_lb_backend_address_pool.worker.id] backend_address_pool_ids = [azurerm_lb_backend_address_pool.worker-ipv4.id]
probe_id = azurerm_lb_probe.ingress.id probe_id = azurerm_lb_probe.ingress.id
} }
resource "azurerm_lb_rule" "ingress-https" { resource "azurerm_lb_rule" "ingress-https-ipv4" {
name = "ingress-https" name = "ingress-https-ipv4"
loadbalancer_id = azurerm_lb.cluster.id loadbalancer_id = azurerm_lb.cluster.id
frontend_ip_configuration_name = "ingress" frontend_ip_configuration_name = "frontend-ipv4"
disable_outbound_snat = true disable_outbound_snat = true
protocol = "Tcp" protocol = "Tcp"
frontend_port = 443 frontend_port = 443
backend_port = 443 backend_port = 443
backend_address_pool_ids = [azurerm_lb_backend_address_pool.worker.id] backend_address_pool_ids = [azurerm_lb_backend_address_pool.worker-ipv4.id]
probe_id = azurerm_lb_probe.ingress.id probe_id = azurerm_lb_probe.ingress.id
} }
# Worker outbound TCP/UDP SNAT resource "azurerm_lb_rule" "ingress-http-ipv6" {
resource "azurerm_lb_outbound_rule" "worker-outbound" { name = "ingress-http-ipv6"
name = "worker"
loadbalancer_id = azurerm_lb.cluster.id loadbalancer_id = azurerm_lb.cluster.id
frontend_ip_configuration { frontend_ip_configuration_name = "frontend-ipv6"
name = "ingress" disable_outbound_snat = true
protocol = "Tcp"
frontend_port = 80
backend_port = 80
backend_address_pool_ids = [azurerm_lb_backend_address_pool.worker-ipv6.id]
probe_id = azurerm_lb_probe.ingress.id
} }
protocol = "All" resource "azurerm_lb_rule" "ingress-https-ipv6" {
backend_address_pool_id = azurerm_lb_backend_address_pool.worker.id name = "ingress-https-ipv6"
loadbalancer_id = azurerm_lb.cluster.id
frontend_ip_configuration_name = "frontend-ipv6"
disable_outbound_snat = true
protocol = "Tcp"
frontend_port = 443
backend_port = 443
backend_address_pool_ids = [azurerm_lb_backend_address_pool.worker-ipv6.id]
probe_id = azurerm_lb_probe.ingress.id
} }
# Backend Address Pools
# Address pool of controllers # Address pool of controllers
resource "azurerm_lb_backend_address_pool" "controller" { resource "azurerm_lb_backend_address_pool" "controller-ipv4" {
name = "controller" name = "controller-ipv4"
loadbalancer_id = azurerm_lb.cluster.id loadbalancer_id = azurerm_lb.cluster.id
} }
# Address pool of workers resource "azurerm_lb_backend_address_pool" "controller-ipv6" {
resource "azurerm_lb_backend_address_pool" "worker" { name = "controller-ipv6"
name = "worker" loadbalancer_id = azurerm_lb.cluster.id
}
# Address pools for workers
resource "azurerm_lb_backend_address_pool" "worker-ipv4" {
name = "worker-ipv4"
loadbalancer_id = azurerm_lb.cluster.id
}
resource "azurerm_lb_backend_address_pool" "worker-ipv6" {
name = "worker-ipv6"
loadbalancer_id = azurerm_lb.cluster.id loadbalancer_id = azurerm_lb.cluster.id
} }
@ -122,10 +170,8 @@ resource "azurerm_lb_probe" "apiserver" {
loadbalancer_id = azurerm_lb.cluster.id loadbalancer_id = azurerm_lb.cluster.id
protocol = "Tcp" protocol = "Tcp"
port = 6443 port = 6443
# unhealthy threshold # unhealthy threshold
number_of_probes = 3 number_of_probes = 3
interval_in_seconds = 5 interval_in_seconds = 5
} }
@ -136,10 +182,29 @@ resource "azurerm_lb_probe" "ingress" {
protocol = "Http" protocol = "Http"
port = 10254 port = 10254
request_path = "/healthz" request_path = "/healthz"
# unhealthy threshold # unhealthy threshold
number_of_probes = 3 number_of_probes = 3
interval_in_seconds = 5 interval_in_seconds = 5
} }
# Outbound SNAT
resource "azurerm_lb_outbound_rule" "outbound-ipv4" {
name = "outbound-ipv4"
protocol = "All"
loadbalancer_id = azurerm_lb.cluster.id
backend_address_pool_id = azurerm_lb_backend_address_pool.worker-ipv4.id
frontend_ip_configuration {
name = "frontend-ipv4"
}
}
resource "azurerm_lb_outbound_rule" "outbound-ipv6" {
name = "outbound-ipv6"
protocol = "All"
loadbalancer_id = azurerm_lb.cluster.id
backend_address_pool_id = azurerm_lb_backend_address_pool.worker-ipv6.id
frontend_ip_configuration {
name = "frontend-ipv6"
}
}

View File

@ -0,0 +1,6 @@
locals {
backend_address_pool_ids = {
ipv4 = [azurerm_lb_backend_address_pool.worker-ipv4.id]
ipv6 = [azurerm_lb_backend_address_pool.worker-ipv6.id]
}
}

View File

@ -1,27 +1,63 @@
# Choose an IPv6 ULA subnet at random
# https://datatracker.ietf.org/doc/html/rfc4193
resource "random_id" "ula-netnum" {
byte_length = 5 # 40 bits
}
locals {
# fd00::/8 -> shift 40 -> 2^40 possible /48 subnets
ula-range = cidrsubnet("fd00::/8", 40, random_id.ula-netnum.dec)
network_cidr = {
ipv4 = var.network_cidr.ipv4
ipv6 = length(var.network_cidr.ipv6) > 0 ? var.network_cidr.ipv6 : [local.ula-range]
}
# Subdivide the virtual network into subnets
# - controllers use netnum 0
# - workers use netnum 1
controller_subnets = {
ipv4 = [for i, cidr in local.network_cidr.ipv4 : cidrsubnet(cidr, 1, 0)]
ipv6 = [for i, cidr in local.network_cidr.ipv6 : cidrsubnet(cidr, 16, 0)]
}
worker_subnets = {
ipv4 = [for i, cidr in local.network_cidr.ipv4 : cidrsubnet(cidr, 1, 1)]
ipv6 = [for i, cidr in local.network_cidr.ipv6 : cidrsubnet(cidr, 16, 1)]
}
cluster_subnets = {
ipv4 = concat(local.controller_subnets.ipv4, local.worker_subnets.ipv4)
ipv6 = concat(local.controller_subnets.ipv6, local.worker_subnets.ipv6)
}
}
# Organize cluster into a resource group # Organize cluster into a resource group
resource "azurerm_resource_group" "cluster" { resource "azurerm_resource_group" "cluster" {
name = var.cluster_name name = var.cluster_name
location = var.region location = var.location
} }
resource "azurerm_virtual_network" "network" { resource "azurerm_virtual_network" "network" {
resource_group_name = azurerm_resource_group.cluster.name
name = var.cluster_name name = var.cluster_name
resource_group_name = azurerm_resource_group.cluster.name
location = azurerm_resource_group.cluster.location location = azurerm_resource_group.cluster.location
address_space = [var.host_cidr] address_space = concat(
local.network_cidr.ipv4,
local.network_cidr.ipv6
)
} }
# Subnets - separate subnets for controller and workers because Azure # Subnets - separate subnets for controllers and workers because Azure
# network security groups are based on IPv4 CIDR rather than instance # network security groups are oriented around address prefixes rather
# tags like GCP or security group membership like AWS # than instance tags (GCP) or security group membership (AWS)
resource "azurerm_subnet" "controller" { resource "azurerm_subnet" "controller" {
resource_group_name = azurerm_resource_group.cluster.name
name = "controller" name = "controller"
resource_group_name = azurerm_resource_group.cluster.name
virtual_network_name = azurerm_virtual_network.network.name virtual_network_name = azurerm_virtual_network.network.name
address_prefixes = [cidrsubnet(var.host_cidr, 1, 0)] address_prefixes = concat(
local.controller_subnets.ipv4,
local.controller_subnets.ipv6,
)
default_outbound_access_enabled = false
} }
resource "azurerm_subnet_network_security_group_association" "controller" { resource "azurerm_subnet_network_security_group_association" "controller" {
@ -30,11 +66,14 @@ resource "azurerm_subnet_network_security_group_association" "controller" {
} }
resource "azurerm_subnet" "worker" { resource "azurerm_subnet" "worker" {
resource_group_name = azurerm_resource_group.cluster.name
name = "worker" name = "worker"
resource_group_name = azurerm_resource_group.cluster.name
virtual_network_name = azurerm_virtual_network.network.name virtual_network_name = azurerm_virtual_network.network.name
address_prefixes = [cidrsubnet(var.host_cidr, 1, 1)] address_prefixes = concat(
local.worker_subnets.ipv4,
local.worker_subnets.ipv6,
)
default_outbound_access_enabled = false
} }
resource "azurerm_subnet_network_security_group_association" "worker" { resource "azurerm_subnet_network_security_group_association" "worker" {

View File

@ -6,13 +6,18 @@ output "kubeconfig-admin" {
# Outputs for Kubernetes Ingress # Outputs for Kubernetes Ingress
output "ingress_static_ipv4" { output "ingress_static_ipv4" {
value = azurerm_public_ip.ingress-ipv4.ip_address value = azurerm_public_ip.frontend-ipv4.ip_address
description = "IPv4 address of the load balancer for distributing traffic to Ingress controllers" description = "IPv4 address of the load balancer for distributing traffic to Ingress controllers"
} }
output "ingress_static_ipv6" {
value = azurerm_public_ip.frontend-ipv6.ip_address
description = "IPv6 address of the load balancer for distributing traffic to Ingress controllers"
}
# Outputs for worker pools # Outputs for worker pools
output "region" { output "location" {
value = azurerm_resource_group.cluster.location value = azurerm_resource_group.cluster.location
} }
@ -51,12 +56,12 @@ output "worker_security_group_name" {
output "controller_address_prefixes" { output "controller_address_prefixes" {
description = "Controller network subnet CIDR addresses (for source/destination)" description = "Controller network subnet CIDR addresses (for source/destination)"
value = azurerm_subnet.controller.address_prefixes value = local.controller_subnets
} }
output "worker_address_prefixes" { output "worker_address_prefixes" {
description = "Worker network subnet CIDR addresses (for source/destination)" description = "Worker network subnet CIDR addresses (for source/destination)"
value = azurerm_subnet.worker.address_prefixes value = local.worker_subnets
} }
# Outputs for custom load balancing # Outputs for custom load balancing
@ -66,9 +71,12 @@ output "loadbalancer_id" {
value = azurerm_lb.cluster.id value = azurerm_lb.cluster.id
} }
output "backend_address_pool_id" { output "backend_address_pool_ids" {
description = "ID of the worker backend address pool" description = "IDs of the worker backend address pools"
value = azurerm_lb_backend_address_pool.worker.id value = {
ipv4 = [azurerm_lb_backend_address_pool.worker-ipv4.id]
ipv6 = [azurerm_lb_backend_address_pool.worker-ipv6.id]
}
} }
# Outputs for debug # Outputs for debug

View File

@ -1,214 +1,223 @@
# Controller security group # Controller security group
resource "azurerm_network_security_group" "controller" { resource "azurerm_network_security_group" "controller" {
resource_group_name = azurerm_resource_group.cluster.name
name = "${var.cluster_name}-controller" name = "${var.cluster_name}-controller"
resource_group_name = azurerm_resource_group.cluster.name
location = azurerm_resource_group.cluster.location location = azurerm_resource_group.cluster.location
} }
resource "azurerm_network_security_rule" "controller-icmp" { resource "azurerm_network_security_rule" "controller-icmp" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.controller_subnets
name = "allow-icmp" name = "allow-icmp-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.controller.name network_security_group_name = azurerm_network_security_group.controller.name
priority = "1995" priority = 1995 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Icmp" protocol = "Icmp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "*" destination_port_range = "*"
source_address_prefixes = concat(azurerm_subnet.controller.address_prefixes, azurerm_subnet.worker.address_prefixes) source_address_prefixes = local.cluster_subnets[each.key]
destination_address_prefixes = azurerm_subnet.controller.address_prefixes destination_address_prefixes = local.controller_subnets[each.key]
} }
resource "azurerm_network_security_rule" "controller-ssh" { resource "azurerm_network_security_rule" "controller-ssh" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.controller_subnets
name = "allow-ssh" name = "allow-ssh-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.controller.name network_security_group_name = azurerm_network_security_group.controller.name
priority = "2000" priority = 2000 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "22" destination_port_range = "22"
source_address_prefix = "*" source_address_prefix = "*"
destination_address_prefixes = azurerm_subnet.controller.address_prefixes destination_address_prefixes = local.controller_subnets[each.key]
} }
resource "azurerm_network_security_rule" "controller-etcd" { resource "azurerm_network_security_rule" "controller-etcd" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.controller_subnets
name = "allow-etcd" name = "allow-etcd-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.controller.name network_security_group_name = azurerm_network_security_group.controller.name
priority = "2005" priority = 2005 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "2379-2380" destination_port_range = "2379-2380"
source_address_prefixes = azurerm_subnet.controller.address_prefixes source_address_prefixes = local.controller_subnets[each.key]
destination_address_prefixes = azurerm_subnet.controller.address_prefixes destination_address_prefixes = local.controller_subnets[each.key]
} }
# Allow Prometheus to scrape etcd metrics # Allow Prometheus to scrape etcd metrics
resource "azurerm_network_security_rule" "controller-etcd-metrics" { resource "azurerm_network_security_rule" "controller-etcd-metrics" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.controller_subnets
name = "allow-etcd-metrics" name = "allow-etcd-metrics-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.controller.name network_security_group_name = azurerm_network_security_group.controller.name
priority = "2010" priority = 2010 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "2381" destination_port_range = "2381"
source_address_prefixes = azurerm_subnet.worker.address_prefixes source_address_prefixes = local.worker_subnets[each.key]
destination_address_prefixes = azurerm_subnet.controller.address_prefixes destination_address_prefixes = local.controller_subnets[each.key]
} }
# Allow Prometheus to scrape kube-proxy metrics # Allow Prometheus to scrape kube-proxy metrics
resource "azurerm_network_security_rule" "controller-kube-proxy" { resource "azurerm_network_security_rule" "controller-kube-proxy" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.controller_subnets
name = "allow-kube-proxy-metrics" name = "allow-kube-proxy-metrics-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.controller.name network_security_group_name = azurerm_network_security_group.controller.name
priority = "2011" priority = 2012 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "10249" destination_port_range = "10249"
source_address_prefixes = azurerm_subnet.worker.address_prefixes source_address_prefixes = local.worker_subnets[each.key]
destination_address_prefixes = azurerm_subnet.controller.address_prefixes destination_address_prefixes = local.controller_subnets[each.key]
} }
# Allow Prometheus to scrape kube-scheduler and kube-controller-manager metrics # Allow Prometheus to scrape kube-scheduler and kube-controller-manager metrics
resource "azurerm_network_security_rule" "controller-kube-metrics" { resource "azurerm_network_security_rule" "controller-kube-metrics" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.controller_subnets
name = "allow-kube-metrics" name = "allow-kube-metrics-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.controller.name network_security_group_name = azurerm_network_security_group.controller.name
priority = "2012" priority = 2014 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "10257-10259" destination_port_range = "10257-10259"
source_address_prefixes = azurerm_subnet.worker.address_prefixes source_address_prefixes = local.worker_subnets[each.key]
destination_address_prefixes = azurerm_subnet.controller.address_prefixes destination_address_prefixes = local.controller_subnets[each.key]
} }
resource "azurerm_network_security_rule" "controller-apiserver" { resource "azurerm_network_security_rule" "controller-apiserver" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.controller_subnets
name = "allow-apiserver" name = "allow-apiserver-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.controller.name network_security_group_name = azurerm_network_security_group.controller.name
priority = "2015" priority = 2016 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "6443" destination_port_range = "6443"
source_address_prefix = "*" source_address_prefix = "*"
destination_address_prefixes = azurerm_subnet.controller.address_prefixes destination_address_prefixes = local.controller_subnets[each.key]
} }
resource "azurerm_network_security_rule" "controller-cilium-health" { resource "azurerm_network_security_rule" "controller-cilium-health" {
resource_group_name = azurerm_resource_group.cluster.name for_each = var.networking == "cilium" ? local.controller_subnets : {}
count = var.networking == "cilium" ? 1 : 0
name = "allow-cilium-health" name = "allow-cilium-health-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.controller.name network_security_group_name = azurerm_network_security_group.controller.name
priority = "2018" priority = 2018 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "4240" destination_port_range = "4240"
source_address_prefixes = concat(azurerm_subnet.controller.address_prefixes, azurerm_subnet.worker.address_prefixes) source_address_prefixes = local.cluster_subnets[each.key]
destination_address_prefixes = azurerm_subnet.controller.address_prefixes destination_address_prefixes = local.controller_subnets[each.key]
} }
resource "azurerm_network_security_rule" "controller-cilium-metrics" { resource "azurerm_network_security_rule" "controller-cilium-metrics" {
resource_group_name = azurerm_resource_group.cluster.name for_each = var.networking == "cilium" ? local.controller_subnets : {}
count = var.networking == "cilium" ? 1 : 0
name = "allow-cilium-metrics" name = "allow-cilium-metrics-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.controller.name network_security_group_name = azurerm_network_security_group.controller.name
priority = "2019" priority = 2035 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "9962-9965" destination_port_range = "9962-9965"
source_address_prefixes = concat(azurerm_subnet.controller.address_prefixes, azurerm_subnet.worker.address_prefixes) source_address_prefixes = local.cluster_subnets[each.key]
destination_address_prefixes = azurerm_subnet.controller.address_prefixes destination_address_prefixes = local.controller_subnets[each.key]
} }
resource "azurerm_network_security_rule" "controller-vxlan" { resource "azurerm_network_security_rule" "controller-vxlan" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.controller_subnets
name = "allow-vxlan" name = "allow-vxlan-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.controller.name network_security_group_name = azurerm_network_security_group.controller.name
priority = "2020" priority = 2020 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Udp" protocol = "Udp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "4789" destination_port_range = "4789"
source_address_prefixes = concat(azurerm_subnet.controller.address_prefixes, azurerm_subnet.worker.address_prefixes) source_address_prefixes = local.cluster_subnets[each.key]
destination_address_prefixes = azurerm_subnet.controller.address_prefixes destination_address_prefixes = local.controller_subnets[each.key]
} }
resource "azurerm_network_security_rule" "controller-linux-vxlan" { resource "azurerm_network_security_rule" "controller-linux-vxlan" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.controller_subnets
name = "allow-linux-vxlan" name = "allow-linux-vxlan-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.controller.name network_security_group_name = azurerm_network_security_group.controller.name
priority = "2021" priority = 2022 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Udp" protocol = "Udp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "8472" destination_port_range = "8472"
source_address_prefixes = concat(azurerm_subnet.controller.address_prefixes, azurerm_subnet.worker.address_prefixes) source_address_prefixes = local.cluster_subnets[each.key]
destination_address_prefixes = azurerm_subnet.controller.address_prefixes destination_address_prefixes = local.controller_subnets[each.key]
} }
# Allow Prometheus to scrape node-exporter daemonset # Allow Prometheus to scrape node-exporter daemonset
resource "azurerm_network_security_rule" "controller-node-exporter" { resource "azurerm_network_security_rule" "controller-node-exporter" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.controller_subnets
name = "allow-node-exporter" name = "allow-node-exporter-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.controller.name network_security_group_name = azurerm_network_security_group.controller.name
priority = "2025" priority = 2025 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "9100" destination_port_range = "9100"
source_address_prefixes = azurerm_subnet.worker.address_prefixes source_address_prefixes = local.worker_subnets[each.key]
destination_address_prefixes = azurerm_subnet.controller.address_prefixes destination_address_prefixes = local.controller_subnets[each.key]
} }
# Allow apiserver to access kubelet's for exec, log, port-forward # Allow apiserver to access kubelet's for exec, log, port-forward
resource "azurerm_network_security_rule" "controller-kubelet" { resource "azurerm_network_security_rule" "controller-kubelet" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.controller_subnets
name = "allow-kubelet" name = "allow-kubelet-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.controller.name network_security_group_name = azurerm_network_security_group.controller.name
priority = "2030" priority = 2030 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "10250" destination_port_range = "10250"
# allow Prometheus to scrape kubelet metrics too # allow Prometheus to scrape kubelet metrics too
source_address_prefixes = concat(azurerm_subnet.controller.address_prefixes, azurerm_subnet.worker.address_prefixes) source_address_prefixes = local.cluster_subnets[each.key]
destination_address_prefixes = azurerm_subnet.controller.address_prefixes destination_address_prefixes = local.controller_subnets[each.key]
} }
# Override Azure AllowVNetInBound and AllowAzureLoadBalancerInBound # Override Azure AllowVNetInBound and AllowAzureLoadBalancerInBound
@ -247,182 +256,189 @@ resource "azurerm_network_security_rule" "controller-deny-all" {
# Worker security group # Worker security group
resource "azurerm_network_security_group" "worker" { resource "azurerm_network_security_group" "worker" {
resource_group_name = azurerm_resource_group.cluster.name
name = "${var.cluster_name}-worker" name = "${var.cluster_name}-worker"
resource_group_name = azurerm_resource_group.cluster.name
location = azurerm_resource_group.cluster.location location = azurerm_resource_group.cluster.location
} }
resource "azurerm_network_security_rule" "worker-icmp" { resource "azurerm_network_security_rule" "worker-icmp" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.worker_subnets
name = "allow-icmp" name = "allow-icmp-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.worker.name network_security_group_name = azurerm_network_security_group.worker.name
priority = "1995" priority = 1995 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Icmp" protocol = "Icmp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "*" destination_port_range = "*"
source_address_prefixes = concat(azurerm_subnet.controller.address_prefixes, azurerm_subnet.worker.address_prefixes) source_address_prefixes = local.cluster_subnets[each.key]
destination_address_prefixes = azurerm_subnet.worker.address_prefixes destination_address_prefixes = local.worker_subnets[each.key]
} }
resource "azurerm_network_security_rule" "worker-ssh" { resource "azurerm_network_security_rule" "worker-ssh" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.worker_subnets
name = "allow-ssh" name = "allow-ssh-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.worker.name network_security_group_name = azurerm_network_security_group.worker.name
priority = "2000" priority = 2000 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "22" destination_port_range = "22"
source_address_prefixes = azurerm_subnet.controller.address_prefixes source_address_prefixes = local.controller_subnets[each.key]
destination_address_prefixes = azurerm_subnet.worker.address_prefixes destination_address_prefixes = local.worker_subnets[each.key]
} }
resource "azurerm_network_security_rule" "worker-http" { resource "azurerm_network_security_rule" "worker-http" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.worker_subnets
name = "allow-http" name = "allow-http-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.worker.name network_security_group_name = azurerm_network_security_group.worker.name
priority = "2005" priority = 2005 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "80" destination_port_range = "80"
source_address_prefix = "*" source_address_prefix = "*"
destination_address_prefixes = azurerm_subnet.worker.address_prefixes destination_address_prefixes = local.worker_subnets[each.key]
} }
resource "azurerm_network_security_rule" "worker-https" { resource "azurerm_network_security_rule" "worker-https" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.worker_subnets
name = "allow-https" name = "allow-https-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.worker.name network_security_group_name = azurerm_network_security_group.worker.name
priority = "2010" priority = 2010 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "443" destination_port_range = "443"
source_address_prefix = "*" source_address_prefix = "*"
destination_address_prefixes = azurerm_subnet.worker.address_prefixes destination_address_prefixes = local.worker_subnets[each.key]
} }
resource "azurerm_network_security_rule" "worker-cilium-health" { resource "azurerm_network_security_rule" "worker-cilium-health" {
resource_group_name = azurerm_resource_group.cluster.name for_each = var.networking == "cilium" ? local.worker_subnets : {}
count = var.networking == "cilium" ? 1 : 0
name = "allow-cilium-health" name = "allow-cilium-health-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.worker.name network_security_group_name = azurerm_network_security_group.worker.name
priority = "2013" priority = 2012 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "4240" destination_port_range = "4240"
source_address_prefixes = concat(azurerm_subnet.controller.address_prefixes, azurerm_subnet.worker.address_prefixes) source_address_prefixes = local.cluster_subnets[each.key]
destination_address_prefixes = azurerm_subnet.worker.address_prefixes destination_address_prefixes = local.worker_subnets[each.key]
} }
resource "azurerm_network_security_rule" "worker-cilium-metrics" { resource "azurerm_network_security_rule" "worker-cilium-metrics" {
resource_group_name = azurerm_resource_group.cluster.name for_each = var.networking == "cilium" ? local.worker_subnets : {}
count = var.networking == "cilium" ? 1 : 0
name = "allow-cilium-metrics" name = "allow-cilium-metrics-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.worker.name network_security_group_name = azurerm_network_security_group.worker.name
priority = "2014" priority = 2014 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "9962-9965" destination_port_range = "9962-9965"
source_address_prefixes = concat(azurerm_subnet.controller.address_prefixes, azurerm_subnet.worker.address_prefixes) source_address_prefixes = local.cluster_subnets[each.key]
destination_address_prefixes = azurerm_subnet.worker.address_prefixes destination_address_prefixes = local.worker_subnets[each.key]
} }
resource "azurerm_network_security_rule" "worker-vxlan" { resource "azurerm_network_security_rule" "worker-vxlan" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.worker_subnets
name = "allow-vxlan" name = "allow-vxlan-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.worker.name network_security_group_name = azurerm_network_security_group.worker.name
priority = "2015" priority = 2016 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Udp" protocol = "Udp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "4789" destination_port_range = "4789"
source_address_prefixes = concat(azurerm_subnet.controller.address_prefixes, azurerm_subnet.worker.address_prefixes) source_address_prefixes = local.cluster_subnets[each.key]
destination_address_prefixes = azurerm_subnet.worker.address_prefixes destination_address_prefixes = local.worker_subnets[each.key]
} }
resource "azurerm_network_security_rule" "worker-linux-vxlan" { resource "azurerm_network_security_rule" "worker-linux-vxlan" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.worker_subnets
name = "allow-linux-vxlan" name = "allow-linux-vxlan-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.worker.name network_security_group_name = azurerm_network_security_group.worker.name
priority = "2016" priority = 2018 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Udp" protocol = "Udp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "8472" destination_port_range = "8472"
source_address_prefixes = concat(azurerm_subnet.controller.address_prefixes, azurerm_subnet.worker.address_prefixes) source_address_prefixes = local.cluster_subnets[each.key]
destination_address_prefixes = azurerm_subnet.worker.address_prefixes destination_address_prefixes = local.worker_subnets[each.key]
} }
# Allow Prometheus to scrape node-exporter daemonset # Allow Prometheus to scrape node-exporter daemonset
resource "azurerm_network_security_rule" "worker-node-exporter" { resource "azurerm_network_security_rule" "worker-node-exporter" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.worker_subnets
name = "allow-node-exporter" name = "allow-node-exporter-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.worker.name network_security_group_name = azurerm_network_security_group.worker.name
priority = "2020" priority = 2020 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "9100" destination_port_range = "9100"
source_address_prefixes = azurerm_subnet.worker.address_prefixes source_address_prefixes = local.worker_subnets[each.key]
destination_address_prefixes = azurerm_subnet.worker.address_prefixes destination_address_prefixes = local.worker_subnets[each.key]
} }
# Allow Prometheus to scrape kube-proxy # Allow Prometheus to scrape kube-proxy
resource "azurerm_network_security_rule" "worker-kube-proxy" { resource "azurerm_network_security_rule" "worker-kube-proxy" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.worker_subnets
name = "allow-kube-proxy" name = "allow-kube-proxy-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.worker.name network_security_group_name = azurerm_network_security_group.worker.name
priority = "2024" priority = 2024 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "10249" destination_port_range = "10249"
source_address_prefixes = azurerm_subnet.worker.address_prefixes source_address_prefixes = local.worker_subnets[each.key]
destination_address_prefixes = azurerm_subnet.worker.address_prefixes destination_address_prefixes = local.worker_subnets[each.key]
} }
# Allow apiserver to access kubelet's for exec, log, port-forward # Allow apiserver to access kubelet's for exec, log, port-forward
resource "azurerm_network_security_rule" "worker-kubelet" { resource "azurerm_network_security_rule" "worker-kubelet" {
resource_group_name = azurerm_resource_group.cluster.name for_each = local.worker_subnets
name = "allow-kubelet" name = "allow-kubelet-${each.key}"
resource_group_name = azurerm_resource_group.cluster.name
network_security_group_name = azurerm_network_security_group.worker.name network_security_group_name = azurerm_network_security_group.worker.name
priority = "2025" priority = 2026 + (each.key == "ipv4" ? 0 : 1)
access = "Allow" access = "Allow"
direction = "Inbound" direction = "Inbound"
protocol = "Tcp" protocol = "Tcp"
source_port_range = "*" source_port_range = "*"
destination_port_range = "10250" destination_port_range = "10250"
# allow Prometheus to scrape kubelet metrics too # allow Prometheus to scrape kubelet metrics too
source_address_prefixes = concat(azurerm_subnet.controller.address_prefixes, azurerm_subnet.worker.address_prefixes) source_address_prefixes = local.cluster_subnets[each.key]
destination_address_prefixes = azurerm_subnet.worker.address_prefixes destination_address_prefixes = local.worker_subnets[each.key]
} }
# Override Azure AllowVNetInBound and AllowAzureLoadBalancerInBound # Override Azure AllowVNetInBound and AllowAzureLoadBalancerInBound

View File

@ -18,7 +18,7 @@ resource "null_resource" "copy-controller-secrets" {
connection { connection {
type = "ssh" type = "ssh"
host = azurerm_public_ip.controllers.*.ip_address[count.index] host = azurerm_public_ip.controllers-ipv4[count.index].ip_address
user = "core" user = "core"
timeout = "15m" timeout = "15m"
} }
@ -45,7 +45,7 @@ resource "null_resource" "bootstrap" {
connection { connection {
type = "ssh" type = "ssh"
host = azurerm_public_ip.controllers.*.ip_address[0] host = azurerm_public_ip.controllers-ipv4[0].ip_address
user = "core" user = "core"
timeout = "15m" timeout = "15m"
} }

View File

@ -5,9 +5,9 @@ variable "cluster_name" {
# Azure # Azure
variable "region" { variable "location" {
type = string type = string
description = "Azure Region (e.g. centralus , see `az account list-locations --output table`)" description = "Azure location (e.g. centralus , see `az account list-locations --output table`)"
} }
variable "dns_zone" { variable "dns_zone" {
@ -22,30 +22,6 @@ variable "dns_zone_group" {
# instances # instances
variable "controller_count" {
type = number
description = "Number of controllers (i.e. masters)"
default = 1
}
variable "worker_count" {
type = number
description = "Number of workers"
default = 1
}
variable "controller_type" {
type = string
description = "Machine type for controllers (see `az vm list-skus --location centralus`)"
default = "Standard_B2s"
}
variable "worker_type" {
type = string
description = "Machine type for workers (see `az vm list-skus --location centralus`)"
default = "Standard_D2as_v5"
}
variable "os_image" { variable "os_image" {
type = string type = string
description = "Channel for a Container Linux derivative (flatcar-stable, flatcar-beta, flatcar-alpha)" description = "Channel for a Container Linux derivative (flatcar-stable, flatcar-beta, flatcar-alpha)"
@ -57,12 +33,60 @@ variable "os_image" {
} }
} }
variable "disk_size" { variable "controller_count" {
type = number type = number
description = "Size of the disk in GB" description = "Number of controllers (i.e. masters)"
default = 1
}
variable "controller_type" {
type = string
description = "Machine type for controllers (see `az vm list-skus --location centralus`)"
default = "Standard_B2s"
}
variable "controller_disk_type" {
type = string
description = "Type of managed disk for controller node(s)"
default = "Premium_LRS"
}
variable "controller_disk_size" {
type = number
description = "Size of the managed disk in GB for controller node(s)"
default = 30 default = 30
} }
variable "worker_count" {
type = number
description = "Number of workers"
default = 1
}
variable "worker_type" {
type = string
description = "Machine type for workers (see `az vm list-skus --location centralus`)"
default = "Standard_D2as_v5"
}
variable "worker_disk_type" {
type = string
description = "Type of managed disk for worker nodes"
default = "Standard_LRS"
}
variable "worker_disk_size" {
type = number
description = "Size of the managed disk in GB for worker nodes"
default = 30
}
variable "worker_ephemeral_disk" {
type = bool
description = "Use ephemeral local disk instead of managed disk (requires vm_type with local storage)"
default = false
}
variable "worker_priority" { variable "worker_priority" {
type = string type = string
description = "Set worker priority to Spot to use reduced cost surplus capacity, with the tradeoff that instances can be deallocated at any time." description = "Set worker priority to Spot to use reduced cost surplus capacity, with the tradeoff that instances can be deallocated at any time."
@ -100,10 +124,15 @@ variable "networking" {
default = "cilium" default = "cilium"
} }
variable "host_cidr" { variable "network_cidr" {
type = string type = object({
description = "CIDR IPv4 range to assign to instances" ipv4 = list(string)
default = "10.0.0.0/16" ipv6 = optional(list(string), [])
})
description = "Virtual network CIDR ranges"
default = {
ipv4 = ["10.0.0.0/16"]
}
} }
variable "pod_cidr" { variable "pod_cidr" {
@ -121,32 +150,31 @@ EOD
default = "10.3.0.0/16" default = "10.3.0.0/16"
} }
variable "enable_reporting" {
type = bool
description = "Enable usage or analytics reporting to upstreams (Calico)"
default = false
}
variable "enable_aggregation" {
type = bool
description = "Enable the Kubernetes Aggregation Layer"
default = true
}
variable "worker_node_labels" { variable "worker_node_labels" {
type = list(string) type = list(string)
description = "List of initial worker node labels" description = "List of initial worker node labels"
default = [] default = []
} }
variable "arch" { # advanced
type = string
description = "Container architecture (amd64 or arm64)"
default = "amd64"
variable "controller_arch" {
type = string
description = "Controller node(s) architecture (amd64 or arm64)"
default = "amd64"
validation { validation {
condition = var.arch == "amd64" || var.arch == "arm64" condition = contains(["amd64", "arm64"], var.controller_arch)
error_message = "The arch must be amd64 or arm64." error_message = "The controller_arch must be amd64 or arm64."
}
}
variable "worker_arch" {
type = string
description = "Worker node(s) architecture (amd64 or arm64)"
default = "amd64"
validation {
condition = contains(["amd64", "arm64"], var.worker_arch)
error_message = "The worker_arch must be amd64 or arm64."
} }
} }
@ -156,14 +184,6 @@ variable "daemonset_tolerations" {
default = [] default = []
} }
# unofficial, undocumented, unsupported
variable "cluster_domain_suffix" {
type = string
description = "Queries for domains with the suffix will be answered by coredns. Default is cluster.local (e.g. foo.default.svc.cluster.local) "
default = "cluster.local"
}
variable "components" { variable "components" {
description = "Configure pre-installed cluster components" description = "Configure pre-installed cluster components"
# Component configs are passed through to terraform-render-bootstrap, # Component configs are passed through to terraform-render-bootstrap,

View File

@ -3,7 +3,7 @@
terraform { terraform {
required_version = ">= 0.13.0, < 2.0.0" required_version = ">= 0.13.0, < 2.0.0"
required_providers { required_providers {
azurerm = ">= 2.8, < 4.0" azurerm = ">= 2.8"
null = ">= 2.1" null = ">= 2.1"
ct = { ct = {
source = "poseidon/ct" source = "poseidon/ct"

View File

@ -4,14 +4,17 @@ module "workers" {
# Azure # Azure
resource_group_name = azurerm_resource_group.cluster.name resource_group_name = azurerm_resource_group.cluster.name
region = azurerm_resource_group.cluster.location location = azurerm_resource_group.cluster.location
subnet_id = azurerm_subnet.worker.id subnet_id = azurerm_subnet.worker.id
security_group_id = azurerm_network_security_group.worker.id security_group_id = azurerm_network_security_group.worker.id
backend_address_pool_id = azurerm_lb_backend_address_pool.worker.id backend_address_pool_ids = local.backend_address_pool_ids
worker_count = var.worker_count worker_count = var.worker_count
vm_type = var.worker_type vm_type = var.worker_type
os_image = var.os_image os_image = var.os_image
disk_type = var.worker_disk_type
disk_size = var.worker_disk_size
ephemeral_disk = var.worker_ephemeral_disk
priority = var.worker_priority priority = var.worker_priority
# configuration # configuration
@ -19,8 +22,7 @@ module "workers" {
ssh_authorized_key = var.ssh_authorized_key ssh_authorized_key = var.ssh_authorized_key
azure_authorized_key = var.azure_authorized_key azure_authorized_key = var.azure_authorized_key
service_cidr = var.service_cidr service_cidr = var.service_cidr
cluster_domain_suffix = var.cluster_domain_suffix
snippets = var.worker_snippets snippets = var.worker_snippets
node_labels = var.worker_node_labels node_labels = var.worker_node_labels
arch = var.arch arch = var.worker_arch
} }

View File

@ -28,7 +28,7 @@ systemd:
After=docker.service After=docker.service
Wants=rpc-statd.service Wants=rpc-statd.service
[Service] [Service]
Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.30.1 Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.31.3
ExecStartPre=/bin/mkdir -p /etc/cni/net.d ExecStartPre=/bin/mkdir -p /etc/cni/net.d
ExecStartPre=/bin/mkdir -p /etc/kubernetes/manifests ExecStartPre=/bin/mkdir -p /etc/kubernetes/manifests
ExecStartPre=/bin/mkdir -p /opt/cni/bin ExecStartPre=/bin/mkdir -p /opt/cni/bin
@ -99,7 +99,7 @@ storage:
cgroupDriver: systemd cgroupDriver: systemd
clusterDNS: clusterDNS:
- ${cluster_dns_service_ip} - ${cluster_dns_service_ip}
clusterDomain: ${cluster_domain_suffix} clusterDomain: cluster.local
healthzPort: 0 healthzPort: 0
rotateCertificates: true rotateCertificates: true
shutdownGracePeriod: 45s shutdownGracePeriod: 45s

View File

@ -5,9 +5,9 @@ variable "name" {
# Azure # Azure
variable "region" { variable "location" {
type = string type = string
description = "Must be set to the Azure Region of cluster" description = "Must be set to the Azure location of cluster"
} }
variable "resource_group_name" { variable "resource_group_name" {
@ -25,9 +25,12 @@ variable "security_group_id" {
description = "Must be set to the `worker_security_group_id` output by cluster" description = "Must be set to the `worker_security_group_id` output by cluster"
} }
variable "backend_address_pool_id" { variable "backend_address_pool_ids" {
type = string type = object({
description = "Must be set to the `worker_backend_address_pool_id` output by cluster" ipv4 = list(string)
ipv6 = list(string)
})
description = "Must be set to the `backend_address_pool_ids` output by cluster"
} }
# instances # instances
@ -55,6 +58,24 @@ variable "os_image" {
} }
} }
variable "disk_type" {
type = string
description = "Type of managed disk"
default = "Standard_LRS"
}
variable "disk_size" {
type = number
description = "Size of the managed disk in GB"
default = 30
}
variable "ephemeral_disk" {
type = bool
description = "Use ephemeral local disk instead of managed disk (requires vm_type with local storage)"
default = false
}
variable "priority" { variable "priority" {
type = string type = string
description = "Set priority to Spot to use reduced cost surplus capacity, with the tradeoff that instances can be evicted at any time." description = "Set priority to Spot to use reduced cost surplus capacity, with the tradeoff that instances can be evicted at any time."
@ -116,12 +137,3 @@ variable "arch" {
error_message = "The arch must be amd64 or arm64." error_message = "The arch must be amd64 or arm64."
} }
} }
# unofficial, undocumented, unsupported
variable "cluster_domain_suffix" {
description = "Queries for domains with the suffix will be answered by coredns. Default is cluster.local (e.g. foo.default.svc.cluster.local) "
type = string
default = "cluster.local"
}

View File

@ -3,7 +3,7 @@
terraform { terraform {
required_version = ">= 0.13.0, < 2.0.0" required_version = ">= 0.13.0, < 2.0.0"
required_providers { required_providers {
azurerm = ">= 2.8, < 4.0" azurerm = ">= 2.8"
ct = { ct = {
source = "poseidon/ct" source = "poseidon/ct"
version = "~> 0.13" version = "~> 0.13"

View File

@ -8,25 +8,28 @@ locals {
} }
# Workers scale set # Workers scale set
resource "azurerm_linux_virtual_machine_scale_set" "workers" { resource "azurerm_orchestrated_virtual_machine_scale_set" "workers" {
resource_group_name = var.resource_group_name
name = "${var.name}-worker" name = "${var.name}-worker"
location = var.region resource_group_name = var.resource_group_name
sku = var.vm_type location = var.location
platform_fault_domain_count = 1
sku_name = var.vm_type
instances = var.worker_count instances = var.worker_count
# instance name prefix for instances in the set
computer_name_prefix = "${var.name}-worker"
single_placement_group = false
custom_data = base64encode(data.ct_config.worker.rendered)
boot_diagnostics {
# defaults to a managed storage account
}
# storage # storage
encryption_at_host_enabled = true
os_disk { os_disk {
storage_account_type = "Standard_LRS" storage_account_type = var.disk_type
caching = "ReadWrite" disk_size_gb = var.disk_size
caching = "ReadOnly"
# Optionally, use the ephemeral disk of the instance type (support varies)
dynamic "diff_disk_settings" {
for_each = var.ephemeral_disk ? [1] : []
content {
option = "Local"
placement = "ResourceDisk"
}
}
} }
# Flatcar Container Linux # Flatcar Container Linux
@ -46,13 +49,6 @@ resource "azurerm_linux_virtual_machine_scale_set" "workers" {
} }
} }
# Azure requires setting admin_ssh_key, though Ignition custom_data handles it too
admin_username = "core"
admin_ssh_key {
username = "core"
public_key = local.azure_authorized_key
}
# network # network
network_interface { network_interface {
name = "nic0" name = "nic0"
@ -60,17 +56,41 @@ resource "azurerm_linux_virtual_machine_scale_set" "workers" {
network_security_group_id = var.security_group_id network_security_group_id = var.security_group_id
ip_configuration { ip_configuration {
name = "ip0" name = "ipv4"
version = "IPv4"
primary = true primary = true
subnet_id = var.subnet_id subnet_id = var.subnet_id
# backend address pool to which the NIC should be added # backend address pool to which the NIC should be added
load_balancer_backend_address_pool_ids = [var.backend_address_pool_id] load_balancer_backend_address_pool_ids = var.backend_address_pool_ids.ipv4
}
ip_configuration {
name = "ipv6"
version = "IPv6"
subnet_id = var.subnet_id
# backend address pool to which the NIC should be added
load_balancer_backend_address_pool_ids = var.backend_address_pool_ids.ipv6
}
}
# boot
user_data_base64 = base64encode(data.ct_config.worker.rendered)
boot_diagnostics {
# defaults to a managed storage account
}
# Azure requires an RSA admin_ssh_key
os_profile {
linux_configuration {
admin_username = "core"
admin_ssh_key {
username = "core"
public_key = local.azure_authorized_key
}
computer_name_prefix = "${var.name}-worker"
} }
} }
# lifecycle # lifecycle
upgrade_mode = "Manual"
# eviction policy may only be set when priority is Spot # eviction policy may only be set when priority is Spot
priority = var.priority priority = var.priority
eviction_policy = var.priority == "Spot" ? "Delete" : null eviction_policy = var.priority == "Spot" ? "Delete" : null
@ -79,35 +99,12 @@ resource "azurerm_linux_virtual_machine_scale_set" "workers" {
} }
} }
# Scale up or down to maintain desired number, tolerating deallocations.
resource "azurerm_monitor_autoscale_setting" "workers" {
resource_group_name = var.resource_group_name
name = "${var.name}-maintain-desired"
location = var.region
# autoscale
enabled = true
target_resource_id = azurerm_linux_virtual_machine_scale_set.workers.id
profile {
name = "default"
capacity {
minimum = var.worker_count
default = var.worker_count
maximum = var.worker_count
}
}
}
# Flatcar Linux worker # Flatcar Linux worker
data "ct_config" "worker" { data "ct_config" "worker" {
content = templatefile("${path.module}/butane/worker.yaml", { content = templatefile("${path.module}/butane/worker.yaml", {
kubeconfig = indent(10, var.kubeconfig) kubeconfig = indent(10, var.kubeconfig)
ssh_authorized_key = var.ssh_authorized_key ssh_authorized_key = var.ssh_authorized_key
cluster_dns_service_ip = cidrhost(var.service_cidr, 10) cluster_dns_service_ip = cidrhost(var.service_cidr, 10)
cluster_domain_suffix = var.cluster_domain_suffix
node_labels = join(",", var.node_labels) node_labels = join(",", var.node_labels)
node_taints = join(",", var.node_taints) node_taints = join(",", var.node_taints)
}) })

View File

@ -11,7 +11,7 @@ Typhoon distributes upstream Kubernetes, architectural conventions, and cluster
## Features <a href="https://www.cncf.io/certification/software-conformance/"><img align="right" src="https://storage.googleapis.com/poseidon/certified-kubernetes.png"></a> ## Features <a href="https://www.cncf.io/certification/software-conformance/"><img align="right" src="https://storage.googleapis.com/poseidon/certified-kubernetes.png"></a>
* Kubernetes v1.30.1 (upstream) * Kubernetes v1.31.3 (upstream)
* Single or multi-master, [Calico](https://www.projectcalico.org/) or [Cilium](https://github.com/cilium/cilium) or [flannel](https://github.com/coreos/flannel) networking * Single or multi-master, [Calico](https://www.projectcalico.org/) or [Cilium](https://github.com/cilium/cilium) or [flannel](https://github.com/coreos/flannel) networking
* On-cluster etcd with TLS, [RBAC](https://kubernetes.io/docs/admin/authorization/rbac/)-enabled, [network policy](https://kubernetes.io/docs/concepts/services-networking/network-policies/), SELinux enforcing * On-cluster etcd with TLS, [RBAC](https://kubernetes.io/docs/admin/authorization/rbac/)-enabled, [network policy](https://kubernetes.io/docs/concepts/services-networking/network-policies/), SELinux enforcing
* Advanced features like [snippets](https://typhoon.psdn.io/advanced/customization/#hosts) customization * Advanced features like [snippets](https://typhoon.psdn.io/advanced/customization/#hosts) customization

View File

@ -1,6 +1,6 @@
# Kubernetes assets (kubeconfig, manifests) # Kubernetes assets (kubeconfig, manifests)
module "bootstrap" { module "bootstrap" {
source = "git::https://github.com/poseidon/terraform-render-bootstrap.git?ref=e1b1e0c75e77e042cf369f463f0e656297a201a8" source = "git::https://github.com/poseidon/terraform-render-bootstrap.git?ref=e6a1c7bccfc45ab299b5f8149bc3840f99b30b2b"
cluster_name = var.cluster_name cluster_name = var.cluster_name
api_servers = [var.k8s_domain_name] api_servers = [var.k8s_domain_name]
@ -10,9 +10,6 @@ module "bootstrap" {
network_ip_autodetection_method = var.network_ip_autodetection_method network_ip_autodetection_method = var.network_ip_autodetection_method
pod_cidr = var.pod_cidr pod_cidr = var.pod_cidr
service_cidr = var.service_cidr service_cidr = var.service_cidr
cluster_domain_suffix = var.cluster_domain_suffix
enable_reporting = var.enable_reporting
enable_aggregation = var.enable_aggregation
components = var.components components = var.components
} }

View File

@ -53,7 +53,7 @@ systemd:
Description=Kubelet (System Container) Description=Kubelet (System Container)
Wants=rpc-statd.service Wants=rpc-statd.service
[Service] [Service]
Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.30.1 Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.31.3
ExecStartPre=/bin/mkdir -p /etc/cni/net.d ExecStartPre=/bin/mkdir -p /etc/cni/net.d
ExecStartPre=/bin/mkdir -p /etc/kubernetes/manifests ExecStartPre=/bin/mkdir -p /etc/kubernetes/manifests
ExecStartPre=/bin/mkdir -p /opt/cni/bin ExecStartPre=/bin/mkdir -p /opt/cni/bin
@ -113,7 +113,7 @@ systemd:
Type=oneshot Type=oneshot
RemainAfterExit=true RemainAfterExit=true
WorkingDirectory=/opt/bootstrap WorkingDirectory=/opt/bootstrap
Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.30.1 Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.31.3
ExecStartPre=-/usr/bin/podman rm bootstrap ExecStartPre=-/usr/bin/podman rm bootstrap
ExecStart=/usr/bin/podman run --name bootstrap \ ExecStart=/usr/bin/podman run --name bootstrap \
--network host \ --network host \
@ -154,7 +154,7 @@ storage:
cgroupDriver: systemd cgroupDriver: systemd
clusterDNS: clusterDNS:
- ${cluster_dns_service_ip} - ${cluster_dns_service_ip}
clusterDomain: ${cluster_domain_suffix} clusterDomain: cluster.local
healthzPort: 0 healthzPort: 0
rotateCertificates: true rotateCertificates: true
shutdownGracePeriod: 45s shutdownGracePeriod: 45s

View File

@ -59,7 +59,6 @@ data "ct_config" "controllers" {
etcd_name = var.controllers.*.name[count.index] etcd_name = var.controllers.*.name[count.index]
etcd_initial_cluster = join(",", formatlist("%s=https://%s:2380", var.controllers.*.name, var.controllers.*.domain)) etcd_initial_cluster = join(",", formatlist("%s=https://%s:2380", var.controllers.*.name, var.controllers.*.domain))
cluster_dns_service_ip = module.bootstrap.cluster_dns_service_ip cluster_dns_service_ip = module.bootstrap.cluster_dns_service_ip
cluster_domain_suffix = var.cluster_domain_suffix
ssh_authorized_key = var.ssh_authorized_key ssh_authorized_key = var.ssh_authorized_key
}) })
strict = true strict = true

View File

@ -139,25 +139,7 @@ variable "kernel_args" {
default = [] default = []
} }
variable "enable_reporting" { # advanced
type = bool
description = "Enable usage or analytics reporting to upstreams (Calico)"
default = false
}
variable "enable_aggregation" {
type = bool
description = "Enable the Kubernetes Aggregation Layer"
default = true
}
# unofficial, undocumented, unsupported
variable "cluster_domain_suffix" {
description = "Queries for domains with the suffix will be answered by coredns. Default is cluster.local (e.g. foo.default.svc.cluster.local) "
type = string
default = "cluster.local"
}
variable "components" { variable "components" {
description = "Configure pre-installed cluster components" description = "Configure pre-installed cluster components"

View File

@ -25,7 +25,7 @@ systemd:
Description=Kubelet (System Container) Description=Kubelet (System Container)
Wants=rpc-statd.service Wants=rpc-statd.service
[Service] [Service]
Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.30.1 Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.31.3
ExecStartPre=/bin/mkdir -p /etc/cni/net.d ExecStartPre=/bin/mkdir -p /etc/cni/net.d
ExecStartPre=/bin/mkdir -p /etc/kubernetes/manifests ExecStartPre=/bin/mkdir -p /etc/kubernetes/manifests
ExecStartPre=/bin/mkdir -p /opt/cni/bin ExecStartPre=/bin/mkdir -p /opt/cni/bin
@ -108,7 +108,7 @@ storage:
cgroupDriver: systemd cgroupDriver: systemd
clusterDNS: clusterDNS:
- ${cluster_dns_service_ip} - ${cluster_dns_service_ip}
clusterDomain: ${cluster_domain_suffix} clusterDomain: cluster.local
healthzPort: 0 healthzPort: 0
rotateCertificates: true rotateCertificates: true
shutdownGracePeriod: 45s shutdownGracePeriod: 45s

View File

@ -53,7 +53,6 @@ data "ct_config" "worker" {
domain_name = var.domain domain_name = var.domain
ssh_authorized_key = var.ssh_authorized_key ssh_authorized_key = var.ssh_authorized_key
cluster_dns_service_ip = cidrhost(var.service_cidr, 10) cluster_dns_service_ip = cidrhost(var.service_cidr, 10)
cluster_domain_suffix = var.cluster_domain_suffix
node_labels = join(",", var.node_labels) node_labels = join(",", var.node_labels)
node_taints = join(",", var.node_taints) node_taints = join(",", var.node_taints)
}) })

View File

@ -103,9 +103,3 @@ The 1st IP will be reserved for kube_apiserver, the 10th IP will be reserved for
EOD EOD
default = "10.3.0.0/16" default = "10.3.0.0/16"
} }
variable "cluster_domain_suffix" {
description = "Queries for domains with the suffix will be answered by coredns. Default is cluster.local (e.g. foo.default.svc.cluster.local) "
type = string
default = "cluster.local"
}

View File

@ -18,7 +18,6 @@ module "workers" {
kubeconfig = module.bootstrap.kubeconfig-kubelet kubeconfig = module.bootstrap.kubeconfig-kubelet
ssh_authorized_key = var.ssh_authorized_key ssh_authorized_key = var.ssh_authorized_key
service_cidr = var.service_cidr service_cidr = var.service_cidr
cluster_domain_suffix = var.cluster_domain_suffix
node_labels = lookup(var.worker_node_labels, var.workers[count.index].name, []) node_labels = lookup(var.worker_node_labels, var.workers[count.index].name, [])
node_taints = lookup(var.worker_node_taints, var.workers[count.index].name, []) node_taints = lookup(var.worker_node_taints, var.workers[count.index].name, [])
snippets = lookup(var.snippets, var.workers[count.index].name, []) snippets = lookup(var.snippets, var.workers[count.index].name, [])

View File

@ -11,7 +11,7 @@ Typhoon distributes upstream Kubernetes, architectural conventions, and cluster
## Features <a href="https://www.cncf.io/certification/software-conformance/"><img align="right" src="https://storage.googleapis.com/poseidon/certified-kubernetes.png"></a> ## Features <a href="https://www.cncf.io/certification/software-conformance/"><img align="right" src="https://storage.googleapis.com/poseidon/certified-kubernetes.png"></a>
* Kubernetes v1.30.1 (upstream) * Kubernetes v1.31.3 (upstream)
* Single or multi-master, [Calico](https://www.projectcalico.org/) or [Cilium](https://github.com/cilium/cilium) or [flannel](https://github.com/coreos/flannel) networking * Single or multi-master, [Calico](https://www.projectcalico.org/) or [Cilium](https://github.com/cilium/cilium) or [flannel](https://github.com/coreos/flannel) networking
* On-cluster etcd with TLS, [RBAC](https://kubernetes.io/docs/admin/authorization/rbac/)-enabled, [network policy](https://kubernetes.io/docs/concepts/services-networking/network-policies/) * On-cluster etcd with TLS, [RBAC](https://kubernetes.io/docs/admin/authorization/rbac/)-enabled, [network policy](https://kubernetes.io/docs/concepts/services-networking/network-policies/)
* Advanced features like [snippets](https://typhoon.psdn.io/advanced/customization/#hosts) customization * Advanced features like [snippets](https://typhoon.psdn.io/advanced/customization/#hosts) customization

View File

@ -1,6 +1,6 @@
# Kubernetes assets (kubeconfig, manifests) # Kubernetes assets (kubeconfig, manifests)
module "bootstrap" { module "bootstrap" {
source = "git::https://github.com/poseidon/terraform-render-bootstrap.git?ref=e1b1e0c75e77e042cf369f463f0e656297a201a8" source = "git::https://github.com/poseidon/terraform-render-bootstrap.git?ref=e6a1c7bccfc45ab299b5f8149bc3840f99b30b2b"
cluster_name = var.cluster_name cluster_name = var.cluster_name
api_servers = [var.k8s_domain_name] api_servers = [var.k8s_domain_name]
@ -10,9 +10,6 @@ module "bootstrap" {
network_ip_autodetection_method = var.network_ip_autodetection_method network_ip_autodetection_method = var.network_ip_autodetection_method
pod_cidr = var.pod_cidr pod_cidr = var.pod_cidr
service_cidr = var.service_cidr service_cidr = var.service_cidr
cluster_domain_suffix = var.cluster_domain_suffix
enable_reporting = var.enable_reporting
enable_aggregation = var.enable_aggregation
components = var.components components = var.components
} }

View File

@ -64,7 +64,7 @@ systemd:
After=docker.service After=docker.service
Wants=rpc-statd.service Wants=rpc-statd.service
[Service] [Service]
Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.30.1 Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.31.3
ExecStartPre=/bin/mkdir -p /etc/cni/net.d ExecStartPre=/bin/mkdir -p /etc/cni/net.d
ExecStartPre=/bin/mkdir -p /etc/kubernetes/manifests ExecStartPre=/bin/mkdir -p /etc/kubernetes/manifests
ExecStartPre=/bin/mkdir -p /opt/cni/bin ExecStartPre=/bin/mkdir -p /opt/cni/bin
@ -114,7 +114,7 @@ systemd:
Type=oneshot Type=oneshot
RemainAfterExit=true RemainAfterExit=true
WorkingDirectory=/opt/bootstrap WorkingDirectory=/opt/bootstrap
Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.30.1 Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.31.3
ExecStart=/usr/bin/docker run \ ExecStart=/usr/bin/docker run \
-v /etc/kubernetes/pki:/etc/kubernetes/pki:ro \ -v /etc/kubernetes/pki:/etc/kubernetes/pki:ro \
-v /opt/bootstrap/assets:/assets:ro \ -v /opt/bootstrap/assets:/assets:ro \
@ -155,7 +155,7 @@ storage:
cgroupDriver: systemd cgroupDriver: systemd
clusterDNS: clusterDNS:
- ${cluster_dns_service_ip} - ${cluster_dns_service_ip}
clusterDomain: ${cluster_domain_suffix} clusterDomain: cluster.local
healthzPort: 0 healthzPort: 0
rotateCertificates: true rotateCertificates: true
shutdownGracePeriod: 45s shutdownGracePeriod: 45s

View File

@ -60,6 +60,7 @@ data "ct_config" "install" {
baseurl_flag = var.cached_install ? "-b ${var.matchbox_http_endpoint}/assets/flatcar" : "" baseurl_flag = var.cached_install ? "-b ${var.matchbox_http_endpoint}/assets/flatcar" : ""
}) })
strict = true strict = true
snippets = lookup(var.install_snippets, var.controllers.*.name[count.index], [])
} }
# Match each controller by MAC # Match each controller by MAC
@ -88,7 +89,6 @@ data "ct_config" "controllers" {
etcd_name = var.controllers.*.name[count.index] etcd_name = var.controllers.*.name[count.index]
etcd_initial_cluster = join(",", formatlist("%s=https://%s:2380", var.controllers.*.name, var.controllers.*.domain)) etcd_initial_cluster = join(",", formatlist("%s=https://%s:2380", var.controllers.*.name, var.controllers.*.domain))
cluster_dns_service_ip = module.bootstrap.cluster_dns_service_ip cluster_dns_service_ip = module.bootstrap.cluster_dns_service_ip
cluster_domain_suffix = var.cluster_domain_suffix
ssh_authorized_key = var.ssh_authorized_key ssh_authorized_key = var.ssh_authorized_key
}) })
strict = true strict = true

View File

@ -61,6 +61,12 @@ variable "snippets" {
default = {} default = {}
} }
variable "install_snippets" {
type = map(list(string))
description = "Map from machine names to lists of Container Linux Config snippets to run during install phase"
default = {}
}
variable "worker_node_labels" { variable "worker_node_labels" {
type = map(list(string)) type = map(list(string))
description = "Map from worker names to lists of initial node labels" description = "Map from worker names to lists of initial node labels"
@ -144,18 +150,6 @@ variable "kernel_args" {
default = [] default = []
} }
variable "enable_reporting" {
type = bool
description = "Enable usage or analytics reporting to upstreams (Calico)"
default = false
}
variable "enable_aggregation" {
type = bool
description = "Enable the Kubernetes Aggregation Layer"
default = true
}
variable "oem_type" { variable "oem_type" {
type = string type = string
description = <<EOD description = <<EOD
@ -167,13 +161,7 @@ EOD
default = "" default = ""
} }
# unofficial, undocumented, unsupported # advanced
variable "cluster_domain_suffix" {
type = string
description = "Queries for domains with the suffix will be answered by coredns. Default is cluster.local (e.g. foo.default.svc.cluster.local) "
default = "cluster.local"
}
variable "components" { variable "components" {
description = "Configure pre-installed cluster components" description = "Configure pre-installed cluster components"

View File

@ -36,7 +36,7 @@ systemd:
After=docker.service After=docker.service
Wants=rpc-statd.service Wants=rpc-statd.service
[Service] [Service]
Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.30.1 Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.31.3
ExecStartPre=/bin/mkdir -p /etc/cni/net.d ExecStartPre=/bin/mkdir -p /etc/cni/net.d
ExecStartPre=/bin/mkdir -p /etc/kubernetes/manifests ExecStartPre=/bin/mkdir -p /etc/kubernetes/manifests
ExecStartPre=/bin/mkdir -p /opt/cni/bin ExecStartPre=/bin/mkdir -p /opt/cni/bin
@ -113,7 +113,7 @@ storage:
cgroupDriver: systemd cgroupDriver: systemd
clusterDNS: clusterDNS:
- ${cluster_dns_service_ip} - ${cluster_dns_service_ip}
clusterDomain: ${cluster_domain_suffix} clusterDomain: cluster.local
healthzPort: 0 healthzPort: 0
rotateCertificates: true rotateCertificates: true
shutdownGracePeriod: 45s shutdownGracePeriod: 45s

View File

@ -55,6 +55,7 @@ data "ct_config" "install" {
baseurl_flag = var.cached_install ? "-b ${var.matchbox_http_endpoint}/assets/flatcar" : "" baseurl_flag = var.cached_install ? "-b ${var.matchbox_http_endpoint}/assets/flatcar" : ""
}) })
strict = true strict = true
snippets = var.install_snippets
} }
# Match a worker to a profile by MAC # Match a worker to a profile by MAC
@ -79,7 +80,6 @@ data "ct_config" "worker" {
domain_name = var.domain domain_name = var.domain
ssh_authorized_key = var.ssh_authorized_key ssh_authorized_key = var.ssh_authorized_key
cluster_dns_service_ip = cidrhost(var.service_cidr, 10) cluster_dns_service_ip = cidrhost(var.service_cidr, 10)
cluster_domain_suffix = var.cluster_domain_suffix
node_labels = join(",", var.node_labels) node_labels = join(",", var.node_labels)
node_taints = join(",", var.node_taints) node_taints = join(",", var.node_taints)
}) })

View File

@ -60,6 +60,12 @@ variable "snippets" {
default = [] default = []
} }
variable "install_snippets" {
type = list(string)
description = "List of Butane snippets to run with the install command"
default = []
}
variable "node_labels" { variable "node_labels" {
type = list(string) type = list(string)
description = "List of initial node labels" description = "List of initial node labels"
@ -114,13 +120,3 @@ The 1st IP will be reserved for kube_apiserver, the 10th IP will be reserved for
EOD EOD
default = "10.3.0.0/16" default = "10.3.0.0/16"
} }
variable "cluster_domain_suffix" {
type = string
description = "Queries for domains with the suffix will be answered by coredns. Default is cluster.local (e.g. foo.default.svc.cluster.local) "
default = "cluster.local"
}

View File

@ -18,10 +18,10 @@ module "workers" {
kubeconfig = module.bootstrap.kubeconfig-kubelet kubeconfig = module.bootstrap.kubeconfig-kubelet
ssh_authorized_key = var.ssh_authorized_key ssh_authorized_key = var.ssh_authorized_key
service_cidr = var.service_cidr service_cidr = var.service_cidr
cluster_domain_suffix = var.cluster_domain_suffix
node_labels = lookup(var.worker_node_labels, var.workers[count.index].name, []) node_labels = lookup(var.worker_node_labels, var.workers[count.index].name, [])
node_taints = lookup(var.worker_node_taints, var.workers[count.index].name, []) node_taints = lookup(var.worker_node_taints, var.workers[count.index].name, [])
snippets = lookup(var.snippets, var.workers[count.index].name, []) snippets = lookup(var.snippets, var.workers[count.index].name, [])
install_snippets = lookup(var.install_snippets, var.workers[count.index].name, [])
# optional # optional
download_protocol = var.download_protocol download_protocol = var.download_protocol

View File

@ -11,7 +11,7 @@ Typhoon distributes upstream Kubernetes, architectural conventions, and cluster
## Features <a href="https://www.cncf.io/certification/software-conformance/"><img align="right" src="https://storage.googleapis.com/poseidon/certified-kubernetes.png"></a> ## Features <a href="https://www.cncf.io/certification/software-conformance/"><img align="right" src="https://storage.googleapis.com/poseidon/certified-kubernetes.png"></a>
* Kubernetes v1.30.1 (upstream) * Kubernetes v1.31.3 (upstream)
* Single or multi-master, [Calico](https://www.projectcalico.org/) or [flannel](https://github.com/coreos/flannel) networking * Single or multi-master, [Calico](https://www.projectcalico.org/) or [flannel](https://github.com/coreos/flannel) networking
* On-cluster etcd with TLS, [RBAC](https://kubernetes.io/docs/admin/authorization/rbac/)-enabled, [network policy](https://kubernetes.io/docs/concepts/services-networking/network-policies/), SELinux enforcing * On-cluster etcd with TLS, [RBAC](https://kubernetes.io/docs/admin/authorization/rbac/)-enabled, [network policy](https://kubernetes.io/docs/concepts/services-networking/network-policies/), SELinux enforcing
* Advanced features like [snippets](https://typhoon.psdn.io/advanced/customization/#hosts) customization * Advanced features like [snippets](https://typhoon.psdn.io/advanced/customization/#hosts) customization

View File

@ -1,6 +1,6 @@
# Kubernetes assets (kubeconfig, manifests) # Kubernetes assets (kubeconfig, manifests)
module "bootstrap" { module "bootstrap" {
source = "git::https://github.com/poseidon/terraform-render-bootstrap.git?ref=e1b1e0c75e77e042cf369f463f0e656297a201a8" source = "git::https://github.com/poseidon/terraform-render-bootstrap.git?ref=e6a1c7bccfc45ab299b5f8149bc3840f99b30b2b"
cluster_name = var.cluster_name cluster_name = var.cluster_name
api_servers = [format("%s.%s", var.cluster_name, var.dns_zone)] api_servers = [format("%s.%s", var.cluster_name, var.dns_zone)]
@ -13,9 +13,6 @@ module "bootstrap" {
pod_cidr = var.pod_cidr pod_cidr = var.pod_cidr
service_cidr = var.service_cidr service_cidr = var.service_cidr
cluster_domain_suffix = var.cluster_domain_suffix
enable_reporting = var.enable_reporting
enable_aggregation = var.enable_aggregation
components = var.components components = var.components
} }

View File

@ -55,7 +55,7 @@ systemd:
After=afterburn.service After=afterburn.service
Wants=rpc-statd.service Wants=rpc-statd.service
[Service] [Service]
Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.30.1 Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.31.3
EnvironmentFile=/run/metadata/afterburn EnvironmentFile=/run/metadata/afterburn
ExecStartPre=/bin/mkdir -p /etc/cni/net.d ExecStartPre=/bin/mkdir -p /etc/cni/net.d
ExecStartPre=/bin/mkdir -p /etc/kubernetes/manifests ExecStartPre=/bin/mkdir -p /etc/kubernetes/manifests
@ -123,7 +123,7 @@ systemd:
--volume /opt/bootstrap/assets:/assets:ro,Z \ --volume /opt/bootstrap/assets:/assets:ro,Z \
--volume /opt/bootstrap/apply:/apply:ro,Z \ --volume /opt/bootstrap/apply:/apply:ro,Z \
--entrypoint=/apply \ --entrypoint=/apply \
quay.io/poseidon/kubelet:v1.30.1 quay.io/poseidon/kubelet:v1.31.3
ExecStartPost=/bin/touch /opt/bootstrap/bootstrap.done ExecStartPost=/bin/touch /opt/bootstrap/bootstrap.done
ExecStartPost=-/usr/bin/podman stop bootstrap ExecStartPost=-/usr/bin/podman stop bootstrap
storage: storage:
@ -151,7 +151,7 @@ storage:
cgroupDriver: systemd cgroupDriver: systemd
clusterDNS: clusterDNS:
- ${cluster_dns_service_ip} - ${cluster_dns_service_ip}
clusterDomain: ${cluster_domain_suffix} clusterDomain: cluster.local
healthzPort: 0 healthzPort: 0
rotateCertificates: true rotateCertificates: true
shutdownGracePeriod: 45s shutdownGracePeriod: 45s

View File

@ -28,7 +28,7 @@ systemd:
After=afterburn.service After=afterburn.service
Wants=rpc-statd.service Wants=rpc-statd.service
[Service] [Service]
Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.30.1 Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.31.3
EnvironmentFile=/run/metadata/afterburn EnvironmentFile=/run/metadata/afterburn
ExecStartPre=/bin/mkdir -p /etc/cni/net.d ExecStartPre=/bin/mkdir -p /etc/cni/net.d
ExecStartPre=/bin/mkdir -p /etc/kubernetes/manifests ExecStartPre=/bin/mkdir -p /etc/kubernetes/manifests
@ -104,7 +104,7 @@ storage:
cgroupDriver: systemd cgroupDriver: systemd
clusterDNS: clusterDNS:
- ${cluster_dns_service_ip} - ${cluster_dns_service_ip}
clusterDomain: ${cluster_domain_suffix} clusterDomain: cluster.local
healthzPort: 0 healthzPort: 0
rotateCertificates: true rotateCertificates: true
shutdownGracePeriod: 45s shutdownGracePeriod: 45s

View File

@ -74,7 +74,6 @@ data "ct_config" "controllers" {
for i in range(var.controller_count) : "etcd${i}=https://${var.cluster_name}-etcd${i}.${var.dns_zone}:2380" for i in range(var.controller_count) : "etcd${i}=https://${var.cluster_name}-etcd${i}.${var.dns_zone}:2380"
]) ])
cluster_dns_service_ip = cidrhost(var.service_cidr, 10) cluster_dns_service_ip = cidrhost(var.service_cidr, 10)
cluster_domain_suffix = var.cluster_domain_suffix
}) })
strict = true strict = true
snippets = var.controller_snippets snippets = var.controller_snippets

View File

@ -86,25 +86,7 @@ EOD
default = "10.3.0.0/16" default = "10.3.0.0/16"
} }
variable "enable_reporting" { # advanced
type = bool
description = "Enable usage or analytics reporting to upstreams (Calico)"
default = false
}
variable "enable_aggregation" {
type = bool
description = "Enable the Kubernetes Aggregation Layer"
default = true
}
# unofficial, undocumented, unsupported
variable "cluster_domain_suffix" {
type = string
description = "Queries for domains with the suffix will be answered by coredns. Default is cluster.local (e.g. foo.default.svc.cluster.local) "
default = "cluster.local"
}
variable "components" { variable "components" {
description = "Configure pre-installed cluster components" description = "Configure pre-installed cluster components"

View File

@ -62,7 +62,6 @@ resource "digitalocean_tag" "workers" {
data "ct_config" "worker" { data "ct_config" "worker" {
content = templatefile("${path.module}/butane/worker.yaml", { content = templatefile("${path.module}/butane/worker.yaml", {
cluster_dns_service_ip = cidrhost(var.service_cidr, 10) cluster_dns_service_ip = cidrhost(var.service_cidr, 10)
cluster_domain_suffix = var.cluster_domain_suffix
}) })
strict = true strict = true
snippets = var.worker_snippets snippets = var.worker_snippets

View File

@ -11,7 +11,7 @@ Typhoon distributes upstream Kubernetes, architectural conventions, and cluster
## Features <a href="https://www.cncf.io/certification/software-conformance/"><img align="right" src="https://storage.googleapis.com/poseidon/certified-kubernetes.png"></a> ## Features <a href="https://www.cncf.io/certification/software-conformance/"><img align="right" src="https://storage.googleapis.com/poseidon/certified-kubernetes.png"></a>
* Kubernetes v1.30.1 (upstream) * Kubernetes v1.31.3 (upstream)
* Single or multi-master, [Calico](https://www.projectcalico.org/) or [Cilium](https://github.com/cilium/cilium) or [flannel](https://github.com/coreos/flannel) networking * Single or multi-master, [Calico](https://www.projectcalico.org/) or [Cilium](https://github.com/cilium/cilium) or [flannel](https://github.com/coreos/flannel) networking
* On-cluster etcd with TLS, [RBAC](https://kubernetes.io/docs/admin/authorization/rbac/)-enabled, [network policy](https://kubernetes.io/docs/concepts/services-networking/network-policies/) * On-cluster etcd with TLS, [RBAC](https://kubernetes.io/docs/admin/authorization/rbac/)-enabled, [network policy](https://kubernetes.io/docs/concepts/services-networking/network-policies/)
* Advanced features like [snippets](https://typhoon.psdn.io/advanced/customization/#hosts) customization * Advanced features like [snippets](https://typhoon.psdn.io/advanced/customization/#hosts) customization

View File

@ -1,6 +1,6 @@
# Kubernetes assets (kubeconfig, manifests) # Kubernetes assets (kubeconfig, manifests)
module "bootstrap" { module "bootstrap" {
source = "git::https://github.com/poseidon/terraform-render-bootstrap.git?ref=e1b1e0c75e77e042cf369f463f0e656297a201a8" source = "git::https://github.com/poseidon/terraform-render-bootstrap.git?ref=e6a1c7bccfc45ab299b5f8149bc3840f99b30b2b"
cluster_name = var.cluster_name cluster_name = var.cluster_name
api_servers = [format("%s.%s", var.cluster_name, var.dns_zone)] api_servers = [format("%s.%s", var.cluster_name, var.dns_zone)]
@ -13,9 +13,6 @@ module "bootstrap" {
pod_cidr = var.pod_cidr pod_cidr = var.pod_cidr
service_cidr = var.service_cidr service_cidr = var.service_cidr
cluster_domain_suffix = var.cluster_domain_suffix
enable_reporting = var.enable_reporting
enable_aggregation = var.enable_aggregation
components = var.components components = var.components
} }

View File

@ -66,7 +66,7 @@ systemd:
After=coreos-metadata.service After=coreos-metadata.service
Wants=rpc-statd.service Wants=rpc-statd.service
[Service] [Service]
Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.30.1 Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.31.3
EnvironmentFile=/run/metadata/coreos EnvironmentFile=/run/metadata/coreos
ExecStartPre=/bin/mkdir -p /etc/cni/net.d ExecStartPre=/bin/mkdir -p /etc/cni/net.d
ExecStartPre=/bin/mkdir -p /etc/kubernetes/manifests ExecStartPre=/bin/mkdir -p /etc/kubernetes/manifests
@ -117,7 +117,7 @@ systemd:
Type=oneshot Type=oneshot
RemainAfterExit=true RemainAfterExit=true
WorkingDirectory=/opt/bootstrap WorkingDirectory=/opt/bootstrap
Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.30.1 Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.31.3
ExecStart=/usr/bin/docker run \ ExecStart=/usr/bin/docker run \
-v /etc/kubernetes/pki:/etc/kubernetes/pki:ro \ -v /etc/kubernetes/pki:/etc/kubernetes/pki:ro \
-v /opt/bootstrap/assets:/assets:ro \ -v /opt/bootstrap/assets:/assets:ro \
@ -153,7 +153,7 @@ storage:
cgroupDriver: systemd cgroupDriver: systemd
clusterDNS: clusterDNS:
- ${cluster_dns_service_ip} - ${cluster_dns_service_ip}
clusterDomain: ${cluster_domain_suffix} clusterDomain: cluster.local
healthzPort: 0 healthzPort: 0
rotateCertificates: true rotateCertificates: true
shutdownGracePeriod: 45s shutdownGracePeriod: 45s

View File

@ -38,7 +38,7 @@ systemd:
After=coreos-metadata.service After=coreos-metadata.service
Wants=rpc-statd.service Wants=rpc-statd.service
[Service] [Service]
Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.30.1 Environment=KUBELET_IMAGE=quay.io/poseidon/kubelet:v1.31.3
EnvironmentFile=/run/metadata/coreos EnvironmentFile=/run/metadata/coreos
ExecStartPre=/bin/mkdir -p /etc/cni/net.d ExecStartPre=/bin/mkdir -p /etc/cni/net.d
ExecStartPre=/bin/mkdir -p /etc/kubernetes/manifests ExecStartPre=/bin/mkdir -p /etc/kubernetes/manifests
@ -103,7 +103,7 @@ storage:
cgroupDriver: systemd cgroupDriver: systemd
clusterDNS: clusterDNS:
- ${cluster_dns_service_ip} - ${cluster_dns_service_ip}
clusterDomain: ${cluster_domain_suffix} clusterDomain: cluster.local
healthzPort: 0 healthzPort: 0
rotateCertificates: true rotateCertificates: true
shutdownGracePeriod: 45s shutdownGracePeriod: 45s

View File

@ -79,7 +79,6 @@ data "ct_config" "controllers" {
for i in range(var.controller_count) : "etcd${i}=https://${var.cluster_name}-etcd${i}.${var.dns_zone}:2380" for i in range(var.controller_count) : "etcd${i}=https://${var.cluster_name}-etcd${i}.${var.dns_zone}:2380"
]) ])
cluster_dns_service_ip = cidrhost(var.service_cidr, 10) cluster_dns_service_ip = cidrhost(var.service_cidr, 10)
cluster_domain_suffix = var.cluster_domain_suffix
}) })
strict = true strict = true
snippets = var.controller_snippets snippets = var.controller_snippets

View File

@ -86,25 +86,7 @@ EOD
default = "10.3.0.0/16" default = "10.3.0.0/16"
} }
variable "enable_reporting" { # advanced
type = bool
description = "Enable usage or analytics reporting to upstreams (Calico)"
default = false
}
variable "enable_aggregation" {
type = bool
description = "Enable the Kubernetes Aggregation Layer"
default = true
}
# unofficial, undocumented, unsupported
variable "cluster_domain_suffix" {
type = string
description = "Queries for domains with the suffix will be answered by coredns. Default is cluster.local (e.g. foo.default.svc.cluster.local) "
default = "cluster.local"
}
variable "components" { variable "components" {
description = "Configure pre-installed cluster components" description = "Configure pre-installed cluster components"

View File

@ -60,7 +60,6 @@ resource "digitalocean_tag" "workers" {
data "ct_config" "worker" { data "ct_config" "worker" {
content = templatefile("${path.module}/butane/worker.yaml", { content = templatefile("${path.module}/butane/worker.yaml", {
cluster_dns_service_ip = cidrhost(var.service_cidr, 10) cluster_dns_service_ip = cidrhost(var.service_cidr, 10)
cluster_domain_suffix = var.cluster_domain_suffix
}) })
strict = true strict = true
snippets = var.worker_snippets snippets = var.worker_snippets

Some files were not shown because too many files have changed in this diff Show More