# 두 개의 디플로이먼트를 실행한다.
kubectl apply -f sleep/sleep1.yaml -f sleep/sleep2.yaml
# 파드가 완전히 시작될 때까지 기다린다.
kubectl wait --for=condition=Ready pod -l app=sleep-2
# 두 번째 파드의 IP 주소를 출력한다.
kubectl get pod -l app=sleep-2 --output jsonpath='{.items[0].status.podIP}'
# 첫 번째 파드에서 두 번째 파드로 ping을 2번 보낸다.
kubectl exec deploy/sleep-1 -- ping -c 2 $(kubectl get pod -l app=sleep-2 --output jsonpath='{.items[0].status.podIP}')
PING 10.1.0.22 (10.1.0.22): 56 data bytes
64 bytes from 10.1.0.22: seq=0 ttl=64 time=0.976 ms
64 bytes from 10.1.0.22: seq=1 ttl=64 time=0.135 ms
--- 10.1.0.22 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.135/0.555/0.976 ms
# 파드의 IP 주소를 확인한다.
kubectl get pod -l app=sleep-2 --output jsonpath='{.items[0].status.podIP}'
# 파드를 삭제한다.
kubectl delete pod -l app=sleep-2
# 파드의 IP 주소를 확인한다. 디플로이먼트가 삭제된 파드를 다시 생성하였으므로 새로운 IP 주소가 부여된다.
kubectl get pod -l app=sleep-2 --output jsonpath='{.items[0].status.podIP}'
# API 버전
apiVersion: v1
kind: Service
# 서비스 이름이다. 도메인 네임으로 사용된다.
metadata:
name: sleep-2
# 서비스 정의에는 셀렉터와 포트 목록이 포함되어야 한다.
spec:
selector:
app: sleep-2 # app 레이블의 값이 sleep-2인 모든 파드가 대상이다.
ports:
- port: 80 # 80번 포트를 주시하다가 파드의 80번 포트로 트래픽을 전달한다.
kubectl apply
명령을 사용하여 배포한다.kubectl apply -f service.yaml
# 서비스의 상세 정보를 출력한다.
kubectl get svc sleep-2
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
sleep-2 ClusterIP 10.108.29.118 <none> 80/TCP 11s
# sleep-1 파드에서 sleep-2 파드로 ping을 보낸다.
kubectl exec deploy/sleep-1 -- ping -c 1 sleep-2
# sleep-2 서비스의 클러스터 IP 주소와 같다.
PING sleep-2 (10.108.29.118): 56 data bytes
# 실패한다.
--- sleep-2 ping statistics ---
1 packets transmitted, 0 packets received, 100% packet loss
command terminated with exit code 1
서비스를 yaml에 정의할 때 유형(type)을 정의할 수 있다. 기본 값은 클러스터IP(ClusterIP)이다.
클러스터IP는 클러스터 전체에서 사용되는 IP 주소를 생성한다. 이 IP 주소는 파드가 어떤 노드에 있더라도 접근 가능하다. 하지만 클러스터 내에서만 유효하다.
따라서 클러스터IP는 파드와 파드 간 통신에서만 쓰인다.
웹 애플리케이션과 API 서버로 이루어진 예제를 아래와 같이 실행해본다.
# 웹 애플리케이션과 API 서버 두 개의 디플로이먼트를 실행한다.
kubectl apply -f numbers/api.yaml -f numbers/web.yaml
# 준비가 끝날 때까지 기다린다.
kubectl wait --for=condition=Ready pod -l app=numbers-web
# 웹 애플리케이션에 포트 포워딩을 적용한다.
kubectl port-forward deploy/numbers-web 8080:80
localhost:8080에 접속하여 버튼을 클릭하면 아래와 같이 오류가 발생한다. 웹 애플리케이션에서 numbers-api 도메인으로 API를 호출하는데 오류가 발생한 것이다.
쿠버네티스 내부 DNS 서버에 numbers-api 서비스를 등록한다.
kubectl apply -f numbers/api-service.yaml
numbers-api
이고 해당 도메인으로 요청시 app
레이블의 값이 numbers-api
인 모든 파드의 80번 포트로 요청을 전달한다.apiVersion: v1
kind: Service
metadata:
name: numbers-api # 서비스 이름이 도메인 네임이 된다.
spec:
ports:
- port: 80
selector:
app: numbers-api
type: ClusterIP
다시 포트포워딩을 시작하고 localhost:8080에 접속하여 버튼을 클릭하면 아래와 같이 랜덤 숫자가 잘 출력된다.
웹 애플리케이션에서 numbers-api로 요청을 보내면 위에서 정의한 서비스에 의해 API 서버 파드로 요청이 전달되는 것이다.
API 파드는 디플로이먼트가 관리한다. 수동으로 파드를 지워도 대체 파드가 생성된다. 생성된 파드 역시 API 서비스에 정의된 레이블 셀렉터와 일치하므로 웹 애플리케이션에서 API 서버에 요청을 보내면 기존처럼 잘 전달된다.
# API 파드의 이름과 IP 주소를 확인한다.
kubectl get pod -l app=numbers-api -o custom-columns=NAME:meta
data.name,POD_IP:status.podIP
# 아래와 같이 출력된다.
NAME POD_IP
numbers-api-545b9d9ccd-nmp2c 10.1.0.26
# API 파드를 수동으로 삭제한다.
kubectl delete pod -l app=numbers-api
# 아래와 같이 출력된다.
pod "numbers-api-545b9d9ccd-nmp2c" deleted
# API 파드의 이름과 IP 주소를 확인한다.
kubectl get pod -l app=numbers-api -o custom-columns=NAME:metadata.name,POD_IP:status.podIP
# 아래와 같이 출력된다.
NAME POD_IP
numbers-api-545b9d9ccd-9cg8k 10.1.0.27
apiVersion: v1
kind: Service
metadata:
name: numbers-web
spec:
ports:
- port: 8080 #서비스가 주시하는 포트
targetPort: 80 # 트래픽이 전달될 파드의 포트
selector:
app: numbers-web
type: LoadBalancer # 로드밸런서 서비스
# 로드밸런서 서비스를 배포한다.
kubectl apply -f numbers/web-service.yaml
# 아래와 같이 출력된다.
service/numbers-web created
# 서비스의 상세 정보를 확인한다.
kubectl get svc numbers-web
# 아래와 같이 출력된다. CLUSTER IP는 클러스터안에서의 IP 주소이다. EXTERNAL IP 주소로 들어오는 트래픽을 클러스터에 전달한다. EXTERNAL IP는 클러스터에서 제공되는 주소이다.
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
numbers-web LoadBalancer 10.105.62.64 localhost 8080:30752/TCP 8s
# 애플리케이션의 URL을 EXTERNAL IP로 출력한다.
kubectl get svc numbers-web -o jsonpath='http://{.status.loadBalancer.ingress[0].*}:8080'
apiVersion: v1
kind: Service
metadata:
name: numbers-web-node
spec:
ports:
- port: 8080 # 다른 파드가 서비스에 접근하기 위해 사용하는 포트
targetPort: 80 # 대상 파드에 트래픽을 전달하는 포트
nodePort: 30080 # 서비스가 외부에 공개되는 포트
selector:
app: numbers-web
type: NodePort # 노드의 IP 주소를 통해 접근 가능한 서비스
db-service
를 사용하면 쿠버네티스 DNS 서버에서 외부 도메인 app.mydatabase.io
로 해소한다.# 현재 배포된 클러스터 IP 서비스를 삭제한다.
kubectl delete svc numbers-api
# 익스터널네임 서비스를 배포한다.
kubectl apply -f numbers-services/api-service-externalName.yaml
# 서비스 상세 정보를 확인한다.
kubectl get svc numbers-api
# 새로운 서비스는 깃허브의 도메인을 가리킨다.
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
numbers-api ExternalName <none> raw.githubusercontent.com <none> 10s
http://numbers-api/sixeyed/kiamol/master/ch03/numbers/rng
를 그대로 사용한다. raw.githubusercontent.com
로 대체되어 http://raw.githubusercontent.com/sixeyed/kiamol/master/ch03/numbers/rng
가 호출된다.apiVersion: v1
kind: Service
metadata:
name: numbers-api
spec:
type: ExternalName
externalName: raw.githubusercontent.com # 로컬 도메인 네임을 해소할 외부 도메인
apiVersion: v1
kind: Service
metadata:
name: numbers-api
spec:
type: ClusterIP # selector 필드가 없으므로 헤드리스 서비스가 된다.
ports:
- port: 80
---
kind: Endpoints #한 파일에 두 번째 리소스를 정의한다.
apiVersion: v1
metadata:
name: numbers-api
subsets:
- addresses: # 정적 IP 주소 목록
- ip: 192.168.123.234
ports:
- port: 80 # 각 IP 주소에서 주시할 포트
numbers-api
도메인 네임으로 보낸 요청이 192.168.123.234:80
으로 연결된다.# 기존 서비스를 제거한다.
kubectl delete svc numbers-api
# 헤드리스 서비스를 배포한다.
kubectl apply -f numbers-services/api-service-headless.yaml
# 서비스의 상세 정보를 확인한다.
kubectl get svc numbers-api
# 서비스 자체의 유형은 클러스터 IP로 클러스터 내부의 가상 IP 주소를 가진다.
numbers-api ClusterIP 10.106.122.106 <none> 80/TCP 10s
# 엔드포인트 상세 정보를 확인한다.
kubectl get endpoints numbers-api
# 클러스터IP가 실제 연결하는 주소를 볼 수 있다.
NAME ENDPOINTS AGE
numbers-api 192.168.123.234:80 74s