일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | |
7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 | 30 |
- Heap
- 자료구조
- Data Structure
- MSA
- Kafka
- 알고리즘
- Algorithm
- 네트워크
- JavaScript
- MySQL
- Proxy
- Java
- 컴퓨터구조
- redis
- mongoDB
- OS
- spring webflux
- JPA
- c언어
- 자바
- 파이썬
- C
- design pattern
- IT
- Galera Cluster
- 운영체제
- Spring
- 디자인 패턴
- react
- 백준
- Today
- Total
시냅스
AWS EKS 구축 가이드, Ingress 설정과 Spring 애플리케이션의 RDS 연동 본문
이 글에서는 AWS EKS 를 구축하여 Nginx Ingress 와 Spring, RDS 를 연동하는 방법을 가이드합니다.
AWS Settings
네트워크 아키텍처의 목표는 3‑Tier 구조를 기반으로 AWS EKS 클러스터를 안정적으로 운영하는 것입니다.
이번에는 다음과 같은 방식으로 구성하겠습니다.
1. Public Subnet
- 웹 서버 (NginX Ingress)를 배치해 클라이언트 요청 수신
- 수신된 요청을 WAS 로 라우팅
2. Private Subnet - Worker Node
- EKS 워커 노드 배치
- 워커 노드는 NAT Gateway를 통해 외부와 통신
3. Private Subnet - DB Layer
- RDS 등 데이터 계층 리소스 배치
- 외부 인터넷 접근 없이 오직 내부 통신만 허용
이처럼 3-Tier 분리로 보안과 가용성을 확보하여 클러스터를 구축해나가겠습니다.
VPC
VPC 는 모든 리소스가 네트워크 관점에서 격리된 공간에서 동작하도록 만드는 논리적 경계입니다.
이번에는 단일 VPC 내에 Public / Private Subnet 으로 분리하여 보안과 가용성을 동시에 확보합니다.
Public / Private 을 분리함으로써 외부에 노출되는 곳과 노출되지 않는 곳을 제어할 수 있어 보안과 가용성에 대한 확보가 가능합니다.
또한 각 영역에 대해 가용 영역을 달리 함으로 물리적 위치를 다르게 두어 가용성을 추가로 확보합니다.
실제로 구축하며 알아보겠습니다.
VPC 생성 및 Subnet 설정
VPC 를 생성합니다.
IPv4 CIDR 는 사설 IP 대역을 사용합니다.
Subnet 을 위처럼 3개를 생성합니다.
운영환경에서 Public Subnet 은 1개가 더 필요합니다.
향후 EKS-PRIVATE-A, EKS-PRIVATE-C 는 EKS-PUBLIC-NAT 영역에 있는 NAT-gateway 와 연결될 예정입니다.
따라서 EKS-PUBLIC-NAT, EKS-PRIVATE-A 는 ap-northeast-2a 에 같은 영역에 있고,
만약 모종의 이유로 ap-northeast-2a 가 가용이 불가능해진다면, EKS-PRIVATE-C 또한 서비스가 불가능해집니다.
따라서 각 가용영역에는 각각의 NAT gateway 를 두는 것을 권장합니다.
EKS-PUBLIC-NAT 에 위와 같은 태그를 추가합니다.
kubernetes.io/cluster/<cluster-name>=shared 태그는 이 서브넷이 해당 EKS 클러스터와 연동됨을 나타냅니다.
kubernetes.io/role/elb=1 태그는 이 서브넷을 외부 로드밸런서용으로 사용하겠다는 표시입니다.
EKS-PRIVATE-A/C 에는 위와 같은 태그를 추가합니다.
Internet Gateway
IGW는 AWS VPC에서 퍼블릭 서브넷에 있는 인스턴스들이 인터넷과 통신할 수 있도록 하는 서비스입니다.
IGW가 하는 역할은 크게 다음과 같습니다.
- VPC에 연결된 가상 라우터 역할을 수행
- 인바운드/아웃바운드 트래픽을 NAT 없이 직접 전달
- EIP 를 가진 EC2 인스턴스가 인터넷과 통신할 수 있도록 중계
즉, IGW 는 VPC 내부의 리소스가 인터넷과 통신할 수 있는 유일한 출입구입니다.
아래에서 설정하며 자세히 알아보겠습니다.
인터넷 게이트웨이를 생성합니다. 위에서 설명했듯 앞으로 인터넷 외부 통신은 이 gateway 를 통해 이뤄집니다.
인터넷 게이트웨이를 위한 라우팅 테이블을 생성하고, 외부 트래픽 규칙(0.0.0.0/0)을 생성합니다.
라우팅 테이블에 NAT Gateway 를 위한 Subnet 을 연결합니다.
이제 EKS-PUBLIC-NAT 에 NAT gateway 를 두어 private subnet 에서도 인터넷 통신을 할 수 있게 구축해보겠습니다.
NAT Gateway 를 생성하며 private subnet 에 있는 인스턴스들이 외부와 통신할 수 있도록 EIP 또한 할당해줍니다.
NAT 를 통한 통신은 외부로 나갈 수만 있고 외부에서 직접 접근할 수는 없습니다.
위와 같이 NAT Routetable 을 생성한 이후 private subnet 2개를 연결해줍니다.
이후 라우팅 편집을 통해 모든 외부 통신을 NAT GW 에 할 수 있게 합니다.
EKS Cluster 생성
EKS 는 완전 관리형 Kubernetes 서비스입니다.
Control plane 에 대한 설치/관리를 편리하게 하며 보안 및 네트워크에 대한 부담도 줄여줍니다.
다시, 생성하며 알아보겠습니다.
EKS 화면에 들어가 클러스터 생성을 누른 후 위와 같이 정의합니다.
다만 클러스터 IAM 역할, 노드 IAM 역할은 권장 역할 생성으로 할 수 있습니다.
현재 저의 셋팅은 기존에 만들어 둔 것을 재사용하였으나 권장 역할 생성으로 해도 동일한 설정입니다.
또 서브넷은 기존에 생성해둔 private subnet 2개를 설정합니다.
private subnet 에서 worker node 가 동작할 예정입니다.
OIDC 자격 증명 공급자 생성
EKS 추가 기능(ADD-on) 을 설치할 떄에는 OIDC 자격 증명 공급자가 필요합니다.
이를테면 VPC CNI, EBS CSI Driver 같은 것들이 그렇습니다.
OIDC 자격 증명 공급자(IAM OIDC Provider) 는 K8s RBAC 을 연동시킬 수 있습니다.
특정 k8s ServiceAccount(Pod) 에게 IAM Role 을 부여하려면 EKS 클러스터에 OIDC 자격 증명 공급자가 등록되어 있어야 합니다.
EKS 는 다음과 같은 흐름으로 IAM 권한을 검증합니다.
- Pod 내부에서 OIDC 토큰을 발급
- 이 토큰을 기반으로 IAM Role Assume
- AWS 는 클러스터의 OIDC Issuer 와 연결된 신뢰 관계를 통해 인증
따라서 어떤 Pod 에게 추가 적인 기능에 대한 인증/인가가 필요하고 이를 위해 OIDC 자격 증명 공급자를 연동하여 확인합니다.
EKS cluster 구성이 완료됐다면 위와 같이 OpenID Connect 공급자 URL 이 생성됩니다.
이 URL 을 복사합니다.
복사한 공급자 URL 을 사용하여 IAM > ID 제공업체 > 공급자 추가로 생성합니다.
이후 위처럼 AmazonEKS_CNI_Policy 권한을 가진 역할을 만들어 줍니다.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::899455914449:oidc-provider/oidc.eks.ap-northeast-2.amazonaws.com/id/......"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"oidc.eks.ap-northeast-2.amazonaws.com/id/......:sub": "system:serviceaccount:kube-system:aws-node",
"oidc.eks.ap-northeast-2.amazonaws.com/id/......:aud": "sts.amazonaws.com"
}
}
}
]
}
해당 역할에 신뢰 관계를 복사한 URL 을 사용하여 위와 같이 설정합니다.
위에서 생성한 정책은 EKS Cluster 추가 기능을 설정할 때 필요합니다.
위 화면에서 추가 기능 불러오기로 들어갑니다.
VPC CNI 를 선택하고 방금 생성한 역할을 할당하여 추가합니다.
다시 추가 기능 가져오기로 들어가 추가로 core dns 와 kube proxy 를 추가합니다.
EKS Cluster 를 구축하면서 3개의 AddOn 을 설치했습니다.
Amazon VPC CNI 플러그인은 k8s 네트워크를 AWS VPC 와 완전히 통합해주는 네트워크 드라이버입니다.
Pod 에 IP 를 할당할 때 VPC 서브넷의 실제 ENI 와 IP를 사용합니다.
즉, 각 Pod 가 VPC 내부의 진짜 IP를 가지고 VPC 내부 자원과도 네이티브하게 통신할 수 있습니다.
kube-proxy 는 k8s 의 Service -> Pod 라우팅을 담당합니다.
ClusterIP, NodePort, LoadBalancer 같은 서비스 유형을 설정했을 때 트래픽을 적절한 백엔드 Pod 로 전달하는 중계자 역할을 합니다.
CoreDNS 는 k8s 내부의 DNS 서버 역할을 합니다.
Pod 간 통신시 service.namespace.svc.cluster.local 같은 FQDN 을 해석해줍니다.
또 다른 AWS Resource 의 endpoint 를 resolve 해주기도 합니다.
실제 운영환경에서는 아래와 같은 추가 Add On 이 필요하기도 합니다.
- EBS CSI Driver : Pod 에 EBS 볼륨을 할당
- AWS Load Balancer Controller : ALB/NLB 리소스 자동 생성
- Cluster Autoscaler : 노드 수 자동 조절
- Metrics Server : Pod 리소스 사용량 수집
- External DNS : Service/Ingress 를 외부 DNS 와 연동
- EFS CSI Driver : 공유 스토리지 할당
Node Group 생성
Node Group 은 EKS Cluster 에 연결된 EC2 인스턴스 그룹입니다.
이 인스턴스들이 실제로 Pod 를 실행하고 클러스터의 작업을 수행합니다.
kubectl get nodes 로 확인할 수 있는 집합입니다.
운영 환경에서 워크로드를 분리하여 물리적으로 다른 위치를 두게 하여 고가용성을 지원하기 위해 Node Group 을 여러개로 나누기도 합니다.
eks cluster 화면에서 노드 그룹 추가를 누른 뒤 노드 IAM 역할 (마찬가지로 권장 역할 생성 과 동일합니다.),
네트워킹 지정에 private subnet 2 군데임을 확인하고 생성합니다.
생성이 완료되면 아래와 같이 kubectl 을 사용하여 eks cluster 에 접속합니다.
EKS 접속하기
# aws configure
AWS Access Key ID [None]: {ACCESS_KEY}
AWS Secret Access Key [None]: {SECRET_KEY}
Default region name [None]: ap-northeast-2
Default output format [None]: json
# configure eks
aws eks update-kubeconfig --region ap-northeast-2 --name {클러스터 이름}
# check nodes
$ k get nodes -A
NAME STATUS ROLES AGE VERSION
i-07e5aaf3f43e6a9b0 Ready <none> 115m v1.33.1-eks-b9364f6
ip-10-0-168-232.ap-northeast-2.compute.internal Ready <none> 27s v1.33.0-eks-802817d
ip-10-0-74-33.ap-northeast-2.compute.internal Ready <none> 26s v1.33.0-eks-802817d
kubectl 로 접속되는 것을 확인할 수 있습니다.
NginX Ingress 및 WAS / DB 설정
K8s Cluster 에 Ingress Controller 를 설치하면 외부 트래픽을 받아 줄 로드 밸런서가 필요합니다.
EKS 는 이 부분을 완전 자동화하여 ingress-nginx 같은 차트를 배포하는 순간
AWS 콘솔에 ALB 또는 NLB 가 새로 떠 있는 것을 볼 수 있습니다.
위에서 설정했던 서브넷 태그를 보고 EKS 는 ELB/ALB 를 할당합니다.
Helm 으로 NginX 를 배포하며 알아보겠습니다.
NginX Ingress
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm uninstall ingress-nginx -n ingress-nginx || true
kubectl delete namespace ingress-nginx || true
helm install ingress-nginx ingress-nginx/ingress-nginx \
--namespace ingress-nginx \
--create-namespace \
--set controller.service.annotations."service\.beta\.kubernetes\.io/aws-load-balancer-scheme"=internet-facing \
--set controller.service.annotations."service\.beta\.kubernetes\.io/aws-load-balancer-type"=external \
--set controller.service.annotations."service\.beta\.kubernetes\.io/aws-load-balancer-nlb-target-type"=ip
위 명령어를 수행하면 아래와 같이 LoadBalancer 가 새로 생성되는 것을 확인할 수 있습니다.
앞으로 이 ingress 가 트래픽을 받아 분배하는 역할을 하게 됩니다.
또한 subnet 은 앞서 elb=1 로 할당했던 subnet 임을 확인할 수 있습니다.
위 ingress 가 안내하는 domain 으로 이동하면 nginx 가 404 를 내려주는 것을 확인할 수 있습니다.
아직 셋팅이 되지 않은 상태로 정상 작동하는 것을 확인할 수 있습니다.
RDS 설정
대충 저렴한 RDS 하나를 만들어줍니다.
이때 vpc 는 EKS Cluster 와 동일한 위치로 설정하고 보안 그룹을 생성합니다.
위와 같이 rds 의 보안 그룹에서 inbound 규칙에 eks cluster 가 접근할 수 있게 설정합니다.
Spring App 준비
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
@RestController
class TestController {
@Value("${server.name:defaultServerName}")
private String serverName;
@GetMapping("/test1/test")
public String test1() {
return "Hello, this is a test1! : " + serverName;
}
@GetMapping("/test2/test")
public String test2() {
return "Hello, this is a test2! : " + serverName;
}
}
@AllArgsConstructor
@NoArgsConstructor
@Entity
class TestEntity {
@Id
private Long id;
private String content;
}
저는 아주 간단한 spring app 을 만들어 docker hub 에 올려두었습니다.
차후 k8s 에 실제로 라우팅을 test1, test2 로 두어 라우팅을 정상적으로 실행하는지 확인하기 위해
endpoint 도 2개를 만들어 두었습니다.
또 TestEntity 를 생성하여, DB 와 연결이 잘 되는지 확인합니다.
K8s 배포
목표가 되는 구성도는 위와 같습니다.
public subnet 에서 사용자 요청을 받아, ingress 로 보내고
받은 ingress 는 각각의 cluster ip 에 routing 한 뒤 spring app 으로 요청을 보내게 됩니다.
Client
↳ ALB/NLB (Public)
↳ Ingress Service (LB)
↳ Ingress Controller Pod (NGINX)
↳ nginx Service (ClusterIP)
↳ Spring Pods
↳ RDS 3306/TCP
EKS Cluster 를 사용하는 Client 는 위와 같은 순서대로 요청을 보내게 됩니다.
위 구성을 토대로 실제로 배포를 진행해보겠습니다.
# 00-namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: app-demo
# bash 로 적용
$ kubectl apply -f 00-namespace.yaml
# ns 확인
$ kubectl get ns app-demo
namespcae 설정
# 01-secret-db-credentials.yaml
# DB credential Secret (edit the base64 values)
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
namespace: app-demo
type: Opaque
data:
username: YWRtaW4= # "admin"
password: ZWtzVGVzdCE= # "eksTest!"
# 02-configmap-app-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: app-demo
data:
TZ: Asia/Seoul
DB_URL: jdbc:mysql://eks-test.cluster-chyqog6a0qbj.ap-northeast-2.rds.amazonaws.com:3306/eks_prac
SPRING_JPA_DATABASE_PLATFORM: org.hibernate.dialect.MySQL8Dialect
# bash 로 적용
$ kubectl apply -f 01-secret-db-credentials.yaml
$ kubectl apply -f 02-configmap-app-config.yaml
# 확인
$ kubectl get secret db-credentials -n app-demo
$ kubectl get configmap app-config -n app-demo
config 설정
# 10-deploy-spring-test1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: spring-test1
namespace: app-demo
spec:
replicas: 2
selector:
matchLabels: { app: spring-test1 }
template:
metadata:
labels: { app: spring-test1 }
spec:
containers:
- name: app
image: {IMAGE_REGISTRY}/eks-prac:0.0.1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
env:
- name: TZ
valueFrom: { configMapKeyRef: { name: app-config, key: TZ } }
- name: DB_URL
valueFrom: { configMapKeyRef: { name: app-config, key: DB_URL } }
- name: DB_USER
valueFrom: { secretKeyRef: { name: db-credentials, key: username } }
- name: DB_PASSWORD
valueFrom: { secretKeyRef: { name: db-credentials, key: password } }
- name: SPRING_JPA_DATABASE_PLATFORM
valueFrom: { configMapKeyRef: { name: app-config, key: SPRING_JPA_DATABASE_PLATFORM } }
- name: SERVER_NAME
value: test1
# 11-svc-spring-test1.yaml
apiVersion: v1
kind: Service
metadata:
name: spring-test1
namespace: app-demo
spec:
type: ClusterIP
selector: { app: spring-test1 }
ports:
- name: http
port: 8080
targetPort: 8080
# 배포 완료 대기
$ kubectl -n app-demo rollout status deploy/spring-test1
# 확인
$ kubectl get pods -n app-demo -l app=spring-test1 -o wide
$ kubectl get svc -n app-demo spring-test1 -o wide
# 로그 샘플
$ kubectl logs -n app-demo deploy/spring-test1 --tail=100
test 1번 app 설정
# 12-deploy-spring-test2.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: spring-test2
namespace: app-demo
spec:
replicas: 2
selector:
matchLabels: { app: spring-test2 }
template:
metadata:
labels: { app: spring-test2 }
spec:
containers:
- name: app
image: {IMAGE_REGISTRY}/eks-prac:0.0.1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
env:
- name: TZ
valueFrom: { configMapKeyRef: { name: app-config, key: TZ } }
- name: DB_URL
valueFrom: { configMapKeyRef: { name: app-config, key: DB_URL } }
- name: DB_USER
valueFrom: { secretKeyRef: { name: db-credentials, key: username } }
- name: DB_PASSWORD
valueFrom: { secretKeyRef: { name: db-credentials, key: password } }
- name: SPRING_JPA_DATABASE_PLATFORM
valueFrom: { configMapKeyRef: { name: app-config, key: SPRING_JPA_DATABASE_PLATFORM } }
- name: SERVER_NAME
value: test2
# 13-svc-spring-test2.yaml
apiVersion: v1
kind: Service
metadata:
name: spring-test2
namespace: app-demo
spec:
type: ClusterIP
selector: { app: spring-test2 }
ports:
- name: http
port: 8080
targetPort: 8080
$ kubectl -n app-demo rollout status deploy/spring-test2
$ kubectl get pods -n app-demo -l app=spring-test2 -o wide
$ kubectl get svc -n app-demo spring-test2 -o wide
$ kubectl logs -n app-demo deploy/spring-test2 --tail=100
test 2번 app 설정
# 20-cm-test1-nginx.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: test1-nginx-conf
namespace: app-demo
data:
nginx.conf: |
worker_processes 1;
events { worker_connections 1024; }
http {
upstream spring_test1 {
server spring-test1.app-demo.svc.cluster.local:8080;
}
server {
listen 80;
# ingress가 /test1(/|$)(.*) 을 /$2 로 리라이트하므로 여기선 루트로 처리
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://spring_test1;
}
}
}
# 21-deploy-test1-nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: test1-nginx
namespace: app-demo
spec:
replicas: 1
selector:
matchLabels: { app: test1-nginx }
template:
metadata:
labels: { app: test1-nginx }
spec:
containers:
- name: nginx
image: nginx:1.25-alpine
ports:
- containerPort: 80
volumeMounts:
- name: conf
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
volumes:
- name: conf
configMap:
name: test1-nginx-conf
# 22-svc-test1-nginx.yaml
apiVersion: v1
kind: Service
metadata:
name: test1-nginx
namespace: app-demo
spec:
type: ClusterIP
selector: { app: test1-nginx }
ports:
- port: 80
targetPort: 80
name: http
$ kubectl -n app-demo rollout status deploy/test1-nginx
$ kubectl get pods -n app-demo -l app=test1-nginx -o wide
$ kubectl get svc -n app-demo test1-nginx -o wide
$ kubectl logs -n app-demo deploy/test1-nginx --tail=100
test 1 번 nginx 설정
# kubectl apply -f 23-cm-test2-nginx.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: test2-nginx-conf
namespace: app-demo
data:
nginx.conf: |
worker_processes 1;
events { worker_connections 1024; }
http {
upstream spring_test2 {
server spring-test2.app-demo.svc.cluster.local:8080;
}
server {
listen 80;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://spring_test2;
}
}
}
# kubectl apply -f 24-deploy-test2-nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: test2-nginx
namespace: app-demo
spec:
replicas: 1
selector:
matchLabels: { app: test2-nginx }
template:
metadata:
labels: { app: test2-nginx }
spec:
containers:
- name: nginx
image: nginx:1.25-alpine
ports:
- containerPort: 80
volumeMounts:
- name: conf
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
volumes:
- name: conf
configMap:
name: test2-nginx-conf
# kubectl apply -f 25-svc-test2-nginx.yaml
apiVersion: v1
kind: Service
metadata:
name: test2-nginx
namespace: app-demo
spec:
type: ClusterIP
selector: { app: test2-nginx }
ports:
- port: 80
targetPort: 80
name: http
$ kubectl -n app-demo rollout status deploy/test2-nginx
$ kubectl get pods -n app-demo -l app=test2-nginx -o wide
$ kubectl get svc -n app-demo test2-nginx -o wide
$ kubectl logs -n app-demo deploy/test2-nginx --tail=100
test 2번 nginx 설정
# 30-ingress-routes.yaml
# Ingress: /test1/* -> test1-nginx, /test2/* -> test2-nginx
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
namespace: app-demo
spec:
ingressClassName: nginx
rules:
- http:
paths:
- path: /test1
pathType: Prefix
backend:
service:
name: test1-nginx
port:
number: 80
- path: /test2
pathType: Prefix
backend:
service:
name: test2-nginx
port:
number: 80
$ kubectl get ingress app-ingress -n app-demo
$ kubectl describe ingress app-ingress -n app-demo
ingress route 설정
ingress route 설정이 완료되었다면 우리의 eks cluster 는 트래픽을 받을 준비가 되었습니다.
nlb 의 domain 을 확인하여 위에서 설정했듯 test1, test2 로 요청을 보내보도록 하겠습니다.
의도한대로 동작하는 것을 확인하였습니다.
다음 글에서는 대표적인 IaC 도구인 terraform 으로 동일한 설정을 진행해보겠습니다.
끝!
참고
이렇게 많은 AWS 리소스들을 생성한 뒤 하나하나 삭제하기 번거로울 때 cloud-nuke 를 사용하여 삭제하고 있습니다.
aws configure 를 마친 aws 계정에서
$ cloud-nuke aws --region ap-northeast-2
명령어 하나로 모든 리소스를 삭제하여 편리하게 관리하고 있습니다.