mirror of
https://github.com/outbackdingo/alicloud-singapore.git
synced 2026-08-25 07:10:17 +00:00
Initial commit: Terraform plan for Singapore production ACK cluster
- Creates VPC with 3 vswitches across availability zones - Creates security group with ports for all production services - Creates ACK managed Kubernetes cluster with 10 worker nodes - Auto-scaling up to 20 worker nodes - Creates SLB for load balancing - Includes deploy.sh script to apply cluster-all.yaml resources
This commit is contained in:
+15
@@ -0,0 +1,15 @@
|
||||
# Terraform
|
||||
*.tfstate
|
||||
*.tfstate.*
|
||||
.terraform/
|
||||
.terraform.lock.hcl
|
||||
|
||||
# IDE
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
@@ -0,0 +1,130 @@
|
||||
#!/bin/bash
|
||||
# Lingble Production Cluster Deployment Script
|
||||
# This script deploys services from cluster-all.yaml to the new Singapore ACK cluster
|
||||
|
||||
set -e
|
||||
|
||||
CLUSTER_ALL_FILE="${CLUSTER_ALL_FILE:-/Users/dingo/cluster-all.yaml}"
|
||||
TEMP_DIR="/tmp/lingble-deploy-$$"
|
||||
|
||||
echo "=== Lingble Production Cluster Deployment ==="
|
||||
echo "Cluster All File: $CLUSTER_ALL_FILE"
|
||||
echo "Target Region: Singapore (ap-southeast-1)"
|
||||
|
||||
# Check if kubeconfig exists
|
||||
if [ ! -f "./kubeconfig" ]; then
|
||||
echo "Error: kubeconfig file not found. Run 'terraform apply' first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if cluster-all.yaml exists
|
||||
if [ ! -f "$CLUSTER_ALL_FILE" ]; then
|
||||
echo "Error: cluster-all.yaml not found at $CLUSTER_ALL_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Export kubeconfig
|
||||
export KUBECONFIG=./kubeconfig
|
||||
|
||||
# Verify cluster connectivity
|
||||
echo "Verifying cluster connectivity..."
|
||||
kubectl cluster-info
|
||||
|
||||
# Create temp directory
|
||||
mkdir -p "$TEMP_DIR"
|
||||
|
||||
# Extract namespaces from cluster-all.yaml
|
||||
echo "Extracting namespaces..."
|
||||
NAMESPACES=$(grep "namespace:" "$CLUSTER_ALL_FILE" | sed 's/.*namespace: //' | sort -u)
|
||||
echo "Found namespaces: $NAMESPACES"
|
||||
|
||||
# Create namespaces
|
||||
echo "Creating namespaces..."
|
||||
for ns in $NAMESPACES; do
|
||||
kubectl create namespace "$ns" --dry-run=client -o yaml | kubectl apply -f - 2>/dev/null || true
|
||||
done
|
||||
|
||||
# Extract and apply resources
|
||||
echo "Extracting resources from cluster-all.yaml..."
|
||||
|
||||
# Apply ServiceAccounts first
|
||||
echo "Applying ServiceAccounts..."
|
||||
kubectl get -f "$CLUSTER_ALL_FILE" --dry-run=client -o json 2>/dev/null | \
|
||||
jq -r '.items[] | select(.kind == "ServiceAccount") | del(.status, .metadata.resourceVersion, .metadata.uid, .metadata.creationTimestamp, .metadata.generation)' | \
|
||||
jq -s '.' | kubectl apply -f - 2>/dev/null || true
|
||||
|
||||
# Apply RBAC
|
||||
echo "Applying RBAC resources..."
|
||||
kubectl get -f "$CLUSTER_ALL_FILE" --dry-run=client -o json 2>/dev/null | \
|
||||
jq -r '.items[] | select(.kind == "Role" or .kind == "RoleBinding" or .kind == "ClusterRole" or .kind == "ClusterRoleBinding") | del(.status, .metadata.resourceVersion, .metadata.uid, .metadata.creationTimestamp, .metadata.generation)' | \
|
||||
jq -s '.' | kubectl apply -f - 2>/dev/null || true
|
||||
|
||||
# Apply ConfigMaps
|
||||
echo "Applying ConfigMaps..."
|
||||
kubectl get -f "$CLUSTER_ALL_FILE" --dry-run=client -o json 2>/dev/null | \
|
||||
jq -r '.items[] | select(.kind == "ConfigMap") | del(.status, .metadata.resourceVersion, .metadata.uid, .metadata.creationTimestamp, .metadata.generation)' | \
|
||||
jq -s '.' | kubectl apply -f - 2>/dev/null || true
|
||||
|
||||
# Apply Secrets
|
||||
echo "Applying Secrets..."
|
||||
kubectl get -f "$CLUSTER_ALL_FILE" --dry-run=client -o json 2>/dev/null | \
|
||||
jq -r '.items[] | select(.kind == "Secret") | del(.status, .metadata.resourceVersion, .metadata.uid, .metadata.creationTimestamp, .metadata.generation)' | \
|
||||
jq -s '.' | kubectl apply -f - 2>/dev/null || true
|
||||
|
||||
# Apply PersistentVolumeClaims
|
||||
echo "Applying PersistentVolumeClaims..."
|
||||
kubectl get -f "$CLUSTER_ALL_FILE" --dry-run=client -o json 2>/dev/null | \
|
||||
jq -r '.items[] | select(.kind == "PersistentVolumeClaim") | del(.status, .metadata.resourceVersion, .metadata.uid, .metadata.creationTimestamp, .metadata.generation)' | \
|
||||
jq -s '.' | kubectl apply -f - 2>/dev/null || true
|
||||
|
||||
# Apply Services
|
||||
echo "Applying Services..."
|
||||
kubectl get -f "$CLUSTER_ALL_FILE" --dry-run=client -o json 2>/dev/null | \
|
||||
jq -r '.items[] | select(.kind == "Service") | del(.status, .metadata.resourceVersion, .metadata.uid, .metadata.creationTimestamp, .metadata.generation)' | \
|
||||
jq -s '.' | kubectl apply -f - 2>/dev/null || true
|
||||
|
||||
# Apply Deployments
|
||||
echo "Applying Deployments..."
|
||||
kubectl get -f "$CLUSTER_ALL_FILE" --dry-run=client -o json 2>/dev/null | \
|
||||
jq -r '.items[] | select(.kind == "Deployment") | del(.status, .metadata.resourceVersion, .metadata.uid, .metadata.creationTimestamp, .metadata.generation)' | \
|
||||
jq -s '.' | kubectl apply -f - 2>/dev/null || true
|
||||
|
||||
# Apply StatefulSets
|
||||
echo "Applying StatefulSets..."
|
||||
kubectl get -f "$CLUSTER_ALL_FILE" --dry-run=client -o json 2>/dev/null | \
|
||||
jq -r '.items[] | select(.kind == "StatefulSet") | del(.status, .metadata.resourceVersion, .metadata.uid, .metadata.creationTimestamp, .metadata.generation)' | \
|
||||
jq -s '.' | kubectl apply -f - 2>/dev/null || true
|
||||
|
||||
# Apply Ingress
|
||||
echo "Applying Ingress resources..."
|
||||
kubectl get -f "$CLUSTER_ALL_FILE" --dry-run=client -o json 2>/dev/null | \
|
||||
jq -r '.items[] | select(.kind == "Ingress") | del(.status, .metadata.resourceVersion, .metadata.uid, .metadata.creationTimestamp, .metadata.generation)' | \
|
||||
jq -s '.' | kubectl apply -f - 2>/dev/null || true
|
||||
|
||||
# Apply remaining resources (DaemonSet, CronJob, Job, etc.)
|
||||
echo "Applying other resources..."
|
||||
kubectl get -f "$CLUSTER_ALL_FILE" --dry-run=client -o json 2>/dev/null | \
|
||||
jq -r '.items[] | select(.kind == "DaemonSet" or .kind == "CronJob" or .kind == "Job" or .kind == "HorizontalPodAutoscaler") | del(.status, .metadata.resourceVersion, .metadata.uid, .metadata.creationTimestamp, .metadata.generation)' | \
|
||||
jq -s '.' | kubectl apply -f - 2>/dev/null || true
|
||||
|
||||
# Cleanup
|
||||
rm -rf "$TEMP_DIR"
|
||||
|
||||
echo "=== Deployment Complete ==="
|
||||
|
||||
# Show results
|
||||
echo ""
|
||||
echo "Namespaces:"
|
||||
kubectl get ns
|
||||
|
||||
echo ""
|
||||
echo "Deployments:"
|
||||
kubectl get deployments -A 2>/dev/null | head -40
|
||||
|
||||
echo ""
|
||||
echo "StatefulSets:"
|
||||
kubectl get statefulsets -A 2>/dev/null | head -20
|
||||
|
||||
echo ""
|
||||
echo "Services:"
|
||||
kubectl get svc -A 2>/dev/null | head -40
|
||||
@@ -0,0 +1,295 @@
|
||||
terraform {
|
||||
required_version = ">= 1.0"
|
||||
|
||||
required_providers {
|
||||
alicloud = {
|
||||
source = "aliyun/alicloud"
|
||||
version = "~> 1.224"
|
||||
}
|
||||
local = {
|
||||
source = "hashicorp/local"
|
||||
version = "~> 2.4"
|
||||
}
|
||||
}
|
||||
|
||||
backend "local" {
|
||||
path = "terraform.tfstate"
|
||||
}
|
||||
}
|
||||
|
||||
provider "alicloud" {
|
||||
region = var.region
|
||||
access_key = var.access_key
|
||||
secret_key = var.secret_key
|
||||
}
|
||||
|
||||
data "alicloud_zones" "sgp" {
|
||||
available_resource_creation = "VSwitch"
|
||||
}
|
||||
|
||||
resource "alicloud_vpc" "this" {
|
||||
vpc_name = "${var.project}-vpc"
|
||||
cidr_block = var.vpc_cidr
|
||||
|
||||
tags = var.tags
|
||||
}
|
||||
|
||||
resource "alicloud_vswitch" "this" {
|
||||
count = 3
|
||||
|
||||
name = "${var.project}-vswitch-${count.index}"
|
||||
vpc_id = alicloud_vpc.this.id
|
||||
cidr_block = cidrsubnet(var.vpc_cidr, 8, count.index)
|
||||
zone_id = data.alicloud_zones.sgp.zones[count.index].id
|
||||
|
||||
tags = var.tags
|
||||
}
|
||||
|
||||
resource "alicloud_security_group" "this" {
|
||||
security_group_name = "${var.project}-sg"
|
||||
vpc_id = alicloud_vpc.this.id
|
||||
|
||||
tags = var.tags
|
||||
}
|
||||
|
||||
resource "alicloud_security_group_rule" "allow_ssh" {
|
||||
type = "ingress"
|
||||
ip_protocol = "tcp"
|
||||
port_range = "22/22"
|
||||
cidr_ip = "0.0.0.0/0"
|
||||
security_group_id = alicloud_security_group.this.id
|
||||
}
|
||||
|
||||
resource "alicloud_security_group_rule" "allow_http" {
|
||||
type = "ingress"
|
||||
ip_protocol = "tcp"
|
||||
port_range = "80/80"
|
||||
cidr_ip = "0.0.0.0/0"
|
||||
security_group_id = alicloud_security_group.this.id
|
||||
}
|
||||
|
||||
resource "alicloud_security_group_rule" "allow_https" {
|
||||
type = "ingress"
|
||||
ip_protocol = "tcp"
|
||||
port_range = "443/443"
|
||||
cidr_ip = "0.0.0.0/0"
|
||||
security_group_id = alicloud_security_group.this.id
|
||||
}
|
||||
|
||||
resource "alicloud_security_group_rule" "allow_k8s_api" {
|
||||
type = "ingress"
|
||||
ip_protocol = "tcp"
|
||||
port_range = "6443/6443"
|
||||
cidr_ip = "0.0.0.0/0"
|
||||
security_group_id = alicloud_security_group.this.id
|
||||
}
|
||||
|
||||
resource "alicloud_security_group_rule" "allow_arangodb" {
|
||||
type = "ingress"
|
||||
ip_protocol = "tcp"
|
||||
port_range = "8529/8529"
|
||||
cidr_ip = "10.0.0.0/16"
|
||||
security_group_id = alicloud_security_group.this.id
|
||||
}
|
||||
|
||||
resource "alicloud_security_group_rule" "allow_mongodb" {
|
||||
type = "ingress"
|
||||
ip_protocol = "tcp"
|
||||
port_range = "27017/27017"
|
||||
cidr_ip = "10.0.0.0/16"
|
||||
security_group_id = alicloud_security_group.this.id
|
||||
}
|
||||
|
||||
resource "alicloud_security_group_rule" "allow_mysql" {
|
||||
type = "ingress"
|
||||
ip_protocol = "tcp"
|
||||
port_range = "3306/3306"
|
||||
cidr_ip = "10.0.0.0/16"
|
||||
security_group_id = alicloud_security_group.this.id
|
||||
}
|
||||
|
||||
resource "alicloud_security_group_rule" "allow_postgres" {
|
||||
type = "ingress"
|
||||
ip_protocol = "tcp"
|
||||
port_range = "5432/5432"
|
||||
cidr_ip = "10.0.0.0/16"
|
||||
security_group_id = alicloud_security_group.this.id
|
||||
}
|
||||
|
||||
resource "alicloud_security_group_rule" "allow_redis" {
|
||||
type = "ingress"
|
||||
ip_protocol = "tcp"
|
||||
port_range = "6379/6379"
|
||||
cidr_ip = "10.0.0.0/16"
|
||||
security_group_id = alicloud_security_group.this.id
|
||||
}
|
||||
|
||||
resource "alicloud_security_group_rule" "allow_elasticsearch" {
|
||||
type = "ingress"
|
||||
ip_protocol = "tcp"
|
||||
port_range = "9200/9200"
|
||||
cidr_ip = "10.0.0.0/16"
|
||||
security_group_id = alicloud_security_group.this.id
|
||||
}
|
||||
|
||||
resource "alicloud_security_group_rule" "allow_rabbitmq" {
|
||||
type = "ingress"
|
||||
ip_protocol = "tcp"
|
||||
port_range = "5672/15672"
|
||||
cidr_ip = "10.0.0.0/16"
|
||||
security_group_id = alicloud_security_group.this.id
|
||||
}
|
||||
|
||||
resource "alicloud_security_group_rule" "allow_kafka" {
|
||||
type = "ingress"
|
||||
ip_protocol = "tcp"
|
||||
port_range = "9092/9092"
|
||||
cidr_ip = "10.0.0.0/16"
|
||||
security_group_id = alicloud_security_group.this.id
|
||||
}
|
||||
|
||||
resource "alicloud_security_group_rule" "allow_kafka_zookeeper" {
|
||||
type = "ingress"
|
||||
ip_protocol = "tcp"
|
||||
port_range = "2181/2181"
|
||||
cidr_ip = "10.0.0.0/16"
|
||||
security_group_id = alicloud_security_group.this.id
|
||||
}
|
||||
|
||||
resource "alicloud_security_group_rule" "allow_kibana" {
|
||||
type = "ingress"
|
||||
ip_protocol = "tcp"
|
||||
port_range = "5601/5601"
|
||||
cidr_ip = "0.0.0.0/0"
|
||||
security_group_id = alicloud_security_group.this.id
|
||||
}
|
||||
|
||||
resource "alicloud_security_group_rule" "allow_prometheus" {
|
||||
type = "ingress"
|
||||
ip_protocol = "tcp"
|
||||
port_range = "9090/9090"
|
||||
cidr_ip = "10.0.0.0/16"
|
||||
security_group_id = alicloud_security_group.this.id
|
||||
}
|
||||
|
||||
resource "alicloud_security_group_rule" "allow_grafana" {
|
||||
type = "ingress"
|
||||
ip_protocol = "tcp"
|
||||
port_range = "3000/3000"
|
||||
cidr_ip = "0.0.0.0/0"
|
||||
security_group_id = alicloud_security_group.this.id
|
||||
}
|
||||
|
||||
resource "alicloud_security_group_rule" "allow_kubernetes_dashboard" {
|
||||
type = "ingress"
|
||||
ip_protocol = "tcp"
|
||||
port_range = "8443/8443"
|
||||
cidr_ip = "10.0.0.0/16"
|
||||
security_group_id = alicloud_security_group.this.id
|
||||
}
|
||||
|
||||
resource "alicloud_security_group_rule" "allow_nodeports" {
|
||||
type = "ingress"
|
||||
ip_protocol = "tcp"
|
||||
port_range = "30000/32767"
|
||||
cidr_ip = "0.0.0.0/0"
|
||||
security_group_id = alicloud_security_group.this.id
|
||||
}
|
||||
|
||||
resource "alicloud_cs_managed_kubernetes" "this" {
|
||||
name_prefix = "${var.project}-k8s"
|
||||
cluster_spec = var.k8s_cluster_spec
|
||||
vswitch_ids = alicloud_vswitch.this[*].id
|
||||
security_group_id = alicloud_security_group.this.id
|
||||
|
||||
service_cidr = "172.20.0.0/16"
|
||||
pod_cidr = "172.21.0.0/16"
|
||||
|
||||
new_nat_gateway = true
|
||||
|
||||
timeouts {
|
||||
delete = "60m"
|
||||
}
|
||||
|
||||
tags = var.tags
|
||||
}
|
||||
|
||||
resource "alicloud_cs_kubernetes_node_pool" "workers" {
|
||||
cluster_id = alicloud_cs_managed_kubernetes.this.id
|
||||
name = "${var.project}-workers"
|
||||
node_pool_name = "${var.project}-workers"
|
||||
instance_types = [var.k8s_worker_instance_type]
|
||||
vswitch_ids = alicloud_vswitch.this[*].id
|
||||
desired_size = var.k8s_worker_count
|
||||
system_disk_category = var.k8s_worker_disk_category
|
||||
system_disk_size = var.k8s_worker_disk_size
|
||||
|
||||
scaling_config {
|
||||
min_size = var.k8s_worker_count
|
||||
max_size = var.k8s_max_worker_count
|
||||
}
|
||||
|
||||
data_disks {
|
||||
category = var.k8s_data_disk_category
|
||||
size = var.k8s_data_disk_size
|
||||
}
|
||||
|
||||
tags = var.tags
|
||||
}
|
||||
|
||||
resource "alicloud_slb" "this" {
|
||||
name = "${var.project}-slb"
|
||||
address_type = "internet"
|
||||
vswitch_id = alicloud_vswitch.this[0].id
|
||||
load_balancer_spec = "slb.s2.small"
|
||||
|
||||
tags = var.tags
|
||||
}
|
||||
|
||||
resource "alicloud_slb_listener" "http" {
|
||||
load_balancer_id = alicloud_slb.this.id
|
||||
frontend_port = 80
|
||||
backend_port = 80
|
||||
protocol = "http"
|
||||
}
|
||||
|
||||
resource "alicloud_slb_listener" "https" {
|
||||
count = var.ssl_certificate_id != "" ? 1 : 0
|
||||
load_balancer_id = alicloud_slb.this.id
|
||||
frontend_port = 443
|
||||
backend_port = 443
|
||||
protocol = "https"
|
||||
}
|
||||
|
||||
resource "local_file" "kubeconfig" {
|
||||
content = alicloud_cs_managed_kubernetes.this.kube_config
|
||||
filename = "${path.module}/kubeconfig"
|
||||
}
|
||||
|
||||
output "cluster_id" {
|
||||
value = alicloud_cs_managed_kubernetes.this.id
|
||||
}
|
||||
|
||||
output "cluster_name" {
|
||||
value = alicloud_cs_managed_kubernetes.this.name
|
||||
}
|
||||
|
||||
output "slb_public_ip" {
|
||||
value = alicloud_slb.this.address
|
||||
}
|
||||
|
||||
output "vpc_id" {
|
||||
value = alicloud_vpc.this.id
|
||||
}
|
||||
|
||||
output "vswitch_ids" {
|
||||
value = alicloud_vswitch.this[*].id
|
||||
}
|
||||
|
||||
output "worker_node_count" {
|
||||
value = var.k8s_worker_count
|
||||
}
|
||||
|
||||
output "api_server_endpoint" {
|
||||
value = "https://${alicloud_cs_managed_kubernetes.this.id}.${var.region}.alicloud.com:6443"
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
variable "region" {
|
||||
description = "Alibaba Cloud region"
|
||||
type = string
|
||||
default = "ap-southeast-1"
|
||||
}
|
||||
|
||||
variable "access_key" {
|
||||
description = "Alibaba Cloud access key"
|
||||
type = string
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "secret_key" {
|
||||
description = "Alibaba Cloud secret key"
|
||||
type = string
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "project" {
|
||||
description = "Project name prefix for resources"
|
||||
type = string
|
||||
default = "lingble-prod"
|
||||
}
|
||||
|
||||
variable "vpc_cidr" {
|
||||
description = "CIDR block for VPC"
|
||||
type = string
|
||||
default = "10.0.0.0/16"
|
||||
}
|
||||
|
||||
variable "tags" {
|
||||
description = "Tags to apply to all resources"
|
||||
type = map(string)
|
||||
default = {
|
||||
Environment = "production"
|
||||
ManagedBy = "terraform"
|
||||
Cluster = "singapore-prod"
|
||||
}
|
||||
}
|
||||
|
||||
variable "k8s_cluster_spec" {
|
||||
description = "ACK cluster spec: ack.pro.small, ack.standard"
|
||||
type = string
|
||||
default = "ack.pro.small"
|
||||
}
|
||||
|
||||
variable "k8s_worker_instance_type" {
|
||||
description = "Worker node instance type"
|
||||
type = string
|
||||
default = "ecs.s6-c2m2"
|
||||
}
|
||||
|
||||
variable "k8s_worker_count" {
|
||||
description = "Number of worker nodes"
|
||||
type = number
|
||||
default = 10
|
||||
}
|
||||
|
||||
variable "k8s_max_worker_count" {
|
||||
description = "Maximum number of worker nodes (for autoscaling)"
|
||||
type = number
|
||||
default = 20
|
||||
}
|
||||
|
||||
variable "k8s_worker_disk_category" {
|
||||
description = "Worker node system disk category"
|
||||
type = string
|
||||
default = "cloud_ssd"
|
||||
}
|
||||
|
||||
variable "k8s_worker_disk_size" {
|
||||
description = "Worker node system disk size in GB"
|
||||
type = number
|
||||
default = 100
|
||||
}
|
||||
|
||||
variable "k8s_data_disk_category" {
|
||||
description = "Worker node data disk category"
|
||||
type = string
|
||||
default = "cloud_ssd"
|
||||
}
|
||||
|
||||
variable "k8s_data_disk_size" {
|
||||
description = "Worker node data disk size in GB"
|
||||
type = number
|
||||
default = 200
|
||||
}
|
||||
|
||||
variable "ssl_certificate_id" {
|
||||
description = "SSL certificate ID for SLB (from alicloud_ssl_certificate)"
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
Reference in New Issue
Block a user