본문 바로가기

infra

쿠버네티스 기본

반응형

쿠버네티스

네임스페이스

  • 클러스터 안에 가상 클러스터를 또 다시 만들수 있다.
  • 가상 클러스터를 네임스페이라고 한다.
  • 클러스터를 처음 구축시 default, docker, kube-public, kube-system 네임스페이스 4개가 이미 만들어져 있다.
kubectl get namespace
  • 네임스페이스는 개발팀이 일정 규모 이상일때 유용하다.
  • 개발자마다 자신만의 네임스페이스를 두면 메인 네임스페이스가 어질러지는 것을 방지할 수 있다.
  • 네임스페이스마다 권한을 설정할 수 있으므로 견고하고 세세한 권한을 제어할 수 있다.

파드

  • 컨테이너가 모인 집합체의 단위로, 적어도 하나 이상의 컨테이너로 이루어진다.
  • 도커와 함께 사용한다면 파드는 컨테이너 하나 혹은 컨테이너의 집합체가 된다.
---Pod---------------------
| ContainerA, ContainerB  |
--------------------------

파드 생성 및 배포

  • nginx-proxy, echo app 애플리케이션, 2개의 컨테이너를 포함하는 파드를 쿠버네티스 환경에 배포
  • 파드 생성은 kubectl만 사용해도 된다.
  • 버전 관리 관점으로 yaml 파일을 사용하는 것이 좋다.

simple-pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: simple-pod
spec:
  containers:
  - name: nginx
    image: gihyodocker/nginx:latest
    env:
    - name: BACKEND_HOST
      value: localhost:8090
    ports:
    - containerPort: 80
  - name: echo
    image: gihyodocker/echo:latest
    ports:
    - containerPort: 8090
kubectl apply -f simple-pod.yaml

파드 다루기

kubectl get pod

컨테이너 안에 접근

kubectl exec -it simple-pod sh -c nginx
  • c옵션에 컨테이너명을 지정

파드안에 컨테이너의 표준 출력

kubectl logs -f simple-pod -c echo

파드 삭제

kubectl delete pod simple-pod
kubectl delete -f simple-pod.yaml

레플리카 세트

  • 파드를 정의한 매니페스트 파일로는 파드를 하나밖에 생성할 수 없다.
  • 어느정도 규모가 되는 애플리케이션을 구축하려면 같은 파드를 여러개 실행해 가용성을 확보해야 하는경우 레플리카 세트를 사용한다.
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: echo
  labels:
    app: echo
spec:
  replicas: 3
  selector:
    matchLabels:
      app: echo
  template: # template 아래 파드 리소스 정의와 같음
    metadata:
      labels:
        app: echo
    spec:
      containers:
     - name: nginx
        image: gihyodocker/nginx:latest
        env:
        - name: BACKEND_HOST
          value: localhost:8090
        ports:
        - containerPort: 80
      - name: echo
        image: gihyodocker/echo:latest
        ports:
        - containerPort: 8090
  • replicas는 레플리카세트에서 만들 파드의 복제본 수를 의미한다.
  • template 속성의 내용은 파드 정의와 같다.

kubectl apply -f simple-replicaset.yaml

kubectl get pod

  • 레플리카세트를 조작해 파드의 수를 줄이면 줄인 개수만큼 파드가 삭제된다.
  • 삭제된 파드는 복원할수 없기 때문에 애플리케이션 같은 무상태 파드를 사용하기에 유리하다.

디플로이먼트

  • 레플리카세트보다 상위에 해당하는 리소스로 디플로이먼트가 있다.
  • 디플로이먼트는 애플리케이션 배포의 기본 단위가 되는 리소드다.
  • 레플리카세트는 똑같은 파드의 레플리케이션 개수를 관리 및 제어하는 리소스인데 비해, 디플로이먼트는 레플리카세트를 관리하고 다루기 위한 리소스다.

Deployment --> ReplicaSet ---> Pod
echo echo-1 echo-1a

apiVersion: apps/v1
kind: Deployment
metadata:
  name: echo
  labels:
    app: echo
spec:
  replicas: 3
  selector:
    matchLabels:
      app: echo
  template: # template 아래 파드 리소스 정의와 같음
    metadata:
      labels:
        app: echo
    spec:
      containers:
     - name: nginx
        image: gihyodocker/nginx:latest
        env:
        - name: BACKEND_HOST
          value: localhost:8090
        ports:
        - containerPort: 80
      - name: echo
        image: gihyodocker/echo:latest
        ports:
        - containerPort: 8090
  • 디플로이먼트가 레플리카세트의 리비전 관리를 할 수 있다.

