replicaset 을 이용해 파드를 관리할 때, 파드 수에 대한 수평적 확장 즉, 파드 스케일 아웃을 수행하는 방법은 두가지가 있다.

먼저 아래 내용으로 파드 레플리카를 3개 구동시킨다.

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: sample-rs
spec:
  replicas: 3
  selector:
    matchLabels:
      app: sample-app
  template:
    metadata:
      labels:
        app: sample-app
    spec:
      containers:
        - name: nginx-container
          image: nginx:1.16
          ports:
            - containerPort: 80

 

아래 커맨드를 실행해 파드 갯수를 확인한다.

$ kubectl describe replicasets.apps sample-rs
# replicaset 의 정보 확인

$ kubectl get pods -o wide -L app
# pod 가 3개 띄워져 있는지 확인

 

1. kubectl scale 명령어를 이용하는 방법

아래 커맨드를 실행해 pod 의 갯수를 5개로 조정 후 다시 파드의 갯수를 확인한다.

$ kubectl scale replicaset sample-rs --replicas 5
# replica 갯수를 5개로 조정

$ kubectl get pods -o wide -L app
# pod 의 갯수가 5개로 변경되었는지 확인

 

kubectl scale 명령어를 이용한 이 방법은 커맨드로 간편하게 스케일링을 할 수 있으나, 현재 상태가 매니페스트 파일과 동일하지 않게 되기 때문에 실무에서는 권장하지 않는 방법이다.

참고로, scale 명령어는 ReplicationController, Deployment, StatefulSet, Job, CronJob 에 대해서도 사용할 수 있다.

 

2. 매니페스트를 동적으로 수정 후 kubectl apply 하는 방법

아래 커맨드를 실행해 replica 수를 3개에서 5개로 수정하여 저장한 후, 매니페스트를 apply 한다.

$ sed -i -e 's|replicas: 3|replicas: 5|' sample-rs.yaml
# sed 명령어를 이용해 sample-rs.yaml 파일의 내용 중 "replicas: 3" 를 "replicas: 5" 로 치환

$ kubectl apply -f sample-rs.yaml
# 변경된 매니페스트 적용

$ kubectl get pods -o wide -L app
# pod 의 갯수가 5개로 변경되었는지 확인

 

이를 원시적으로 응용하면 원격에서 쉘스크립트를 호출하며 인자를 넘겨 replica 갯수를 조정할 수 있을 것이다. IaC 를 구현하기 위해서라도 이러한 형태로 사용하는 것이 권장된다.

블로그 이미지

망원동똑똑이

프로그래밍 지식을 자유롭게 모아두는 곳입니다.

,

Dockerfile 에서 WORKDIR 지시자를 통해 컨테이너 내부에서의 작업 디렉터리를 설정하는 것처럼, 파드 매니페스트 설정에서도 작업 디렉터리를 설정할 수 있다. 이 설정은 Dockerfile 의 WORKDIR 을 덮어쓰게 된다.

apiVersion: v1
kind: Pod
metadata:
  name: workingdir
spec:
  containers:
  - name: nginx-container
    image: nginx:1.16
    workingDir: /tmp

 

위 내용으로 파드를 생성한 후, 아래 커맨드로 프로세스가 실행되는 디렉터리가 변경되었음을 확인할 수 있다.

 

$ kubectl exec -it workingdir -- pwd
/tmp

 

블로그 이미지

망원동똑똑이

프로그래밍 지식을 자유롭게 모아두는 곳입니다.

,

리눅스에서는 /etc/resolv.conf 에 명시된 DNS 서버를 통해 호스트명을 해석하기 전에 먼저 /etc/hosts 파일로 정적 호스트명을 해석한다. 쿠버네티스에서 파드 내의 모든 컨테이너의 /etc/hosts 설정을 변경하기 위해서는 아래와 같이 설정한다.

 

apiVersion: v1
kind: Pod
metadata:
  name: hostaliases
spec:
  containers:
    - name: nginx-container
      image: nginx:1.16
  hostAliases:
    - ip: 8.8.8.8
      hostnames:
        - google-dns
        - google-public-dns

 

