현대 오토에버 클라우드 스쿨
Kubernetes Service, AWS EC2
Gom3rye
2025. 7. 22. 17:33
728x90
반응형
Load Balancer
- 로드 밸런싱을 해주는 쿠버네티스 서비스
- 참고) Cluster IP도 로드 밸런싱을 해준다. (애플리케이션의 포트, 클러스터 ip의 포트)
- 클러스터 내부에서 다른 파드에 접근하고자 할 때 사용한다.
- 실제 IP보다는 서비스 이름으로 접근하는 것을 권장한다.(서비스 디스커버리로 이동 권장)
- 실제 애플리케이션은 컨테이너, 파드는 배포 단위
- IP가 파드 단위로 부여되니까 (도커랑은 다른 점, 도커는 컨테이너 단위로 ip부여된다.)
- 파드의 IP는 고정이 아니니까 파드의 IP로는 통신할 수 없다. → 그러면 파드를 가리키는 고정된 IP가 필요한데 그 IP가 클러스터 IP이다. ⇒ 클러스터 IP는 Private IP이고 이걸 Flannel이 부여하는 것, 따라서 Flannel이 없으면 파드끼리 통신을 할 수 없다. (그래서 Flannel을 init 하고 깐 것)
- 근데 그 클러스터 IP도 일반적으로는 고정되지만 서비스가 삭제되었다가 다시 생성되면 변경될 수 있다. → IP 주소 대신 서비스 이름(서비스 디스커버리)을 사용하여 통신해야 한다.
- 참고) Node port : 외부에서 Node의 public ip를 통해서 pod에 접근하기 위해서 생성되는 것, Cluster IP가 자동으로 생성된다. (외부에서 통신이 가능하면 내부도 당연히 통신이 되야 하니까) (애플리케이션 포트, 클러스터 ip의 포트, 노드 포트)
- 헬름으로 yaml파일 여러 개를 묶어서 배포할 수 있다.
- 하나의 pod에 있는 앱들은 localhost로 서로 포트만 바꾸면 통신할 수 있다.
- 참고) Ingress vs. LB
- Ingress는 pod1, pod2를 갈 수 있고 (path 기반, host기반) 안에 놔도 되고 밖에 놔도 된다. (하나의 진입점으로 들어오는 요청을 Pod1, Pod2 등 다양한 서비스로 라우팅할 수 있다.)
- Ingress = ALB (application load balancer)
- naver.com은 host기반 (맨 앞부분만 보면 무슨 섹션인지 쉽게 알 수 있으니까 ex, news.naver.com, endic.naver.com)
- LB는 밖에 놔서 pod1끼리에만 가서 부하 분산 (안에 놓을 거면 cluster ip 쓰면 되니까)
- LB = NLB (network load balancer)
- 순서 중요) cluster ip → node port → load balancer → ingress
- 참고) Cluster IP도 로드 밸런싱을 해준다. (애플리케이션의 포트, 클러스터 ip의 포트)
항목 Ingress LoadBalancer (서비스)
| 역할 | HTTP(S) 트래픽을 라우팅 (L7, 애플리케이션 계층) | 외부에서 내부로 트래픽 전달 (L4, 네트워크 계층) |
| 라우팅 대상 | 여러 서비스(Pod1, Pod2, ...) | 단일 서비스(Pod1) |
| 부하 분산 대상 | 여러 서비스로 조건부 라우팅 가능 | 해당 서비스의 Pod들만 부하 분산 |
| 경로 기반 라우팅 | 가능 (예: /api, /web) | 불가능 |
| 도메인 기반 라우팅 | 가능 (예: api.example.com) | 불가능 |
| 공개 IP | 일반적으로 Ingress Controller 앞에 LB가 있음 | 서비스에 직접 퍼블릭 IP 할당 |
| 비용 | 상대적으로 적음 (LB 1개로 여러 서비스 핸들링) | 서비스마다 LB 비용 발생 |
- Metal LB
- public cloud의 managed kubernetes service가 아닌 곳에서 사용할 수 있는 load balancer
- 사용 절차
- MetalLB를 k8s에 설치 (Manifest 방식)
- LoadBalancer 서비스에 할당할 IP 주소 범위 지정
- tyep: LoadBalancer 서비스 생성 시 자동으로 외부 IP 부여
- 설치: kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.10/config/manifests/metallb-native.yaml
- pod가 4개(speaker3개, controller1개)만들어지고 service, daemonset, deployment, replicaset 만들어진다.
- 확인: kubectl get all -n metallb-system
- MetalLB IP 대역 설정
- YAML로 (or 명령어로 해도 된다.)
# metallb-config.yaml apiVersion: metallb.io/v1beta1 kind: IPAddressPool metadata: name: my-ip-pool namespace: metallb-system spec: addresses: - 192.168.56.240-192.168.56.250 --- apiVersion: metallb.io/v1beta1 kind: L2Advertisement metadata: name: l2adv namespace: metallb-system - 모드 및 서비스 대역 지정 확인: kubectl get l2advertisements -n metallb-system
- LoadBalancer 리소스 파일 생성
apiVersion: v1 kind: Service metadata: name: sample-lb spec: type: LoadBalancer ports: - name: "http-port" protocol: "TCP" port: 8080 targetPort: 80 nodePort: 30082 selector: app: sample-app- 서비스 생성 후 실행: kubectl apply -f sample-lb.yaml
- 리소스 확인: kubectl get svc
- External IP로 확인: curl 192.168.56.240:8080

