관리형 쿠버네티스 클러스터 시작하기

관리형 쿠버네티스 클러스터 시작하기

이 코드 예제에서는 AWS CLI로 Amazon EKS 클러스터와 관리형 노드 그룹을 만드는 방법을 보여드려요.

출처: 문서

본문

다음 작업을 다루어요.

  • EKS 클러스터용 VPC 생성
  • EKS 클러스터용 IAM 역할 생성
  • EKS 클러스터 생성
  • kubectl이 클러스터와 통신하도록 구성
  • 관리형 노드 그룹 생성
  • 리소스 정리

Bash (AWS CLI with Bash script)

Note GitHub에 더 많은 내용이 있어요. 전체 예제와 설정·실행 방법은 Sample developer tutorials 저장소에서 확인할 수 있어요.

이 스크립트는 CloudFormation으로 VPC를 만들고 IAM 역할(클러스터·노드 역할)을 생성한 뒤 EKS 클러스터와 관리형 노드 그룹을 만들어요.

#!/bin/bash

# Amazon EKS Cluster Creation Script (v2)
# This script creates an Amazon EKS cluster with a managed node group using the AWS CLI

# Set up logging
LOG_FILE="eks-cluster-creation-v2.log"
exec > >(tee -a "$LOG_FILE") 2>&1

echo "Starting Amazon EKS cluster creation script at $(date)"
echo "All commands and outputs will be logged to $LOG_FILE"

# Error handling function
handle_error() {
	echo "ERROR: $1"
	echo "Attempting to clean up resources..."
	cleanup_resources
	exit 1
}

# Function to check command success
check_command() {
	if [ $? -ne 0 ] || echo "$1" | grep -i "error" > /dev/null; then
		handle_error "$1"
	fi
}

# Function to check if kubectl is installed
check_kubectl() {
	if ! command -v kubectl &> /dev/null; then
		echo "WARNING: kubectl is not installed or not in your PATH."
		echo ""
		echo "To install kubectl, follow these instructions based on your operating system:"
		echo ""
		echo "For Linux:"
		echo " 1. Download the latest release:"
		echo " curl -LO \"https://dl.k8s.io/release/\$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl\""
		echo ""
		echo " 2. Make the kubectl binary executable:"
		echo " chmod +x ./kubectl"
		echo ""
		echo " 3. Move the binary to your PATH:"
		echo " sudo mv ./kubectl /usr/local/bin/kubectl"
		echo ""
		echo "For macOS:"
		echo " 1. Using Homebrew:"
		echo " brew install kubectl"
		echo " or"
		echo " 2. Using curl:"
		echo " curl -LO \"https://dl.k8s.io/release/\$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/darwin/amd64/kubectl\""
		echo " chmod +x ./kubectl"
		echo " sudo mv ./kubectl /usr/local/bin/kubectl"
		echo ""
		echo "For Windows:"
		echo " 1. Using curl:"
		echo " curl -LO \"https://dl.k8s.io/release/v1.28.0/bin/windows/amd64/kubectl.exe\""
		echo " Add the binary to your PATH"
		echo " or"
		echo " 2. Using Chocolatey:"
		echo " choco install kubernetes-cli"
		echo ""
		echo "After installation, verify with: kubectl version --client"
		echo ""
		return 1
	fi
	return 0
}

# Generate a random identifier for resource names
RANDOM_ID=$(LC_ALL=C tr -dc 'a-z0-9' < /dev/urandom | fold -w 6 | head -n 1)
STACK_NAME="eks-vpc-stack-${RANDOM_ID}"
CLUSTER_NAME="eks-cluster-${RANDOM_ID}"
NODEGROUP_NAME="eks-nodegroup-${RANDOM_ID}"
CLUSTER_ROLE_NAME="EKSClusterRole-${RANDOM_ID}"
NODE_ROLE_NAME="EKSNodeRole-${RANDOM_ID}"

echo "Using the following resource names:"
echo "- VPC Stack: $STACK_NAME"
echo "- EKS Cluster: $CLUSTER_NAME"
echo "- Node Group: $NODEGROUP_NAME"
echo "- Cluster IAM Role: $CLUSTER_ROLE_NAME"
echo "- Node IAM Role: $NODE_ROLE_NAME"

# Array to track created resources for cleanup
declare -a CREATED_RESOURCES