위 내용으로 파드를 생성한 후, 아래 커맨드로 /etc/hosts 를 확인한다.

$ kubectl exec -it hostaliases -- cat /etc/resolv.conf

# Entries added by HostAliases.
8.8.8.8	google-dns	google-public-dns

 

블로그 이미지

망원동똑똑이

프로그래밍 지식을 자유롭게 모아두는 곳입니다.

,

파드가 사용하는 DNS 또한 매니페스트 파일을 통해 설정할 수 있다.

spec.dnsPolicy 필드에 지정하며, 지정할 수 있는 값은 아래와 같다.

설정값 동작
ClusterFirst k8s 클러스터 내부 DNS 서비스에 질의하고, 해석되지 않으면 업스트림 DNS 서버(외부 DNS)에 질의(기본값)
None 파드 정의 내에서 정적으로 설정(직접 지정)
Default 파드가 올라간 k8s 노드의 /etc/resolv.conf 를 상속받음
ClusterFirstWithHostNet spec.hostNetwork: true 설정시, DNS 만 ClustFirst 로 동작

 

1. ClusterFirst

기본값으로, 클러스터 내부의 DNS 서버에 질의를 하고, 해석이 안되는 경우 업스트림 DNS 서버에 질의한다.

apiVersion: v1
kind: Pod
metadata:
  name: dnspolicy-clusterfirst
spec:
  dnsPolicy: ClusterFirst
  containers:
  - name: nginx-container
    image: nginx:1.16

 

위 파드를 실행하고, 아래 커맨드를 이용해서 컨테이너 내부의 DNS 설정파일과 클러스터 내부의 DNS Service에 할당된 IP 주소가 동일한 것을 알 수 있다.

 

$ kubectl exec -it dnspolicy-clusterfirst -- cat /etc/resolv.conf
# nameserver 의 IP 주소 확인

$ kubectl get services -n kube-system
# kube-dns 서비스의 CLUSTER-IP 확인

 

2. None

파드에서 클러스터 내부의 DNS 를 사용하지 않고, 외부 DNS 를 사용하도록 설정하는 방식이다. sepc.dnsConfig 에 직접 DNS 를 설정한다.

apiVersion: v1
kind: Pod
metadata:
  name: dnspolicy-none
spec:
  dnsPolicy: None
  dnsConfig:
    nameservers:
    - 8.8.8.8
    - 8.8.4.4
    searches:
    - example.com
    options:
    - name: ndots
      value: "5"
  containers:
  - name: nginx-container
    image: nginx:1.16

 

위 파드를 실행하고, 아래 커맨드를 실행시, DNS 설정이 직접 지정한 값으로 사용되는 것을 확인할 수 있다.

다만, search 와 ndots option 없이 정적으로 외부 DNS 서버만 사용하도록 설정하면, 클러스터 내부 DNS 를 사용한 서비스 디스커버리는 사용할 수 없게 된다.

$ kubectl exec -it dnspolicy-none -- cat /etc/resolv.conf
# nameserver 의 IP 주소 확인
search example.com
nameserver 8.8.8.8
nameserver 8.8.4.4
options ndots:5

 

참고로, 컨테이너 내의 /etc/resolv.conf 의 의미는 다음과 같다.

  • options ndots:5 와 search example.com
    • ndots 는 name with dots 의 약자로, 질의된 도메인 이름에 최소 몇개의 dot 이 있어야 완전한 도메인(FQDN)으로 인식할지 정의하는 값이다.
      • FQDN 으로 인식하지 않으면, search 에 설정된 도메인 이름을 하나씩 suffix 로 붙여 질의함.
        • 예를 들어, ndots:5 이고, search search.domain.com 일 때 test.example.com 으로 질의하면, test.example.com.search.domain.com 과 같이 search 도메인을 붙여 질의한다.
      • FQDN 으로 인식되면, 그대로 DNS 로 질의함.
        • 예를 들어, ndots:2 일 때 test.example.com 으로 질의하면 그대로 DNS 로 질의한다.
    • 내부 DNS 이름으로 통신하는 경우가 많은 경우, 대부분의 짧은 이름들이 내부 DNS 도메인을 통해 먼저 해석되도록 유도하기 위해 ndots:5 를 설정하는 경우가 많다.(응답속도 빠름)

 

