본문 바로가기
Tech/Kubernetes

[PKOS_2기] 1주차 (kOps on AWS, ExternalDNS)

by 구름_쟁이 2023. 3. 6.

본 시리즈는 가시다님의 PKOS(Production Kubernetes Online Study) 2기 진행 내용입니다.

스터디에 사용된 서적은 이정훈님의 24단계 실습으로 정복하는 쿠버네티스 입니다.

도서 링크 : http://www.yes24.com/Product/Goods/115187666

 


kOps란?

프로덕션 수준의 쿠버네티스 클러스터를 구축하고 운영하기 위한 툴이라고 설명되어 있다.

그 전에 이미 많이들 알고있는 kubeadm, kubespray와는 어떤 부분이 다른지, 얼마나 편리하고 Cloud환경에 유효하게 배포되는지 살펴본다.

 


사전 준비
  • AWS 실습 계정
  • AWS의 도메인 서비스인 Route53로 도메인 구매
    • 혹은 도메인 구매 후 NameServer를 Route53에 위임

 

실습 구성도
  • Cloudformation을 통해 kops-ec2 vm 배포와 kops 실행에 필요한 기본적인 프로비저닝 진행
  • kops로 k8s 클러스터 생성 시 S3에 k8s 설정 파일 저장
  • Master Node와 Worker Node는 EC2 Auto Scaling Group(ASG)로 구성됨
  • 퍼블릭 도메인(Route53) 사용

 

1주차에서 진행할 2가지

1. kOps를 AWS 환경에서 배포 (kOps on AWS)

2. ExternalDNS를 활용하여 애플리케이션 배포

 

kOps on AWS 진행 순서
  1. CloudFormation으로 kops-ec2 배포
  2. awscli configuration
  3. S3 배포
  4. kops cluster 배포
  5. kops 배포 확인

 

 

 


 

kOps on AWS

1. CloudFormation으로 kops-ec2 배포

[AWS Console] 에서 CloudFormation으로 kops-ec2 배포
https://console.aws.amazon.com/cloudformation/home?region=ap-northeast-2#/stacks/new?stackName=mykops&templateURL=https:%2F%2Fs3.ap-northeast-2.amazonaws.com%2Fcloudformation.cloudneta.net%2FK8S%2Fkops-new-ec2.yaml

 

KeyName은 기존에 생성해둔 key 선택 / SgIngressSshCidr는 접속지의 공용 IP 입력

 

[코드]로 CloudFormation kops-ec2 배포
# 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 netcloudyops --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 netcloudyops --parameter-overrides KeyName=kp-gasida SgIngressSshCidr=$(curl -s ipinfo.io/ip)/32 --region ap-northeast-2

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

2. awscli configuration

  • 사전에 IAM 유저 생성해두면 편리함(별도 IAM 사용자를 만들어야 하는 이유는 보안 강화의 목적)
    • 편의를 위해 AdministratorAccess 권한 부여

IAM - 사용자 추가
사용자 이름 지정 후 다음
편의를 위해 AdministratorAccess 정책 부여
생성된 pkos 사용자 - 보안 자격 증명 - 액세스 키 만들기

 

CLI 선택
※ 액세스 키, 비밀 액세스 키 복사

다시 kops-ec2로 돌아와서

aws configure

AWS Access Key ID [None]: <액세스 키>
AWS Secret Access Key [None]: <비밀 액세스 키>
Default region name [None]: ap-northeast-2
Default output format [None]: json

3. S3 배포

S3를 생성하지 않은 경우에만 진행

kops-ec2에서 진행

REGION=ap-northeast-2

# netcloudy-s3 부분은 전세계적으로 고유한 문자여야 함
aws s3 mb s3://netcloudy-s3 --region $REGION

# S3 배포 확인
aws s3 ls

# KOPS_CLUSTER_NAME = Route53으로 구매한 도메인
# KOPS_STATE_STORE = 고유한 자신의 S3 주소

export KOPS_CLUSTER_NAME=netcloudy.im
export KOPS_STATE_STORE=s3://netcloudy-s3
export AWS_PAGER=""
export REGION=ap-northeast-2

