brunch

EKS 4탄-2.데이터베이스,백엔드,프론트-2/17

실습 4탄 = 2/17

by Master Seo

웹 프론트 : html 을 s3 에 저장, Cloudfront로 서비스

백엔드 : ELB통해 서비스, EKS 워커노드에 배포, RDS 접속 , ECR 를 통해 이미지 저장

배치 : EKS , S3 저장된 파일 처리, RDS 에 쓰기 실행



0 service.jpeg


<1> EKS 실습 데이터베이스 설정

<2> 백엔드 구성

<3> EC2에서 소스 빌드한다.

<4> ECR 생성

<5> 로컬 이미지를 ECR에 Push 하기

<6> 백엔드 배포

<7> 데이터베이스를 시크릿에 등록하자

<8> 외부에서 접근가능하게 서비스를 만들어 노출을 해보자

<9> 프런트엔드 빌드

<10> 프런트엔드 배포 - Cloudformation으로 S3버킷 , CloudFront 배포 (5단계-15분 소요)

<11> 삭제

<20> 심화

<30> 다음은 EKS 배치




<1> EKS 실습 데이터베이스 설정


앞에서 Cloudformation을 이용해 Private Subnet 3개 + RDS 를 구축했다.


3 데이터베이스.png


1

vpc1개

Public Subnet 3개

Private Subnet 3개 - Private Subnet에 rds 1개를 구축한다.

시크릿 매니저를 사용한다.



2

eks-work-host ec2에 로그인해서 db관련 내용을 확인한다.

// Secrets Manager에서 admin 암호 확인

수명 주기 동안 보안 암호를 손쉽게 교체, 관리 및 검색



3

DB 관리자 암호 확인 ?

aws secretsmanager list-secrets


AWS콘솔 > AWS Secret Manager의 보안 암호 이름 : RdsMasterSecret , RdsUserSecret 로 검색

보안 암호키 : password로 검색


1 secret key.png


AdminDbPw=`aws secretsmanager get-secret-value --secret-id RdsMasterSecret | jq --raw-output .SecretString | jq -r ."password"`

echo $AdminDbPw

+glH>th4Ds_T?Dp2



4

AWS콘솔 > AWS Secret Manager의 보안 암호 이름 : RdsMasterSecret , RdsUserSecret 로 검색

보안 암호키 : password로 검색


사용자 암호 확인 ?

AppDbPw=`aws secretsmanager get-secret-value --secret-id RdsUserSecret | jq --raw-output .SecretString | jq -r ."password"`

echo $AppDbPw

C:Nbiz)P0eIck~Ql



5

rds 엔드포인트를 변수로 지정 - 스택 이름이 맞아야 한다. eks-work-rds

RDSEP=`aws cloudformation describe-stacks --stack-name eks-work-rds --query 'Stacks[*].Outputs[0].OutputValue' --output text`

echo $RDSEP

eks-work-db.cn5kwtftpfwb.ap-northeast-2.rds.amazonaws.com


// stack name을 rds1 으로 만든경우

RDSEP=`aws cloudformation describe-stacks --stack-name rds1 --query 'Stacks[*].Outputs[0].OutputValue' --output text`

echo $RDSEP



6

postgresql 클라이언트로 mywork 라는 사용자 생성 ?


createuser -d -U eksdbadmin -P -h $RDSEP mywork

Enter password for new role: ( app 암호 )

Enter it again : ( app 암호 )

Password : (admin 암호)


참고 userdata 파일



7

애플리케이션 db 생성

PGPASSWORD=$AppDbPw createdb -U mywork -h $RDSEP -E UTF8 myworkdb



8

접속 확인

PGPASSWORD=$AppDbPw psql -U mywork -h $RDSEP myworkdb


[root@eksctl-host ~]# PGPASSWORD=$AppDbPw psql -U mywork -h $RDSEP myworkdb

psql (11.12)

SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off)

Type "help" for help.


myworkdb=>


나오기

myworkdb=> \q



9

EC2 로그인 / 소스 다운로드


git clone https://github.com/dybooksIT/k8s-aws-book.git



10

예제 실행

테이블 생성

데이터 입력

확인

#


PGPASSWORD=$AppDbPw psql -U mywork -h $RDSEP myworkdb -c '\i k8s-aws-book/backend-app/scripts/10_ddl.sql'