3. Default

쿠버네티스 노드의 DNS 설정을 그대로 상속받는다. 이름이 default 이지만 기본값이 아님에 유의하자.

쿠버네티스 노드의 네트워크 설정(DNS 설정 포함)을 상속받는 설정인 spec.hostNetwork: true 과 동일한 효과를 가진다.

apiVersion: v1
kind: Pod
metadata:
  name: dnspolicy-default
spec:
  dnsPolicy: Default
  containers:
  - name: nginx-container
    image: nginx:1.16

 

위 파드를 실행하고, 아래 커맨드를 실행하면 노드에서 상속받은 DNS 설정을 확인할 수 있다.

$ kubectl exec -it dnspolicy-default -- cat /etc/resolv.conf
# node 에서 상속받은 DNS 설정이 조회됨

 

 

노드의 DNS 설정을 상속받기 때문에, 클러스터 내부의 DNS 를 사용한 서비스 디스커버리를 할 수 없다.

 

4. ClusterFirstWithHostNet

spec.hostNetwork: true 를 설정한 파드는 노드의 네트워크 설정을 상속받기 때문에, spec.dnsPolicy: ClusterFirst 를 설정해도 클러스터 내부 DNS 를 사용하지 않게 된다. 이때 ClusterFirst 와 같은 효과를 가지기 위해 사용하는 설정이다.

apiVersion: v1
kind: Pod
metadata:
  name: dnspolicy-clusterfirstwithhostnet
spec:
  dnsPolicy: ClusterFirstWithHostNet
  hostNetwork: true
  containers:
  - name: nginx-container
    image: nginx:1.16

 

위 파드를 실행하고, 아래 커맨드를 실행하면 ClusterFirst 와 동일하게 컨테이너 내부의 DNS 설정파일과 클러스터 내부의 DNS Service에 할당된 IP 주소가 동일한 것을 알 수 있다.

$ kubectl exec -it dnspolicy-clusterfirstwithhostnet -- cat /etc/resolv.conf
# nameserver 의 IP 주소 확인

$ kubectl get services -n kube-system
# kube-dns 서비스의 CLUSTER-IP 확인

 

블로그 이미지

망원동똑똑이

프로그래밍 지식을 자유롭게 모아두는 곳입니다.

,

파드는 멀티 컨테이너 파드로 구성할 수 있지만, 일반적으로 파드 내 여러 메인 컨테이너가 있을 시 관리하기 어렵다는 점으로 인해 1개의 컨테이너만 띄워서 사용한다. 하지만, 아래와 같은 역할을 하는 서브 컨테이너를 종종 같이 띄우기도 한다.

  • 프록시
  • 런타임에 설정값을 변경
  • 로컬 캐시
  • SSL

멀티 컨테이터 파드를 구성하는 파드 디자인 패턴 3가지를 소개한다.

종류 개요
사이드카 패턴(sidecar pattern) 메인 컨테이너에 기능을 추가한다.
앰배서더 패턴(ambassador pattern) 외부 시스템과의 통신을 중계한다.
어댑터 패턴(adapter pattern) 외부 접속을 위한 인터페이스를 제공한다.

 

1. 사이드카 패턴

메인 컨테이너(애플리케이션) 외에 보조적인 기능을 하는 컨테이너를 추가로 두는 패턴이다. 예를 들어 런타임에 애플리케이션의 설정값을 변경해주는 컨테이너, Git 저장소의 소스를 파드 로컬 스토리지에 싱크하여 애플리케이션에서 참조할 수 있도록 하는 컨테이너, 적재된 애플리케이션 로그를 외부 오브젝트 스토리지로 전송하는 컨테이너 등이 있을 수 있다.

 

2. 앰배서더 패턴