kubectl apply -f simple-deployment.yaml --record

--record kubectl 명령을 실행했는지 기록을 남기는 옵션

kubectl get pod,replicas,deployment --selector app=echo

디플로이먼트의 리비전확인
kubectl rollout history deployment echo

레플리카세트의 생애주기

  • 쿠버네티스는 디플로이먼트를 단위로 애플리케이션을 배포한다.
  • 실제 운영에서는 레플리카세트를 직접 다루기보다는 디플로이먼트 매니페스트 파일을 통해 다루는 경우가 대부분
  • 파드 개수만 수정하면 레플리카세트가 새로 생성되지 않음
  • 컨테이너 이미지가 수정된 경우 새로운 파드가 생성되고 기존 파드는 단계적으로 정지된다.

롤백실행
리비전 번호 확인
kubectl rollout history deployment echo --revision=1

undo 실행으로 직전 리비전으로 롤백
kubectl rollout undo deployment echo

  • 최신 디플로이먼트에 문제가 있을 경우 곧바로 이전 버전으로 돌아갈 수 있으며, 애플리케이션의 이전 버전의 동작을 확인하려는 경우에 활용할 수 있다.

서비스

  • 클러스터안에서 파드의 집합(주로 레플리카세트)에 대한 경로나 서비스 디스커버리를 제공하는 리소스다.
  • 서비스의 대상이 되는 파드는 서비스에서 정의하는 레이블 셀렉터로 정해진다.

simple-replicaset-with-labels.yaml

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: echo-spring
  labels:
    app: echo
    release: spring
spec:
  replicas: 1
  selector:
    matchLabels:
      app: echo
      release: spring
  template: # template 아래 파드 리소스 정의와 같음
    metadata:
      labels:
        app: echo
        release: spring
    spec:
      containers:
     - name: nginx
        image: gihyodocker/nginx:latest
        env:
        - name: BACKEND_HOST
          value: localhost:8080
        ports:
        - containerPort: 80
      - name: echo
        image: gihyodocker/echo:latest
        ports:
        - containerPort: 8080
---
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: echo-summer
  labels:
    app: echo
    release: summer
spec:
  replicas: 1
  selector:
    matchLabels:
      app: echo
      release: summer
  template: # template 아래 파드 리소스 정의와 같음
    metadata:
      labels:
        app: echo
        release: summer
    spec:
      containers:
     - name: nginx
        image: gihyodocker/nginx:latest
        env:
        - name: BACKEND_HOST
          value: localhost:8080
        ports:
        - containerPort: 80
      - name: echo
        image: gihyodocker/echo:latest
        ports:
        - containerPort: 8080        

kubectl apply -f simple-replicaset-with-labels.yaml

kubectl get pod -l app=echo -l release=spring

kubectl get pod -l app=echo -l release=summer

release=summer인 파드만 접근할수 있는 서비스를 생성

apiVersion: v1
kind: Service
metadata:
  name: echo
spec:
  selector:
    app: echo
    release: summer
  ports:
    - name: http
      port: 80

http://echo/ --------> service(name=echo) -----> Pod app=echo release = summer
app= -----> Pod app=echo release = summer
release=summer --x--> Pod app=echo release = spring
http:80

kubectl apply -f simple-service.yaml

kubectl get svc echo

release=summer인 파드에만 트래픽 전달 확인

kubectl run -i --rm --tty debug --image=gihyodocker/fundamental:0.1.0 --restart=Naver -- bash -il

curl http://echo/

서비스의 네임 레졸루션

  • 쿠버네티스 클러스터의 DNS는 서비스를 서비스명.네임스페이스.svc.local로 연결해준다.
  • echo는 default 네임스페이스인 경우
    curl http://echo.default.svc.local

curl http://echo.default

같은 네임스페이스라면 서비스명으로만 참조가 가능
curl http://echo

