Service에 대해 공부한 내용을 정리한 글입니다.
쿠버네티스 공식 홈페이지 - Service and Expose (https://kubernetes.io/docs/concepts/services-networking/service/)를 참고하여 진행하였습니다.
또한, 마스터 노드1, 워커노드 2로 실습 진행하였습니다.
🤣🤩😊CKA 자격증 준비 및 쿠버네티스 공부 정리입니다.
Kubernetes에서 서비스는 하나 이상의 서비스로 실행되는 네트워크 애플리케이션을 노출하는 방법입니다.
- 익숙하지 않은 서비스 검색 매커니즘을 사용하기 위해 기존 애플리케이션을 수정할 필요가 없습니다
- 쿠버네티스 내부의 다양한 객체들이 애플리케이션과, 애플리케이션이 다른 외부의 애플리케이션이나 사용자와 연결될 수 있도록 도와주는 역할을 합니다.
- 클라이언트가 상호작용할 수 있도록 서비스를 사용하여 해당 포드 세트를 네트워크에서 사용할 수 있게 만듭니다.
pod들은 동적으로 생성되고 삭제될 수 있습니다.
pod들은 자체 IP주소를 갖습니다.
그렇기 때문에 새로 생성되는 pod들끼리 IP가 충돌이 일어날 수 있게 됩니다.
애플리케이션의 일부 부분(예: 프런트엔드)의 경우 클러스터 외부에서 액세스할 수 있는 외부 IP 주소에 서비스를 노출할 수 있습니다.
- 클러스터 내부 IP에 서비스를 노출합니다. 이 값을 선택하면 클러스터 내에서만 서비스에 연결할 수 있습니다.
type
을 서비스에 대해 명시적으로 지정하지 않은 경우 사용되는 기본값입니다 .- Ingress 또는 Gateway를 사용하여 공용 인터넷에 서비스를 노출할 수 있습니다 .
<ClusterIP>
로 들어온 클러스터 내부 트래픽을 해당 파드의<파드IP>: targetport>
로 넘겨주도록 동작하므로, 오직 클러스터 내부에서만 접근 가능하게 됩니다.
# my-nginx라는 Pod 정의
apiVersion: v1
kind: Pod
metadata:
name: my-nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
# my-service라는 Service 정의
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: ClusterIP
selector:
app: nginx # app: nginx라는 label를 가진 pod를 찾음
ports:
- name: http
port: 80 # Service의 port
targetPort: 80 # pod의 spec.containers.ports 가르킴
protocol: TCP
ClusterIP는 .spec.ports
에 port, targetPort의 속성을 가집니다.
.spec.ports.port
: 서비스 리소스의 포트
.spec.ports.targetPort
: 파드(대상) 리소스의 포트
.spec.selector
: 파드 레이블 셀렉터, 엔드포인트 리소스 생성
my-service.yaml 을 적용해보았습니다.
$ kubectl apply -f [파일명]
80번 port로 type: ClusterIP로 생성이 되었습니다.
Service의 label selector의 값인 app: nginx에 해당되는 pod가 생성되자 endpoint 주소가 생겨남을 확인할 수 있었습니다.
- NodePort 서비스 유형은 ClusterIP 서비스 유형의 확장입니다. 따라서 ClusterIP도 자동으로 생성됩니다.
- NodePort는 외부에서 노드 IP의 특정 포트(
<NodeIP>:<NodePort>
)로 들어오는 요청을 감지하여, 해당 포트와 연결된 파드로 트래픽을 전달하는 유형의 서비스입니다.- NodePort 타입에서는
spec.ports
아래에 nodePort 속성을 추가로 지정할 수 있다. nodePort는 외부에서 노드 안의 특정 서비스로 접근할 수 있도록 지정된 노드의 특정 포트를 의미한다.- nodePort로 할당 가능한 포트 번호의 범위는 30000 ~ 32767 사이이며, 미지정시 해당 범위 안에서 임의로 부여된다.
# NodePort 타입으로 생성한 Service
apiVersion: v1
kind: Service
metadata:
name: my-service2
spec:
type: NodePort
ports:
- targetPort: 80
port: 80
nodePort: 30008
selector:
app: nginx
my-service2를 적용해보자
PORTS
에 <service Port: node Port
> 형태로 80:30008이 지정되어 있는 것을 알 수 있습니다.
NodePort의 경우에도 spec.selector에 해당하는 모든 파드들에 동일한 로드 밸런싱이 적용됩니다.
클러스터의 모든 노드는 할당된 포트에서 수신 대기하고 해당 서비스와 연결된 준비된 엔드포인트 중 하나로 트래픽을 전달하도록 자체 구성됩니다.
node_IP:nodePort
를 통해 endpoint인 pod로 접근이 가능해진다.
- Nodeport 타입의 확장판이라고 할 수 있으며 서비스를 외부에 노출 할 수 있습니다.
- NodePort타입 앞단에 Loadbalancer가 붙어서 살아있는 노드를 체크하여 트래픽을 전달 할 수 있는 장점이 있습니다.
- 클라우드 공급업체(AWS, GCP 등)에서 지원하는 기능입니다.
- 서비스를 클라우드 제공자 측의 자체 로드 밸런서로 노출시키며, 이에 필요한 NodePort와 ClusterIP 역시 자동 생성된다.
- 클라우드 제공자의 프로비저닝 된 load balancer의 정보는 추가로
status.loadBalancer
에 표기한다.- 로드 밸런서 프로비저닝을 지원하지 않는 클라우드 환경일 경우 NodePort와 같은 방식으로 동작한다.
#loadBalancer 타입의 service 정의
apiVersion: v1
kind: Service
metadata:
name: my-service3
spec:
type: LoadBalancer
selector:
app: nginx
ports:
- port: 80
targetPort: 80
nodePort: 30009 # nodePort 타입으로 my-service2를 만들었기에
# 30009번 포트로 할당해줍니다!!
이 환경이 클라우드 환경이었으면 EXTERNAL-IP가 할당이 되었을테지만, 온프레미스 환경에서는 클러스터가 LocadBalancer 타입을 지원하지 않기에 pending상태로 남아있게 됩니다.
따라서 우리는 로드밸런서를 직접 설치해서 사용해보겠습니다.(Manifest)
sejong.jeonjo@gmail.comd의 블로그
metallb 공식 홈페이지
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.11/config/manifests/metallb-native.yaml
## 아래 명령을 수행
$ kubectl edit configmap -n kube-system kube-proxy
... 중간 생략 ...
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"
ipvs:
strictARP: true ## 이 부분을 수정한다. false -> true
... 중간 생략 ...
$ kubectl get -n metallb-system pod
# my-network.yaml 생성
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: first-pool
namespace: metallb-system
spec:
addresses:
- 10.1.4.160/28
- 10.1.4.176/28
- 10.1.4.192-10.1.4.200
---
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: second-pool
namespace: metallb-system
spec:
addresses:
- 10.1.4.150-10.1.4.159
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: my-network-l2
namespace: metallb-system
spec:
ipAddressPools:
- first-pool
- second-pool
$ kubectl apply -n metallb-system -f my-network.yaml
주의할 점:
- 위와 같이 L2Advertisement, IPAddressPool을 변경하고 적용해도 실제로 Service resource가 생성될 때, 과거의 IPAddressPool을 이용한다.
- 과감하게 metallb-system 네임스페이스의 controller pod를 종료시키고 재기동하면 새로운 IPAddressPool이 적용된다.
여기까지 진행했다면 아까 pending상태였던 my-service3의 상태를 확인해 보겠습니다.
EXTERNAL-IP가 10.1.4.160으로 잘 설정이 되었습니다.
이제 확인해보겠습니다.
loadBalancer -> service -> pod 순으로 잘 적용하는 것을 알 수 있습니다.
부하 분산기(load balancer)는 외부 부하 분산기, 내부 부하 분산기로 각각 외부ip, 내부ip를 할당 받아서 사용할 수 있습니다.
spec.allocateLoadBalancerNodePorts
속성을 설정하여 선택적으로 서비스에 대한 노드 포트 할당을 비활성화 할 수 있습니다.spec.allocateLoadBalancerNodePorts
유형 true은 노드 포트를 계속 할당합니다.
- ExternalName 유형의 서비스는 외부 DNS 이름에 대한 내부 별칭을 제공합니다. 내부 클라이언트는 내부 DNS 이름을 사용하여 요청을 수행하고, 요청이 외부 이름으로 리디렉션됩니다.
# ExternalName type의 service 정의
apiVersion: v1
kind: Service
metadata:
name: my-xn-service
spec:
type: ExternalName
externalName: www.google.com
ExternalName 유형의 서비스는 일반적인 셀렉터에 대한 서비스가 아니라 DNS 이름에 대한 서비스에 매핑
Fully Qualified Domain Name 으로 "전체 도메인 네임" "절대 도메인 네임" 으로 불리는 도메인 전체 이름 표기 방식을 의미합니다.
www.google.com => www(호스트), google.com(도메인)
캐노니컬 네임 레코드(Canonical Name record), 줄여서 CNAME 레코드(CNAME record)는 하나의 도메인 네임(에일리어스)을 다른 이름(표준 형식의 이름)으로 매핑시키는 도메인 네임 시스템(DNS)의 리소스 레코드의 일종입니다.
외부 FQDN은 www.google.com이며, CNAME은 my-xn-serviced인 서비스입니다.
$ kubectl run testpod -it --image=centos:7
kubectl exec testpod -it -- /bin/bash
인터넷 게이트웨이가 없기 때문에 404에러가 출력됩니다.
그래도 ExternalName의 서비스 이름으로 google 메인페이지의 정보를 가져올 수 있었습니다.
이번에는 service의 종류 4가지에 대해서 공부해보고 실습도 진행해 보았다. 어려운 내용이기도 했고, 쿠버네티스에서 중요한게 네트워크라고 하신 멘토님의 말씀을 한 번 더 생각하게 되는 계기였던 것 같다.
이번에는 개념에서 멈췄지만, 다른 개념을 숙지한 후에 자체 시나리오를 구축해서 진행해보는 것도 좋은 기회일 것이다. 블로그 작성하면서
kubernetes for the Absolute Beginners - Hands-on
내용을 보면 이해가 훨씬 잘되는 것 같다.
다음에는 expose로 쉽게 노출하는 방법에 대해서 포스팅해보겠습니다.