외부 접속을 중계해주는 컨테이너를 두는 패턴이다. 중계자를 두는 목적은 메인 컨테이너와 외부 서비스의 결합도를 낮추기 위함인데, 객체지향 프로그래밍 언어의 인터페이스를 떠올리면 이해하기 쉽다. 예를 들어 외부 DB와 애플리케이션을 연결해야 하는데, 애플리케이션이 직접 외부 DB를 접속하면, DB 인터페이스가 변경되거나 샤딩이나 분산 DB로 인해 어떤 머신으로 접속해야 할 지 불분명할 때 이를 애플리케이션 코드나 설정에서 직접 구현해야 한다. 하지만 애플리케이션에서는 중계자 컨테이너만 바라보고, 중계자가 외부 서비스의 인터페이스를 구현하게 한다면, 애플리케이션에서는 디커플링이 된다. 동일 파드 내에서 이기 때문에 애플리케이션은 중계 컨테이너를 localhost 로 간단하게 접속할 수 있다.

 

3. 어댑터 패턴

메인 컨테이너에서 출력하는 데이터 형식과 외부 서비스에서 요구하는 데이터 형식이 다를 때, 데이터 형식을 변환해주는 컨테이너를 두는 패턴이다. 예를 들어 프로메테우스 같은 모니터링 툴을 사용할 때는 정의된 형식으로 메트릭을 수집해야 한다. 그러나 애플리케이션 출력은 프로메테우스의 메트릭 형식을 지원하지 않는다. 따라서 이를 요구되는 형식으로 변환해주는 어댑터 컨테이너를 둔다. 앰배서더 패턴과 동일하게 localhost로 접속할 수 있다.

 

 

 

 

블로그 이미지

망원동똑똑이

프로그래밍 지식을 자유롭게 모아두는 곳입니다.

,

들어가기 전에

- 일반적인 pod가 동작하는 방식에 대한 간단한 설명

파드 생성 명령어를 입력하면, 클러스터 내에 있는 master 노드(control plane)의 API pod로 요청이 들어간다.

API pod는 master 노드 내의 etcd 파드에 저장되어있는 클러스터의 상태정보를 꺼내어 scheduler pod 에 전달하여 pod 를 실행하기 가장 적합한 node 가 어딘지 조회한다.

API 는 해당 노드의 kubelet 에 pod 실행을 요청하며, kubelet 은 노드 내의 컨테이너 엔진을 통해 registry hub 에서 컨테이너 이미지를 다운받아 파드 형태로 실행하게 된다. 실행이 완료되면 컨테이너 엔진은 다시 kubelet 에게 실행정보를 전달하고, kubelet 은 다시 master 노드의 API 에 실행정보를 전달한다. API 는 etcd 파드에 해당 정보를 저장한다.

 

- 그렇다면 static pod 는 어떻게 실행될까?

일반 pod 는 API 를 통해 실행되는 반면, static pod 는 각 노드의 kubelet 에 의해 직접 실행된다.

더 자세히 설명하면, 각 node 에 daemon 형태로 떠있는 kubelet 프로세스는 각 노드 파일시스템의 /var/lib/kubelet/config.yaml 파일의 kubelet 구성정보를 기반으로 동작하는데, 이 파일에 static pod 를 배치시킬 위치 정보를 설정할 수 있다.(기본값 /etc/kubernets/manifests 디렉토리) 즉, /etc/kubernets/manifests 디렉토리 내에 pod.yaml 파일을 저장하면, kubelet 은 해당 정보로 pod 를 실행한다.(이것이 static pod). 반대로 해당 pod.yaml 을 삭제하면 kubelet 은 해당 pod 를 삭제한다.

 

여기서 master 노드(control plane)에 존재하는 API, etcd, scheduler, controller 등의 component 들도 실제로는 pod 인데, 어떻게 API pod 가 아직 생성되지 않은 상태에서 생성이 되는지에 대한 의문이 풀린다. mster node 의 kubelet daemon이 바라보는 manifests 내에 해당 컴포넌트들이 설정되어있기 때문이다.(모두 static pod 인 것이다)

 

 

 

참고: CKA의 static pod 를 문제에서는 configure kubelet to start a pod on the node 로 표현함.

1. pod 템플릿 생성

$ kubectl run <파드명> --image=<이미지명> --dry-run=client -o yaml

출력된 파드 설정 내용을 복사해둔다.

 

2. 작업할 node 접속

$ ssh <접속할노드명>

 

3. root 전환

$ sudo -i

 

4. static pod 설정파일을 생성하여 pod 실행

