7 분 소요

이정훈님의 ‘24단계 실습으로 정복하는 쿠버네티스’ 기반으로 작성된 포스팅 입니다. 도서 링크 : 여기

kOps란?

  • kOps는 서버 인스턴스와 네트워크 리소스 등을 클라우드에서 자동으로 생성해 k8s 를 설치 할 수 있는 도구 중 하나입니다. kOps를 사용하면 클라우드 플랫폼(aws, gcp, azure 등)에서 쉽게 k8s 를 설치할 수 있습니다.

  • kOps 특징 자세히 보기: https://kops.sigs.k8s.io/#features

Overall

  • k8s 를 배포할 수 있는 kops 가 설치된 ec2cloudformation 에 의해서 생성됨
  • kopsk8s 클러스터를 생성 : k8s 설정 파일을 s3 에 저장
  • 버전 : k8s v1.24.10, OS Ubuntu 20.04 LTS
  • kops-ec2 역할 : kOps 배포 수행, kubectl 명령 실행 등
  • 마스터 노드와 워커 노드는 EC2 Auto Scaling Group(=ASG) 설정으로 구성됨
  • 도메인은 퍼블릭 도메인을 사용함
  • 퍼블릭 호스팅 메인 주소는 여기 에서 구입할 수 있다. 등록 까지 시간이 조금 걸리니 미리 진행하는 것을 추천한다

AWS kOps 설치

기본 인프라 배포 (방법 1)

  • 링크 ← AWS CloudFormation 페이지로 연결되며, 파라미터 입력 후 스택 실행

  • 인스턴스 접근 시 사용할 keypair 선택
  • SgIngressSshCidr: 접속할 PC IP

기본 인프라 배포 (방법 2)

  • 같은 내용 CLI로 진행하려면

# yaml 파일 다운로드
curl -O https://s3.ap-northeast-2.amazonaws.com/cloudformation.cloudneta.net/K8S/kops-new-ec2.yaml

# 배포
# aws cloudformation deploy --template-file ~/Downloads/kops-new-ec2.yaml --stack-name mykops --parameter-overrides KeyName=<My SSH Keyname> SgIngressSshCidr=<My Home Public IP Address>/32 --region <리전>

예시) aws cloudformation deploy --template-file ~/Downloads/kops-new-ec2.yaml --stack-name mykops --parameter-overrides KeyName=yuran SgIngressSshCidr=$(curl -s ipinfo.io/ip)/32 --region ap-northeast-2

kOps-ec2 접속

# CloudFormation 스택 배포 완료 후 EC2 IP 출력
aws cloudformation describe-stacks --stack-name mykops --query 'Stacks[*].Outputs[*].OutputValue' --output text
예시) 3.35.137.31

# kOps-ec2 에 SSH 접속
예시) ssh -i <My SSH Keyfile> ec2-user@3.35.137.31
ssh -i ~/.ssh/kp-gasida.pem ec2-user@$(aws cloudformation describe-stacks --stack-name mykops --query 'Stacks[*].Outputs[0].OutputValue' --output text)

kOps 클러스터 배포 및 확인

kOps-ec2 에 SSH 로그인 후 아래 실행

기본 툴 및 SSH 키 설치 등 확인

[root@kops-ec2 ~]# kubectl version --client=true -o yaml | yh

clientVersion:
  buildDate: "2023-02-22T13:39:03Z"
  compiler: gc
  gitCommit: fc04e732bb3e7198d2fa44efa5457c7c6f8c0f5b
  gitTreeState: clean
  gitVersion: v1.26.2
  goVersion: go1.19.6
  major: "1"
  minor: "26"
  platform: linux/amd64
kustomizeVersion: v4.5.7

[root@kops-ec2 ~]# kops version
Client version: 1.25.3 (git-v1.25.3)

[root@kops-ec2 ~]# aws --version
aws-cli/2.11.0 Python/3.11.2 Linux/4.14.305-227.531.amzn2.x86_64 exe/x86_64.amzn.2 prompt/off

[root@kops-ec2 ~]# ls /root/.ssh/id_rsa*
/root/.ssh/id_rsa  /root/.ssh/id_rsa.pub

IAM User 자격 구성 : 실습 편리를 위해 administrator 권한을 가진 IAM User 의 자격 증명 입력

