의존성 용량에 대해서는 큰 차이는 없지만, 엄격하게 생각한다면 AWS-SDK를 사용하는 것 보다는 SMTP를 사용하는 방법이 컴파일 하는 시간을 단축시킬 수 있을 것이다.
3. Hands On Lab
SES를 처음 이용하게 되면 SES Sandbox가 설정되어 있다. Sandbox가 설정이 되어있으면, 다음과 같은 제약사항이 따른다.
1. 하루 보낼 수 있는 제한이 200개로 제한
2. 초당 발송 이메일 1개
3. 등록된 이메일로만 이메일 전송 가능
Sandbox를 해제하기 위해서는 AWS Support Center에 case를 open하여 sandbox를 해제하여야 한다.
자세한 절차는 직접 콘솔에 들어가서 확인 후, 가이드에 따라서 절차를 진행하는 것을 권장한다.
먼저, 다음과 같이 SES console에서 이메일을 등록하고, 이메일 인증을 거쳐야 Amazon SES를 이용가능하다.
이메일 인증 절차를 진행하게 되면, 등록한 이메일 주소로 다음과 같은 메일이 발송된다. 메일에 첨부된 verification request link에 대해 http request를 보내면 최종적으로
SES console의 email verification status가 verified로 바뀐다. 이제 등록한 이메일을 사용할 수 있게 되었다.
SMTP를 이용하기 위해서는 별도의 IAM Credential이 필요하다. 다음 화면에서 발급 절차를 진행한 후, 발급된 credential를 잘 보관하길 바란다.
download한 credential정보와 Amazon SES SMTP Server Specification을 다음과 같이 spring boot의 application.properties에 기입한다.
#SES Credentials
aws.ses.username=<YOUR_SMS_CREDENTIAL_USERNAME>
aws.ses.password=<YOUR_SMS_CREDENTIAL_PASSWORD>
#Amazon SES SMTP Server Info
aws.ses.host=email-smtp.ap-south-1.amazonaws.com
aws.ses.port=587
일반적인 리눅스 터미널에서 awscli를 설치하였을 때, 보통은 제대로 작동하지만, git bash는 윈도우 상에서 리눅스 시스템을 사용하도록 에뮬레이터로 “흉내” 낸 것이기 때문에 경로가 잘 매칭 되지 않는 문제가 빈번히 일어난다. 그 결과로 다음과 같이 제대로 명령어가 작동하지 않는 경우가 종종 일어난다.
리눅스 환경에서도 경로 해석이 잘못 될 경우, 일어나는 에러이다.
위 문제를 해결하기 위하여 가장 먼저 awscli가 어떤 언어 기반으로 실행되는지 찾아보았다. 공식 aws github를 찾아본 결과, python을 사용하는 것을 알 수 있었다.
Python기반으로 실행되는 스크립트 임을 알게 되었으니, 이제 실행파일이 어디 있는지 확인해보았다. 일반적으로 pip uninstall 명령어를 사용하면 다음과 같이 패키지가 설치 된 경로를 출력한다.
awscli를 사용할 때 마다 위 경로를 계속하여 타이핑 하는 것은 매우 비효율적이므로 위 경로의 스크립트를 python으로 실행시키는 것을 “aws“명령어로 alias시켜 사용하기로 결정하였다. alias를 등록하기 위해서 사용자 root 디렉토리 경로에서 ./bashrc파일을 생성하였다.
vi ~/.bashrc
//vi editor 상으로 aws script가 있는 경로에 있는 파일을 python으로 실행시키는 코드를 입력한다.
alias aws='python "c:\users\it1903004\appdata\roaming\python\python37\scripts\aws"'
//입력 후 :wq로 저장한다.
source ./bashrc
//source 명령어로 ./bashrc 파일을 시스템 상에 적용한다.
다음과 같은 절차를 거치게 되면 최종적으로 시스템 상에서 aws명령어를 정상적으로 사용할 수 있게 된다.
자주 사용하는 AWS Resource에 대해 조사하는 도중 홈페이지에 기술된 EC2 Default Limit과 AWS Service Quota의 내용이 상이하였습니다. 이에 대한 자료가 없어 상이한 내용에 대한 캡처본과 함께 AWS Support Center에 Case Open을 하였습니다.
상이한 내용은 다음과 같습니다.
AWS 공식 홈페이지의 EC2 Default Limit
AWS Service Quota에서의 EC2 Default Limit (개인 실습 계정 현황)
2. case 답변 본문
답변의 본문은 다음과 같습니다.
Hello,
I would like to thank you for your patience while we waited for the EC2 Service Team to get back to me.
When they were reviewing your questions as well as the screenshots provided, they have informed me of the following:
There is a slight difference between the new change vCPU's and the old from EC2 classic platform. The difference is that vCPUs uses a quota that allows you to lunch resources dependant on what is the factor as per the documentation below:
Example if your quota is 1,308 you can launch 1,308 t2.micro instances and/or 654 t2.nano's with 654 t2.mirco's.
The previous quota limits were based on what is provisioned to your account, which means if the limit was 5 for t2.micro you would only be able to lunch 5 t2.micro's and nothing else.
Also the reason why your default limits differ from the documentation is due to account specific information such as when your AWS Account was created, billing history and utilization of the account. The documentation was based on an average of all our customers.
Should you at any time have any additional questions or concerns in this regard, please do let us know by responding back to this case. I wish you a wonderful day further!
3. 정리 및 결론
위 본문을 정리하면 다음 두문장으로 설명이 가능합니다.
공식 홈페이지 EC2 Default Limit : AWS 전체 사용자가 사용하고 있는 자원에 대에 대해 프로비저닝 된 Limit.
AWS Service Quota Default Limit : 계정의 생성날자, 지불 이력, 자원 사용 이력 등에 따라 프로비저닝 된 한도.
즉, 모든 계정은 새로 만들게 되면 지불 이력과 자원 사용 이력이 없기 때문에 default Limit을 매우 낮게 잡습니다. 그러나 사용이력이 생기면 이를 AWS에서 프로비저닝 하여 새로운 Limit을 적용합니다. 이에 대해 실제로 적용이 되는지 주변에서 Service Quota 현황을 동의를 구하고 수집하였습니다.
t2.micro를 5회 미만 생성한 계정의 Service Quota 현황
t2.medium을 10회 이상 생성한 계정의 Service Quota 현황
프리티어를 한도 내에서 다양한 실험을 한 계정의 Service Quota 현황
위 경우와 같이 한도 증가 신청을 하지 않고도 자동으로 프로비저닝 되어 할당된 한도가 증가하는 것을 확인 할 수 있었습니다.
The official CLI for Amazon EKS
Usage: eksctl [command] [flags]
Commands:
eksctl create Create resource(s)
eksctl get Get resource(s)
eksctl update Update resource(s)
eksctl delete Delete resource(s)
eksctl scale Scale resources(s)
eksctl drain Drain resource(s)
eksctl utils Various utils
eksctl completion Generates shell completion scripts
eksctl version Output the version of eksctl
eksctl help Help about any command
Common flags:
-C, --color string toggle colorized logs (valid options: true, false, fabulous) (default "true")
-h, --help help for this command
-v, --verbose int set log level, use 0 to silence, 4 for debugging and 5 for debugging with AWS debug logging (default 3)
Use 'eksctl [command] --help' for more information about a command.
이제 클러스터를 구성할 것이다. 다음 명령어를 입력하여 node가 3개고, alb ingress filter(alb를 쿠버네티스 상에서 프로비저닝하는 역할)가 적용된 application load balancer가 포함된 vpc로 구성된 eksworkshop 클러스터를 구성한다.
+20191010 추가내용
클러스터 생성시, 입력하는 노드 갯수와 같은 수의 인스턴스가 생성되며, 서브넷은 가용영역 당 하나씩 생성된다. 싱가포르 리전의 경우, 가용영역이 a,b,c이므로, 이에 상응하는 서브넷이 생성된다. 인스턴스 생성 순서는 가용영역 알파벳 순서이다.
eksctl에는 많은 파라미터 들이 있으니 eksctl 사용법을 참고바란다.
eksctl create cluster --name=eksworkshop-eksctl --nodes=3 --alb-ingress-access --region=${AWS_REGION}
다음과 같이 로그가 보이면 성공적으로 구성이 된 것이다.
[ℹ] using region ap-southeast-1
[ℹ] setting availability zones to [ap-southeast-1a ap-southeast-1b ap-southeast-1c]
[ℹ] subnets for ap-southeast-1a - public:192.168.0.0/19 private:192.168.96.0/19
[ℹ] subnets for ap-southeast-1b - public:192.168.32.0/19 private:192.168.128.0/19
[ℹ] subnets for ap-southeast-1c - public:192.168.64.0/19 private:192.168.160.0/19
[ℹ] nodegroup "ng-abc5205f" will use "ami-06206d907abb34bbc" [AmazonLinux2/1.13]
[ℹ] using Kubernetes version 1.13
[ℹ] creating EKS cluster "eksworkshop-eksctl" in "ap-southeast-1" region
[ℹ] will create 2 separate CloudFormation stacks for cluster itself and the initial nodegroup
[ℹ] if you encounter any issues, check CloudFormation console or try 'eksctl utils describe-stacks --region=ap-southeast-1 --name=eksworkshop-eksctl'
[ℹ] CloudWatch logging will not be enabled for cluster "eksworkshop-eksctl" in "ap-southeast-1"
[ℹ] you can enable it with 'eksctl utils update-cluster-logging --region=ap-southeast-1 --name=eksworkshop-eksctl'
[ℹ] 2 sequential tasks: { create cluster control plane "eksworkshop-eksctl", create nodegroup "ng-abc5205f" }
[ℹ] building cluster stack "eksctl-eksworkshop-eksctl-cluster"
[ℹ] deploying stack "eksctl-eksworkshop-eksctl-cluster"
[ℹ] building nodegroup stack "eksctl-eksworkshop-eksctl-nodegroup-ng-abc5205f"
[ℹ] --nodes-min=3 was set automatically for nodegroup ng-abc5205f
[ℹ] --nodes-max=3 was set automatically for nodegroup ng-abc5205f
[ℹ] deploying stack "eksctl-eksworkshop-eksctl-nodegroup-ng-abc5205f"
[✔] all EKS cluster resource for "eksworkshop-eksctl" had been created
[✔] saved kubeconfig as "/home/ec2-user/.kube/config"
[ℹ] adding role "arn:aws:iam::511105578551:role/eksctl-eksworkshop-eksctl-nodegro-NodeInstanceRole-ECWQU3TC1J17" to auth ConfigMap
[ℹ] nodegroup "ng-abc5205f" has 0 node(s)
[ℹ] waiting for at least 3 node(s) to become ready in "ng-abc5205f"
[ℹ] nodegroup "ng-abc5205f" has 3 node(s)
[ℹ] node "ip-192-168-0-173.ap-southeast-1.compute.internal" is ready
[ℹ] node "ip-192-168-49-93.ap-southeast-1.compute.internal" is ready
[ℹ] node "ip-192-168-72-198.ap-southeast-1.compute.internal" is ready
[ℹ] kubectl command should work with "/home/ec2-user/.kube/config", try 'kubectl get nodes'
[✔] EKS cluster "eksworkshop-eksctl" in "ap-southeast-1" region is ready
+20191009 추가내용
workshop때는 admin권한을 주고 cluster를 구성하였으나, admin권한은 보안적으로 취약하므로, 위 로그를 참고하여 생성되는 리소스에 대한 권한은 모두 포함되는 role를 생성하여 할당 하는 것이 바람직합니다.
sg, cluster, internet gateway, elastic ip, subnet route table, iam policy, subnet, vpc, vpc gateway
위와 같이 성공 하였다면, 지금 우리는 다음과 같은 구성으로 Architecture를 구축한 것입니다.
3. Kubectl을 이용해 노드 구성하기
이제 각 노드에 대해 디플로이먼트와 서비스를 배포해보겠다. (현재는 퍼블릭 서브넷에다 배포를 하지만, 추후 private subnet으로 노드를 구성하여 배포를 하는 방법도 위키에 올리겠습니다.)
앱을 배포하기 위해서는 이전에 설치한kubectl을 사용해야 하며 사용법은 링크를 참고한다.
deployment를 복제하여 앱을 배포한 결과, 다음과 같이 고가용성을 만족한 배포가 이루어 졌음을 눈으로 볼 수 있다.
4. helm 설치
이 부분에 대해서는 설치만 진행하였습니다. 자세한 내용은 개인적으로 더 스터디 하여 공유하겠습니다.
Helm은 여러 Kubernetes 리소스를 Chart라는 단일 논리적 배포 단위(쿠버네티스를 관리하면서 나오는 yaml로 구성된 파일의 집합)로 패키지화하는 Kubernetes 용 패키지 관리자 및 응용 프로그램 관리 도구이다. Helm은 tiller라는 서버를 통하여 Kubernetes api server과 통신을 하여 Kubernetes를 관리할 수 있다. 이후 챕터에 필요하므로, 건너뛰지 말고 꼭 설치하도록 하자.
Helm의 기능을 정리하면 다음과 같다.
단일 또는 반복이 가능한 배포
3rd party서비스를 사용하여 응용 프로그램의 종속성 관리
환경에 알맞는 배포의 구성 관리 (ex. test, stagging, production)
사후 / 사전 배포 작업 실행
응용 프로그램 배포 업데이트 / 롤백 / 테스트
Helm을 설치하는 script를 curl로 받아와서 해당 파일을 실행해야하므로, 실행권한까지 부여한다.
cd ~/environment
https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get > get_helm.sh
chmod +x get_helm.sh
sh get_helm.sh
helm 설치 쉘스크립트를 실행하면 helm init을 입력하라고 메시지가 뜬다. 이를 입력 하지 말고, 다음 안내를 따라서 tiller에 최적화된 helm을 설치한다. 만약 입력 하였을시,helm reset -force를 입력하여 helm을 초기화하고 다시 진행한다.
2. 다음 스크립트를 입력하여 tiller(helm 클라이언트의 서버)를 운영할 service account를 만들고 tiller까지 설치한다.
Creating /home/ec2-user/.helm
Creating /home/ec2-user/.helm/repository
Creating /home/ec2-user/.helm/repository/cache
Creating /home/ec2-user/.helm/repository/local
Creating /home/ec2-user/.helm/plugins
Creating /home/ec2-user/.helm/starters
Creating /home/ec2-user/.helm/cache/archive
Creating /home/ec2-user/.helm/repository/repositories.yaml
Adding stable repo with URL: https://kubernetes-charts.storage.googleapis.com
Adding local repo with URL: http://127.0.0.1:8879/charts
$HELM_HOME has been configured at /home/ec2-user/.helm.
Tiller (the Helm server-side component) has been installed into your Kubernetes Cluster.
Please note: by default, Tiller is deployed with an insecure 'allow unauthenticated users' policy.
To prevent this, run `helm init` with the --tiller-tls-verify flag.
For more information on securing your installation see: https://docs.helm.sh/using_helm/#securing-your-helm-installation
다음과 같이 출력되면 정상이다.
5. Autoscaling Application and Clusters
이전 튜토리얼에서는 수동으로 스케일링을 하였다. 그러나 이번 튜토리얼은 자동으로 scaling하는 방법에 대해 알아 볼 것이다.
먼저 Scaling의 유형에는 2가지 유형이 존재한다.
Horizontal Pod Autoscaler (HPA) 는 deployment안에 있는 pod의 replica set을 scaling한다. HPA는 Kubernetes API 리소스와 컨트롤러에 대해서 상속되어있다. 컨트롤러 관리자는 HorzontalPodAutoScaler 정의에 대해 명세된 지표에 따라 이때 resource utilization을 쿼리한다.
Cluster Autoscaler(CA)는 Kubernetes의 pod과 node에 대해서 모두 scaling을 할 수 있닌 기본 컴포넌트이다. CA는 자동으로 pod이 자리를 잡아 실행 될 수 있도록 Auto Scaling Group의 크기를 늘릴 수 있으며, 유휴상태일 시 자동으로 node를 줄일 수도 있다.
5-1. HPA
Metric서버는 리소스 사용량에 관한 데이터를 수집하는 서버다. 이 지표는 배포의 확장 및 축소에 관한 동작을 주관한다. 이제 이 metric서버를 설치를 할 것이다. helm 글로벌 chart list에서 metric 서버를 설치해보자. 다음 코드로 설치를 진행한다.
NAME: metrics-server
LAST DEPLOYED: Sat Oct 19 08:03:30 2019
NAMESPACE: metrics
STATUS: DEPLOYED
RESOURCES:
==> v1/ClusterRole
NAME AGE
system:metrics-server 0s
==> v1/ClusterRoleBinding
NAME AGE
metrics-server:system:auth-delegator 0s
system:metrics-server 0s
==> v1/Pod(related)
NAME READY STATUS RESTARTS AGE
metrics-server-5b5bfd85cf-crbn5 0/1 ContainerCreating 0 0s
==> v1/Service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
metrics-server ClusterIP 10.100.132.85 <none> 443/TCP 0s
==> v1/ServiceAccount
NAME SECRETS AGE
metrics-server 1 0s
==> v1beta1/APIService
NAME AGE
v1beta1.metrics.k8s.io 0s
==> v1beta1/RoleBinding
NAME AGE
metrics-server-auth-reader 0s
==> v1beta2/Deployment
NAME READY UP-TO-DATE AVAILABLE AGE
metrics-server 0/1 1 0 0s
NOTES:
The metric server has been deployed.
In a few minutes you should be able to list metrics using the following
command:
kubectl get --raw "/apis/metrics.k8s.io/v1beta1/nodes"
api service가 제대로 실행되고 있는지 확인을 해보면,
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
creationTimestamp: "2019-10-19T08:03:30Z"
labels:
app: metrics-server
chart: metrics-server-2.0.4
heritage: Tiller
release: metrics-server
name: v1beta1.metrics.k8s.io
resourceVersion: "14654"
selfLink: /apis/apiregistration.k8s.io/v1/apiservices/v1beta1.metrics.k8s.io
uid: f03b0180-f246-11e9-b522-0245eea98ecc
spec:
group: metrics.k8s.io
groupPriorityMinimum: 100
insecureSkipTLSVerify: true
service:
name: metrics-server
namespace: metrics
version: v1beta1
versionPriority: 100
status:
conditions:
- lastTransitionTime: "2019-10-19T08:03:34Z"
message: all checks passed
reason: Passed
status: "True"
type: Available
ec2-user:~/environment $ kubectl get apiservice
NAME SERVICE AVAILABLE AGE
v1. Local True 6h
v1.apps Local True 6h
v1.authentication.k8s.io Local True 6h
v1.authorization.k8s.io Local True 6h
v1.autoscaling Local True 6h
v1.batch Local True 6h
v1.networking.k8s.io Local True 6h
v1.rbac.authorization.k8s.io Local True 6h
v1.storage.k8s.io Local True 6h
v1alpha1.crd.k8s.amazonaws.com Local True 6h
v1beta1.admissionregistration.k8s.io Local True 6h
v1beta1.apiextensions.k8s.io Local True 6h
v1beta1.apps Local True 6h
v1beta1.authentication.k8s.io Local True 6h
v1beta1.authorization.k8s.io Local True 6h
v1beta1.batch Local True 6h
v1beta1.certificates.k8s.io Local True 6h
v1beta1.coordination.k8s.io Local True 6h
v1beta1.events.k8s.io Local True 6h
v1beta1.extensions Local True 6h
v1beta1.metrics.k8s.io metrics/metrics-server True 3h
v1beta1.policy Local True 6h
v1beta1.rbac.authorization.k8s.io Local True 6h
v1beta1.scheduling.k8s.io Local True 6h
v1beta1.storage.k8s.io Local True 6h
v1beta2.apps Local True 6h
v2beta1.autoscaling Local True 6h
v2beta2.autoscaling Local True 6h
다음과 같이 available하고, vlbetal.metrics.k8s.io가 실행되고 있는 것을 알 수 있다.
이제 Kubernetes에서 제공하는 기본 앱 샘플을 생성할 것이다. 생성하면 그에 대한 deployment와 service가 생성된다.
c2-user:~/environment $ kubectl run php-apache --image=k8s.gcr.io/hpa-example --requests=cpu=200m --expose --port=80
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
service/php-apache created
deployment.apps/php-apache created
ec2-user:~/environment $ kubectl get service
kuNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.100.0.1 <none> 443/TCP 8h
php-apache ClusterIP 10.100.207.222 <none> 80/TCP 42s
ec2-user:~/environment $ kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
php-apache 1/1 1 1 48s
php-apache 앱에 대해서 hpa 오토 스케일링을 적용하기 위해서 다음 명령어를 입력하자. 입력 후, 오토 스케일링이 어떤 상태인지 까지 조회해보자.
ec2-user:~/environment $ kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10
horizontalpodautoscaler.autoscaling/php-apache autoscaled
ec2-user:~/environment $ kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
php-apache Deployment/php-apache 0%/50% 1 10 1 38m
wget 요청을 지속적으로 앱에 보내어 부하를 가한다.
ec2-user:~/environment $ kubectl run -i --tty load-generator --image=busybox /bin/sh
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
If you don't see a command prompt, try pressing enter.
/ # while true; do wget -q -O - https://php-apache; done
OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK
그에 따라 지속적으로 hpa의 상태를 조회하면 다음과 같이 auto scaling이 적용이 되어 replica의 수가 늘어나는 것을 관찰 할 수 있다.
다음과 같이 deployment의 scale을 증가시킨 다음, 실제로 콘솔을 확인하면 node가 추가된 것을 알 수 있다. (저는 실패해서 원인 분석중입니다.)
6. Prometheus
SoundCloud에서 제작한 시스템 모니터링 및 알람 툴킷이다. 현재는 독립형 오픈소스 프로젝트가 되었으며, 모든 사용자가 독립적으로 유지보수한다. 이 프로젝트는 2016년 두 번째 호스팅 프로젝트로 Cloud Native Computing Foundation에 합류하였다.
프로메테우스의 기능을 정리해보았다.
metric 이름과 키-값으로 구분되는 다양한 시계열를 가진 다차원 데이터 모델을 지원한다.
다차원 데이터를 처리하기 위해 PromQL이라는 질의어를 사용한다.
분산 스토리지에 의존하지 않으며, 단일 서버 노드는 자율적이다.
HTTP의 pull model을 통해 시계열 수집이 일어난다.
중개 게이트워이를 통해 시계열의 push를 지원한다.
다양한 형태의 그래프 및 대시보드를 지원한다.
프로메테우스의 구조는 다음과 같다.
프로메테우스 설치
먼저 다음 명령어로 prometheus라는 이름을 가진 namespace를 만들고, helm을 통해서 prometheus를 설치한다.
먼저 로드밸런서 가용영역에 대해 알아보자.로드밸런서 가용영역이란, 일반적인 우리가 알고 있는 AZ가 아닌 로드밸런서가 접근할 수 있는 subnet을 의미 한다.이에 대해서는 다음 캡쳐본을 참고한다.
현재 로드밸런서는 활성화된 가용 영역(서브넷)이 private subnet이다. private subnet은 igw와 연결되어있지 않으며, 로드밸런싱 대상은 public ip 또는 탄력적 ip가 할당되어 있지 않기 때문에 외부 트래픽을 다룰 수 없게 된다.
이를 해결하기 위해서는로드밸런서의 활성화된 가용영역(서브넷)을 public subnet으로 설정해준다. public 서브넷은 외부와는 물론 내부 서브넷과 통신이 가능하므로 public subnet을 거쳐 로드밸런싱 대상으로 트래픽을 전달하면 쌍방으로 통신이 가능해지기 때문에 위와 같은 이슈를 해결 할 수 있다.
2-2. Data Flow Diagram
다음과 같이 public subnet을 통해서 private subnet의 인스턴스로 접근하게 설정해준다.