ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 쿠버네티스 시작
    인프라 2022. 12. 12. 09:21
    728x90
    반응형
    SMALL

    쿠버네티스 실행 방법

    kubectl이라는 명령어로 쿠버네티스를 사용할 수 있다.

    YAML파일을 통해 컨테이너 리소스를 생성 및 삭제할 수 있다. (더 많이 쓰이는 방법)

     

    쿠버네티스의 컴포넌트

    마스터 노드에서 API 서버(kube-apiserver), 컨트롤러 매니저(kube-controller-manager), 스케줄러(kube-scheduler), DNS서버(coreDNS) 등이 실행되고, 모든 노드에서는 오버레이 네트워크 구성을 위해 프락시와 네트워크 플러그인이 실행된다.

    kubelet이라는 에이전트가 모든 노드에서 실행된다. kubelet은 컨테이너의 생성, 삭제뿐만 아니라 마스터와 워커 노드 간의 통신 역할을 함께 담당한다.

    → 아직까지는 ‘kubelet이라는 에이전트가 모든 노드에서 기본적으로 실행되며, 마스터 노드에는 API 서버 등이 컨테이너로 실행된다.’ 정도만 알아도 된다.

     

    포드

    컨테이너 애플리케이션의 기본 단위, 1개 이상의 컨테이너로 구성된 컨테이너 집합

    ex) nginx컨테이너가 들어있는 pod 생성을 위한 yaml파일

    apiVersion: v1
    kind: Pod
    metadata:
    	name: my-nginx-pod
    spec:
    	containers:
    	- name: my-nginx-container
    		image: nginx:latest
    		ports:
    		- containerPort: 80
    			protocol: TCP
    

    kubectl apply -f nginx-pod.yaml을 통해 쿠버네티스에 생성할 수 있다.

    현재 Nginx포드가 생성되긴 했지만, 아직 외부에서 접근할 수 있도록 노출된 상태는 아니다.

    특정 오브젝트의 목록 확인

    kubectl get <오브젝트이름>
    

    포드의 컨테이너에 접속

    kubectl exec -it <pod이름> bash
    
    pod의 특정 container에 접속
    kubectl exec -it <pod이름> -c <container이름> bash
    

    포드 삭제

    # yaml파일에 정의된 pod 삭제
    kubectl delete -f <yaml>
    # pod이름으로 삭제
    kubectl delete pods my-nginx-pod
    

    kubectl get pods 명령어 실행 시 나오는 항목 중 READY는 현재 실행중인 컨테이너의 개수를 뜻한다.

    → 1/1일 경우 1개 2/2일 경우 2개의 컨테이너가 실행되고 있다는 뜻이다.

     

    ex) 한 포드 안에 2개의 컨테이너를 포함하도록 하는 yaml파일

    apiVersion: v1
    kind: Pod
    metadata:
    	name: my-nginx-pod
    spec:
    	containers:
    	- name: my-nginx-container
    		image: nginx:latest
    		ports:
    		- containerPort: 80
    			protocol: TCP
    	- name: ubuntu-sidecar-container
    		image: alicek106/rr-test:curl
    		command: ["tail"]
    		args: ["-f", "/dev/null"]
    

    대시(-)를 사용하여 여러 개의 항목을 정의할 수 있다.

    kubectl exec 명령어에서 -c옵션을 통해 포드중에서 원하는 컨테이너에 접근할 수 있다.

    kubectl exec -it my-nginx-pod -c ubuntu-sidecar-container bash - ubuntu-sidecar-container내에 접근

    ubuntu-sidecar-container에 접속하면 로컬호스트로 nginx에 접근할 수 있게 되는데, 그 이유는 포드 내의 컨테이너들이 네트워크 네임스페이스 등과 같은 리눅스 네임스페이스를 공유해 사용하기 때문이다.

     

    레플리카셋

    포드를 직접 생성해서 사용하는 방법은 여러 장애가 있을 경우 다시 직접 생성해줘야 해서 비효율적인 작업이다. 이러한 비효율적인 작업을 해결해주는 것이 레플리카셋이다.

    레플리카셋의 역할

    • 정해진 수의 동일한 포드가 항상 실행되도록 관리
    • 노드 장애 등의 이유로 포드를 사용할 수 없다면 다른 노드에서 포드를 다시 생성

    →포드를 직접관리하지 않아도 됨

     

    ex) yaml 예시

    apiVersion: apps/v1
    kind: ReplicaSet
    metadata:
    	name: replicaset-nginx
    spec:
    	replicas: 3
    	selector:
    		matchLabels:
    			app: my-nginx-pods-label
    	template:
    		metadata:
    			name: my-nginx-pod
    			labels:
    				app: my-nginx-pods-label
    		spec:
    			containers:
    			- name: nginx
    				image: nginx:latest
    				ports:
    				- containerPort: 80
    

    🔈 yaml파일에서 들여쓰기된 항목은 상위 항목에서 .을 통해 표현될 수 있다. ex. metadata.name

    spec.replicas - 동일한 pod를 몇 개 유지시킬 것인지 설정

    spec.template - 포드를 생성할 때 사용할 템플릿을 정의 이전에 pod 생성 시 사용한 yaml파일과 거의 동일(포드 스펙, 포드 템플릿이라고 불린다.)

    kubectl apply -f replicaset-nginx.yaml을 통해 생성

     

    이미 생성된 리소스의 속성 변경

    kubextl edit, kubectl path 등의 방법으로 변경할 수 있다.

     

    레플리카셋 동작원리

    레플리카셋은 포드와 느슨한 연결을 유지하고 있고 이 느슨한 연결은 포드와 레플리카셋의 정의 중 라벨 셀렉터에 의해 이뤄진다.

    metadata항목에서는 리소스의 부가적인 정보를 설명하는데 여기에 라벨이 포함된다.

    이 metadata항목의 리소스 정보는 서로 다른 오브젝트가 서로를 찾아야할 때 사용되기도 한다.

     

    yaml파일을 보면 spec.selector.matchLabel에 레플리카셋이 관리할 포드의 정보가 있다.

    위의 예시에서는 app: my-nginx-pods-label 라벨을 가지고 있는 포드의 개수가 3개여야 한다고 해석할 수 있다.

    만약, app: my-nginx-pods-label 라벨을 가지고 있는 포드가 이미 한 개 있었다면, 레플리카셋 생성 시 포드는 2개만 생성이 되고, 원래 생성됐던 포드를 삭제하면 레플리카셋이 app: my-nginx-pods-label 라벨을 가진 포드가 2개 밖에 없다는 것을 인지하고 하나의 포드를 더 생성하게 된다.

    →레플리카셋의 목적은 ‘포드를 생성하는 것'이 아닌, ‘일정 개수의 포드를 유지하는 것’

     

    추가

    레플리카셋은 표현식 기반의 라벨 셀렉터를 사용한다.

    selector:
    	matchExpressions:
    		- key: app
    			values:
    				- my-nginx-pods-label
    				- your-nginx-pods-label
    			operator: In
    template:
    	...
    

    위 yaml파일의 뜻은 레플리카셋이 pod의 label이 app이라는 key를 가지고 있고 value로는 values밑에 정의된 값 중 하나인 pod를 관리하겠다는 뜻이다.

     

    디플로이먼트

    디플로이먼트는 레플리카셋의 상위 오브젝트이다. 실제 쿠버네티스 운영 환경에서는 레플리카셋과 포드의 정보를 디플로이먼트 오브젝트가 yaml 파일에 정의해서 사용한다.

    ex) yaml 예시

    apiVersion: apps/v1
    kind: Deployment
    metadata:
    	name: my-nginx-deployment
    spec:
    	replicas: 3
    	selector:
    		matchLabels:
    			app: my-nginx
    	template:
    		metadata:
    			name: my-nginx-pod
    			labels:
    				app: my-nginx
    		spec:
    			containers:
    			- name: nginx
    				image: nginx:latest
    				ports:
    				- containerPort: 80
    

    kubectl apply -f deployment-nginx.yaml로 디플로이먼트를 생성

    위에서 따로 레플리카셋을 정의하지는 않았지만 실제 포드의 개수가 3개이도록 유지시켜주는 것은 레플리카셋이므로 레플리카셋도 디플로이먼트와 함께 생성된다. 이 때 레플리카셋의 이름은 해시값으로 나타난다.

    →디플로이먼트를 생성하면 레플리카셋이 생성되고 레플리카셋이 포드를 생성한다.

     

    디플로이먼트를 사용하는 이유

    디플로이먼트는 컨테이너 애플리케이션을 배포하고 관리하는 역할을 담당한다. 예를 들어 애플리케이션을 업데이트할 때 레플리카셋의 변경 사항을 저장하는 리비전을 남겨 롤백을 가능하게 해주고 무중단 서비스를 위해 포드의 롤링 업데이트의 전략을 지정할 수 있다.

    kubectl apply -f deployment-nginx.yaml —record로 디플로이먼트, 레플리카셋, 포드를 생성한 뒤 nginx 컨테이너의 버전을 수정하고 싶다면 kubectl set image deployment my-nginx-deployment nginx=nginx:1.11 —record 로 수정할 수 있다. 여기서 —record 옵션을 통해 모든 상황을 기록할 수 있다.

     

    수정될 경우 포드와 레플리카셋은 전부 새롭게 생성이 된다. 이 때, 이전의 레플리카셋에 대한 정보를 리비전으로 보존한다.

    kubectl rollout history deployment my-nginx-deployment 로 리비전 정보를 자세히 확인할 수 있다.

    kubectl rollout undo deployment my-nginx-deployment —to-revision=<번호> 로 이전 리비전으로 롤백을 할 수 있다.

    컨테이너가 수정될 경우 여러개의 레플리카셋이 새롭게 만들어질 경우 포드 템플릿으로부터 계산된 해시값은 각 레플리카셋의 라벨 셀렉터에서 pod-template-hash라는 이름의 라벨값으로서 자동으로 설정된다.

    →디플로이먼트를 사용하면 레플리카셋의 리비전 관리뿐만 아니라 다양한 포드의 롤링 업데이트 정책을 사용할 수도 있다.

     

    지금은 ‘디플로이먼트는 레플리카셋의 상위 수준의 오브젝트이며, 일반적으로 디플로이먼트를 통해 포드를 생성한다.’고 알고 있으면 된다.

     

    서비스

    현재까지 포드의 내부 IP로 직접 접근하는 방법은 로컬 개발 환경 또는 쿠버네티스 클러스터 내부에서만 사용할 수 있다. 게다가 포드의 IP는 영속적이지 않아 항상 변할 수 있다.

    도커 컨테이너와 달리 쿠버네티스는 디플로이먼트를 생성할 때 포드를 외부로 노출하지 않으며, 디플로이먼트의 yaml파일에는 단지 포드의 애플리케이션이 사용할 내부 포트만 정의한다.

    yaml 파일에서 containerPort를 정의했다고 해서 이 포드가 바로 외부에 노출되는 것은 아니다. 이 포트를 외부로 노출해 사용자들이 접근하거나, 다른 디플로이먼트의 포드들이 내부적으로 접근하려면 서비스라는 오브젝트를 생성해야 한다.

     

    서비스의 종류

    포드에 어떻게 접근할 것이냐에 따라 종류가 여러 개로 세분화 돼 있다.

    • ClusterIP 타입: 쿠버네티스 내부에서만 포드들에 접근할 경우 사용한다. 외부로 포드를 노출하지 않기 때문에 쿠버네티스 클러스터 내부에서만 사용되는 포드에 적합하다.
    • NodePort 타입: 포드에 접근할 수 있는 포트를 클러스터의 모든 노드에 동일하게 개방한다. 따라서 외부에서 포드에 접근할 수 있는 서비스 타입이다. 접근할 수 있는 포트는 랜덤으로 정해지지만, 특정 포트로 접근할 수 있도록 설정할 수도 있다.
    • LoadBalancer 타입: 클라우드 플랫폼에서 제공하는 로드 밸런서를 동적으로 프로비저닝해 포드에 연결한다. NodePort 타입과 마찬가지로 외부에서 포드에 접근할 수 있는 서비스 타입. 그렇지만 일반적으로 AWS, GCP 등과 같은 클라우드 플랫폼 환경에서만 사용할 수 있다.

    ex) ClusterIP 타입 yaml파일

    apiVersion: v1
    kind: Service
    metadata:
    	name: hostname-svc-clusterip
    spec:
    	ports:
    		- name: web-port
    			port: 8080
    			targetPort: 80
    	selector:
    		app: webserver
    	type: ClusterIP
    
    • spec.selector - selector항목은 이 서비스에 어떠한 라벨을 가지고 있는 포드에 접근할 수 있게 만들 것인지 결정한다.
    • spec.ports.port - 생성된 서비스는 쿠버네티스 내부에서만 사용할 수 있는 고유한 IP를 할당받는다. 서비스의 IP에 접근할 때 사용하는 포트이다.
    • spec.ports.targetPort - selector 항목에서 정의된 라벨에 의해 접근 대상이 된 포드들이 내부적으로 사용하고 있는 포트를 입력한다. ←포드 템플릿에 정의된 containerPort와 같은 값으로 설정해야 한다.
    • spec.type - 이 서비스가 어떤 타입인지 나타낸다.

    서비스가 생성됐을 경우 이 서비스의 IP주소를 통해 이 서비스와 연결된 포드에 접근할 수 있게 된다.

     

    ex) NodePort 타입 yaml파일

    apiVersion: v1
    kind: Service
    metadata:
    	name: hostname-svc-nodeport
    spec:
    	ports:
    		- name: web-port
    			port: 8080
    			targetPort: 80
    	selector:
    		app: webserver
    	type: NodePort
    

    type을 Nodeport로 바꿔준 것을 제외하면 ClusterIP와 동일하다.

    NodePort 서비스를 생성하면 외부로부터 들어올 수 있는 포트가 30000~32768 포트 중 랜덤으로 부여된다.

     

    원하는 포트를 지정하는 방법

    spec:
    	ports:
    		- name: web-port
    			port: 8080
    			targetPort: 80
    			nodePort: 31000
    

    원하는 포트를 30000~32768 포트 중에서 고를 수 있다.

    실제 서비스에서는 NodePort로 서비스를 외부에 제공하는 경우는 많지 않다. Ingress라는 오브젝트를 통해 서비스를 외부로 제공해준다. Ingress는 현재로써는 ‘외부 요청을 실제로 받아들이는 관문'정도로 알고 넘어가면 된다. LoadBalancer와 NodePort를 합치면 ingress 오브젝트를 사용할 수 있다.

     

    ex) LoadBalancer 타입

    클라우드 플랫폼으로부터 도메인 이름과 IP를 할당받기 때문에 NodePort보다 더욱 쉽게 포드에 접근할 수 있다.

    LoadBalancer 타입의 서비스는 로드 밸런서를 동적으로 생성하는 기능을 제공하는 환경에서만 사용할 수 있다.(AWS, GCP). 가상 머신이나 온프레미스 환경에서는 사용하기 어려울 수 있다.

    AWS는 kops를 통해 설치한 쿠버네티스

    GCP는 GKE(Google Kubernetes Engin)

    AWS에서 클라우드 프로바이더를 설정해 kubeadm으로 설치한 쿠버네티스를 사용해도 된다.

    apiVersion: v1
    kind: Service
    metadata:
    	name: hostname-svc-lb
    spec:
    	ports:
    		- name: web-port
    			port: 80
    			targetPort: 80
    	selector:
    		app: webserver
    	type: NodePort
    

    ports.port항목은 로드 밸런서에 접근하기 위한 포트를 의미하므로 80으로 설정

    반응형
    LIST

    '인프라' 카테고리의 다른 글

    서버 안정화를 위한 조사  (0) 2022.12.12
    aws 인스턴스 & 도커 자동 시작  (0) 2022.12.12
    dockerfile 관련 정리  (0) 2022.12.09
    Nginx Load balancing, 도커 컨테이너 실습  (0) 2022.12.08
    Nginx 개념 + 간단 실습  (0) 2022.12.08

    댓글

Designed by Tistory.