Run The Bridge

k8s 2일차 본문

Cloud/k8s

k8s 2일차

anfrhrl5555 2021. 8. 6. 10:28
728x90

0. 포드 vs 도커 컨테이너

  • 포드는 1개 이상의 컨테이너로 구성
  • 포드 내의 컨테이너들은 동일한 네트워크를 사용 -> 네트워크 네임스페이스를 공유한다
  • 포드는 하나의 완전한 애플리케이션으로 부가적인 기능을 하는 컨테이너를 추가하여 완전체를 만들 수 있다 
    → sidecar 컨테이너
  • 권장 사항은 포드에 1개의 컨테이너를 사용하는 것이고 불가피할 경우 컨테이너를 추가한다
  • sidecar 컨테이너는 변경을 가할 수 없는 포드에 추가적인 기능이 필요할 때 추가하여 사용하고, 이렇게 추가하는 것을 injection(주입)이라고 표현한다

ReplicaSet은 Pod가 무슨일이 있어 down 되었을 때도, 계속 up 할려고 하는 성격을 가진다.

ReplicaSet과 Pod는 느슨한 연결 → 라벨 셀렉터 이용

 

(실습) app: my-nginx-pods-label을 가지는 포드 미리 생성 후 레플리카셋 생성하는 경우

# vi nginx-pod-without-rs.yaml

apiVersion: v1
kind: Pod
metadata:
  name: my-nginx-pod
  labels:  # 임의의 labels 값, key: value값으로 자유롭게 주면된다.
    app: my-nginx-pods-label
spec:
  containers:
  - name: my-nginx-container
    image: nginx:latest
    ports:
    - containerPort: 80
      protocol: TCP
kubectl apply -f nginx-pod-without-rs.yaml  # run
kubectl get pod --show-labels

 

kubectl get pod -l app  # app라는 label을 가지는 pod를 보여줘

 

어제 올린 replicaset-nginx.yaml을 다시 실행시켜 준다.

kubectl apply -f replicaset-nginx.yaml

하지만 레플리카셋 3개가 아니고, nginx-pod를 포함하여 3개가 나왔다. why? → 3개의 pod label이 모두 동일하다.

 

그러면 삭제를 했을 때는 결과는 어떨까? 'my-nginx-pod'를 지우자

kubectl delete pod my-nginx-pod

my-nginx-pod 삭제 후 새로운 pod 생성

 

(실습) 레플리카셋이 생성해 놓은 포드의 라벨을 삭제하는 경우

kubectl edit pod replicaset-nginx-6dq4b  # edit명령으로 vi 편집기에 진입

해당 부분을 'dd'로 삭제한다.
4개의 pod가 존재하고 있다.

마치 zombie process같은 느낌이다.

delete해도 혼자남는다.

 

다음 명령으로 강제 삭제 시켜줘야 한다.

kubectl delete pod replicaset-nginx-6dq4b


1. 디플로이먼트(Deployent): 레플리카셋, 포드의 배포를 관리

  1. application 업데이트 및 배포를 더욱 편하게 할 수 있다.
  2. 문제 발생 시 이전 버전으로 롤백 가능(이전 정보를 리비전으로 저장 후 롤백)
  3. 포드의 롤링 업데이트 정책 가능
  4. 레플리카셋만으로는 운영 환경에서 서비스를 구성하기 어렵다
    → 레플레카셋과 포드 정보를 정의하는 디플로이먼트(deployment) 오브젝트를 정의하여 사용
  5. 디플로이먼트 > 레플리카셋 > 포드
    → 디플로이먼트를 정의하면 레플리카셋과 포드를 함께 정의
# vi deployment-nginx.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:1.10
        ports:
        - containerPort: 80
kubectl apply -f deployment-nginx.yaml  # run

 

이제 nginx image을 1.10에서 1.11로 바꿔보자(롤링 업데이트)

kubectl set image deploy my-nginx-deployment nginx=nginx:1.11 --record
kubectl get replicaset

 

  kubectl rollout history deployment my-nginx-deployment  # 명령 history 확인

 

내가 다시 nginx 1.10버전으로 돌아가고 싶다면?

kubectl rollout undo deploy my-nginx-deployment --to-revision=1

 

(실습) RollingUpdate와 Recreate

# vi deployment-nignx-recreate.yaml

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

이 방법은 한꺼번에 다 내리고, 다시 올린다.

 


※ pod가 내려가지 않을 때(deployment 설정 및 replicaset 작업 중)

kubectl get deployment  # replicaset 설정을 확인한다.

kubectl delete deployment replicaset-nginx  # NAME 입력 후 삭제

서비스(Service): 포드를 연결하고 외부에 노출

  • 포드, 레플리카셋, 디플로이먼트에서 컨테이너 포트를 열었지만 외부에서는 접근할 수 없다
  • 외부 사용자들이나 다른 디플로이먼트의 포드들이 접근하려면 서비스(service)라는 오브젝트 필요
  • 여러 개의 포드에 쉽게 접근할 수 있도록 고유한 도메인 이름 부여
  • 여러 개의 포드에 접근할 때, 요청을 분산하는 로드 밸런서 기능 수행
  • 로드 밸런서나 노드의 포트를 통해 포드를 외부로 노출