PGPASSWORD=$AppDbPw psql -U mywork -h $RDSEP myworkdb -c '\i k8s-aws-book/backend-app/scripts/20_insert_sample_data.sql'


확인 ?

PGPASSWORD=$AppDbPw psql -U mywork -h $RDSEP myworkdb -c 'SELECT * FROM region;' -c 'SELECT * FROM location;'





<2> 백엔드 구성


1

백엔드 구성 ?

L4 CLB 사용

컨테이너

DB를 불러옴

2 backend.png



2

소스 빌드


EC2 로그인 / 소스 다운로드

git clone https://github.com/dybooksIT/k8s-aws-book.git



3

순서?

EC2에서 소스 빌드한다.

ECR생성

ECR에 Push 한다.

워커 노드의 컨테이너에 배포한다.(디플로이먼트 생성)

서비스 LB 생성해 서비스 한다.

DB는 PostgreSQL 사용



<3> EC2에서 소스 빌드한다.


EC2에서 소스 빌드한다.

// 아래 하나는 설치해줘야 한다.

yum install java-11-amazon-corretto -y


cd $HOME/k8s-aws-book/backend-app/

./gradlew clean build


(10분 걸림)


gradle wrapper 줄여서 gradlew 는

새로운 환경에서 프로젝트를 설정할 때 java나 gradle을 설치하지 않고 바로 빌드할 수 있게 해주는 역할을 한다.



4

컨테이너 이미지 생성 (참고)

Corretto는 Amazon의 장기적인 지원을 받는 OpenJDK(Open Java Development Kit) 바이너리 배포판

https://hub.docker.com/_/amazoncorretto



5

이미지 생성을 위해 도커 허브 ID가 있어야 한다.

도커 허브 id

MyID=masterseo11

echo $MyID



6

도커 이미지 로컬 생성

// 도커가 설치되어 있어야 한다.

docker build -t $MyID/backend-app:1.0.0 --build-arg JAR_FILE=build/libs/backend-app-1.0.0.jar .


7

docker images

REPOSITORY TAG IMAGE ID CREATED SIZE

masterseo11/backend-app 1.0.0 8aafddccff56 About a minute ago 749MB

amazoncorretto 11 2b27f3c83c92 2 weeks ago 445MB



8

docker login

Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.

Username: masterseo11

Password: g102!



9

docker push $MyID/backend-app:1.0.0



10

docker images

REPOSITORY TAG IMAGE ID CREATED SIZE

masterseo11/backend-app 1.0.0 8aafddccff56 13 minutes ago 749MB

amazoncorretto 11 2b27f3c83c92 2 weeks ago 445MB



9

amazoncorretto:11 에 들어가 확인 (선택)

docker run -it amazoncorretto:11 /bin/bash

java -version

javac -version

exit



<4> ECR 생성


1

account id 확인

ACCOUNT_ID=`aws sts get-caller-identity --query 'Account' --output text`

echo $ACCOUNT_ID



2

로그인 인증

aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin $ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com


WARNING! Your password will be stored unencrypted in /root/.docker/config.json.

Configure a credential helper to remove this warning. See

https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded



[root@eksctl-host ~]# cat /root/.docker/config.json