# Function to clean up resources
cleanup_resources() {
	echo "Cleaning up resources in reverse order..."

	# Check if node group exists and delete it
	if aws eks list-nodegroups --cluster-name "$CLUSTER_NAME" --query "nodegroups[?contains(@,'$NODEGROUP_NAME')]" --output text 2>/dev/null | grep -q "$NODEGROUP_NAME"; then
		echo "Deleting node group: $NODEGROUP_NAME"
		aws eks delete-nodegroup --cluster-name "$CLUSTER_NAME" --nodegroup-name "$NODEGROUP_NAME"
		echo "Waiting for node group deletion to complete..."
		aws eks wait nodegroup-deleted --cluster-name "$CLUSTER_NAME" --nodegroup-name "$NODEGROUP_NAME"
		echo "Node group deleted successfully."
	fi

	# Check if cluster exists and delete it
	if aws eks describe-cluster --name "$CLUSTER_NAME" 2>/dev/null; then
		echo "Deleting cluster: $CLUSTER_NAME"
		aws eks delete-cluster --name "$CLUSTER_NAME"
		echo "Waiting for cluster deletion to complete (this may take several minutes)..."
		aws eks wait cluster-deleted --name "$CLUSTER_NAME"
		echo "Cluster deleted successfully."
	fi

	# Check if CloudFormation stack exists and delete it
	if aws cloudformation describe-stacks --stack-name "$STACK_NAME" 2>/dev/null; then
		echo "Deleting CloudFormation stack: $STACK_NAME"
		aws cloudformation delete-stack --stack-name "$STACK_NAME"
		echo "Waiting for CloudFormation stack deletion to complete..."
		aws cloudformation wait stack-delete-complete --stack-name "$STACK_NAME"
		echo "CloudFormation stack deleted successfully."
	fi

	# Clean up IAM roles
	if aws iam get-role --role-name "$NODE_ROLE_NAME" 2>/dev/null; then
		echo "Detaching policies from node role: $NODE_ROLE_NAME"
		aws iam detach-role-policy --policy-arn arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy --role-name "$NODE_ROLE_NAME"
		aws iam detach-role-policy --policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly --role-name "$NODE_ROLE_NAME"
		aws iam detach-role-policy --policy-arn arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy --role-name "$NODE_ROLE_NAME"
		echo "Deleting node role: $NODE_ROLE_NAME"
		aws iam delete-role --role-name "$NODE_ROLE_NAME"
		echo "Node role deleted successfully."
	fi

	if aws iam get-role --role-name "$CLUSTER_ROLE_NAME" 2>/dev/null; then
		echo "Detaching policies from cluster role: $CLUSTER_ROLE_NAME"
		aws iam detach-role-policy --policy-arn arn:aws:iam::aws:policy/AmazonEKSClusterPolicy --role-name "$CLUSTER_ROLE_NAME"
		echo "Deleting cluster role: $CLUSTER_ROLE_NAME"
		aws iam delete-role --role-name "$CLUSTER_ROLE_NAME"
		echo "Cluster role deleted successfully."
	fi

	echo "Cleanup complete."
}

# Trap to ensure cleanup on script exit
trap 'echo "Script interrupted. Cleaning up resources..."; cleanup_resources; exit 1' SIGINT SIGTERM

# Verify AWS CLI configuration
echo "Verifying AWS CLI configuration..."
AWS_ACCOUNT_INFO=$(aws sts get-caller-identity)
check_command "$AWS_ACCOUNT_INFO"
echo "AWS CLI is properly configured."

# Step 1: Create VPC using CloudFormation
echo "Step 1: Creating VPC with CloudFormation..."
echo "Creating CloudFormation stack: $STACK_NAME"

# Create the CloudFormation stack
CF_CREATE_OUTPUT=$(aws cloudformation create-stack \
	--stack-name "$STACK_NAME" \
	--template-url https://s3.us-west-2.amazonaws.com/amazon-eks/cloudformation/2020-10-29/amazon-eks-vpc-private-subnets.yaml \
	--tags Key=project,Value=doc-smith Key=tutorial,Value=eks-gs)
check_command "$CF_CREATE_OUTPUT"
CREATED_RESOURCES+=("CloudFormation Stack: $STACK_NAME")

