컨트롤러는 쿠버네티스의 두뇌를 담당하여 쿠버네티스 오브젝트를 모니터링하고 반응하는 프로세스이다.
복제 컨트롤러에 대해 이야기 해보자!
Replica란 무엇이고, Replication Controller는 왜 필요한걸까?
애플리케이션을 실행하는 단일 파드가 있다고 가정한다.
어떤 이유로 애플리케이션과 파드가 죽게 되면 사용자는 더이상 애플리케이션에 접근할 수 없다.
따라서 사용자의 애플리케이션 접근 권한을 보장하기 위해 동시에 실행되는 둘 이상의 파드를 동작시킬 수 있다.
복제 컨트롤러는 쿠버네티스 클러스터에서 파드의 여러 인스턴스를 실행할 수 있도록 고가용성을 제공한다.
여러 개의 파드가 아닌 하나의 파드만 유지하기 위해서도 복제 컨트롤러를 사용할 수 있다.
이경우에는 기존 파드에 문제가 발생하면 복제 컨트롤러가 자동으로 새 파드를 생성해준다.
😎 따라서 복제 컨트롤러는 특정 파드가 항상 실행되도록 보장해준다
복제 컨트롤러는 부하를 분산하기 위해 여러 파드를 생성해준다.
사용자에게 서비스를 제공하는 하나의 애플리케이션 파드가 있다.
사용자 수가 증가하면 파드를 추가하여 로드밸런싱을 수행한다.
파드의 증가로 해당 노드의 리소스가 부족해지면 클러스터의 다른 노드에 파드를 추가로 배포한다.
복제 컨트롤러는 클러스터 내의 노드들에 걸쳐있기 때문에 여러 노드에서 파드와 애플리케이션 로드 밸런싱과 오토 스케일링에 도움을 줄 수 있다.
복제 컨트롤러와 레플리카셋의 용도는 같다. 그러나 차이점이 존재한다.
복제 컨트롤러
복제 컨트롤러 기술이 더 오래된 기술이며, 레플리카셋에 의해 대체되었다.
레플리카 셋
레플리카셋은 복제를 설정하는 새로운 권장 방법이다.
vim rc-definition.yaml
apiVersion: v1
kind: ReplicationController
metadata:
name: myapp-rc
labels:
app: myapp
type: front-end
spec:
template:
# 무슨 내용이 들어가야 할까?
spec
spec
부분은 오브젝트 내부에 무엇이 있는지 정의한다.
현재 ReplicaController를 생성하고 있으므로, 생성할 복제 컨트롤러가 관리하는데 필요한 파드의 template를 정의하면 된다.
spec:
template:
metadata:
name: myapp-pod
labels:
app: myapp
type: front-end
spec:
containers:
- name: nginx-container
image: nginx
replicas: 3
esc를 누른 후 wq
커맨드로 파일을 저장한다.
yaml 파일을 적용하여 ReplicaController를 생성한다.
kubectl create -f rc-definition.yaml
복제 컨트롤러가 생성되면서 설정한 개수(3)의 파드가 함께 생성된다.
kubectl get replicationcontroller
kubectl get pods
🤷♀️ create와 apply의 차이?
리소스가 존재하지 않을 경우에는 차이가 없지만 리소스가 이미 존재할 경우 create 명령에서 error가 발생하고, apply 명령은 업데이트가 된다.
vim replicaset-definition.yaml
apiVersion
: v1이 아닌 app/v1
으로 작성해야 한다. v1으로 작성하면 에러가 발생한다. (레플리카 셋은 app/v1
버전으로 생성 가능하다.)kind
: ReplicaSet
metadata
: 파드의 이름과 label을 설정한다.spec
: Replica Controller와 유사하게 template을 작성해주어야 한다.template
: 복제할 pod의 템플릿이 들어가며, 템플릿 아래에는 metadata
와 spec
이 들어간다.replicas
: 복제본 수selector
: ReplicaSet에는 selector
부분을 꼭 작성해주어야 한다.selector
selector
섹션은 어떤 파드가 ReplicaSet 아래에 있는지 식별하는 역할을 한다.
selector
의 하위 항목에는 matchLabels
속성이 있다.
matchLabels
는 파드의 labels
와 매칭되는 정보이다. 이 속성은 지정된 라벨과 같은 라벨을 가진 파드를 연결한다.
apiVersion: app/v1
kind: ReplicaSet
metadata:
name: myapp-replicaset
labels:
app: myapp
type: front-end
spec:
template:
metadata:
name: myapp-pod
labels:
app: myapp
type: front-end
spec:
containers:
- name: nginx-continaer
image: nginx
replicas: 3
selector:
matchLabels:
type: front-end
esc를 누른 후 wq
커맨드로 파일을 저장한다.
yaml 파일을 적용하여 ReplicaController를 생성한다.
kubectl create -f replicaset-definition.yaml
레플리카 셋이 생성되면서 설정한 개수(3)의 파드가 함께 생성된다.
kubectl get replicaset
kubectl get pods
labels
와 selector
속성은 무엇이고, labels
를 지정하는 이유는 무엇일까?
ReplicaSet
의 역할은 파드를 모니터링하고, 파드가 존재하지 않거나 관리하고 있는 파드에 문제가 생기면 새 파드를 배포함으로써 복제본 수를 유지한다.
그렇다면 ReplicaSet
은 어떤 파드를 모니터링 해야 할지 알고 있어야 한다. 바로 여기서 파드의 labels가 사용된다.
labels
는ReplicaSet
에 대한 필터 역할을 한다.
selector의 matchLabels
에 기입된 label과 관리할 대상 파드의 labels
를 일치시켜, 해당 label을 가지고 있는 pod를 대상으로 모니터링하고, 관리할 수 있다.
replicas
항목 값을 변경해준다. (3 -> 6)apiVersion: app/v1
kind: ReplicaSet
metadata:
name: myapp-replicaset
labels:
app: myapp
type: front-end
spec:
template:
...
replicas: 6
selector:
matchLabels:
type: front-end
ReplicaSet
의 구성이 변경되어 업데이트 된다.kubectl replace -f replicaset-definition.yaml
kubectl apply -f replicaset-definition.yaml
scale
커맨드로 변경kubectl scale --replicas=6 -f replicaset-definition.yaml
scale
커맨드를 통해 구성 파일 내의 replica의 수를 업데이트 할 수 있다.
scale
커맨드로 직접 변경kubectl scale --replicas=6 replicaset myapp-replicaset
구성 파일 내용은 변경되지 않지만 오브젝트 타입(ReplicaSet)과 오브젝트 이름(myapp-replicaset)을 직접 기입하여 레플리카 수를 변경할 수 있다.
이러한 요구사항을 쿠버네티스의 Deployment
를 사용하여 만족할 수 있다.
Deployment
는 원활한 업그레이드를 통해 롤링 업데이트 사용, 롤백, 중지, 재개하는 기능을 제공한다.
롤아웃 상태 보기
kubectl rollout status deployment/myapp-deployment
# 결과
Waiting for rollout to finish: 1 out of 3 new replicas have been updated...
롤아웃 기록 확인하기
kubectl rollout history deployment/myapp-deployment
# 결과
deployments "nginx-deployment"
REVISION CHANGE-CAUSE
1 kubectl apply --filename=https://k8s.io/examples/controllers/nginx-deployment.yaml
2 kubectl set image deployment/nginx-deployment nginx=nginx:1.16.1
3 kubectl set image deployment/nginx-deployment nginx=nginx:1.161
이전 단계로 롤백하기
kubectl rollout undo deployment/nginx-deployment
# 결과
deployment.apps/nginx-deployment rolled back
특정 단계로 롤백하기
kubectl rollout undo deployment/nginx-deployment --to-revision=2
# 결과
deployment.apps/nginx-deployment rolled back
레플리카 수 늘리기 (확장)
kubectl scale deployment/nginx-deployment --replicas=10
# 결과
deployment.apps/nginx-deployment scaled
텍스트 편집기를 통해 구성 파일을 작성한다.
vim deployment-definition.yaml
kind
항목만 제외하면 ReplicaSet
과 작성 방법이 똑같다.
apiVersion: app/v1
kind: Deployment
metadata:
name: myapp-deployment
labels:
app: myapp
type: front-end
spec:
template:
metadata:
name: myapp-pod
labels:
app: myapp
type: front-end
spec:
containers:
- name: nginx-continaer
image: nginx
replicas: 3
selector:
matchLabels:
type: front-end
Deployment
는 ReplicaSet
보다 더 높은 계층 구조에 위치하며, Deployment
를 생성하면 ReplicaSet
이 자동으로 생성된다.
kubectl create -f deployment-definition.yaml
디플로이를 생성하면 replicaset
과 pod
가 함께 생성된다.
kubectl get deployments
kubectl get replicaset
kubectl get pods
모든 오브젝트를 한번에 보는 커맨드
kubectl get all
yaml 파일을 생성하고 편집하는 것이 다소 어려울 수 있다. 또한 시험 중 yaml 파일 복사, 붙여넣기가 불편할 수 있다.
이때 kubectl run
커맨드를 사용하면 yaml 파일 템플릿을 생성하는데 도움이 된다.
kubectl run nginx --image=nginx
kubectl run nginx --image=nginx --dry-run=client -o yaml
kubectl create deployment --image=nginx nginx
kubectl create deployment --image=nginx nginx --dry-run=client -o yaml
kubectl create deployment --image=nginx nginx --dry-run=client -o yaml > nginx-deployment.yaml
커맨드를 입력한 후 ls
를 입력하면 nginx-deployment.yaml
파일이 생성된 것을 확인할 수 있다.
텍스트 편집기로 파일을 열어(vim nginx-deployment.yaml
) replicas 항목 값을 4로 설정한다.
설정 후 디플로이를 생성한다
kubectl create -f nginx-deployment.yaml
kubectl create deployment --image=nginx nginx --replicas=4 --dry-run=client -o yaml > nginx-deployment.yaml
k8s의 버전 중 1.19 이상의 버전에서는 --replicas
옵션으로 replicas 값을 설정할 수 있다.
쿠버네티스의 Services
는 내부 구성요소 간, 외부에 있는 애플리케이션과 통신할 수 있게 해주는 역할을 한다.
예를 들어, 애플리케이션이 프론트엔드 그룹, 백엔드 그룹, 데이터 그룹으로 구성되어 있다고 생각해보자!
이러한 파드 그룹을 연결해주는 것이 Service
이다.
Service
를 통해 사용자가 애플리케이션의 프론트엔드에 접근할 수 있고, 백엔드와 프론트엔드 파드가 통신할 수 있으며, 외부 데이터 베이스와 연결할 수 있다.
웹 애플리케이션 파드를 배포할 경우, 외부에서 사용자가 웹페이지에 접속하는 방법은 무엇일까?
기본 설정을 살펴보자!
192.168.1.2
이다. 192.168.1.10
이다. 10.244.0.0
이다.10.244.0.2
이다.현재 사용자의 IP 주소와 파드의 IP는 다른 네트워크 주소를 가지므로, ping을 보내거나 접속할 수 없다.
이 경우, 쿠버네티스 노드와 SSH 연결을 통해 curl이나 노드 내에서 웹페이지 내용을 확인할 수 있다.
그러나 이 방법은 쿠버네티스 노드 내부에서 파드에 접근하는 것이므로, 사용자의 노트북에서 파드에 접속할 수 있는 다른 방법을 선택해야 한다.
따라서 노트북->노드, 노드->파드로 노트북에서 보낸 요청을 파드로 전달해주어야 하는데 이 역할을 하는 것이 쿠버네티스의 Service
이다.
쿠버네티스에는 3가지 타입의 Service
가 존재한다.
노드 포트로 내부의 파드 포트에 접근가능하게 하는 서비스
TargetPort
: 실제 접속하려는 파드의 포트, Service가 최종적으로 요청을 전달하는 포트Port
: 서비스 자체의 포트, 라고 부른다. 서비스는 노드 내의 가상 서버와 같으며, ClusterIP:Port
로 들어온 요청을 TargetPort
로 전달한다.NodePort
: 외부에서 내부 파드에 액세스하기 위해 사용할 포트, 노드포트는 30000~32767 사이의 범위에서 값을 가짐vim service-definition.yml
구성파일 내용
NodePort
, ClusterIP
, LoadBalancer
)apiVersion: v1
kind: Service
metadata:
name: myapp-service
spec:
type: NodePort
ports:
- targetPort: 80
port: 80
nodePort: 30008
selector:
app: myapp
type: front-end
kubectl create -f service-definition.yml
kubectl get services
curl
커맨드를 통해 애플리케이션 내용 확인curl http://192.168.1.2:30008
만약 동일한 애플리케이션이 동작하는 3개의 파드가 있고, 이 파드들이 동일한 label을 가지고 있을 경우에는 Service
가 랜덤 알고리즘으로 요청을 전달할 파드를 선택하여 로드 밸런싱을 한다.
파드가 여러 노드에 분산되어 있는 경우, 서비스가 생성될 때 쿠버네티스가 자동으로 클러스터의 모든 노드에 대상 파드의 포트를 매핑한다.
이때 매핑된 노드 포트들은 모두 동일하다.
어떤 경우든지 파드가 추가되거나 삭제되면 서비스는 자동으로 업데이트 되어 새로운 파드로 요청을 전달해준다.
ClusterIP
서비스는 서로 다른 서비스 간 통신이 가능하도록 클러스터 안에 Virtual IP를 생성한다.
loadBalancer
서비스는 파드들의 부하 분산 기능을 제공한다.