$ cat /var/lib/kubelet/config.yaml # kubelet 구성파일 출력

출력된 정보 중 staticPodPath 경로 확인 후 해당 경로로 이동

$ cd /etc/kubernetes/manifests

 

$ cat > <pod설정파일명>.yaml

복사했던 pod 설정정보 shift + insert 로 붙여넣고 ctrl + d 로 저장(불필요한 내용은 제거)

자동으로 static pod 가 실행된다.

 

5. master 노드로 복귀 후 static pod 확인

$ kubectl get pods

<pod명>-<node명> 규칙으로 파드가 생성된 것을 확인 가능

 

참고영상: https://www.youtube.com/watch?v=u0Wg0HBVmmk&list=PLApuRlvrZKojqx9-wIvWP3MPtgy2B372f&index=7&ab_channel=TTABAE-LEARN

블로그 이미지

망원동똑똑이

프로그래밍 지식을 자유롭게 모아두는 곳입니다.

,

1. 클러스터 전환

$ kubectl config use-context <사용할컨텍스트명>

 

2. 네임스페이스 생성

$ kubectl create namespace <네임스페이스명> # 네임스페이스 생성
$ kubectl get namespaces # 네임스페이스 확인

 

3. 네임스페이스 내부에 pod 생성

공식문서: https://kubernetes.io/docs/reference/kubectl/generated/kubectl_run/

$ kubectl run <파드명> \
  --namespace <네임스페이스명> \
  --image=<사용할이미지명:버전> \
  --env=<key=value> \
  --dry-run-client \ # 테스트로 돌리기
  -o yaml # 생성 결과를 yaml 형태로 출력하기
$ kubectl get pod --namespace <네임스페이스명> # 특정 네임스페이스에서 동작중인 파드 확인

 

 

 

참고영상: https://www.youtube.com/watch?v=c5kdKi3wAaM&list=PLApuRlvrZKojqx9-wIvWP3MPtgy2B372f&index=6&ab_channel=TTABAE-LEARN

블로그 이미지

망원동똑똑이

프로그래밍 지식을 자유롭게 모아두는 곳입니다.

,

1. 현재 컨텍스트 확인

$ kubectl config current-context

 

 

2. 작업 시스템(node) 접속 및 환경 확인

$ ssh <node명> # 특정 node에 ssh 접속
$ etcd --version # etcd 버전 확인
$ etcdctl version # etcdctl 버전 확인

 

3. etcd backup

공식문서: https://kubernetes.io/docs/tasks/administer-cluster/configure-upgrade-etcd/#restoring-an-etcd-cluster

$ ETCDCTL_API=3 etcdctl \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=<인증서ca파일경로> \
  --cert=<클라이언트인증서파일경로> \
  --key=<클라이언트키파일경로> \
  snapshot save <백업스냅샷파일경로>

 

4. restore

공식문서: https://kubernetes.io/docs/tasks/administer-cluster/configure-upgrade-etcd/#restoring-an-etcd-cluster

$ ETCDCTL_API=3 etcdctl \
  --data-dir <복구한스냅샷이풀릴경로> \
  snapshot restore <복구할스냅샷파일경로>

 

5. etcd 파드의 data 경로 수정 적용

 

특정 네임스페이스로 동작중인 etcd pod 확인

$ kubectl get pod -n kube-system

 

 

출력 중 etcd pod 확인 가능

해당 etcd pod의 설정경로는 /etc/kubernetes/manifests/etcd.yaml 이며, spec.volumes[].name: etcd-data 의 hostPath.path 부분을 복구한 스냅샷이 풀린 경로로 수정하여 저장하면 static pod 이기 때문에 자동으로 restart 되며 적용됨.

docker ps | grep etcd 로 etcd pod 내의 컨테이너가 정상적으로 up 되었는지 확인.

 

 

 

참고 영상: https://www.youtube.com/watch?v=dv_5WCYS5P8&list=PLApuRlvrZKojqx9-wIvWP3MPtgy2B372f&index=4&ab_channel=TTABAE-LEARN

블로그 이미지

망원동똑똑이

프로그래밍 지식을 자유롭게 모아두는 곳입니다.

,