nginx ingress 실습
클러스터 내부의 Ingress
# 클러스터 내부에 인그레스용 파드를 배포하는 인그레스 설치
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.6.4/deploy/static/provider/cloud/deploy.yaml
## nginx ingress controller가 설치되면서 k8s object들이 배포됨(pod, service, delpoyment, replicaset, job.batch)
# 설치 확인
kubectl get all -n ingress-nginx
# Ingress 생성 및 확인- Deployment 생성(deploy-test.yaml)
apiVersion: apps/v1
kind: Deployment
metadata:
name: service-test
spec:
replicas: 3
selector:
matchLabels:
app: service-test-pod
template:
metadata:
labels:
app: service-test-pod
spec:
containers:
- name: simple-http
image: python:2.7
imagePullPolicy: IfNotPresent
command: ["/bin/bash"]
args:
- -c
- echo '<p>Hello from $(hostname)</p>' > index.html && python -m SimpleHTTPServer 8080
ports:
- name: http
containerPort: 8080
# Service 생성(svc-test.yaml)
apiVersion: v1
kind: Service
metadata:
name: service-test
spec:
selector:
app: service-test-pod
ports:
- protocol: TCP
port: 80
targetPort: 8080
# 서비스 잘 만들어졌는지 확인
kubectl get svc
## service-test ClusterIP 10.109.235.107 <none> 80/TCP 39s
# Ingress 생성(ingress-test.yaml)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-nginx
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: "ingress.test.com"
http:
paths:
- pathType: Prefix
path: /test
backend:
service:
name: service-test
port:
number: 80
# 디플로이먼트를 위한 서비스 생성
kubectl apply -f ingress-test.yaml
# 로컬 PC에 URL과 Ingress 서비스의 EXTERNAL-IP 연결
kubectl get svc -n ingress-nginx
## ingress-nginx-controller LoadBalancer 10.104.241.51 192.168.56.241 80:31530/TCP,443:31238/TCP 47
## 여기서 EXTERNAL-IP에 해당하는 192.168.56.241 을 적어준다.
sudo vi /etc/hosts
192.168.56.241 ingress.test.com
# Ingress 확인
curl http://ingress.test.com/test
## <p>Hello from $(hostname)</p>