ClusterIP 서비스

  • 서비스에도 여러가지 종류가 있어서 그 종류를 yaml파일에서 지정할 수 있다. 기본값은 ClusterIP 서비스다.
  • ClusterIP를 사용하면 쿠버네티스 클러스터의 내부 IP 주소에 서비스를 공개할 수 있다.
  • 이를 이용해 어떤 파드에서 다른 파드 그룹으로 접근할 때 서비스를 거쳐가도록 할 수 있으며, 서비스명으로 네임 레졸루션이 가능해진다.
  • 다만, 외부로부터 접근할 수 없다.

NodePort 서비스

  • NodePort 서비스는 클러스터 외부에서 접근할 수 있는 서비스다.
  • NodePort 서비스는 ClusterIP를 만든다는 점은 ClusterIP 서비스와 같다.
  • 각 노드에서 서비스 포트로 접속하기 위한 글로벌 포트를 개방한다는 점이 차이점
apiVersion: v1
kind: Service
metadata:
  name: echo
spec:
  selector:
    type: NodePort
    app: echo
  ports:
    - name: http
      port: 80
  • NodePort 서비스를 생성했다면 80:31058/TCP라고 나왔듯이 노드의 포트 31058를 통해 서비스에 접근할 수 있다.

kubectl get svc echo

curl http://127.0.0.1:31058

LoadBalancer 서비스

  • 로컬 쿠버네티스 환경에서는 사용할 수 없는 서비스다.
  • 이 서비스로는 주로 각 클라우드 플랫폼에서 제공하는 로드밸런서와 연동하기 위해 사용된다.

ExternalName 서비스

  • 셀렉터도 포트 정의도 없는 상당히 특이한 서비스다.
  • 쿠버네티스 클러스터에서 외부 호스트를 네임 레졸루션하기 위한 제공한다.
apiVersion: v1
kind: Service
metadata:
  name: echo
spec:
  selector:
    type: ExternalName
    externalName: gihyo.jp

인그레이스

  • 쿠버네티스 클러스터 외부로 서비스를 공개하려면 서비스를 NodePort로 노출시킨다.
  • 그러나 이방법은 L4 레벨까지만 다루기 때문에 HTTP/HTTPS 처럼 경로를 기반으로 서비스를 전환하는 L7 레벨의 제어는 불가능하다.
  • 이를 해결하기 위한 리소스가 인그레이스다.
  • 쿠버네티스 외부에 대한 노출과 가상 호스트 및 경로 기반의 정교한 HTTP 라우팅을 양립시킬 수 있다.
  • HTTP/HTTPS 서비스를 노출하려는 경우 인그레이스를 사용한다.
  • 로컬 쿠버네티스 환경에서는 인그레이스를 사용해 서비스를 노출시킬수 없다.
  • 클러스터 외부에서 온 HTTP 요청을 서비스로 라우팅하기 위한 nginx_ingress_controller 배포한다.

kubectl apply -f https://raw.githubusercontent.com/~~~/mandatory.yaml
kubectl apply -f https://raw.githubusercontent.com/~~~/cloud-generic.yaml

네임스페이스 ingress-nginx에 서비스와 파드가 생성된다.

kubectl -n ingress-nginx get service,pod

인그레스를 통해 접근하기

  • 실제로 인그레스를 통해 서비스에 접근
  • spec.type 값을 지정하지 않으면 ClusterIP 서비스가 생성된다.
apiVersion: v1
kind: Service
metadata:
  name: echo
spec:
  selector:
    app: echo
  ports:
    - name: http
      port: 80

kubectl apply -f simple-service.yaml

simple-ingress.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: echo
spec:
  rules:
  - host: ch05.gihyo.local
    http:
      paths:
      - path: /
        backend:
          serviceName: echo
          servicePort: 80

kubectl apply -f simple-ingress.yaml

kubectl get ingress

  • 인그레스는 L7 라우팅이 가능하므로 가상 호스팅 기능처럼 지정된 호스트 혹은 경로와 일치하는 서비스로 요청을 전달할 수 있다.
    curl http://localhost -H 'Host: ch05.gihyo.local'
  • 인그레스 층에서 HTTP 요청에 다양한 제어를 할수 있다.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: echo
  annotations:
    nginx.ingress.kubernetes.io/server-snippet: |
      set $agentflag 0;

      if ($http_user_agent ~* "(Mobile)") {
        set $agentflag 1;
      }

      if ($agentflag = 1) {
        return 301 http://gihyo.jp/;
      }