[root@kops-ec2 ~]# aws ec2 describe-instances
  • 만약 IAM User가 생성 되지 않았다면, 여기 에서 admin 권한 갖은 IAM 생성 후 csv 파일 다운 받은 후 진행

  • 자격증명 입력

[root@kops-ec2 ~]# aws configure

AWS Access Key ID [None]: AKIA5...
AWS Secret Access Key [None]: CVNa2...
Default region name [None]: ap-northeast-2
Default output format [None]: json

자격 구성 적용 확인 : 노드 IP 확인
aws ec2 describe-instances

aws cli 페이지 출력 옵션

export AWS_PAGER=""
리소스를 배치할 리전이름을 변수 지정
REGION=ap-northeast-2  # 서울 리전 사용

k8s 설정 파일이 저장될 버킷 생성 (있으면 있는거 써도됨)

aws s3 mb s3://버킷<유일한 이름> --region <S3 배포될 AWS 리전>
aws s3 mb s3://버킷<유일한 이름> --region $REGION
aws s3 ls
## 예시)
aws s3 mb s3://gasida-k8s-s3 --region ap-northeast-2

배포 시 참고할 정보를 환경 변수에 저장

퍼블릭 호스팅 메인 주소는 여기 에서 구입할 수 있다. 등록 까지 시간이 조금 걸리니 미리 진행하는 것을 추천한다

## export NAME=<자신의 퍼블릭 호스팅 메인 주소>
## export KOPS_STATE_STORE=s3://(위에서 생성한 자신의 버킷 이름)
export KOPS_CLUSTER_NAME=<자신의 퍼블릭 호스팅 메인 주소>
export KOPS_STATE_STORE=<s3://(위에서 생성한 자신의 버킷 이름)>
export AWS_PAGER=""
export REGION=ap-northeast-2

## 예시)
export AWS_PAGER=""
export REGION=ap-northeast-2
export KOPS_CLUSTER_NAME=**gasida.link**
export KOPS_STATE_STORE=s3://gasida-k8s-s3
echo 'export AWS_PAGER=""' >>~/.bashrc
echo 'export REGION=ap-northeast-2' >>~/.bashrc
echo 'export KOPS_CLUSTER_NAME=gasida.link' >>~/.bashrc
echo 'export KOPS_STATE_STORE=s3://gasida-k8s-s3' >>~/.bashrc

옵션 [터미널1] EC2 생성 모니터링

[root@kops-ec2 ~]# while true; do aws ec2 describe-instances --query "Reservations[*].Instances[*].{PublicIPAdd:PublicIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value,Status:State.Name}" --filters Name=instance-state-name,Values=running --output text ; echo "------------------------------" ; sleep 1; done

kops 설정 파일 생성(s3) 및 k8s 클러스터 배포 : 6분 정도 소요

  • CNI는 aws vpc cni 사용, 마스터 노드 1대(t3.medium), 워커 노드 2대(t3.medium), 파드 사용 네트워크 대역 지정(172.30.0.0/16)

  • container-runtime containerd –kubernetes-version: 1.24.0 ~ 1.25.6

kops create cluster --zones="$REGION"a,"$REGION"c --networking amazonvpc --cloud aws \
--master-size t3.medium --node-size t3.medium --node-count=2 --network-cidr 172.30.0.0/16 \
--ssh-public-key ~/.ssh/id_rsa.pub --name=$KOPS_CLUSTER_NAME --kubernetes-version "1.24.10" --dry-run -o yaml > mykops.yaml

kops create cluster --zones="$REGION"a,"$REGION"c --networking amazonvpc --cloud aws \
--master-size t3.medium --node-size t3.medium --node-count=2 --network-cidr 172.30.0.0/16 \
--ssh-public-key ~/.ssh/id_rsa.pub --name=$KOPS_CLUSTER_NAME --kubernetes-version "1.24.10" -y

# validate
kops validate cluster --wait 10m

완료시 이렇게 마스터 노드 1대(t3.medium), 워커 노드 2대(t3.medium) 생성됨

NODE STATUS
NAME			ROLE	READY
i-0bda4b6485eeac1a4	node	True
i-0de11644f4168ad2a	node	True
i-0f0b4d32ec78557b0	master	True

Your cluster yuran.link is ready

AWS Route53 도메인 정보 확인