echo "Waiting for CloudFormation stack to complete (this may take a few minutes)..."
aws cloudformation wait stack-create-complete --stack-name "$STACK_NAME"
if [ $? -ne 0 ]; then
	handle_error "CloudFormation stack creation failed"
fi
echo "CloudFormation stack created successfully."

# Step 2: Create IAM roles for EKS
echo "Step 2: Creating IAM roles for EKS..."

# Create cluster role trust policy
echo "Creating cluster role trust policy..."
cat > eks-cluster-role-trust-policy.json << EOF
{
	"Version":"2012-10-17",
	"Statement": [
		{
			"Effect": "Allow",
			"Principal": {
				"Service": "eks.amazonaws.com"
			},
			"Action": "sts:AssumeRole"
		}
	]
}
EOF

# Create cluster role
echo "Creating cluster IAM role: $CLUSTER_ROLE_NAME"
CLUSTER_ROLE_OUTPUT=$(aws iam create-role \
	--role-name "$CLUSTER_ROLE_NAME" \
	--assume-role-policy-document file://"eks-cluster-role-trust-policy.json")
check_command "$CLUSTER_ROLE_OUTPUT"
aws iam tag-role --role-name "$CLUSTER_ROLE_NAME" \
	--tags Key=project,Value=doc-smith Key=tutorial,Value=eks-gs
CREATED_RESOURCES+=("IAM Role: $CLUSTER_ROLE_NAME")

# Attach policy to cluster role
echo "Attaching EKS cluster policy to role..."
ATTACH_CLUSTER_POLICY_OUTPUT=$(aws iam attach-role-policy \
	--policy-arn arn:aws:iam::aws:policy/AmazonEKSClusterPolicy \
	--role-name "$CLUSTER_ROLE_NAME")
check_command "$ATTACH_CLUSTER_POLICY_OUTPUT"

# Create node role trust policy
echo "Creating node role trust policy..."
cat > node-role-trust-policy.json << EOF
{
	"Version":"2012-10-17",
	"Statement": [
		{
			"Effect": "Allow",
			"Principal": {
				"Service": "ec2.amazonaws.com"
			},
			"Action": "sts:AssumeRole"
		}
	]
}
EOF

# Create node role
echo "Creating node IAM role: $NODE_ROLE_NAME"
NODE_ROLE_OUTPUT=$(aws iam create-role \
	--role-name "$NODE_ROLE_NAME" \
	--assume-role-policy-document file://"node-role-trust-policy.json")
check_command "$NODE_ROLE_OUTPUT"
aws iam tag-role --role-name "$NODE_ROLE_NAME" \
	--tags Key=project,Value=doc-smith Key=tutorial,Value=eks-gs
CREATED_RESOURCES+=("IAM Role: $NODE_ROLE_NAME")

# Attach policies to node role
echo "Attaching EKS node policies to role..."
ATTACH_NODE_POLICY1_OUTPUT=$(aws iam attach-role-policy \
	--policy-arn arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy \
	--role-name "$NODE_ROLE_NAME")
check_command "$ATTACH_NODE_POLICY1_OUTPUT"

ATTACH_NODE_POLICY2_OUTPUT=$(aws iam attach-role-policy \
	--policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly \
	--role-name "$NODE_ROLE_NAME")
check_command "$ATTACH_NODE_POLICY2_OUTPUT"

ATTACH_NODE_POLICY3_OUTPUT=$(aws iam attach-role-policy \
	--policy-arn arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy \
	--role-name "$NODE_ROLE_NAME")
check_command "$ATTACH_NODE_POLICY3_OUTPUT"

# Step 3: Get VPC and subnet information
echo "Step 3: Getting VPC and subnet information..."

VPC_ID=$(aws cloudformation describe-stacks \
	--stack-name "$STACK_NAME" \
	--query "Stacks[0].Outputs[?OutputKey=='VpcId'].OutputValue" \
	--output text)
if [ -z "$VPC_ID" ]; then
	handle_error "Failed to get VPC ID from CloudFormation stack"
fi
echo "VPC ID: $VPC_ID"

SUBNET_IDS=$(aws cloudformation describe-stacks \
	--stack-name "$STACK_NAME" \
	--query "Stacks[0].Outputs[?OutputKey=='SubnetIds'].OutputValue" \
	--output text)
if [ -z "$SUBNET_IDS" ]; then
	handle_error "Failed to get Subnet IDs from CloudFormation stack"
fi
echo "Subnet IDs: $SUBNET_IDS"

SECURITY_GROUP_ID=$(aws cloudformation describe-stacks \
	--stack-name "$STACK_NAME" \
	--query "Stacks[0].Outputs[?OutputKey=='SecurityGroups'].OutputValue" \
	--output text)
if [ -z "$SECURITY_GROUP_ID" ]; then
	handle_error "Failed to get Security Group ID from CloudFormation stack"
fi
echo "Security Group ID: $SECURITY_GROUP_ID"

# Step 4: Create EKS cluster
echo "Step 4: Creating EKS cluster: $CLUSTER_NAME"

CLUSTER_ROLE_ARN=$(aws iam get-role --role-name "$CLUSTER_ROLE_NAME" --query "Role.Arn" --output text)
if [ -z "$CLUSTER_ROLE_ARN" ]; then
	handle_error "Failed to get Cluster Role ARN"
fi

echo "Creating EKS cluster (this will take 10-15 minutes)..."
CREATE_CLUSTER_OUTPUT=$(aws eks create-cluster \
	--name "$CLUSTER_NAME" \
	--role-arn "$CLUSTER_ROLE_ARN" \
	--resources-vpc-config subnetIds="$SUBNET_IDS",securityGroupIds="$SECURITY_GROUP_ID" \
	--tags Key=project,Value=doc-smith,Key=tutorial,Value=eks-gs)
check_command "$CREATE_CLUSTER_OUTPUT"
CREATED_RESOURCES+=("EKS Cluster: $CLUSTER_NAME")

echo "Waiting for EKS cluster to become active (this may take 10-15 minutes)..."
aws eks wait cluster-active --name "$CLUSTER_NAME"
if [ $? -ne 0 ]; then
	handle_error "Cluster creation failed or timed out"
fi
echo "EKS cluster is now active."

# Step 5: Configure kubectl
echo "Step 5: Configuring kubectl to communicate with the cluster..."

# Check if kubectl is installed
if ! check_kubectl; then
	echo "Will skip kubectl configuration steps but continue with the script."
	echo "You can manually configure kubectl later with: aws eks update-kubeconfig --name \"$CLUSTER_NAME\""
else
	UPDATE_KUBECONFIG_OUTPUT=$(aws eks update-kubeconfig --name "$CLUSTER_NAME")
	check_command "$UPDATE_KUBECONFIG_OUTPUT"
	echo "kubectl configured successfully."

	# Test kubectl configuration
	echo "Testing kubectl configuration..."
	KUBECTL_TEST_OUTPUT=$(kubectl get svc 2>&1)
	if [ $? -ne 0 ]; then
		echo "Warning: kubectl configuration test failed. This might be due to permissions or network issues."
		echo "Error details: $KUBECTL_TEST_OUTPUT"
		echo "Continuing with script execution..."
	else
		echo "$KUBECTL_TEST_OUTPUT"
		echo "kubectl configuration test successful."
	fi
fi

# Step 6: Create managed node group
echo "Step 6: Creating managed node group: $NODEGROUP_NAME"

NODE_ROLE_ARN=$(aws iam get-role --role-name "$NODE_ROLE_NAME" --query "Role.Arn" --output text)
if [ -z "$NODE_ROLE_ARN" ]; then
	handle_error "Failed to get Node Role ARN"
fi

# Convert comma-separated subnet IDs to space-separated for the create-nodegroup command
SUBNET_IDS_ARRAY=(${SUBNET_IDS//,/ })

echo "Creating managed node group (this will take 5-10 minutes)..."
CREATE_NODEGROUP_OUTPUT=$(aws eks create-nodegroup \
	--cluster-name "$CLUSTER_NAME" \
	--nodegroup-name "$NODEGROUP_NAME" \
	--node-role "$NODE_ROLE_ARN" \
	--subnets "${SUBNET_IDS_ARRAY[@]}" \
	--tags Key=project,Value=doc-smith,Key=tutorial,Value=eks-gs)
check_command "$CREATE_NODEGROUP_OUTPUT"
CREATED_RESOURCES+=("EKS Node Group: $NODEGROUP_NAME")

echo "Waiting for node group to become active (this may take 5-10 minutes)..."
aws eks wait nodegroup-active --cluster-name "$CLUSTER_NAME" --nodegroup-name "$NODEGROUP_NAME"
if [ $? -ne 0 ]; then
	handle_error "Node group creation failed or timed out"
fi
echo "Node group is now active."

# Step 7: Verify nodes
echo "Step 7: Verifying nodes..."
echo "Waiting for nodes to register with the cluster (this may take a few minutes)..."
sleep 60 # Give nodes more time to register

# Check if kubectl is installed before attempting to use it
if ! check_kubectl; then
	echo "Cannot verify nodes without kubectl. Skipping this step."
	echo "You can manually verify nodes after installing kubectl with: kubectl get nodes"
else
	NODES_OUTPUT=$(kubectl get nodes 2>&1)
	if [ $? -ne 0 ]; then
		echo "Warning: Unable to get nodes. This might be due to permissions or the nodes are still registering."
		echo "Error details: $NODES_OUTPUT"
		echo "Continuing with script execution..."
	else
		echo "$NODES_OUTPUT"
		echo "Nodes verified successfully."
	fi
fi

# Step 8: View resources
echo "Step 8: Viewing cluster resources..."

echo "Cluster information:"
CLUSTER_INFO=$(aws eks describe-cluster --name "$CLUSTER_NAME")
echo "$CLUSTER_INFO"

echo "Node group information:"
NODEGROUP_INFO=$(aws eks describe-nodegroup --cluster-name "$CLUSTER_NAME" --nodegroup-name "$NODEGROUP_NAME")
echo "$NODEGROUP_INFO"

echo "Kubernetes resources:"
if ! check_kubectl; then
	echo "Cannot list Kubernetes resources without kubectl. Skipping this step."
	echo "You can manually list resources after installing kubectl with: kubectl get all --all-namespaces"
else
	KUBE_RESOURCES=$(kubectl get all --all-namespaces 2>&1)
	if [ $? -ne 0 ]; then
		echo "Warning: Unable to get Kubernetes resources. This might be due to permissions."
		echo "Error details: $KUBE_RESOURCES"
		echo "Continuing with script execution..."
	else
		echo "$KUBE_RESOURCES"
	fi
fi

# Display summary of created resources
echo ""
echo "==========================================="
echo "RESOURCES CREATED"
echo "==========================================="
for resource in "${CREATED_RESOURCES[@]}"; do
	echo "- $resource"
done
echo "==========================================="

# Prompt for cleanup
echo ""
echo "==========================================="
echo "CLEANUP CONFIRMATION"
echo "==========================================="
echo "Do you want to clean up all created resources? (y/n): "
read -r CLEANUP_CHOICE

if [[ "${CLEANUP_CHOICE,,}" == "y" ]]; then
	cleanup_resources
else
	echo "Resources will not be cleaned up. You can manually clean them up later."
	echo "To clean up resources, run the following commands:"
	echo "1. Delete node group: aws eks delete-nodegroup --cluster-name $CLUSTER_NAME --nodegroup-name $NODEGROUP_NAME"
	echo "2. Wait for node group deletion: aws eks wait nodegroup-deleted --cluster-name $CLUSTER_NAME --nodegroup-name $NODEGROUP_NAME"
	echo "3. Delete cluster: aws eks delete-cluster --name $CLUSTER_NAME"
	echo "4. Wait for cluster deletion: aws eks wait cluster-deleted --name $CLUSTER_NAME"
	echo "5. Delete CloudFormation stack: aws cloudformation delete-stack --stack-name $STACK_NAME"
	echo "6. Detach and delete IAM roles for the node group and cluster"
fi

echo "Script completed at $(date)"

API 상세는 AWS CLI Command Reference의 다음 항목을 참고해요.

  • AttachRolePolicy, CreateCluster, CreateNodegroup, CreateRole, CreateStack, DeleteCluster, DeleteNodegroup, DeleteRole, DeleteStack, DescribeCluster, DescribeNodegroup, DescribeStacks, DetachRolePolicy, GetCallerIdentity, GetRole, ListNodegroups, UpdateKubeconfig, Wait (CloudFormation), Wait (Amazon EKS)

더 알아보기 (Learn more)