{

"auths": {

"451032684083.dkr.ecr.ap-northeast-2.amazonaws.com": {




3

레파지토리 생성

k8sbook/backend-app 이름으로 만듬

aws ecr create-repository --repository-name k8sbook/backend-app --image-scanning-configuration scanOnPush=true --region $AWS_REGION



4

ecr 확인

aws ecr describe-repositories




<5> 로컬 이미지를 ECR에 Push 하기


1

ECR에 Push 하기위해 컨테이너 이미지에 태그 설정

직접 빌드의 경우

docker tag $MyID/backend-app:1.0.0 $ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/k8sbook/backend-app:1.0.0



2

태그 확인

docker images

REPOSITORY TAG IMAGE ID CREATED SIZE

.ecr.ap-northeast-2.amazonaws.com/k8sbook/backend-app 1.0.0 8aafddccff56 17 749MB

masterseo11/backend-app 1.0.0 8aafddccff56 17 minutes ago 749MB

amazoncorretto 11 2b27f3c83c92 2 weeks ago 445MB



3

컨테이너 이미지 push 하기

ecr로 push

docker push $ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/k8sbook/backend-app:1.0.0



4

확인

aws ecr list-images --repository-name k8sbook/backend-app --output text

IMAGEIDS sha256:11c2e580127314f8


aws ecr describe-images --repository-name k8sbook/backend-app



5

AWS 콘솔에서 ECR 가서 확인

k8sbook/backend-app






<6> 백엔드 배포


1

순서?

네임스페이스 생성과 변경

kubeconfig 네임스페이스 반영

db 시크릿 등록

애플리케이션 배포

애플리케이션 외부 공개


2 backend.png


2

터미널 2에서 모니터링

watch -d 'kubectl get deploy,pods,svc,ep -o wide'



3

kubeconfig 설정?

eksctl은 클러스터 구축중에 kubeconfig 파일을 자동 업데이트 한다.

eksctl이 이용할 설정파일

접속 정보를 저장 한다. 컨트롤 플레인 URL , 인증정보 , 네임스페이스등



4

네임스페이스 확인, 생성, 변경


슬라이드2.JPG


5

네임스페이스 확인

kubens

default

kube-node-lease

kube-public

kube-system



6

생성

kubectl create namespace eks-work

kubens



7

변경

kubens eks-work

[root@eksctl-host backend-app]# kubens eks-work

Context "i-05cb09ed85ec0b51c@first-eks.ap-northeast-2.eksctl.io" modified.

Active namespace is "eks-work".


kubens

default

eks-work

kube-node-lease

kube-public

kube-system

[root@eksctl-host backend-app]#




<7> 데이터베이스를 시크릿에 등록하자


1

RDSEP=`aws cloudformation describe-stacks --stack-name eks-work-rds --query 'Stacks[*].Outputs[0].OutputValue' --output text` AppDbPw=`aws secretsmanager get-secret-value --secret-id RdsUserSecret | jq --raw-output .SecretString | jq -r ."password"`


echo $RDSEP


echo $AppDbPw


eks-work-db.cu95crn7o6gd.ap-northeast-2.rds.amazonaws.com

~Raj(;7NRh8e.=sW



2

DB 접속용 시크릿 등록

envsubst 명령어는?

yaml 파일에서 환경 변수 대체해주는 역할을 한다.


21_db_config_k8s.yaml 파일

apiVersion: v1

kind: Secret

type: Opaque

metadata:

name: db-config

stringData:

db-url: ${DB_URL}

db-username: mywork

db-password: ${DB_PASSWORD}



cd $HOME


DB_URL=jdbc:postgresql://$RDSEP/myworkdb DB_PASSWORD=$AppDbPw envsubst < $HOME/k8s-aws-book/eks-env/21_db_config_k8s.yaml.template | kubectl apply -f -

secret/db-config created



3

kubectl get secret db-config

NAME TYPE DATA AGE

db-config Opaque 3 13s



kubectl get secret db-config -o yaml

apiVersion: v1

data:

db-password: QzpO



4

변수 확인

ACCOUNT_ID=`aws sts get-caller-identity --query 'Account' --output text`

echo $ACCOUNT_ID



5

배포

cd $HOME


ECR_HOST=$ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com envsubst < $HOME/k8s-aws-book/eks-env/22_deployment_backend-app_k8s.yaml.template | kubectl apply -f -

deployment.apps/backend-app created



6

kubectl get all

pod 2개가 보임

0/1 -> 1/1 변경됨.


kubectl get pod -o wide

watch -d kubectl get pod -o wide




7

디플로이먼트라 스케일 조정해 확인 가능하다.


kubectl scale deployment backend-app --replicas=5

kubectl scale deployment backend-app --replicas=24

kubectl scale deployment backend-app --replicas=0




<8> 외부에서 접근가능하게 서비스를 만들어 노출을 해보자


1

서비스 생성하자.

ELB 포트 8080

노드 포트 32760

파드포트 8080


CLB 8080으로 접속하면 내부 Pod 에 접속하는 과정이다.



2

서비스 생성


cat <<EOF | kubectl create -f -

apiVersion: v1

kind: Service

metadata:

name: backend-app-service

spec:

type: LoadBalancer

selector:

app: backend-app

ports:

- protocol: TCP

port: 8080

targetPort: 8080

EOF



첨부



3

kubectl get svc

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE

backend-app-service LoadBalancer 10.100.11.107 a834b556bb8b449c0a0d1fa0e8cf8952-863335935.ap-northeast-2.elb.amazonaws.com 8080:32758/TCP 26s

ab300c3df4812423584faf50caa6a5d7-693573332.ap-northeast-2.elb.amazonaws.com



4

LB 도메인 접속 주소 확인 ?

APIEXIP=`kubectl get svc backend-app-service -o jsonpath='{.status.loadBalancer.ingress[*].hostname}'`

echo $APIEXIP



5

AWS 웹 콘솔 > ELB 가면 LB가 만들어져 있다.


curl -s http://$APIEXIP:8080/health

{"status":"OK"}


웹브라우저로 접속

xxxxxxxxxxxxxxxxxxxxx.ap-northeast-1.elb.amazonaws.com:8080/health



6

while true; do curl -s http://$APIEXIP:8080/health; echo; date "+%Y-%m-%d %H:%M:%S"; sleep 1; done

{"status":"OK"}

2021-08-23 18:06:38

{"status":"OK"}

2021-08-23 18:06:39



7

pod log 확인

kubectl logs -l app=backend-app -f --max-log-requests 8

2021-08-23 18:04:39.029 [http-nio-8080-exec-7] INFO k.s.presentation.api.HealthApi - Health GET API called.

2021-08-23 18:05:09.029 [http-nio-8080-exec-10] INFO k.s.presentation.api.HealthApi - Health GET API called.



8

콘솔에서 LB 확인



9

서비스 확인

kubectl get svc backend-app-service -o jsonpath='{.status}'

{"loadBalancer":{"ingress":[{"hostname":"ab300c3df4812423584faf50caa6a5d7-693573332.ap-northeast-2.elb.amazonaws.com"}]}}[



10

APIEXIP=`kubectl get svc backend-app-service -o jsonpath='{.status.loadBalancer.ingress[*].hostname}'`

echo $APIEXIP




<9> 프론트엔드 빌드



1

순서?

EC2에서 소스 빌드

S3버킷 생성

S3에 소스 업로드

CloudFront를 통해 확인


4 front.png



2


yum install -y gcc-c++ make

curl -sL https://rpm.nodesource.com/setup_14.x | sudo -E bash -

yum install -y nodejs



라이블러리 다운로드

cd $HOME/k8s-aws-book/frontend-app/

npm install


업데이트

npm audit fix



3

빌드하기 위해 LB 다시 확인한다.

APIEXIP=`kubectl get svc backend-app-service -o jsonpath='{.status.loadBalancer.ingress[*].hostname}'`

echo $APIEXIP



4

빌드 실행

BASE_URL=http://$APIEXIP:8080 npm run build


N





<10> 프런트엔드 배포 - Cloudformation으로 S3버킷 , CloudFront 배포 (5단계-15분 소요)



순서?

프런트엔드는 S3로 만든다.

EC2와 Sync시켜 홈페이지를 유지한다.

S3를 오리진으로하는 CDN을 연결시켜 서비스한다.



1

// 버킷 이름은 유일해야 한다. s3 이름을 본인 이름으로 해라.

S3suffix=masterseo0923

echo $S3suffix



2

Cloudformation으로 S3버킷 , CloudFront 배포 (15분 소요) (서울 리전 사용시)


aws cloudformation deploy --template-file $HOME/k8s-aws-book/eks-env/30_s3_cloudfront_cfn.yaml --stack-name eks-work-frontend --parameter-overrides BucketSuffix=$S3suffix


// 만들다 실패한 경우는 콘솔에서 Cloudformation 스택을 삭제하고 다시 만들자.

기존 실패 스택이 있으면 아래 처럼 오류가 난다.

An error occurred (ValidationError) when calling the CreateChangeSet operation: Stack:arn:aws:cloudformation:ap-northeast-2:451032684083:stack/eks-work-frontend/24da1110-03f3-11ec-97bd-0a6a7510121c is in ROLLBACK_COMPLETE state and can not be updated.


echo $S3suffix



3

# CloudFormation 으로 S3 CloudFront 배포 (도쿄 리전 사용 시)

sed -i 's/ap-northeast-2/ap-northeast-1/g' $HOME/k8s-aws-book/eks-env/30_s3_cloudfront_cfn.yaml


aws cloudformation deploy --template-file $HOME/k8s-aws-book/eks-env/30_s3_cloudfront_cfn.yaml --stack-name eks-work-frontend --parameter-overrides BucketSuffix=$S3suffix



4

# CloudFormation 으로 S3 CloudFront 배포 (싱가포르 리전 사용 시)

sed -i 's/ap-northeast-2/ap-southeast-1/g' $HOME/k8s-aws-book/eks-env/30_s3_cloudfront_cfn.yaml


aws cloudformation deploy --template-file $HOME/k8s-aws-book/eks-env/30_s3_cloudfront_cfn.yaml --stack-name eks-work-frontend --parameter-overrides BucketSuffix=$S3suffix



5

S3 버킷 확인

aws s3 ls

2021-08-23 18:28:36 eks-work-frontend-masterseo08231



6

s3와 동기화

aws s3 sync $HOME/k8s-aws-book/frontend-app/dist s3://eks-work-frontend-$S3suffix --delete --include "*" --acl public-read



7

업로드 확인

aws s3 ls s3://eks-work-frontend-$S3suffix --recursive

2021-08-23 18:34:06 3017 200.html



8

서비스 동작 ?

사용자가 CloudFront 접속해 사용, S3가 원본

LB > 컨테이너 > PostgreSQL DB에서 정보 가져옴



9

cloudfront 확인


aws cloudformation describe-stacks --stack-name eks-work-frontend --query 'Stacks[*].Outputs[1].OutputValue' --output text


http://d3fop4nghz24dz.cloudfront.net




10

웹 브라우저로 접속



참고

https://brunch.co.kr/@topasvga/746





<11> 삭제 순서



db , cloudfront , s3 삭제 한다.

cloud formation 스택 삭제 한다.



1

kubectl delete deploy,svc,cronjob --all



2

DB 삭제

aws cloudformation delete-stack --stack-name eks-work-rds


3

프론트 삭제

aws cloudformation delete-stack --stack-name eks-work-frontend



4

클러스터 삭제 (10분)

eksctl delete cluster --name $CLUSTER_NAME



5

s3 삭제

aws s3 rm s3://eks-work-frontend-$S3suffix --recursive

aws s3 rm s3://eks-work-batch-$S3suffix --recursive


6

배치 삭제

aws cloudformation delete-stack --stack-name eks-work-batch



7

ecr 삭제

aws ecr delete-repository --repository-name k8sbook/backend-app --force

aws ecr delete-repository --repository-name k8sbook/batch-app --force



8

콘솔에서 로드 밸런서 삭제



9

스택 삭제

1번째 생성한 EC2 와 Public Subnet

aws cloudformation delete-stack --stack-name eks-work-base



10

Cloudformation 콘솔에서 스택 삭제

삭제 불가 이유 확인

리소스 삭제후 스택 삭제





<20> 심화


1

aws-node 파드에 매핑된 AWS IAM Role(AmazonEKS_CNI_Policy 정책)을 사용


role/eksctl-first-eks-addon-iamserviceaccount-kub-Role1-G

AmazonEKS_CNI_Policy


{

"Version": "2012-10-17",

"Statement": [

{

"Effect": "Allow",

"Action": [

"ec2:AssignPrivateIpAddresses",

"ec2:AttachNetworkInterface",

"ec2:CreateNetworkInterface",

"ec2:DeleteNetworkInterface",

"ec2:DescribeInstances",

"ec2:DescribeTags",

"ec2:DescribeNetworkInterfaces",

"ec2:DescribeInstanceTypes",

"ec2:DetachNetworkInterface",

"ec2:ModifyNetworkInterfaceAttribute",

"ec2:UnassignPrivateIpAddresses"

],

"Resource": "*"

},

{

"Effect": "Allow",

"Action": [

"ec2:CreateTags"

],

"Resource": [

"arn:aws:ec2:*:*:network-interface/*"

]

}

]





<30> 다음은 EKS 배치


https://brunch.co.kr/@topasvga/1819



감사합니다.

keyword
매거진의 이전글EKS 4탄-1. EKS 클러스터 생성-1/17