# 자신의 도메인 변수 지정 : 소유하고 있는 자신의 도메인을 입력하시면 됩니다
MyDomain=<자신의 도메인>
MyDomain=yuran.link

# 자신의 Route 53 도메인 ID 조회 및 변수 지정
aws route53 list-hosted-zones-by-name --dns-name "${MyDomain}." | jq
aws route53 list-hosted-zones-by-name --dns-name "${MyDomain}." --query "HostedZones[0].Name"
aws route53 list-hosted-zones-by-name --dns-name "${MyDomain}." --query "HostedZones[0].Id" --output text
MyDnzHostedZoneId=`aws route53 list-hosted-zones-by-name --dns-name "${MyDomain}." --query "HostedZones[0].Id" --output text`
echo $MyDnzHostedZoneId

# A 레코드 타입 조회
aws route53 list-resource-record-sets --hosted-zone-id "${MyDnzHostedZoneId}" --query "ResourceRecordSets[?Type == 'A']" | jq
aws route53 list-resource-record-sets --hosted-zone-id "${MyDnzHostedZoneId}" --query "ResourceRecordSets[?Type == 'A'].Name" | jq
aws route53 list-resource-record-sets --hosted-zone-id "${MyDnzHostedZoneId}" --query "ResourceRecordSets[?Type == 'A'].Name" --output text

# A 레코드 값 반복 조회
while true; do aws route53 list-resource-record-sets --hosted-zone-id "${MyDnzHostedZoneId}" --query "ResourceRecordSets[?Type == 'A']" | jq ; date ; echo ; sleep 1; done

설치 확인

노드 IP 확인

aws ec2 describe-instances --query "Reservations[*].Instances[*].{PublicIPAdd:PublicIpAddress,PrivateIPAdd:PrivateIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value,Status:State.Name}" --filters Name=instance-state-name,Values=running --output table

파드 IP 확인

kubectl get pod -n kube-system -o=custom-columns=NAME:.metadata.name,IP:.status.podIP,STATUS:.status.phase

kops 클러스터 정보 확인

[root@kops-ec2 ~]# kops get cluster
NAME		CLOUD	ZONES
yuran.link	aws	ap-northeast-2a,ap-northeast-2c

kops get cluster -o yaml
kops get cluster -o yaml | yh
...

인스턴스그룹 정보 확인

kops get ig

kops get ig -o yaml
kops get ig -o yaml | yh
...

#### 인스턴스 정보 확인
kops get instances
kops get instances -o yaml | yh
...

#### 자동 완성 및 alias 축약 설정
source <(kubectl completion bash)
echo 'source <(kubectl completion bash)' >> ~/.bashrc
echo 'alias k=kubectl' >> ~/.bashrc
echo 'complete -F __start_kubectl k' >> ~/.bashrc
exit
exit

#### 클러스터 정보 확인
kubectl cluster-info
kubectl cluster-info dump


#### 배포 완료 후 정보 확인
tree -L 1 ~/.kube
cat .kube/config
cat .kube/config | yh
  • master node에 SSH 접속 후 확인
# [master node] SSH 접속
ssh -i ~/.ssh/id_rsa ubuntu@api.$KOPS_CLUSTER_NAME

# [master node] EC2 메타데이터 확인 : IAM Role - [링크](https://docs.aws.amazon.com/ko_kr/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html)
TOKEN=`curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"`
echo $TOKEN

curl -s -H "X-aws-ec2-metadata-token: $TOKEN" –v http://169.254.169.254/
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" –v http://169.254.169.254/latest/
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" –v http://169.254.169.254/latest/meta-data/iam/security-credentials/
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" –v http://169.254.169.254/latest/meta-data/iam/security-credentials/masters.yuran.link| jq
  • 워커 노드에 SSH 접속 후 확인 : 워커 노드의 public ip 로 SSH 접속
# 워커 노드 Public IP 확인
aws ec2 describe-instances --query "Reservations[*].Instances[*].{PublicIPAdd:PublicIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value}" --filters Name=instance-state-name,Values=running --output table

# 워커 노드 Public IP 변수 지정
W1PIP=<워커 노드 1 Public IP>
W2PIP=<워커 노드 2 Public IP>
W1PIP=3.35.50.183
W2PIP=54.180.118.11

# 워커 노드 SSH 접속
ssh -i ~/.ssh/id_rsa ubuntu@$W1PIP
exit
ssh -i ~/.ssh/id_rsa ubuntu@$W2PIP
exit



