반응형
Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- 알고리즘
- 고차원 함수
- 완주하지 못한 선수
- 루씬 인 액션
- 코딩 테스트
- 프로그래머스
- 스프링 스케쥴러
- H-index
- 기능개발
- 크론 표현식
- kubenetes
- 가장 큰 수
- 해시
- 모던 자바 인 액션
- @configuration
- @Getter
- 영속 자료구조
- 정렬
- 검색 기능 확장
- @Setter
- 쿠버네티스
- 커링
- @Data
- 전화번호 목록
- 다리를 지나는 트럭
- 롬복 어노테이션
- @EnableScheduling
- Java
- 스택/큐
- K번째수
Archives
- Today
- Total
Today I Learned
[쿠버네티스 인 액션] 5. 서비스: 클라이언트가 파드를 검색하고 통신을 가능하게 함 (3) 본문
728x90
5.4 인그레스 리소스로 서비스 외부 노출
- 앞서 설명한 방법 외에도 인그레스 리소스를 생성해 외부 클라이언트에 서비스를 노출할 수 있다.
인그레스가 필요한 이유
- 로드밸런서 서비스는 자신의 공용 IP 주소를 가진 로드밸런서가 필요하지만, 인그레스는 한 IP 주소로 수십 개의 서비스에 접근이 가능하도록 지원해준다.
- 클라이언트가 HTTP 요청을 인그레스에 보낼 때, 요청한 호스트와 경로에 따라 요청을 전달할 서비스를 결정한다.
- 인그레스는 네트워크 스택의 애플리케이션 계층(HTTP)에서 작동하며 서비스가 할 수 없는 쿠키 기반 세션 어피니티 등과 같은 기능을 제공할 수 있다.
인그레스 컨트롤러가 필요한 경우
- 인그레스 리소스를 작동시키려면 클러스터에 인그레스 컨트롤러를 실행해야 한다. 쿠버네티스 환경마다 다른 컨트롤러 구현을 사용할 수 있지만 일부는 기본 컨트롤러를 제공하지 않는다.
5.4.1 인그레스 리소스 설정
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: kubia
spec:
rules:
- host: kubia.example.com
http:
paths:
- path: /
backend:
serviceName: kubia-nodeport
servicePort: 80
5.4.2 인그레스로 서비스 엑세스
- http://kubia.example.com 서비스에 엑세스하려면 도메인명이 인그레스 컨트롤러의 IP와 매핑되도록 확인해야 한다.
인그레스의 IP 주소 얻기
인그레스 컨트롤러가 구성된 호스트의 IP를 인그레스 엔드포인트로 지정
- kubia.example.com을 해당 IP로 확인하도록 DNS 서버를 구성하거나, 다음 줄을 /etc/hosts에 추가할 수 있다.
인그레스로 파드 엑세스
- 이제 http://kubia.example.com 서비스에 엑세스할 수 있다.
인그레스 동작 방식
- 인그레스 컨트롤러는 대부분 요청을 서비스로 전달하지 않으며, 파드를 선택하는 데만 사용한다.
5.4.3 하나의 인그레스로 여러 서비스 노출
- 인그레스 스펙은 규칙과 경로가 모두 배열이므로 여러 항목을 가질 수 있다.
동일한 호스트의 다른 경로로 여러 서비스 매핑
...
- host: kubia.example.com
http:
paths:
- path: /kubia
backend:
serviceName: kubia
servicePort: 80
- path: /bar
backend:
serviceName: bar
servicePort: 80
- 요청은 URL의 경로에 따라 두 개의 다른 서비스로 전송된다. 따라서 클라이언트는 단일 IP 주소로 두 개의 서비스에 도달할 수 있다.
서로 다른 호스트로 서로 다른 서비스 매핑하기
spec:
rules:
- host: kubia.example.com
http:
paths:
- path: /
backend:
serviceName: foo
servicePort: 80
- host: bar.example.com
http:
paths:
- path: /
backend:
serviceName: bar
servicePort: 80
- 요청은 호스트 헤더에 따라 서비스로 전달되며, DNS는 foo.example.com과 bar.example.com 도메인을 모두 인그레스 컨트롤러의 IP 주소로 지정해야 한다.
5.4.4 TLS 트래픽을 처리하도록 인그레스 구성
- HTTPS로 트래픽을 전달하기 위해 TLS를 지원하도록 인그레스를 구성하는 방법을 살펴보자.
인그레스를 위한 TLS 인증서 생성
- 클라이언트가 인그레스 컨트롤러에 대한 TLS 연결을 하면 컨트롤러는 TLS 연결을 종료한다.
- 클라이언트와 컨트롤러 간의 통신은 암호화되지만 컨트롤러와 백엔드 파드 간의 통신은 암호화되지 않는다.
- 파드에서 실행 중인 애플리케이션은 TLS를 지원할 필요가 없다.
- 이를 위해 개인키와 인증서가 필요하다.
- 그리고 두 파일로 시크릿을 만든다. (시크릿은 7장에서 자세히 설명한다)
- 개인키와 인증서는 tls-secret이라는 시크릿에 저장되며, 인그레스 오브젝트를 업데이트하면 kubia.example.com에 대한 https 요청도 수락할 수 있다.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: kubia
spec:
tls:
- hosts:
- kubia.example.com
secretName: tls-secret
rules:
- host: kubia.example.com
http:
paths:
- path: /
backend:
serviceName: kubia-nodeport
servicePort: 80
- 명령어 출력에는 애플리케이션의 응답과 인그레스에 구성한 서버 인증서가 표시된다.
5.5 파드가 연결을 수락할 준비가 됐을 때 신호 보내기
- 적절한 레이블을 가진 새 파드가 만들어지자마자 서비스의 일부가 돼 요청이 파드로 전달되기 시작한다.
- 하지만 파드의 구성 시간이나 데이터 로드 등으로 인해 파드가 즉시 요청을 처리할 준비가 되어있지 않을 수 있다.
5.5.1 레디니스 프로브 소개
- 라이프니스 프로브와 마찬가지로 세 가지 유형의 레디니스 프로브가 있다.
- Exec 프로브는 프로세스를 실행하며, 컨테이너 상태를 프로세스의 종료 상태 코드로 결정한다.
- HTTP GET 프로브는 HTTP GET 요청을 컨테이너로 보내고 응답의 HTTP 상태코드를 통해 컨테이너가 준비됐는지 결정한다.
- TCP 소켓 프로브는 컨테이너로 지정된 포트로 TCP 연결을 연다. 소켓이 연결되면 컨테이너가 준비된 것으로 간주한다.
레디니스 프로브의 동작
- 첫 번째 레디니스 점검을 수행하기 전에 구성 가능한 시간이 경과하기를 기다리도록 구성할 수 있다.(initialDelaySecond)
- 그리고 주기적으로 프로브를 호출하면서 레디니스 프로브의 결과에 따라 작동한다.
- 파드가 준비되지 않았다면 서비스에서 제거하고, 준비되면 다시 서비스에 추가한다.
- 라이브니스 프로브와 달리 컨테이너가 준비 상태 점검에 실패하더라도 컨테이너가 종료되거나 다시 시작되지 않는다.
레디니스 프로브가 중요한 이유
- 파드 그룹이 다른 파드에 제공하는 서비스에 의존한다고 가정할 때, 파드 중 하나가 요청을 처리할 준비가 되지 않았다면 레디니스 프로브를 통해 쿠버네티스에게 알리고 다른 파드 인스턴스로 요청을 보내 정상적으로 처리할 수 있다.
5.2.2 파드에 레디니스 프로브 추가
파드 템플릿에 레디니스 프로브 추가
$kubectl edit rc kubia
apiVersion: v1
kind: ReplicationController
metadata:
name: kubia
spec:
replicas: 3
selector:
app: kubia
template:
metadata:
labels:
app: kubia
spec:
containers:
- name: kubia
image: luksa/kubia
ports:
- name: http
containerPort: 8080
readinessProbe:
exec:
command:
- ls
- /var/ready
- 레디니스 프로브는 컨테이너 내부에서 ls /var/ready 명령어를 주기적으로 수행한다.
- ls 명령어는 파일이 존재하면 종료 코드 0을 반환하고 그렇지 않으면 다른 값을 반환한다. 파일이 있다면 레디니스 프로브가 성공한다.
- 레플리케이션컨트롤러의 파드 템플릿을 변경해도 기존 파드에는 영향을 미치지 않으므로, 기존 파드는 여전히 레디니스 프로브가 정의되어 있지 않다.
- 파드를 삭제했다가 레플리케이션컨트롤러로 인해 재생성되면, 새 파드는 레디니스 점검에 실패하고 각각에 /var/ready 파일을 만들 때까지 서비스의 엔드포인트에 포함되지 않는다.
파드의 레디니스 상태 확인과 수정
- 파드를 삭제하고 다시 조회하면 READY 열에 준비된 컨테이너가 없음으로 표시된다.
- /var/ready 파일을 만들어 레디니스 프로브가 성공하도록 반환해야 한다.
$kubectl exec kubia-zsrht -- touch /var/ready
- 레디니스 프로브는 기본으로 10초마다 호출되므로, 파드가 아직 준비되지 않았다면 레디니스 프로브가 호출되지 않은 것이다.
하나의 READY 파드로 서비스 호출
- 세 개의 파드가 실행 중이지만 하나의 파드만 준비됐음을 보고하기 때문에 이 파드가 요청을 수신하는 유일한 파드다.
5.3.3 실제 환경에서 레디니스 프로브가 수행해야 하는 기능
- 실제 환경에서 레디니스 프로브는 애플리케이션이 클라이언트의 요청을 수신할 수 있는지 여부에 따라 성공 또는 실패를 반환해야 한다.
- 서비스에서 파드를 수동으로 제거하려면 수동으로 프로브의 스위치를 전환하는 대신 파드를 삭제하거나 파드의 레이블을 변경해야 한다.
레디니스 프로브를 항상 정의하라
- 레디니스 프로브를 추가하지 않으면 파드가 시작하는 즉시 서비스 엔드 포인트가 된다.
- 애플리케이션이 수신 연결을 시작하는 데 오래걸리는 경우 클라이언트 요청은 수신 연결을 수락할 준비가 되지 않은 상태에서 파드로 전달된다.
- 따라서 클라이언트는 "Connection refused" 유형의 에러를 보게 된다.
레디니스 프로브에 파드의 종료 코드를 포함하지 마라
- 파드가 종료할 때, 실행되는 에플리케이션은 종료 신호를 받자마자 연결 수락을 중단한다. 그렇기 때문에 종료 절차가 시작되는 즉시 레디니스 프로브가 실행하도록 만들어 파드가 모든 서비스에서 확실하게 제거되어야 한다고 생각할 수 있다.
- 하지만 쿠버네티스는 파드를 삭제하자마자 모든 서비스에서 파드를 제거하기 때문에 불필요하다.
5.6 헤드리스 서비스로 개별 파드 찾기
- 서비스의 연결은 임의의 파드로 전달된다. 하지만 클라이언트가 모든 파드에 연결해야하는 경우라면 각 파드의 IP를 알아야 한다.
- 클라이언트가 쿠버네티스 API 서버를 호출해 파드의 IP 주소 목록을 가져올 수 있지만 애플리케이션과 쿠버네티스는 무관하게 유지하도록 해야하므로 바람직하지 않다.
- 일반적으로 DNS 조회를 수행하면 하나의 IP(서비스의 클러스터 IP)를 반환하지만, 서비스를 헤드리스로 설정해놓으면 DNS 서버는 서비스 IP 대신 파드 IP들을 반환한다.
5.6.1 헤드리스 서비스 생성
- 서비스 스펙에서 clusterIP 필드를 None으로 설정하면 쿠버네티스는 클라이언트가 서비스의 파드에 연결할 수 있는 클러스터 IP를 할당하지 않기 때문에 서비스가 헤드리스 상태가 된다.
apiVersion: v1
kind: Service
metadata:
name: kubia-headless
spec:
clusterIP: None
ports:
- port: 80
targetPort: 8080
selector:
app: kubia
5.6.2 DNS로 파드 찾기
- 클러스터에서 실행중인 파드 내부에서 DNS 조회를 위해 필요한 바이너리가 포함된 이미지를 기반으로 새 파드를 실행하자
(kubia 컨테이너에는 nslookup이 포함되어있지 않으므로 DNS 조회를 할 수 없다). - 도커 허브의 nslookup 및 dig 바이너리를 모두 포함하는 tutum/dnsutils 컨테이너 이미지를 사용할 수 있다.
YAML 메니페스트를 쓰지 않고 파드 실행
- kubectl run 명령어를 사용해 YAML 메니페스트를 작성하지 않고 파드만 생성한다.
- 책에 나온 명령어를 수행하면 다음과 같은 error가 발생하는데, generator 옵션이 deprecated 되서 그렇다.
https://community.kodekloud.com/t/unknown-tag-generator/25444
- 대신 다음 명령어로 수행할 수 있다.
$kubectl run dnsutils --image=tutum/dnstuils --command -- sleep infinity
헤드리스 서비스를 위해 반환된 DNS A 레코드
$kubectl exec dnsutils -- nslookup kubia-headless
- DNS 서버는 kubia-headless.default.svc.cluster.local FQDN 에 대해 준비되 파드들의 IP를 각각 반환한다.
- 이는 kubia 서비스와 같이 일반 서비스를 DNS가 반환하는 것과 다르다.
- 헤드리스 서비스를 사용하더라도 클라이언트는 일반 서비스와 마찬가지로 서비스의 DNS 이름으로 파드에 연결할 수 있지만, DNS가 파드의 IP를 반환하기 때문에 클라이언트는 서비스 프록시 대신 파드에 직접 연결한다.
5.6.3 모든 파드 검색 - 준비되지 않은 파드 소개
- 준비되지 않은 파드를 포함해서 서비스 레이블 셀렉터에 매칭되는 모든 파드를 찾고자 한다면 DNS 조회 메커니즘을 사용할 수 있다.
- 쿠버네티스가 파드의 레디니스 상태에 관계없이 모든 파드를 서비스에 추가되게 하려면 서비스에 다음 어노테이션을 추가해야 한다.
5.7 서비스 문제 해결
- 서비스로 파드에 엑세스할 수 없는 경우 다음과 같은 내용을 확인한 후에 다시 시작해보자.
- 외부가 아닌 클러스터 내에서 서비스 클러스터 IP에 연결되는지 확인한다.
- 서비스에 엑세스할 수 있는지 확인하려고 서비스 IP로 핑을 할 필요 없다(서비스 클러스터 IP는 가상 IP이므로 핑되지 않는다).
- 레디니스 프로브를 정의했다면 성공했는지 확인하라. 그렇지않으면 파드는 서비스에 포함되지 않는다.
- 파드가 서비스의 일부인지 확인하려면 kubectl get endpoints를 사용해 해당 엔드포인트 오브젝트를 확인한다.
- FQDN이나 그 일부로 서비스에 엑세스하려고 하는데 작동하지 않는 경우, FQDN 대신 클러스터 IP를 사용해 엑세스할 수 있는지 확인한다.
- 대상 포트가 아닌 서비스로 노출된 포트에 연결하고 있는지 확인한다.
- 파드 IP에 직접 연결해 파드가 올바른 포트에 연결돼 있는지 확인한다.
- 파드 IP로 애플리케이션에 엑세스 할 수 없는 경우 애플리케이션이 로컬호스트에만 바인딩하고 있는지 확인한다.
728x90
'쿠버네티스' 카테고리의 다른 글
[쿠버네티스 인 액션] 6. 볼륨: 컨테이너에 디스크 스토리지 연결 (2) (0) | 2022.10.20 |
---|---|
[쿠버네티스 인 액션] 6. 볼륨: 컨테이너에 디스크 스토리지 연결 (1) (0) | 2022.10.07 |
[쿠버네티스 인 액션] 5. 서비스: 클라이언트가 파드를 검색하고 통신을 가능하게 함 (2) (0) | 2022.09.26 |
[쿠버네티스 인 액션] 5. 서비스: 클라이언트가 파드를 검색하고 통신을 가능하게 함 (1) (0) | 2022.09.13 |
[쿠버네티스 인 액션] 4. 레플리케이션과 그 밖의 컨트롤러: 관리되는 파드 배포 (2) (0) | 2022.08.25 |
Comments