호스트 기반 NGINX Ingress Controller 라우팅 설정(ingress-test.yaml)
# Ingress Controller를 이용한 배포 (ingress-resource.yaml)
# backend1 Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend1
spec:
replicas: 2
selector:
matchLabels:
app: backend1
template:
metadata:
labels:
app: backend1
spec:
containers:
- name: backend1
image: nginxdemos/nginx-hello:plain-text
ports:
- containerPort: 8080
---
# backend1 Service
apiVersion: v1
kind: Service
metadata:
name: backend1-svc
spec:
selector:
app: backend1
ports:
- port: 80
targetPort: 8080
protocol: TCP
name: http
---
# backend2 Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend2
spec:
replicas: 1
selector:
matchLabels:
app: backend2
template:
metadata:
labels:
app: backend2
spec:
containers:
- name: backend2
image: nginxdemos/nginx-hello:plain-text
ports:
- containerPort: 8080
---
# backend2 Service
apiVersion: v1
kind: Service
metadata:
name: backend2-svc
spec:
selector:
app: backend2
ports:
- port: 80
targetPort: 8080
protocol: TCP
name: http
# 리소스 생성
kubectl apply -f ingress-resource.yaml
# 리소스 확인
kubectl get pod,service
# 호스트 기반 Ingress생성 (도메인을 가지고 라우팅 하는 것)
# ingress-test.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-nginx
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx # ← 이 줄로 대체 (이제는 권장 방식)
rules:
- host: example1.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: backend1-svc
port:
number: 80
- host: example2.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: backend2-svc
port:
number: 80
# 리소스 배포 후 확인
kubectl apply -f ingress-test.yaml
kubectl get ingress
## NAME CLASS HOSTS ADDRESS PORTS AGE
## ingress-nginx nginx example1.com,example2.com 192.168.56.241 80 24m
# 노드 포트 확인
kubectl get svc -n ingress-nginx
## NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
## ingress-nginx-controller LoadBalancer 10.104.241.51 192.168.56.241 80:31530/TCP,443:31238/TCP 70m
# /etc/hosts 파일에 Ingress Controller의 EXTERNAL-IP와 도메인 연결
192.168.56.241 example1.com example2.com
# 접속 테스트
curl <http://example1.com>
curl <http://example2.com>
## 호스트에 따라서 서로 다른 백엔드가 불려진다.

Path 기반 NGINX Ingress Controller 라우팅 설정(ingress-test.yaml)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-nginx
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: example.com
http:
paths:
- path: /backend1
pathType: Prefix
backend:
service:
name: backend1-svc
port:
number: 80
- path: /backend2
pathType: Prefix
backend:
service:
name: backend2-svc
port:
number: 80
# 배포 후 확인
kubectl get ingress
## NAME CLASS HOSTS ADDRESS PORTS AGE
## ingress-nginx example.com 192.168.56.241 80 39m
# /etc/hosts 파일에 연결
192.168.56.241 example.com
# 확인
curl <http://example.com/backend1>
curl <http://example.com/backend2>