# 워커 노드 SSH 접속 후 node EC2 메타데이터 확인 : IAM Role - [링크](https://docs.aws.amazon.com/ko_kr/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html)
ssh -i ~/.ssh/id_rsa ubuntu@$W1PIP
ssh -i ~/.ssh/id_rsa ubuntu@$W2PIP

TOKEN=`curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"`
echo $TOKEN
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" –v http://169.254.169.254/latest/meta-data/iam/security-credentials/
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" –v http://169.254.169.254/latest/meta-data/iam/security-credentials/nodes.yuran.link | jq

  • kOps 설치 중간에 실패 시 삭제 방법
    1. EC2 Auto Scaling 그룹 : 3개 삭제
    2. EC2 시작 템플릿 Launch Templates : 3개 삭제
    3. S3 버킷 비우기
    4. Route53에 추가된 A 레코드 3개 삭제
    5. CloudFormation 삭제

ExternalDNS : K8S 서비스/인그레스 생성 시 도메인을 설정하면, AWS(Route 53), Azure(DNS), GCP(Cloud DNS) 에 A 레코드(TXT 레코드)로 자동 생성/삭제

##ExternalDNS Addon 설치 - 링크

    # 모니터링
    watch -d kubectl get pod -A
    
    # 정책 생성 -> 마스터/워커노드에 정책 연결
    curl -s -O https://s3.ap-northeast-2.amazonaws.com/cloudformation.cloudneta.net/AKOS/externaldns/externaldns-aws-r53-policy.json
    aws iam create-policy --policy-name AllowExternalDNSUpdates --policy-document file://externaldns-aws-r53-policy.json
    
    # ACCOUNT_ID 변수 지정
    export ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text)
    
    # EC2 instance profiles 에 IAM Policy 추가(attach)
    aws iam attach-role-policy --policy-arn arn:aws:iam::$ACCOUNT_ID:policy/AllowExternalDNSUpdates --role-name masters.$KOPS_CLUSTER_NAME
    aws iam attach-role-policy --policy-arn arn:aws:iam::$ACCOUNT_ID:policy/AllowExternalDNSUpdates --role-name nodes.$KOPS_CLUSTER_NAME
    
    # 설치
    kops edit cluster
    --------------------------
    spec:
      externalDns:
        provider: external-dns
    --------------------------
    
    # 업데이트 적용
    kops update cluster --yes && echo && sleep 3 && kops rolling-update cluster
    
    # externalDns 컨트롤러 파드 확인
    kubectl get pod -n kube-system -l k8s-app=external-dns
    NAME                            READY   STATUS    RESTARTS   AGE
    external-dns-66969c4497-wbs5p   1/1     Running   0          8m53s
    ```
    


CLB에 ExternanDNS 로 도메인 연결

curl -s -O https://raw.githubusercontent.com/gasida/PKOS/main/1/mario.yaml
kubectl apply -f mario
kubectl annotate service mario "external-dns.alpha.kubernetes.io/hostname=mario.$KOPS_CLUSTER_NAME"

####확인

dig +short mario.$KOPS_CLUSTER_NAME
kubectl logs -n kube-system -l k8s-app=external-dns
웹 접속 주소 확인 및 접속
 echo -e "Maria Game URL = http://mario.$KOPS_CLUSTER_NAME"
Maria Game URL = http://mario.yuran.link

image

[root@kops-ec2 ~]# kubectl describe svc mario
Name:                     mario
Namespace:                default
Labels:                   <none>
Annotations:              external-dns.alpha.kubernetes.io/hostname: mario.yuran.link
Selector:                 app=mario
Type:                     LoadBalancer
IP Family Policy:         SingleStack
IP Families:              IPv4
IP:                       100.71.52.109
IPs:                      100.71.52.109
LoadBalancer Ingress:     a7ac657470af04c109d2048f0ccb7dc2-75386274.ap-northeast-2.elb.amazonaws.com
Port:                     <unset>  80/TCP
TargetPort:               8080/TCP
NodePort:                 <unset>  31321/TCP
Endpoints:                172.30.86.217:8080
Session Affinity:         None
  • AWS Route53 A 레코드 확인
  • 실습 완료 후 mario 게임 삭제

업데이트:

댓글남기기