brunch

You can make anything
by writing

C.S.Lewis

by Master Seo Aug 23. 2021

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

실습 4탄 =  2/17

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

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

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




<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 를 구축했다.

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



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로 검색



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

소스 빌드


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

터미널 2에서 모니터링

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



3

kubeconfig  설정?

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

eksctl이 이용할 설정파일

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



4

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



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를 통해 확인




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



감사합니다.

매거진의 이전글 EKS 4탄-1. EKS 클러스터 생성-2021
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari