Rewrote AWS Terraform for Kargo
Rewrote AWS Terraform deployment for AWS Kargo. It supports now multiple Availability Zones, AWS Loadbalancer for Kubernetes API, Bastion Host, ... For more information see README
This commit is contained in:
parent
4ce0421142
commit
18298bfeb7
20 changed files with 794 additions and 327 deletions
2
contrib/terraform/aws/.gitignore
vendored
2
contrib/terraform/aws/.gitignore
vendored
|
@ -1,2 +1,2 @@
|
|||
*.tfstate*
|
||||
inventory
|
||||
.terraform
|
||||
|
|
|
@ -1,261 +0,0 @@
|
|||
variable "deploymentName" {
|
||||
type = "string"
|
||||
description = "The desired name of your deployment."
|
||||
}
|
||||
|
||||
variable "numControllers"{
|
||||
type = "string"
|
||||
description = "Desired # of controllers."
|
||||
}
|
||||
|
||||
variable "numEtcd" {
|
||||
type = "string"
|
||||
description = "Desired # of etcd nodes. Should be an odd number."
|
||||
}
|
||||
|
||||
variable "numNodes" {
|
||||
type = "string"
|
||||
description = "Desired # of nodes."
|
||||
}
|
||||
|
||||
variable "volSizeController" {
|
||||
type = "string"
|
||||
description = "Volume size for the controllers (GB)."
|
||||
}
|
||||
|
||||
variable "volSizeEtcd" {
|
||||
type = "string"
|
||||
description = "Volume size for etcd (GB)."
|
||||
}
|
||||
|
||||
variable "volSizeNodes" {
|
||||
type = "string"
|
||||
description = "Volume size for nodes (GB)."
|
||||
}
|
||||
|
||||
variable "subnet" {
|
||||
type = "string"
|
||||
description = "The subnet in which to put your cluster."
|
||||
}
|
||||
|
||||
variable "securityGroups" {
|
||||
type = "string"
|
||||
description = "The sec. groups in which to put your cluster."
|
||||
}
|
||||
|
||||
variable "ami"{
|
||||
type = "string"
|
||||
description = "AMI to use for all VMs in cluster."
|
||||
}
|
||||
|
||||
variable "SSHKey" {
|
||||
type = "string"
|
||||
description = "SSH key to use for VMs."
|
||||
}
|
||||
|
||||
variable "master_instance_type" {
|
||||
type = "string"
|
||||
description = "Size of VM to use for masters."
|
||||
}
|
||||
|
||||
variable "etcd_instance_type" {
|
||||
type = "string"
|
||||
description = "Size of VM to use for etcd."
|
||||
}
|
||||
|
||||
variable "node_instance_type" {
|
||||
type = "string"
|
||||
description = "Size of VM to use for nodes."
|
||||
}
|
||||
|
||||
variable "terminate_protect" {
|
||||
type = "string"
|
||||
default = "false"
|
||||
}
|
||||
|
||||
variable "awsRegion" {
|
||||
type = "string"
|
||||
}
|
||||
|
||||
provider "aws" {
|
||||
region = "${var.awsRegion}"
|
||||
}
|
||||
|
||||
variable "iam_prefix" {
|
||||
type = "string"
|
||||
description = "Prefix name for IAM profiles"
|
||||
}
|
||||
|
||||
resource "aws_iam_instance_profile" "kubernetes_master_profile" {
|
||||
name = "${var.iam_prefix}_kubernetes_master_profile"
|
||||
roles = ["${aws_iam_role.kubernetes_master_role.name}"]
|
||||
}
|
||||
|
||||
resource "aws_iam_role" "kubernetes_master_role" {
|
||||
name = "${var.iam_prefix}_kubernetes_master_role"
|
||||
assume_role_policy = <<EOF
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": { "Service": "ec2.amazonaws.com"},
|
||||
"Action": "sts:AssumeRole"
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
resource "aws_iam_role_policy" "kubernetes_master_policy" {
|
||||
name = "${var.iam_prefix}_kubernetes_master_policy"
|
||||
role = "${aws_iam_role.kubernetes_master_role.id}"
|
||||
policy = <<EOF
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": ["ec2:*"],
|
||||
"Resource": ["*"]
|
||||
},
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": ["elasticloadbalancing:*"],
|
||||
"Resource": ["*"]
|
||||
},
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": "s3:*",
|
||||
"Resource": "*"
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
resource "aws_iam_instance_profile" "kubernetes_node_profile" {
|
||||
name = "${var.iam_prefix}_kubernetes_node_profile"
|
||||
roles = ["${aws_iam_role.kubernetes_node_role.name}"]
|
||||
}
|
||||
|
||||
resource "aws_iam_role" "kubernetes_node_role" {
|
||||
name = "${var.iam_prefix}_kubernetes_node_role"
|
||||
assume_role_policy = <<EOF
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": { "Service": "ec2.amazonaws.com"},
|
||||
"Action": "sts:AssumeRole"
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
resource "aws_iam_role_policy" "kubernetes_node_policy" {
|
||||
name = "${var.iam_prefix}_kubernetes_node_policy"
|
||||
role = "${aws_iam_role.kubernetes_node_role.id}"
|
||||
policy = <<EOF
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": "s3:*",
|
||||
"Resource": "*"
|
||||
},
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": "ec2:Describe*",
|
||||
"Resource": "*"
|
||||
},
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": "ec2:AttachVolume",
|
||||
"Resource": "*"
|
||||
},
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": "ec2:DetachVolume",
|
||||
"Resource": "*"
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
resource "aws_instance" "master" {
|
||||
count = "${var.numControllers}"
|
||||
ami = "${var.ami}"
|
||||
instance_type = "${var.master_instance_type}"
|
||||
subnet_id = "${var.subnet}"
|
||||
vpc_security_group_ids = ["${var.securityGroups}"]
|
||||
key_name = "${var.SSHKey}"
|
||||
disable_api_termination = "${var.terminate_protect}"
|
||||
iam_instance_profile = "${aws_iam_instance_profile.kubernetes_master_profile.id}"
|
||||
root_block_device {
|
||||
volume_size = "${var.volSizeController}"
|
||||
}
|
||||
tags {
|
||||
Name = "${var.deploymentName}-master-${count.index + 1}"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_instance" "etcd" {
|
||||
count = "${var.numEtcd}"
|
||||
ami = "${var.ami}"
|
||||
instance_type = "${var.etcd_instance_type}"
|
||||
subnet_id = "${var.subnet}"
|
||||
vpc_security_group_ids = ["${var.securityGroups}"]
|
||||
key_name = "${var.SSHKey}"
|
||||
disable_api_termination = "${var.terminate_protect}"
|
||||
root_block_device {
|
||||
volume_size = "${var.volSizeEtcd}"
|
||||
}
|
||||
tags {
|
||||
Name = "${var.deploymentName}-etcd-${count.index + 1}"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
resource "aws_instance" "minion" {
|
||||
count = "${var.numNodes}"
|
||||
ami = "${var.ami}"
|
||||
instance_type = "${var.node_instance_type}"
|
||||
subnet_id = "${var.subnet}"
|
||||
vpc_security_group_ids = ["${var.securityGroups}"]
|
||||
key_name = "${var.SSHKey}"
|
||||
disable_api_termination = "${var.terminate_protect}"
|
||||
iam_instance_profile = "${aws_iam_instance_profile.kubernetes_node_profile.id}"
|
||||
root_block_device {
|
||||
volume_size = "${var.volSizeNodes}"
|
||||
}
|
||||
tags {
|
||||
Name = "${var.deploymentName}-minion-${count.index + 1}"
|
||||
}
|
||||
}
|
||||
|
||||
output "kubernetes_master_profile" {
|
||||
value = "${aws_iam_instance_profile.kubernetes_master_profile.id}"
|
||||
}
|
||||
|
||||
output "kubernetes_node_profile" {
|
||||
value = "${aws_iam_instance_profile.kubernetes_node_profile.id}"
|
||||
}
|
||||
|
||||
output "master-ip" {
|
||||
value = "${join(", ", aws_instance.master.*.private_ip)}"
|
||||
}
|
||||
|
||||
output "etcd-ip" {
|
||||
value = "${join(", ", aws_instance.etcd.*.private_ip)}"
|
||||
}
|
||||
|
||||
output "minion-ip" {
|
||||
value = "${join(", ", aws_instance.minion.*.private_ip)}"
|
||||
}
|
||||
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
variable "SSHUser" {
|
||||
type = "string"
|
||||
description = "SSH User for VMs."
|
||||
}
|
||||
|
||||
resource "null_resource" "ansible-provision" {
|
||||
|
||||
depends_on = ["aws_instance.master","aws_instance.etcd","aws_instance.minion"]
|
||||
|
||||
##Create Master Inventory
|
||||
provisioner "local-exec" {
|
||||
command = "echo \"[kube-master]\" > inventory"
|
||||
}
|
||||
provisioner "local-exec" {
|
||||
command = "echo \"${join("\n",formatlist("%s ansible_ssh_user=%s", aws_instance.master.*.private_ip, var.SSHUser))}\" >> inventory"
|
||||
}
|
||||
|
||||
##Create ETCD Inventory
|
||||
provisioner "local-exec" {
|
||||
command = "echo \"\n[etcd]\" >> inventory"
|
||||
}
|
||||
provisioner "local-exec" {
|
||||
command = "echo \"${join("\n",formatlist("%s ansible_ssh_user=%s", aws_instance.etcd.*.private_ip, var.SSHUser))}\" >> inventory"
|
||||
}
|
||||
|
||||
##Create Nodes Inventory
|
||||
provisioner "local-exec" {
|
||||
command = "echo \"\n[kube-node]\" >> inventory"
|
||||
}
|
||||
provisioner "local-exec" {
|
||||
command = "echo \"${join("\n",formatlist("%s ansible_ssh_user=%s", aws_instance.minion.*.private_ip, var.SSHUser))}\" >> inventory"
|
||||
}
|
||||
|
||||
provisioner "local-exec" {
|
||||
command = "echo \"\n[k8s-cluster:children]\nkube-node\nkube-master\" >> inventory"
|
||||
}
|
||||
}
|
|
@ -2,27 +2,34 @@
|
|||
|
||||
**Overview:**
|
||||
|
||||
- This will create nodes in a VPC inside of AWS
|
||||
This project will create:
|
||||
* VPC with Public and Private Subnets in # Availability Zones
|
||||
* Bastion Hosts and NAT Gateways in the Public Subnet
|
||||
* A dynamic number of masters, etcd, and worker nodes in the Private Subnet
|
||||
* even distributed over the # of Availability Zones
|
||||
* AWS ELB in the Public Subnet for accessing the Kubernetes API from the internet
|
||||
|
||||
- A dynamic number of masters, etcd, and nodes can be created
|
||||
|
||||
- These scripts currently expect Private IP connectivity with the nodes that are created. This means that you may need a tunnel to your VPC or to run these scripts from a VM inside the VPC. Will be looking into how to work around this later.
|
||||
**Requirements**
|
||||
- Terraform 0.8.7 or newer
|
||||
|
||||
**How to Use:**
|
||||
|
||||
- Export the variables for your Amazon credentials:
|
||||
- Export the variables for your AWS credentials or edit credentials.tfvars:
|
||||
|
||||
```
|
||||
export AWS_ACCESS_KEY_ID="xxx"
|
||||
export AWS_SECRET_ACCESS_KEY="yyy"
|
||||
export aws_access_key="xxx"
|
||||
export aws_secret_key="yyy"
|
||||
export aws_ssh_key_name="zzz"
|
||||
```
|
||||
|
||||
- Update contrib/terraform/aws/terraform.tfvars with your data
|
||||
|
||||
- Run with `terraform apply`
|
||||
- Run with `terraform apply -var-file="credentials.tfvars"` or `terraform apply` depending if you exported your AWS credentials
|
||||
|
||||
- Once the infrastructure is created, you can run the kubespray playbooks and supply contrib/terraform/aws/inventory with the `-i` flag.
|
||||
- Once the infrastructure is created, you can run the kargo playbooks and supply inventory/hosts with the `-i` flag.
|
||||
|
||||
**Future Work:**
|
||||
**Architecture**
|
||||
|
||||
- Update the inventory creation file to be something a little more reasonable. It's just a local-exec from Terraform now, using terraform.py or something may make sense in the future.
|
||||
Pictured is an AWS Infrastructure created with this Terraform project distributed over two Availability Zones.
|
||||
|
||||
![AWS Infrastructure with Terraform ](docs/aws_kargo.png)
|
||||
|
|
185
contrib/terraform/aws/create-infrastructure.tf
Normal file
185
contrib/terraform/aws/create-infrastructure.tf
Normal file
|
@ -0,0 +1,185 @@
|
|||
terraform {
|
||||
required_version = ">= 0.8.7"
|
||||
}
|
||||
|
||||
provider "aws" {
|
||||
access_key = "${var.AWS_ACCESS_KEY_ID}"
|
||||
secret_key = "${var.AWS_SECRET_ACCESS_KEY}"
|
||||
region = "${var.AWS_DEFAULT_REGION}"
|
||||
}
|
||||
|
||||
/*
|
||||
* Calling modules who create the initial AWS VPC / AWS ELB
|
||||
* and AWS IAM Roles for Kubernetes Deployment
|
||||
*/
|
||||
|
||||
module "aws-vpc" {
|
||||
source = "modules/vpc"
|
||||
|
||||
aws_cluster_name = "${var.aws_cluster_name}"
|
||||
aws_vpc_cidr_block = "${var.aws_vpc_cidr_block}"
|
||||
aws_avail_zones="${var.aws_avail_zones}"
|
||||
|
||||
aws_cidr_subnets_private="${var.aws_cidr_subnets_private}"
|
||||
aws_cidr_subnets_public="${var.aws_cidr_subnets_public}"
|
||||
|
||||
}
|
||||
|
||||
|
||||
module "aws-elb" {
|
||||
source = "modules/elb"
|
||||
|
||||
aws_cluster_name="${var.aws_cluster_name}"
|
||||
aws_vpc_id="${module.aws-vpc.aws_vpc_id}"
|
||||
aws_avail_zones="${var.aws_avail_zones}"
|
||||
aws_subnet_ids_public="${module.aws-vpc.aws_subnet_ids_public}"
|
||||
aws_elb_api_port = "${var.aws_elb_api_port}"
|
||||
k8s_secure_api_port = "${var.k8s_secure_api_port}"
|
||||
|
||||
}
|
||||
|
||||
module "aws-iam" {
|
||||
source = "modules/iam"
|
||||
|
||||
aws_cluster_name="${var.aws_cluster_name}"
|
||||
}
|
||||
|
||||
/*
|
||||
* Create Bastion Instances in AWS
|
||||
*
|
||||
*/
|
||||
resource "aws_instance" "bastion-server" {
|
||||
ami = "${var.aws_bastion_ami}"
|
||||
instance_type = "${var.aws_bastion_size}"
|
||||
count = "${length(var.aws_cidr_subnets_public)}"
|
||||
associate_public_ip_address = true
|
||||
availability_zone = "${element(var.aws_avail_zones,count.index)}"
|
||||
subnet_id = "${element(module.aws-vpc.aws_subnet_ids_public,count.index)}"
|
||||
|
||||
|
||||
vpc_security_group_ids = [ "${module.aws-vpc.aws_security_group}" ]
|
||||
|
||||
key_name = "${var.AWS_SSH_KEY_NAME}"
|
||||
|
||||
tags {
|
||||
Name = "kubernetes-${var.aws_cluster_name}-bastion-${count.index}"
|
||||
Cluster = "${var.aws_cluster_name}"
|
||||
Role = "bastion-${var.aws_cluster_name}-${count.index}"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Create K8s Master and worker nodes and etcd instances
|
||||
*
|
||||
*/
|
||||
|
||||
resource "aws_instance" "k8s-master" {
|
||||
ami = "${var.aws_cluster_ami}"
|
||||
instance_type = "${var.aws_kube_master_size}"
|
||||
|
||||
count = "${var.aws_kube_master_num}"
|
||||
|
||||
|
||||
availability_zone = "${element(var.aws_avail_zones,count.index)}"
|
||||
subnet_id = "${element(module.aws-vpc.aws_subnet_ids_private,count.index)}"
|
||||
|
||||
|
||||
vpc_security_group_ids = [ "${module.aws-vpc.aws_security_group}" ]
|
||||
|
||||
|
||||
iam_instance_profile = "${module.aws-iam.kube-master-profile}"
|
||||
key_name = "${var.AWS_SSH_KEY_NAME}"
|
||||
|
||||
|
||||
tags {
|
||||
Name = "kubernetes-${var.aws_cluster_name}-master${count.index}"
|
||||
Cluster = "${var.aws_cluster_name}"
|
||||
Role = "master"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_elb_attachment" "attach_master_nodes" {
|
||||
count = "${var.aws_kube_master_num}"
|
||||
elb = "${module.aws-elb.aws_elb_api_id}"
|
||||
instance = "${element(aws_instance.k8s-master.*.id,count.index)}"
|
||||
}
|
||||
|
||||
|
||||
resource "aws_instance" "k8s-etcd" {
|
||||
ami = "${var.aws_cluster_ami}"
|
||||
instance_type = "${var.aws_etcd_size}"
|
||||
|
||||
count = "${var.aws_etcd_num}"
|
||||
|
||||
|
||||
availability_zone = "${element(var.aws_avail_zones,count.index)}"
|
||||
subnet_id = "${element(module.aws-vpc.aws_subnet_ids_private,count.index)}"
|
||||
|
||||
|
||||
vpc_security_group_ids = [ "${module.aws-vpc.aws_security_group}" ]
|
||||
|
||||
key_name = "${var.AWS_SSH_KEY_NAME}"
|
||||
|
||||
|
||||
tags {
|
||||
Name = "kubernetes-${var.aws_cluster_name}-etcd${count.index}"
|
||||
Cluster = "${var.aws_cluster_name}"
|
||||
Role = "etcd"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
resource "aws_instance" "k8s-worker" {
|
||||
ami = "${var.aws_cluster_ami}"
|
||||
instance_type = "${var.aws_kube_worker_size}"
|
||||
|
||||
count = "${var.aws_kube_worker_num}"
|
||||
|
||||
availability_zone = "${element(var.aws_avail_zones,count.index)}"
|
||||
subnet_id = "${element(module.aws-vpc.aws_subnet_ids_private,count.index)}"
|
||||
|
||||
vpc_security_group_ids = [ "${module.aws-vpc.aws_security_group}" ]
|
||||
|
||||
iam_instance_profile = "${module.aws-iam.kube-worker-profile}"
|
||||
key_name = "${var.AWS_SSH_KEY_NAME}"
|
||||
|
||||
|
||||
tags {
|
||||
Name = "kubernetes-${var.aws_cluster_name}-worker${count.index}"
|
||||
Cluster = "${var.aws_cluster_name}"
|
||||
Role = "worker"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Create Kargo Inventory File
|
||||
*
|
||||
*/
|
||||
data "template_file" "inventory" {
|
||||
template = "${file("${path.module}/templates/inventory.tpl")}"
|
||||
|
||||
vars {
|
||||
public_ip_address_bastion = "${join("\n",formatlist("bastion ansible_ssh_host=%s" , aws_instance.bastion-server.*.public_ip))}"
|
||||
connection_strings_master = "${join("\n",formatlist("%s ansible_ssh_host=%s",aws_instance.k8s-master.*.tags.Name, aws_instance.k8s-master.*.private_ip))}"
|
||||
connection_strings_node = "${join("\n", formatlist("%s ansible_ssh_host=%s", aws_instance.k8s-worker.*.tags.Name, aws_instance.k8s-worker.*.private_ip))}"
|
||||
connection_strings_etcd = "${join("\n",formatlist("%s ansible_ssh_host=%s", aws_instance.k8s-etcd.*.tags.Name, aws_instance.k8s-etcd.*.private_ip))}"
|
||||
list_master = "${join("\n",aws_instance.k8s-master.*.tags.Name)}"
|
||||
list_node = "${join("\n",aws_instance.k8s-worker.*.tags.Name)}"
|
||||
list_etcd = "${join("\n",aws_instance.k8s-etcd.*.tags.Name)}"
|
||||
elb_api_fqdn = "apiserver_loadbalancer_domain_name=\"${module.aws-elb.aws_elb_api_fqdn}\""
|
||||
elb_api_port = "loadbalancer_apiserver.port=${var.aws_elb_api_port}"
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
resource "null_resource" "inventories" {
|
||||
provisioner "local-exec" {
|
||||
command = "echo '${data.template_file.inventory.rendered}' > ../../../inventory/hosts"
|
||||
}
|
||||
|
||||
}
|
8
contrib/terraform/aws/credentials.tfvars.example
Normal file
8
contrib/terraform/aws/credentials.tfvars.example
Normal file
|
@ -0,0 +1,8 @@
|
|||
#AWS Access Key
|
||||
AWS_ACCESS_KEY_ID = ""
|
||||
#AWS Secret Key
|
||||
AWS_SECRET_ACCESS_KEY = ""
|
||||
#EC2 SSH Key Name
|
||||
AWS_SSH_KEY_NAME = ""
|
||||
#AWS Region
|
||||
AWS_DEFAULT_REGION = "eu-central-1"
|
BIN
contrib/terraform/aws/docs/aws_kargo.png
Normal file
BIN
contrib/terraform/aws/docs/aws_kargo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 114 KiB |
50
contrib/terraform/aws/modules/elb/main.tf
Normal file
50
contrib/terraform/aws/modules/elb/main.tf
Normal file
|
@ -0,0 +1,50 @@
|
|||
resource "aws_security_group" "aws-elb" {
|
||||
name = "kubernetes-${var.aws_cluster_name}-securitygroup-elb"
|
||||
vpc_id = "${var.aws_vpc_id}"
|
||||
|
||||
tags {
|
||||
Name = "kubernetes-${var.aws_cluster_name}-securitygroup-elb"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
resource "aws_security_group_rule" "aws-allow-api-access" {
|
||||
type = "ingress"
|
||||
from_port = "${var.aws_elb_api_port}"
|
||||
to_port = "${var.k8s_secure_api_port}"
|
||||
protocol = "TCP"
|
||||
cidr_blocks = ["0.0.0.0/0"]
|
||||
security_group_id = "${aws_security_group.aws-elb.id}"
|
||||
}
|
||||
|
||||
|
||||
# Create a new AWS ELB for K8S API
|
||||
resource "aws_elb" "aws-elb-api" {
|
||||
name = "kubernetes-elb-${var.aws_cluster_name}"
|
||||
subnets = ["${var.aws_subnet_ids_public}"]
|
||||
security_groups = ["${aws_security_group.aws-elb.id}"]
|
||||
|
||||
listener {
|
||||
instance_port = "${var.k8s_secure_api_port}"
|
||||
instance_protocol = "tcp"
|
||||
lb_port = "${var.aws_elb_api_port}"
|
||||
lb_protocol = "tcp"
|
||||
}
|
||||
|
||||
health_check {
|
||||
healthy_threshold = 2
|
||||
unhealthy_threshold = 2
|
||||
timeout = 3
|
||||
target = "HTTP:8080/"
|
||||
interval = 30
|
||||
}
|
||||
|
||||
cross_zone_load_balancing = true
|
||||
idle_timeout = 400
|
||||
connection_draining = true
|
||||
connection_draining_timeout = 400
|
||||
|
||||
tags {
|
||||
Name = "kubernetes-${var.aws_cluster_name}-elb-api"
|
||||
}
|
||||
}
|
7
contrib/terraform/aws/modules/elb/outputs.tf
Normal file
7
contrib/terraform/aws/modules/elb/outputs.tf
Normal file
|
@ -0,0 +1,7 @@
|
|||
output "aws_elb_api_id" {
|
||||
value = "${aws_elb.aws-elb-api.id}"
|
||||
}
|
||||
|
||||
output "aws_elb_api_fqdn" {
|
||||
value = "${aws_elb.aws-elb-api.dns_name}"
|
||||
}
|
28
contrib/terraform/aws/modules/elb/variables.tf
Normal file
28
contrib/terraform/aws/modules/elb/variables.tf
Normal file
|
@ -0,0 +1,28 @@
|
|||
variable "aws_cluster_name" {
|
||||
description = "Name of Cluster"
|
||||
}
|
||||
|
||||
variable "aws_vpc_id" {
|
||||
description = "AWS VPC ID"
|
||||
}
|
||||
|
||||
variable "aws_elb_api_port" {
|
||||
description = "Port for AWS ELB"
|
||||
}
|
||||
|
||||
variable "k8s_secure_api_port" {
|
||||
description = "Secure Port of K8S API Server"
|
||||
}
|
||||
|
||||
|
||||
|
||||
variable "aws_avail_zones" {
|
||||
description = "Availability Zones Used"
|
||||
type = "list"
|
||||
}
|
||||
|
||||
|
||||
variable "aws_subnet_ids_public" {
|
||||
description = "IDs of Public Subnets"
|
||||
type = "list"
|
||||
}
|
138
contrib/terraform/aws/modules/iam/main.tf
Normal file
138
contrib/terraform/aws/modules/iam/main.tf
Normal file
|
@ -0,0 +1,138 @@
|
|||
#Add AWS Roles for Kubernetes
|
||||
|
||||
resource "aws_iam_role" "kube-master" {
|
||||
name = "kubernetes-${var.aws_cluster_name}-master"
|
||||
assume_role_policy = <<EOF
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": "sts:AssumeRole",
|
||||
"Principal": {
|
||||
"Service": "ec2.amazonaws.com"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
resource "aws_iam_role" "kube-worker" {
|
||||
name = "kubernetes-${var.aws_cluster_name}-node"
|
||||
assume_role_policy = <<EOF
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": "sts:AssumeRole",
|
||||
"Principal": {
|
||||
"Service": "ec2.amazonaws.com"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
#Add AWS Policies for Kubernetes
|
||||
|
||||
resource "aws_iam_role_policy" "kube-master" {
|
||||
name = "kubernetes-${var.aws_cluster_name}-master"
|
||||
role = "${aws_iam_role.kube-master.id}"
|
||||
policy = <<EOF
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": ["ec2:*"],
|
||||
"Resource": ["*"]
|
||||
},
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": ["elasticloadbalancing:*"],
|
||||
"Resource": ["*"]
|
||||
},
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": ["route53:*"],
|
||||
"Resource": ["*"]
|
||||
},
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": "s3:*",
|
||||
"Resource": [
|
||||
"arn:aws:s3:::kubernetes-*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
resource "aws_iam_role_policy" "kube-worker" {
|
||||
name = "kubernetes-${var.aws_cluster_name}-node"
|
||||
role = "${aws_iam_role.kube-worker.id}"
|
||||
policy = <<EOF
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": "s3:*",
|
||||
"Resource": [
|
||||
"arn:aws:s3:::kubernetes-*"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": "ec2:Describe*",
|
||||
"Resource": "*"
|
||||
},
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": "ec2:AttachVolume",
|
||||
"Resource": "*"
|
||||
},
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": "ec2:DetachVolume",
|
||||
"Resource": "*"
|
||||
},
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": ["route53:*"],
|
||||
"Resource": ["*"]
|
||||
},
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"ecr:GetAuthorizationToken",
|
||||
"ecr:BatchCheckLayerAvailability",
|
||||
"ecr:GetDownloadUrlForLayer",
|
||||
"ecr:GetRepositoryPolicy",
|
||||
"ecr:DescribeRepositories",
|
||||
"ecr:ListImages",
|
||||
"ecr:BatchGetImage"
|
||||
],
|
||||
"Resource": "*"
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
|
||||
#Create AWS Instance Profiles
|
||||
|
||||
resource "aws_iam_instance_profile" "kube-master" {
|
||||
name = "kube_${var.aws_cluster_name}_master_profile"
|
||||
roles = ["${aws_iam_role.kube-master.name}"]
|
||||
}
|
||||
|
||||
resource "aws_iam_instance_profile" "kube-worker" {
|
||||
name = "kube_${var.aws_cluster_name}_node_profile"
|
||||
roles = ["${aws_iam_role.kube-worker.name}"]
|
||||
}
|
7
contrib/terraform/aws/modules/iam/outputs.tf
Normal file
7
contrib/terraform/aws/modules/iam/outputs.tf
Normal file
|
@ -0,0 +1,7 @@
|
|||
output "kube-master-profile" {
|
||||
value = "${aws_iam_instance_profile.kube-master.name }"
|
||||
}
|
||||
|
||||
output "kube-worker-profile" {
|
||||
value = "${aws_iam_instance_profile.kube-worker.name }"
|
||||
}
|
3
contrib/terraform/aws/modules/iam/variables.tf
Normal file
3
contrib/terraform/aws/modules/iam/variables.tf
Normal file
|
@ -0,0 +1,3 @@
|
|||
variable "aws_cluster_name" {
|
||||
description = "Name of Cluster"
|
||||
}
|
138
contrib/terraform/aws/modules/vpc/main.tf
Normal file
138
contrib/terraform/aws/modules/vpc/main.tf
Normal file
|
@ -0,0 +1,138 @@
|
|||
|
||||
resource "aws_vpc" "cluster-vpc" {
|
||||
cidr_block = "${var.aws_vpc_cidr_block}"
|
||||
|
||||
#DNS Related Entries
|
||||
enable_dns_support = true
|
||||
enable_dns_hostnames = true
|
||||
|
||||
tags {
|
||||
Name = "kubernetes-${var.aws_cluster_name}-vpc"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
resource "aws_eip" "cluster-nat-eip" {
|
||||
count = "${length(var.aws_cidr_subnets_public)}"
|
||||
vpc = true
|
||||
}
|
||||
|
||||
|
||||
|
||||
resource "aws_internet_gateway" "cluster-vpc-internetgw" {
|
||||
vpc_id = "${aws_vpc.cluster-vpc.id}"
|
||||
|
||||
tags {
|
||||
Name = "kubernetes-${var.aws_cluster_name}-internetgw"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_subnet" "cluster-vpc-subnets-public" {
|
||||
vpc_id = "${aws_vpc.cluster-vpc.id}"
|
||||
count="${length(var.aws_avail_zones)}"
|
||||
availability_zone = "${element(var.aws_avail_zones, count.index)}"
|
||||
cidr_block = "${element(var.aws_cidr_subnets_public, count.index)}"
|
||||
|
||||
tags {
|
||||
Name = "kubernetes-${var.aws_cluster_name}-${element(var.aws_avail_zones, count.index)}-public"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_nat_gateway" "cluster-nat-gateway" {
|
||||
count = "${length(var.aws_cidr_subnets_public)}"
|
||||
allocation_id = "${element(aws_eip.cluster-nat-eip.*.id, count.index)}"
|
||||
subnet_id = "${element(aws_subnet.cluster-vpc-subnets-public.*.id, count.index)}"
|
||||
|
||||
}
|
||||
|
||||
resource "aws_subnet" "cluster-vpc-subnets-private" {
|
||||
vpc_id = "${aws_vpc.cluster-vpc.id}"
|
||||
count="${length(var.aws_avail_zones)}"
|
||||
availability_zone = "${element(var.aws_avail_zones, count.index)}"
|
||||
cidr_block = "${element(var.aws_cidr_subnets_private, count.index)}"
|
||||
|
||||
tags {
|
||||
Name = "kubernetes-${var.aws_cluster_name}-${element(var.aws_avail_zones, count.index)}-private"
|
||||
}
|
||||
}
|
||||
|
||||
#Routing in VPC
|
||||
|
||||
#TODO: Do we need two routing tables for each subnet for redundancy or is one enough?
|
||||
|
||||
resource "aws_route_table" "kubernetes-public" {
|
||||
vpc_id = "${aws_vpc.cluster-vpc.id}"
|
||||
route {
|
||||
cidr_block = "0.0.0.0/0"
|
||||
gateway_id = "${aws_internet_gateway.cluster-vpc-internetgw.id}"
|
||||
}
|
||||
tags {
|
||||
Name = "kubernetes-${var.aws_cluster_name}-routetable-public"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_route_table" "kubernetes-private" {
|
||||
count = "${length(var.aws_cidr_subnets_private)}"
|
||||
vpc_id = "${aws_vpc.cluster-vpc.id}"
|
||||
route {
|
||||
cidr_block = "0.0.0.0/0"
|
||||
gateway_id = "${element(aws_nat_gateway.cluster-nat-gateway.*.id, count.index)}"
|
||||
}
|
||||
tags {
|
||||
Name = "kubernetes-${var.aws_cluster_name}-routetable-private-${count.index}"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_route_table_association" "kubernetes-public" {
|
||||
count = "${length(var.aws_cidr_subnets_public)}"
|
||||
subnet_id = "${element(aws_subnet.cluster-vpc-subnets-public.*.id,count.index)}"
|
||||
route_table_id = "${aws_route_table.kubernetes-public.id}"
|
||||
|
||||
}
|
||||
|
||||
resource "aws_route_table_association" "kubernetes-private" {
|
||||
count = "${length(var.aws_cidr_subnets_private)}"
|
||||
subnet_id = "${element(aws_subnet.cluster-vpc-subnets-private.*.id,count.index)}"
|
||||
route_table_id = "${element(aws_route_table.kubernetes-private.*.id,count.index)}"
|
||||
|
||||
}
|
||||
|
||||
|
||||
#Kubernetes Security Groups
|
||||
|
||||
resource "aws_security_group" "kubernetes" {
|
||||
name = "kubernetes-${var.aws_cluster_name}-securitygroup"
|
||||
vpc_id = "${aws_vpc.cluster-vpc.id}"
|
||||
|
||||
tags {
|
||||
Name = "kubernetes-${var.aws_cluster_name}-securitygroup"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_security_group_rule" "allow-all-ingress" {
|
||||
type = "ingress"
|
||||
from_port = 0
|
||||
to_port = 65535
|
||||
protocol = "-1"
|
||||
cidr_blocks= ["${var.aws_vpc_cidr_block}"]
|
||||
security_group_id = "${aws_security_group.kubernetes.id}"
|
||||
}
|
||||
|
||||
resource "aws_security_group_rule" "allow-all-egress" {
|
||||
type = "egress"
|
||||
from_port = 0
|
||||
to_port = 65535
|
||||
protocol = "-1"
|
||||
cidr_blocks = ["0.0.0.0/0"]
|
||||
security_group_id = "${aws_security_group.kubernetes.id}"
|
||||
}
|
||||
|
||||
|
||||
resource "aws_security_group_rule" "allow-ssh-connections" {
|
||||
type = "ingress"
|
||||
from_port = 22
|
||||
to_port = 22
|
||||
protocol = "TCP"
|
||||
cidr_blocks = ["0.0.0.0/0"]
|
||||
security_group_id = "${aws_security_group.kubernetes.id}"
|
||||
}
|
16
contrib/terraform/aws/modules/vpc/outputs.tf
Normal file
16
contrib/terraform/aws/modules/vpc/outputs.tf
Normal file
|
@ -0,0 +1,16 @@
|
|||
output "aws_vpc_id" {
|
||||
value = "${aws_vpc.cluster-vpc.id}"
|
||||
}
|
||||
|
||||
output "aws_subnet_ids_private" {
|
||||
value = ["${aws_subnet.cluster-vpc-subnets-private.*.id}"]
|
||||
}
|
||||
|
||||
output "aws_subnet_ids_public" {
|
||||
value = ["${aws_subnet.cluster-vpc-subnets-public.*.id}"]
|
||||
}
|
||||
|
||||
output "aws_security_group" {
|
||||
value = ["${aws_security_group.kubernetes.*.id}"]
|
||||
|
||||
}
|
24
contrib/terraform/aws/modules/vpc/variables.tf
Normal file
24
contrib/terraform/aws/modules/vpc/variables.tf
Normal file
|
@ -0,0 +1,24 @@
|
|||
variable "aws_vpc_cidr_block" {
|
||||
description = "CIDR Blocks for AWS VPC"
|
||||
}
|
||||
|
||||
|
||||
variable "aws_cluster_name" {
|
||||
description = "Name of Cluster"
|
||||
}
|
||||
|
||||
|
||||
variable "aws_avail_zones" {
|
||||
description = "AWS Availability Zones Used"
|
||||
type = "list"
|
||||
}
|
||||
|
||||
variable "aws_cidr_subnets_private" {
|
||||
description = "CIDR Blocks for private subnets in Availability zones"
|
||||
type = "list"
|
||||
}
|
||||
|
||||
variable "aws_cidr_subnets_public" {
|
||||
description = "CIDR Blocks for public subnets in Availability zones"
|
||||
type = "list"
|
||||
}
|
20
contrib/terraform/aws/output.tf
Normal file
20
contrib/terraform/aws/output.tf
Normal file
|
@ -0,0 +1,20 @@
|
|||
output "bastion_ip" {
|
||||
value = "${join("\n", aws_instance.bastion-server.*.public_ip)}"
|
||||
}
|
||||
|
||||
output "masters" {
|
||||
value = "${join("\n", aws_instance.k8s-master.*.private_ip)}"
|
||||
}
|
||||
|
||||
output "workers" {
|
||||
value = "${join("\n", aws_instance.k8s-worker.*.private_ip)}"
|
||||
}
|
||||
|
||||
output "etcd" {
|
||||
value = "${join("\n", aws_instance.k8s-etcd.*.private_ip)}"
|
||||
}
|
||||
|
||||
|
||||
output "aws_elb_api_fqdn" {
|
||||
value = "${module.aws-elb.aws_elb_api_fqdn}:${var.aws_elb_api_port}"
|
||||
}
|
27
contrib/terraform/aws/templates/inventory.tpl
Normal file
27
contrib/terraform/aws/templates/inventory.tpl
Normal file
|
@ -0,0 +1,27 @@
|
|||
${connection_strings_master}
|
||||
${connection_strings_node}
|
||||
${connection_strings_etcd}
|
||||
|
||||
|
||||
${public_ip_address_bastion}
|
||||
|
||||
[kube-master]
|
||||
${list_master}
|
||||
|
||||
|
||||
[kube-node]
|
||||
${list_node}
|
||||
|
||||
|
||||
[etcd]
|
||||
${list_etcd}
|
||||
|
||||
|
||||
[k8s-cluster:children]
|
||||
kube-node
|
||||
kube-master
|
||||
|
||||
|
||||
[k8s-cluster:vars]
|
||||
${elb_api_fqdn}
|
||||
${elb_api_port}
|
|
@ -1,22 +1,32 @@
|
|||
deploymentName="test-kube-deploy"
|
||||
#Global Vars
|
||||
aws_cluster_name = "devtest"
|
||||
aws_region = "eu-central-1"
|
||||
|
||||
numControllers="2"
|
||||
numEtcd="3"
|
||||
numNodes="2"
|
||||
#VPC Vars
|
||||
aws_vpc_cidr_block = "10.250.192.0/18"
|
||||
aws_cidr_subnets_private = ["10.250.192.0/20","10.250.208.0/20"]
|
||||
aws_cidr_subnets_public = ["10.250.224.0/20","10.250.240.0/20"]
|
||||
aws_avail_zones = ["eu-central-1a","eu-central-1b"]
|
||||
|
||||
volSizeController="20"
|
||||
volSizeEtcd="20"
|
||||
volSizeNodes="20"
|
||||
#Bastion Host
|
||||
aws_bastion_ami = "ami-5900cc36"
|
||||
aws_bastion_size = "t2.small"
|
||||
|
||||
awsRegion="us-west-2"
|
||||
subnet="subnet-xxxxx"
|
||||
ami="ami-32a85152"
|
||||
securityGroups="sg-xxxxx"
|
||||
SSHUser="core"
|
||||
SSHKey="my-key"
|
||||
|
||||
master_instance_type="m3.xlarge"
|
||||
etcd_instance_type="m3.xlarge"
|
||||
node_instance_type="m3.xlarge"
|
||||
#Kubernetes Cluster
|
||||
|
||||
terminate_protect="false"
|
||||
aws_kube_master_num = 3
|
||||
aws_kube_master_size = "t2.medium"
|
||||
|
||||
aws_etcd_num = 3
|
||||
aws_etcd_size = "t2.medium"
|
||||
|
||||
aws_kube_worker_num = 4
|
||||
aws_kube_worker_size = "t2.medium"
|
||||
|
||||
aws_cluster_ami = "ami-903df7ff"
|
||||
|
||||
#Settings AWS ELB
|
||||
|
||||
aws_elb_api_port = 443
|
||||
k8s_secure_api_port = 443
|
||||
|
|
97
contrib/terraform/aws/variables.tf
Normal file
97
contrib/terraform/aws/variables.tf
Normal file
|
@ -0,0 +1,97 @@
|
|||
variable "AWS_ACCESS_KEY_ID" {
|
||||
description = "AWS Access Key"
|
||||
}
|
||||
|
||||
variable "AWS_SECRET_ACCESS_KEY" {
|
||||
description = "AWS Secret Key"
|
||||
}
|
||||
|
||||
variable "AWS_SSH_KEY_NAME" {
|
||||
description = "Name of the SSH keypair to use in AWS."
|
||||
}
|
||||
|
||||
variable "AWS_DEFAULT_REGION" {
|
||||
description = "AWS Region"
|
||||
}
|
||||
|
||||
//General Cluster Settings
|
||||
|
||||
variable "aws_cluster_name" {
|
||||
description = "Name of AWS Cluster"
|
||||
}
|
||||
|
||||
|
||||
//AWS VPC Variables
|
||||
|
||||
variable "aws_vpc_cidr_block" {
|
||||
description = "CIDR Block for VPC"
|
||||
}
|
||||
|
||||
variable "aws_avail_zones" {
|
||||
description = "Availability Zones Used"
|
||||
type = "list"
|
||||
}
|
||||
|
||||
variable "aws_cidr_subnets_private" {
|
||||
description = "CIDR Blocks for private subnets in Availability zones1"
|
||||
type = "list"
|
||||
}
|
||||
|
||||
variable "aws_cidr_subnets_public" {
|
||||
description = "CIDR Blocks for public subnets in Availability zones1"
|
||||
type = "list"
|
||||
}
|
||||
|
||||
//AWS EC2 Settings
|
||||
|
||||
variable "aws_bastion_ami" {
|
||||
description = "AMI ID for Bastion Host in chosen AWS Region"
|
||||
}
|
||||
|
||||
variable "aws_bastion_size" {
|
||||
description = "EC2 Instance Size of Bastion Host"
|
||||
}
|
||||
|
||||
/*
|
||||
* AWS EC2 Settings
|
||||
* The number should be divisable by the number of used
|
||||
* AWS Availability Zones without an remainder.
|
||||
*/
|
||||
variable "aws_kube_master_num" {
|
||||
description = "Number of Kubernetes Master Nodes"
|
||||
}
|
||||
|
||||
variable "aws_kube_master_size" {
|
||||
description = "Instance size of Kube Master Nodes"
|
||||
}
|
||||
|
||||
variable "aws_etcd_num" {
|
||||
description = "Number of etcd Nodes"
|
||||
}
|
||||
|
||||
variable "aws_etcd_size" {
|
||||
description = "Instance size of etcd Nodes"
|
||||
}
|
||||
|
||||
variable "aws_kube_worker_num" {
|
||||
description = "Number of Kubernetes Worker Nodes"
|
||||
}
|
||||
|
||||
variable "aws_kube_worker_size" {
|
||||
description = "Instance size of Kubernetes Worker Nodes"
|
||||
}
|
||||
|
||||
variable "aws_cluster_ami" {
|
||||
description = "AMI ID for Kubernetes Cluster"
|
||||
}
|
||||
/*
|
||||
* AWS ELB Settings
|
||||
*
|
||||
*/
|
||||
variable "aws_elb_api_port" {
|
||||
description = "Port for AWS ELB"
|
||||
}
|
||||
|
||||
variable "k8s_secure_api_port" {
|
||||
description = "Secure Port of K8S API Server"
|
||||
}
|
Loading…
Reference in a new issue