spec:
  rules:
  - host: ch05.gihyo.local
    http:
      paths:
      - path: /
        backend:
          serviceName: echo
          servicePort: 80
  • 로컬 쿠버네티스 환경에서는 nginx-ingress-controller를 사용한다.
  • metadata.annotations 파일에 nginx-ingress-controller 자체의 제어 설정을 할 수 있다.
  • nginx.ingress.kubernetes.io/server-snippet 설정하면 Nginx 설정 파일 문법에 따라 요청 필터링 등을 사이에 추가할 수 있다.
  • User-Agent 값에 Mobile이 포함되는 경우 요청을 다른 URL로 리다이렉트가 된다.

curl http://localhost
-H 'Host: ch05.gihyo.local'
-H 'User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X)a AppleWebKit/604.13 (KHTML, like Geccko) Version/11.0 Mobile/15A372 Safari/604.1'

  • 요청 제어를 인그레이스에서 처리할 수 있기 때문에 백엔드나 웹서버, 애플리케이션 서버에서 이를 신경쓸 필요가 없다.
  • nginx-ingress-controller는 이외에도 다양한 기능을 갖추고 있다.
  • 퍼블릭 클라우드 환경에서 인그레이스는 해당 플랫폼의 L7 로드 밸런서를 이용할 수 있다.

freshpod로 이미지 업데이트 탐지하고 파드 자동 업데이트 하기

  • freshpod는 쿠버네티스로 배포된 컨테이너의 이미지가 업데이트 됐는지 탐지해 파드를 자동으로 다시 배포하는 도구다.
  • freshpod는 애초 Minikube의 애드온으로 개발된 것이지만 윈도우/Mac 도커에서도 사용할 수 있으므로 로컬 쿠버네티스 개발 환경에서 빼놓을 수 없는 도구다.

freshpod를 설치하려면 Minikube 리포지토리에 공개된 매니페스트 파일을 적용하면된다.

kubectl apply -f https://raw.githubusercontent.com/kubernetes/minikube/master/deploy/addons/freshpod/freshpod-rc.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template: # template 아래 파드 리소스 정의와 같음
    metadata:
      labels:
        app: nginx
    spec:
      containers:
     - name: nginx
        image: ch04/nginx:latest
        imagePullPolicy: IfNotPresent
        env:
        - name: BACKEND_HOST
          value: 127.0.0.1:8080
        ports:
        - containerPort: 80
      - name: echo
        image: gihyodocker/echo:latest
        ports:
        - containerPort: 8090

freshpod로 컨테이너를 업데이트 하려면 imagePullPolicy를 Always(파드를 재시작할때마다 항상 최신 이미지를 받아옴)가 아니라 IfNotPresent(전에 받아둔 이미지가 있으면 재사용)으로 설정해야 한다.
이미지를 수정하기 전에 -w 옵션을 사용해 파드의 실행상태를 모니터링 한다.

kubectl get pod -l app=nginx -w

그리고 ch04/nginx 이미지를 아무것이나 수정한 다음. 이미지를 빌드한다.

docker image build -t ch04/nginx:latest .

새로운 이미지가 만들어지자마자 해당 파드가 교체되기 시작한다.

  • 로컬 쿠버네티스 환경에서 freshpod를 사용하면 새로 만든 이미지를 매번 레지스트리에 등록하거나 직접 파드를 업데이트 하지 않아도 되기 때문에 효율적인 개발이 된다.

kube-prompt

  • 쿠버네티스 리소스를 다루기 위한 명령행 도구로 kubectl이 있지만 편의성이 개선된 도구가 있다.
  • kube-prompt는 kubectl 명령 및 리소스 이름의 자동완성 기능을 제공한다.
  • macOS/리눅스용 이다.

쿠버네티스 API

  • 매니페스트 파일의 apiVersion 필드의 값이 리소스 종류에 따라 달라진다.
  • 쿠버네티스 리소스를 생성, 수정, 삭제하는 작업은 쿠버네티스 클러스터에 배포된 API가 수행한다.
  • 여러 API를 하나로 묶은 형태로 구성되는데, 이 apiVersion은 해당 작업에 사용되는 API 종류를 나타내는 값이다.

kubectl api-versions

  • 쿠버네티스의 리소스가 각각 어떤 API를 통해 지원되는지 알고 있다면 쿠버네티스 API 리포지토리를 확인한다.

 

도커/쿠버네티스를 활용한 컨테이너 개발 실전 입문
야마다 아키노리 지음 / ㅣ심효섭 옮김

반응형