본문 바로가기
Devops

[Kubernetes] 쿠버네티스 오브젝트 (Service, Volume, ConfigMap)

by heekng 2022. 8. 30.
반응형

쿠버네티스 오브젝트 (Service, Volume, ConfigMap)

지난 포스팅에 이어 쿠버네티스의 오브젝트에 대하여 알아보겠습니다.

Service

Pod은 IP를 가지고, 다른 Pod과 통신할 수 있습니다.
하지만 Pod은 쉽게 삭제되고, 생성될 수 있기 때문에 쿠버네티스는 고정된 IP를 가진 서비스를 만들고 서비스를 통해 Pod에 접근합니다.

Service(ClusterIP) 만들기

ClusterIP는 클러스터 내부에 새 IP를 할당하고, 여러 Pod을 바라보는 로드밸런서 기능을 제공합니다.
그리고 서비스 이름을 내부 도메인 서버에 등록하고 Pod간 서비스 이름으로 통신할 수 있습니다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis
spec:
  selector:
    matchLabels:
      app: counter
      tier: db
  template:
    metadata:
      labels:
        app: counter
        tier: db
    spec:
      containers:
        - name: redis
          image: redis
          ports:
            - containerPort: 6379
              protocol: TCP

---
apiVersion: v1
kind: Service
metadata:
  name: redis
spec:
  ports:
    - port: 6379
      protocol: TCP
  selector:
    app: counter
    tier: db

redis라는 이름의 서비스를 만드는 yaml 파일입니다.

selector을 통해 접근할 Pod을 지정하고, ports를 통해 연결되는 port를 지정합니다.

Service(NodePort) 만들기

ClusterIP는 클러스터 내부에서만 접근할 수 있으므로 클러스터 외부에서 접근하려면 NodePort 서비스를 사용해야 합니다.

apiVersion: v1
kind: Service
metadata:
  name: counter-np
spec:
  type: NodePort
  ports:
    - port: 3000
      protocol: TCP
      nodePort: 31000
  selector:
    app: counter
    tier: app

이전과 달라진 점은 nodePort가 추가된 것과 type이 명시되었다는 것입니다.

해당 서비스가 외부 IP의 31000포트와 연결됩니다.

spec.ports.nodePort는 노드에 오픈할 Port로 미지정시 30000~32768번 포트중 하나로 자동 할당됩니다.

또한 NodePort는 ClusterIP의 기능을 기본으로 포함합니다.

Service(LoadBalancer) 만들기

NodePort는 하나의 노드에 할당되어 해당 노드가 사라진다면 다른 노드를 통해 접근이 불가능합니다.
3개의 노드가 있을 때, 어떠한 노드로 접근하더라도 NodePort로 연결할 수 있지만 어떤 노드가 살아있는지는 알 수 없습니다.

이를 해결해 정상적인 노드에 접근하기 위해 모든 노드를 바라보는 LoadBalancer가 필요합니다.

LoadBalancer을 이용하면 NodePort에 요청하는 것이 아닌 LoadBalancer에 요청하고, LoadBalancer은 정상 노드에 자동으로 연결해줘 NodePort의 단점을 해결할 수 있습니다.

apiVersion: v1
kind: Service
metadata:
  name: counter-lb
spec:
  type: LoadBalancer
  ports:
    - port: 30000
      targetPort: 3000
      protocol: TCP
  selector:
    app: counter
    tier: app

Volume

Pod 안의 컨테이너는 Pod이 제거될 때, 내부 저장 데이터 또한 모두 사라집니다.
데이터베이스의 경우 데이터가 유실되지 않도록 별도의 저장소에 데이터를 저장하고 새 데이터베이스 컨테이너를 만들 때 이전 데이터를 가져와 동기화를 해야합니다.

이 때 사용하는 기술은 Volume입니다.

제 환경이 로컬이기 때문에 클라우드와 같은 외부 스토리지를 이용하지 않고, local저장소를 이용하는 방법을 알아봅니다.

Volume(Local) 사용하기

apiVersion: v1
kind: Pod
metadata:
  name: sidecar
spec:
  containers:
    - name: app
      image: busybox
      args:
        - /bin/sh
        - -c
        - >
          while true;
          do
            echo "$(date)\n" >> /var/log/example.log;
            sleep 1;
          done
      volumeMounts:
        - name: varlog
          mountPath: /var/log
    - name: sidecar
      image: busybox
      args: [/bin/sh, -c, "tail -f /var/log/example.log"]
      volumeMounts:
        - name: varlog
          mountPath: /var/log
  volumes:
    - name: varlog
      emptyDir: {}
---
apiVersion: v1
kind: Pod
metadata:
  name: host-log
spec:
  containers:
    - name: log
      image: busybox
      args: ["/bin/sh", "-c", "sleep infinity"]
      volumeMounts:
        - name: varlog
          mountPath: /host/var/log
  volumes:
    - name: varlog
      hostPath:
        path: /var/log

일반적인 Pod의 생성과 함께 volumes를 이용해 볼륨을 생성하고, 컨테이너 생성에 해당 볼륨을 마운트했습니다.

ConfigMap

지금까지 여러 오브젝트를 만들면서 여러 env를 직접 지정했습니다.
이렇게 yaml파일마다 env를 지정하기보다 설정, 환경변수를 외부로 빼고 관리할 수 있는 방법을 알아봅니다.

ConfigMap 파일로 관리하기

global:
  scrape_interval: 15s

scrape_configs:
  - job_name: prometheus
    metrics_path: /prometheus/metrics
    static_configs:
      - targets:
          - localhost:9090
kubectl create cm my-config --from-file=config-file.yml

kubectl get cm

kubectl describe cm/my-config

이렇게 생성한 ConfigMap을 연결할 Pod에 volumes로 연결합니다.

apiVersion: v1
kind: Pod
metadata:
  name: alpine
spec:
  containers:
    - name: alpine
      image: alpine
      command: ["sleep"]
      args: ["100000"]
      volumeMounts:
        - name: config-vol
          mountPath: /etc/config
  volumes:
    - name: config-vol
      configMap:
        name: my-config

이렇게 연결한 configfile은 볼륨으로 마운트한 디렉토리에 생성되게 됩니다.

env파일로 만들기

configMap을 env포멧으로 만들어 사용할 때에는

hello=world
haha=hoho

위와 같이 파일을 만들고, 이전과 동일하게 사용합니다.

YAML파일로 선언하기

apiVersion: v1
kind: ConfigMap
metadata:
  name: my-config
data:
  hello: world
  kuber: netes
  multiline: |-
    first
    second
    third

volume이 아닌 환경변수로 사용하기

위에서는 파일 자체를 volume으로 연결해 사용했지만, 환경변수로 바로 사용할 수도 있습니다.

apiVersion: v1
kind: Pod
metadata:
  name: alpine-env
spec:
  containers:
    - name: alpine
      image: alpine
      command: ["sleep"]
      args: ["100000"]
      env:
        - name: hello
          valueFrom:
            configMapKeyRef:
              name: my-config
              key: hello

위와 같이 env에서 valueFrom을 이용해 바로 값을 가져와 사용할 수 있습니다.

마침

여기까지 쿠버네티스의 기본적인 Object를 알아보았습니다.

물론 Secret, Ingress와 같은 중요한 오브젝트도 존재하지만, 간략하게 정리해보았습니다.

감사합니다.

반응형