EKS Study 1주차 과제

김호수·2023년 4월 29일
0

EKS Study 1주차 과제 제출을 위한 글입니다. 이번에 Online Study를 통해서 배운 지식들을 실습을 통해서 더욱 공고히 하고 , 제출용으로 사용하기 위해 글 들을 올립니다. 처음 배운 부분들이 다소 있어 , 글들이 매끄럽지 않은 부분이 있을 거라 생각이 됩니다. 이 점 양해 부탁드립니다.

이번 1주차 과제의 주된 내용은 EKS Cluster을 설치입니다. 그래서 아래 서술하는 부분들 대부분 EKS Cluster 설치 관련된 부분이고, 사전준비 작업/설치 과정/사후 확인 등으로 구분을 해서 작성을 할 예정입니다.

설치 전 과정에서 인용되는 Script는 Online Study에서 알려주신 부분을 대부분 이용을 할 예정입니다.

이번 1주차의 서비스 기본 구성은 아래와 같다

EKS Cluster work node on private subnet

  • Data plane을 Private subnet에 구성
  • Cluster API Server의 endpoint를 Private으로 설정

Bastion Host

  • Private subnet에 있는 EKS Cluster의 관리를 위한 외부 접속 Point

관련 AWS Resource
VPC
Secruity Group : Bastion Host와 Control Plane의 SG
AZ : 2개의 AZ
Subnet : Private 2개와 Public Subnet 2개
EC2 : for Bastion Host
Key-Pair : Bastion Host 접속 인증시 사용

배포 방식
EKS Cluster : AWS Web Console, eskctl, Iac 방식이 있으나, 이번에는 eksctl을 통해서 구성

관련 AWS Resource : Cloudformation을 통해 구성, 신속한 설치 및 삭제를 통한 비용 절감 목적

1. 사전 준비 작업

1.1 Key-Pair 생성

Key-Pair만 AWS WEB Console을 통해서 생성
AWS EC2 메뉴 -> 좌측 키 페어 선택 -> 우측 상단 '키페어 생성' 버튼 클릭 후 키 페이서 생성

아래와 같이 aeks_bastion Key 생성

2.설치

2.1 관련 AWS 배포를 위한 Template 파일 준비

아래 yaml 파일은 Online Study에서 제공한 파일에서 Bastion Hoat의 SG 부분만 일부 수정

Yaml 파일 주요 구성은 아래와 같다
AWS::CloudFormation::Interface

  • AWS Console에서 Parameter 값을 입력시 일정한 Group화 하여 보여준게 한다

Parameter(Resource Part에서 참조되는 Parameter 값 들을 정의)

  • ClusterBaseName : EKS Cluster Name
  • KeyName(Key Pair Name)
  • MyInstanceType(Bastion Host Instane Type)
  • LatestAmiId(Bastion Host의 AMI ID 값)
  • TargetRegion(배포 대상의 Reigion)
  • AvailabilityZone1,AvailabilityZone2(대상 Subnet의 AZ)
  • VpcBlock(VPC CIDR 범위 정의)
  • Subnet(Private, Public) 4개 정의

Resource

  • 배포하고자 하는 Resouce 정의, VPC, Subnet , Bastion Host 관련 AWS Resource(EC2, Security Group), IGW

User Data

  • Bastion Host EC2가 기동 시 실행하는 Script
  • 주요 실행 Part는 EKS Cluster 생성 및 관리를 eksctl, kubectl, CLI등이 있다. 여기에 추가적으로 관리 CLI 실행 편리를 위해 관련 환경변수를 profile에 추가 하는 부분이 있다.
AWSTemplateFormatVersion: '2010-09-09'

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: "<<<<< EKSCTL MY EC2 >>>>>"
        Parameters:
          - ClusterBaseName
          - KeyName
#          - SgIngressSshCidr
          - MyInstanceType
          - LatestAmiId
      - Label:
          default: "<<<<< Region AZ >>>>>"
        Parameters:
          - TargetRegion
          - AvailabilityZone1
          - AvailabilityZone2
      - Label:
          default: "<<<<< VPC Subnet >>>>>"
        Parameters:
          - VpcBlock
          - PublicSubnet1Block
          - PublicSubnet2Block
          - PrivateSubnet1Block
          - PrivateSubnet2Block