# vi deployment-hostname.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hostname-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: webserver
  template:
    metadata:
      name: my-webserver
      labels:
        app: webserver
    spec:
      containers:
      - name: my-webserver
        image: alicek106/rr-test:echo-hostname
        ports:
        - containerPort: 80
kubectl apply -f deployment-hostname.yaml  # run

 

이제 service yaml 파일을 생성해본다.

# vi hostname-svc-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

 

get service로 확인한다.

kubectl get service

 

curl 10.105.249.1  # curl 명령어로 확인

curl request

우리가 호출한 쿠버네티스 클러스터 안에서 사용한 IP대역이다.

 

pod가 사용한 IP대역은 100.200 이다

 

docker와 다른점은 docker는 호출한 IP 자체가 node의 IP이다, 즉 내부 컨테이너 IP로 호출 불가

 

하지만 쿠버네티스는 클러스터 VM를 이루는 100.200의 IP대역은 내부 컨테이너 IP끼리 호출이 가능하다.

 

그러면 이제 Service에 대해 실습해보자

# vi deployment-hostname.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hostname-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: webserver
  template:
    metadata:
      name: my-webserver
      labels:
        app: webserver
    spec:
      containers:
      - name: my-webserver
        image: alicek106/rr-test:echo-hostname
        ports:
        - containerPort: 80
kubectl apply -f deployment-hostname.yaml

pod들의 상태확인
curl 명령 request가 잘 나온다.

 

이제 Service라는 새로운 Objecet를 생성한다.

 

hostname를 출력하는 application을 만들고, 다른곳에서 접속할 수 있는 상태로 만든다

 # vi hostanme-svc-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
  
  
kubectl apply -f hostanme-svc-clusterip.yaml

 

우리가 만든 service는 hostname-svc-clusterip 이다. port: 8080/tcp

pod의 IP는 100.200이지만, service의 IP대역은 10번 대역이 나왔다. 전혀다른 IP...

 

이 Cluster-IP는 쿠버네티스에서 자동으로 할당하는 IP인데, 이 IP의 역할은 말그대로 클러스터 IP이다.

 

3대의 pod를 대표하는 하나의 클러스터 IP라고 보면된다.

 

중간에 Hello 라인을 보면 끝에 '6shvb', 'krlnb' 처럼 pod들의 name 마지막 자리가 나온다.

 

아까 ClusterIP라고 적힌 yaml파일을 'nodePort'로 바꿔보자

# vi hostanme-svc-nodeport.yaml

apiVersion: v1
kind: Service
metadata:
  name: hostname-svc-nodeport
spec:
  ports:
    - name: web-port
      port: 8080  # 호출할 때 사용할 port
      targetPort: 80  # 컨테이너에서 사용할 port
  selector:
    app: webserver
  type: NodePort

kubectl apply -f hostanme-svc-nodeport.yaml

'NodePort'라는 Service가 올라왔다, 뒤에 나오는 포트는 임의의 포트
똑같이 볼 수 있다.

 

NodePort를 사용하면 외부에서 Node IP + Port를 입력하여 접속이 가능하다.
  → 새로고침할 때 마다 호스트 name 변경된다.
  → 140, 141, 142번 모두 접속이 가능하다(docker의 ingree모드, swarm)

외부접속

 

ClusterIP

  • 클러스터 내부에서만 사용
  • 모든 포드간 통신에 적합
  • 외부에서 접근 불가

NodePort(30000 ~ 32768)

  • 포드에 접근할 수 있는 포트를 클러스터의 모든 노드에 동일하게 개방
  • 노드 IP를 통해서 외부에서 접근 가능
  • 외부에서 접근하는 포트는 랜덤이거나 사용자가 직접 정할 수 있다

LoadBalancer

  • 클라우드 플랫폼(AWS, GCP 등)에서 제공하는 로드 밸런서를 통해 포드에 연결
  • NodePort와 마찬가지로 외부에서 포드에 접근할 수 있다

 

Service의 간단한 Test

# vi nginx-pod-label.yaml
apiVersion: v1
kind: Pod
metadata:
  name: my-nginx-pod
  labels:
    app: webserver
spec:
  containers:
  - name: my-nginx-container
    image: nginx:latest
    ports:
    - containerPort: 80
      protocol: TCP

kubectl apply -f nginx-pod-label.yaml

 

중간중간에 curl 값이 나오지않는것을 볼 수 있다. 이것으로 인해 label값은 고유의 값, 즉 중복되지 않고 Unique한 값으로 주는것이 매우 중요하다.

 

트래픽의 분배를 결정하는 서비스 속성: externalTrafficPolicy

외부로부터 어떤 노드로 요청이 들어오면 노드에서 다시 포드로 요청을 전달, 이 때 노드에서 포드로 요청을 전달하는 규칙을 설정

  • externalTrafficPolicy: Cluster - 클러스터 전체의 포드 중에서 선택
  • externalTrafficPolicy: Local - 해당 노드에 있는 포드 중에서 선택

현재 우리가 192.168.100.140:31175로 호출하면, kubectl get pods -o wide에 나와 있는 4개의 IP중에서 랜덤하게 호출이 된다. 하지만 external 설정을 하면 특정 포드만 호출한다.

 

경우에 따라서는 트래픽이 불균형해질 수 있다.

 

쿠버네티스 시스템이 외부 시스템과 연동해야 할 때


 

 
728x90
Comments