echo 'export AWS_PAGER=""' >>~/.bashrc
echo 'export REGION=ap-northeast-2' >>~/.bashrc
echo 'export KOPS_CLUSTER_NAME=netcloudy.im' >>~/.bashrc
echo 'export KOPS_STATE_STORE=s3://netcloudy-s3' >>~/.bashrc

 

4. kops cluster 배포

 

# 쿠버네티스 클러스터용 Master Node, Worker Node VM 배포 상태 확인 (모니터링 탭)
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)

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

 

대략 6분이 지난 후 완료가 되면 아래 진행

5. kops 배포 확인

# 노드 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 클러스터 정보 확인
kops get cluster

# kubectl 명령 자동 완성 및 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
kops-ec2에서 Master Node 에 명령하는 방법은?
# [master node] iptable rule 확인
ssh -i ~/.ssh/id_rsa ubuntu@api.$KOPS_CLUSTER_NAME sudo iptables -t nat -S

# [master node] 컨테이너 정보 확인
ssh -i ~/.ssh/id_rsa ubuntu@api.$KOPS_CLUSTER_NAME ps axf |grep /usr/bin/containerd
ssh -i ~/.ssh/id_rsa ubuntu@api.$KOPS_CLUSTER_NAME ps afxuwww

 

 

 

ExternalDNS
  1. test 앱 배포
  2. 자동생성 도메인으로 접속
  3. ExternalDNS 설정
  4. 구매한 도메인과 연동하여 접속

 

ExternalDNS 설명

https://edgehog.blog/a-self-hosted-external-dns-resolver-for-kubernetes-111a27d6fc2c

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

 

 

 

1. test 앱 배포

# 수퍼마리오 디플로이먼트 배포
curl -s -O https://raw.githubusercontent.com/gasida/PKOS/main/1/mario.yaml
kubectl apply -f mario.yaml
cat mario.yaml | yh

# 배포 확인 : CLB 배포 확인 >> 5분 이상 소요
kubectl get deploy,svc,ep mario
watch kubectl get svc mario

# 마리오 게임 접속 : CLB 주소로 웹 접속
kubectl get svc mario -o jsonpath={.status.loadBalancer.ingress[0].hostname} | awk '{ print "Maria URL = http://"$1 }'

2. 자동생성 도메인으로 접속

 

자동 생성된 External-IP를 통해 접속


 

3. ExternalDNS 설정

 

아직 우리 Master Node와 Worker Node는 ExternalDNSUpdate 할 권한을 가지고 있지 않다.

따라서, ExternalDNSUpdate할 수 있는 정책을 추가하고 할당해주어야 한다.

# 정책 생성 -> 마스터/워커노드에 정책 연결
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 클러스터 설정 역시 변경해준다.

# kops 클러스터 설정 변경
kops edit cluster
--------------------------
spec:
  certManager:
    enabled: true
  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-*********-******   1/1     Running   0          8m53s

4. 구매한 도메인과 연동하여 접속

이제 Master Node와 Worker Node에게 권한도 주었고, kops 클러스터 설정도 변경했으니 구매한 도메인과 앱의 service를 연동해보자.

# CLB에 ExternanDNS 로 도메인 연결
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"

# 도메인 체크
echo -e "My Domain Checker = https://www.whatsmydns.net/#A/mario.$KOPS_CLUSTER_NAME"

 

test 앱 삭제

kubectl delete deploy,svc mario

service annotate 혹은 service delete 후 external-dns의 로그를 살펴보면 정상적으로 동작하는지 확인할 수 있다.

mario service 삭제 후 external-dns 로그

 

 

 

추가

위 test 앱과 같은 방식으로 Wordpress와 같은 블로그도 배포하고 연동할 수 있다.
도메인이 안나오게 캡쳐해서 아쉽지만...
예시)

 

마치며
블로그에 아직 익숙치 않지만, 이번 스터디를 계기로 꾸준히 관리해보자.
물론 이 글도 단순 과제를 넘어 지식 저장고가 되기를.

댓글