Parameters:
  ClusterBaseName:
    Type: String
    Default: myeks
    AllowedPattern: "[a-zA-Z][-a-zA-Z0-9]*"
    Description: must be a valid Allowed Pattern '[a-zA-Z][-a-zA-Z0-9]*'
    ConstraintDescription: ClusterBaseName - must be a valid Allowed Pattern

  KeyName:
    Description: Name of an existing EC2 KeyPair to enable SSH access to the instances. Linked to AWS Parameter
    Type: AWS::EC2::KeyPair::KeyName
    ConstraintDescription: must be the name of an existing EC2 KeyPair.

 # SgIngressSshCidr:
 #   Description: The IP address range that can be used to communicate to the EC2 instances
 #   Type: String
 #    MinLength: '9'
 #   MaxLength: '18'
 #   Default: 0.0.0.0/0
 #   AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})
 #   ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x.

  MyInstanceType:
    Description: Enter t2.micro, t2.small, t2.medium, t3.micro, t3.small, t3.medium. Default is t2.micro.
    Type: String
    Default: t3.medium
    AllowedValues:
      - t2.micro
      - t2.small
      - t2.medium
      - t3.micro
      - t3.small
      - t3.medium

  LatestAmiId:
    Description: (DO NOT CHANGE)
    Type: 'AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>'
    Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2'
    AllowedValues:
      - /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2

  TargetRegion:
    Type: String
    Default: ap-northeast-2

  AvailabilityZone1:
    Type: String
    Default: ap-northeast-2a

  AvailabilityZone2:
    Type: String
    Default: ap-northeast-2c

  VpcBlock:
    Type: String
    Default: 192.168.0.0/16

  PublicSubnet1Block:
    Type: String
    Default: 192.168.1.0/24

  PublicSubnet2Block:
    Type: String
    Default: 192.168.2.0/24

  PrivateSubnet1Block:
    Type: String
    Default: 192.168.3.0/24

  PrivateSubnet2Block:
    Type: String
    Default: 192.168.4.0/24

Resources:
# VPC
  EksVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VpcBlock
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Sub ${ClusterBaseName}-VPC

# PublicSubnets
  PublicSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: !Ref AvailabilityZone1
      CidrBlock: !Ref PublicSubnet1Block
      VpcId: !Ref EksVPC
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Sub ${ClusterBaseName}-PublicSubnet1
        - Key: kubernetes.io/role/elb
          Value: 1

  PublicSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: !Ref AvailabilityZone2
      CidrBlock: !Ref PublicSubnet2Block
      VpcId: !Ref EksVPC
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Sub ${ClusterBaseName}-PublicSubnet2
        - Key: kubernetes.io/role/elb
          Value: 1

  InternetGateway:
    Type: AWS::EC2::InternetGateway

  VPCGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      InternetGatewayId: !Ref InternetGateway
      VpcId: !Ref EksVPC

  PublicSubnetRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref EksVPC
      Tags:
        - Key: Name
          Value: !Sub ${ClusterBaseName}-PublicSubnetRouteTable

  PublicSubnetRoute:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PublicSubnetRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway

  PublicSubnet1RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet1
      RouteTableId: !Ref PublicSubnetRouteTable

  PublicSubnet2RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet2
      RouteTableId: !Ref PublicSubnetRouteTable

# PrivateSubnets
  PrivateSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: !Ref AvailabilityZone1
      CidrBlock: !Ref PrivateSubnet1Block
      VpcId: !Ref EksVPC
      Tags:
        - Key: Name
          Value: !Sub ${ClusterBaseName}-PrivateSubnet1
        - Key: kubernetes.io/role/internal-elb
          Value: 1

  PrivateSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: !Ref AvailabilityZone2
      CidrBlock: !Ref PrivateSubnet2Block
      VpcId: !Ref EksVPC
      Tags:
        - Key: Name
          Value: !Sub ${ClusterBaseName}-PrivateSubnet2
        - Key: kubernetes.io/role/internal-elb
          Value: 1

  PrivateSubnetRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref EksVPC
      Tags:
        - Key: Name
          Value: !Sub ${ClusterBaseName}-PrivateSubnetRouteTable

  PrivateSubnet1RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet1
      RouteTableId: !Ref PrivateSubnetRouteTable

  PrivateSubnet2RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet2
      RouteTableId: !Ref PrivateSubnetRouteTable