EC2
애플리케이션 배포
- django app 만들기
- 가상 환경 생성: python -m venv ./myvenv
- 가상 환경 활성화:
- cd /app/myvenv/Scripts
- activate
- cd ../../
- django 설치
- django 라이브러리 설치: pip install django
- django 프로젝트 생성: django-admin startproject ec2django
- django 실행
- 디렉토리 이동: cd ec2django
- 서버 실행: python manage.py runserver
- 애플리케이션을 모든 컴퓨터에서 실행할 수 있도록 설정을 수정
- settings.py 파일의 ALLOWED_HOSTS 부분을 *로 수정
- ALLOWED_HOSTS = ['*']
- 의존성 라이브러리를 별도의 파일에 기록
- pip freeze > requirements.txt (다른 곳에 옮겨주려면 이 작업을 해줘야 한다. 다른 곳에서 동일한 환경을 재현하기 위해서)
- git hub에 push
- EC2에서 코드를 가져와서 실행
- sudo apt update
- sudo apt inatll git
- git clone URL
- sudo apt upgrade python3
- sudo pip install -r requirements.txt --break-system-packages
- pip install django --break-system-packages
- sudo python3 manage.py runserver 0.0.0.0.:80
- 다른 컴퓨터의 브라우저에서 EC2의 http://EC2 의 Public IP
- 접속이 안되면 EC2의 보안 그룹에서 80번 포트가 열려있는지 확인
도메인 연결 - Route53 서비스
- 웹 애플리케이션의 경우 일반적으로 IP를 기반으로 통신하지 않고 도메인을 기반으로 통신한다.
- IP 주소에는 HTTPS를 적용할 수 없으므로 HTTPS를 적용하고자 한다면 도메인은 필수이다.
- Route53 이외에도 DNS 역할을 사는 서비스는 많다.
도메인과 EC2 연결
- Route53에서 구입한 도메인을 클릭
- 레코드 생성 버튼 클릭
- 레코드 이름(도메인) 설정하고 A레코드를 선택하고 EC2의 public ip 주소를 입력한다.
Elastic Load Balancing
ELB
- AWS가 제공하는 Load Balancer
- Load Balancer는 집중되는 접속을 여러 대나 네트워크에 분배하는 장비
- 한 대에 집중되는 부하를 분산시키기 때문에 부하 분산 장치라고도 한다.
- ELB 종류
- ALB
- HTTP 및 HTTPS에 가장 적합한 Load Balancer로 OSI 모형의 애플리케이션 계층에서 동작한다. 요청하는 명령어를 보고 판단하기 때문에 대상의 URL 디렉토리 단위로 분배하는 것이 가능하며 인스턴스와 LoadBalancer 사이의 통신은 암호화가 가능하다.
- 분배 대상으로 정적 IP 주소를 설정하고 그 IP를 가진 호스트 기기로 전송할 수 없다.
- HTTP와 HTTPS를 지원한다.
- NLB
- OSI 계층 중 4계층에서 동작하는데 패킷이라고 불리는 단편 데이터밖에 볼 수 없기 때문에 ALB만큼 상세하게 분배할 수 없지만 분배 대상의 정적 IP 주소를 설정할 수 있고 서버에 접속한 클라이언트의 IP 주소를 그대로 서버에 전송하도록 설정할 수 있다.
- TCP, TLS 등을 지원한다.
- CLB
- 오래된 유형의 Load Balancer
- 지원하는 프로토콜이 많다.
- 앞으로 구축하는 시스템에는 사용하지 않는 것을 권장한다.
- TCP, SSL/TLS, HTTP, HTTPS 등을 지원
- ALB
- 요금 체계
- 시간 당 요금과 LCU(Load Balancer 용량 단위) 요금의 합계로 계산한다.
- 시간 당 단가는 1시간 당 0.0225 달러 정도이고 LCU 요금은 1시간당 0.005 달러이다.
- 에러가 발생하는 경우
- 최대 접속 시간 제한이라는 설정이 있는데 디폴트는 60초로 지정되어 있으며 Load Balancer가 60초 동안 아무런 데이터도 전달 받지 못할 경우 연결을 자동으로 종료하고 타임 아웃 에러를 생성한다.
- 대표적인 에러가 애플리케이션 또는 데이터 서버에서 특정 시간 내에 응답을 받지 못할 경우 생기는 Load Balancer Error, 504 Error로 서버 레이어나 데이터베이스 레이어에서 발생하기 때문에 상대적으로 쉽게 해결할 수 있다.
- 현재 돌아가는 애플리케이션의 규모가 크다면 최대 접속 시간 제한을 변경해서 Load Balancer가 기다려줄 수 있는 시간을 조금이라도 늘려서 해결하거나 직접 애플리케이션을 수정해서 서버로 전송되는 데이터의 양을 조절하거나 응답 시간을 최적화 시켜야 한다.
- Load Balancer 연결
- EC2 하단에 로드 밸런서 > Application Load Balancer 생성
- EC2 하단에 대상 그룹 > 대상 그룹 생성
- 다시 Load Balancer에 가서 리스너 및 라우딩] 프로토콜 http, 포트 80, 만든 대상 그룹 선택
HTTPS 적용
SSL/TLS
- HTTP를 HTTPS로 바꿔주는 인증서
- HTTP가 아닌 HTTPS로 통신할 수 있게 만들 수 있다.
인증서 발급
- AWS Certificate Manager 서비스에 접속
- 인증서 요청 클릭
- 도메인을 작성
- 인증서가 만들어지면서 검증 대기 중 일텐데 이 때 Route53에서 레코드 생성 버튼을 눌러서 레코드를 생성한다.
728x90
반응형