# EKSCTL-Host
  EKSEC2SG:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: eksctl-host Security Group
      VpcId: !Ref EksVPC
      Tags:
        - Key: Name
          Value: !Sub ${ClusterBaseName}-HOST-SG
      SecurityGroupIngress:
      #- IpProtocol: '-1'
        #FromPort: '22'
        #ToPort: '22'
        #CidrIp: !Ref SgIngressSshCidr
      - IpProtocol: tcp
        FromPort: 22
        ToPort: 22
        CidrIp: 0.0.0.0/0

  EKSEC2:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: !Ref MyInstanceType
      ImageId: !Ref LatestAmiId
      KeyName: !Ref KeyName
      Tags:
        - Key: Name
          Value: !Sub ${ClusterBaseName}-host
      NetworkInterfaces:
        - DeviceIndex: 0
          SubnetId: !Ref PublicSubnet1
          GroupSet:
          - !Ref EKSEC2SG
          AssociatePublicIpAddress: true
          PrivateIpAddress: 192.168.1.100
      BlockDeviceMappings:
        - DeviceName: /dev/xvda
          Ebs:
            VolumeType: gp3
            VolumeSize: 20
            DeleteOnTermination: true
      UserData:
        Fn::Base64:
          !Sub |
            #!/bin/bash
            hostnamectl --static set-hostname "${ClusterBaseName}-host"

            # Config convenience
            echo 'alias vi=vim' >> /etc/profile
            echo "sudo su -" >> /home/ec2-user/.bashrc

            # Change Timezone
            sed -i "s/UTC/Asia\/Seoul/g" /etc/sysconfig/clock
            ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime

            # Install Packages
            cd /root
            yum -y install tree jq git htop lynx

            # Install kubectl & helm
            #curl -O https://s3.us-west-2.amazonaws.com/amazon-eks/1.26.2/2023-03-17/bin/linux/amd64/kubectl
            curl -O https://s3.us-west-2.amazonaws.com/amazon-eks/1.25.7/2023-03-17/bin/linux/amd64/kubectl
            install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
            curl -s https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash

            # Install eksctl
            curl --silent --location "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp
            mv /tmp/eksctl /usr/local/bin

            # Install aws cli v2
            curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
            unzip awscliv2.zip >/dev/null 2>&1
            sudo ./aws/install
            complete -C '/usr/local/bin/aws_completer' aws
            echo 'export AWS_PAGER=""' >>/etc/profile
            export AWS_DEFAULT_REGION=${AWS::Region}
            echo "export AWS_DEFAULT_REGION=$AWS_DEFAULT_REGION" >> /etc/profile

            # Install YAML Highlighter
            wget https://github.com/andreazorzetto/yh/releases/download/v0.4.0/yh-linux-amd64.zip
            unzip yh-linux-amd64.zip
            mv yh /usr/local/bin/

            # Install krew
            curl -LO https://github.com/kubernetes-sigs/krew/releases/download/v0.4.3/krew-linux_amd64.tar.gz
            tar zxvf krew-linux_amd64.tar.gz
            ./krew-linux_amd64 install krew
            export PATH="$PATH:/root/.krew/bin"
            echo 'export PATH="$PATH:/root/.krew/bin"' >> /etc/profile

            # Install kube-ps1
            echo 'source <(kubectl completion bash)' >> /etc/profile
            echo 'alias k=kubectl' >> /etc/profile
            echo 'complete -F __start_kubectl k' >> /etc/profile

            git clone https://github.com/jonmosco/kube-ps1.git /root/kube-ps1
            cat <<"EOT" >> /root/.bash_profile
            source /root/kube-ps1/kube-ps1.sh
            KUBE_PS1_SYMBOL_ENABLE=false
            function get_cluster_short() {
              echo "$1" | cut -d . -f1
            }
            KUBE_PS1_CLUSTER_FUNCTION=get_cluster_short
            KUBE_PS1_SUFFIX=') '
            PS1='$(kube_ps1)'$PS1
            EOT

            # Install krew plugin
            kubectl krew install ctx ns get-all  # ktop df-pv mtail tree

            # Install Docker
            amazon-linux-extras install docker -y
            systemctl start docker && systemctl enable docker

            # CLUSTER_NAME
            export CLUSTER_NAME=${ClusterBaseName}
            echo "export CLUSTER_NAME=$CLUSTER_NAME" >> /etc/profile

            # Create SSH Keypair
            ssh-keygen -t rsa -N "" -f /root/.ssh/id_rsa

Outputs:
  eksctlhost:
    Value: !GetAtt EKSEC2.PublicIp코드를 입력하세요

2.2 AWS Console의 CloudFormation을 통한 Stack 생성

AWS Console의 Cloudformation 를 통해서 AWS Resource 생성

Online Study에서 제공한 Template파일을 Upload

KeyName에서 기 생성한 Key-Pair 값을 선택

3 관련 AWS Resource 배포 결과 확인

WEB Console 확인 과 CLI 명령으로도 일부 확인
WEB Console은 Cloudformation으로 생성한 Stack과 실제 생성된 Resource 비교 확인

3.1 WEB Console 확인 사항

VPC ID 확인

Private Subnet ID 확인

EKS Cluster의 Control Plane SG ID 확인

3.2 CLI 명령으로 확인 사항

Bastion Host에 kubctl, eksctl,AWS CLI 설치 확인

Bastion Host에서 kubectl 명령 사용을 위해 aws configure 명령을 통한 AWS IAM 자격 증명을 실행
IAM User의 권한은 시험을 위한 간단히 administrator으로 설정 , 이 권한의 가지 IAM User의 Access Key ID와 Secret Access Key 값을 이용

4. EKS Cluster 생성

4.1 eksctl 명령으로 통한 EKS Cluster 생성_public API Server End Point

eksctl create cluster --name $CLUSTER_NAME --region=$AWS_DEFAULT_REGION --nodegroup-name=$CLUSTER_NAME-nodeg24 --ssh-access --external-dns-access --verbose 4

아래와 같은 결과가 화면에 출력

지금까지의 실행 결과 아래 3가지 Stack이 생성

EKS와 EC2 -> auto Scaling 그룹을 통해서 현재 생성된 자원을 확인 가능

EKS

EC2 -> auto scaling

CLI on Bastion Host를 통해서 eks 정보 확인

#eks 클러스터 정보 확인
(eks_admin@myeks:N/A) [root@myeks-host ~]# eksctl get nodegroup --cluster $CLUSTER_NAME --name $CLUSTER_NAME-nodegroup

#eks API 접속 
curl -k -s $(aws eks describe-cluster --name $CLUSTER_NAME | jq -r .cluster.endpoint)

#파드 정보 확인
kubectl get pod -A

4.2 Cluster API Server의 End Point를 Public -> Private으로 변경

- 보안 강화를 목적으로 외부(AWS VPC 밖) 에서 접근이 가능했던 API Server의 End Point를 AWS VPC내에서 접근이 가능하도록 변경

bastion host에서 아래 API Server End Point 설정 변경 명령어 실행
aws eks update-cluster-config \
--region ap-northeast-2 \
--name myeks \
--resources-vpc-config endpointPublicAccess=false,endpointPrivateAccess=true

실행 결과는 아래와 같다

이후 kubectl cluster-info와 curl -k -s 명령어가 실행 시 무 응답 상태로 변경

Bastion Host에서 API Server로 접속이 가능하도록 Control Plane의 SG에 Bastion Host Ingress 규칙을 하나 추가

이후 실행시 무 응답이었던 명령어가 실행 결과를 출력

profile
집사양반

0개의 댓글

관련 채용 정보