본문 바로가기

메가존 클라우드 2기 교육/실무 특화

Kubernetes - NFS, configMap, namepsace, ResourceQuota

NFS

 NFS 설치

## docker에 nfs 설치
yum install -y nfs-utils.x86_64
mkdir /nfs_shared
chmod 777 /nfs_shared/
echo '/nfs_shared 192.168.0.0/21(rw,sync,no_root_squash)' >> /etc/exports
systemctl enable --now nfs

# 원활한 테스트를 위해 방화벽 중지
systemctl stop firewalld

## worker1과 worker2에도 nfs 설치
## 쿠버네티스가 기본적으로 nfs타입을 모르기 때문
yum install -y nfs-utils.x86_64

NFS 사용

# nfs-pv 템플릿 작성
vi nfs-pv.yaml
//
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv
spec:
  capacity:
    storage: 100Mi    # 2진법
  accessModes:
    - ReadWriteMany    # 여러 노드로 읽기 쓰기 가능하게 마운트
  persistentVolumeReclaimPolicy: Retain
  nfs:
    server: 192.168.1.158  # nfs를 설치한 아이피
    path: /nfs_shared
//

# kubectl apply -f nfs-pv.yaml
# kubectl get pv
Available: PVC와 연결 가능 / Bound: PVC와 연결 중

# nfs-pvc 생성
vi nfs-pvc.yaml
//
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 10Mi
//

# kubectl apply -f nfs-pvc.yaml
# kubectl get pvc
# kubectl get pv
pvc와 연결되어 'Bound'가 되었다.

# nfs-pvc-deploy 템플릿 생성 
vi nfs-pvc-deploy.yaml
//
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-pvc-deploy
spec:
  replicas: 4
  selector:
    matchLabels:
      app: nfs-pvc-deploy

  template:
    metadata:
      labels:
        app: nfs-pvc-deploy
    spec:
      containers:
      - name: nginx
        image: 192.168.1.158:5000/nginx:latest
        volumeMounts:
        - name: nfs-vol
          mountPath: /usr/share/nginx/html
      volumes:
      - name: nfs-vol
        persistentVolumeClaim:
          claimName: nfs-pvc
//
# kubectl apply -f nfs-pvc-deploy.yaml
# kubectl get pod
배포가 되어 생선된 파드들은 PVC와 연결되어 마운트가 된다.

# 로드밸런서 부여 (80포트)
kubectl expose deployment nfs-pvc-deploy --type=LoadBalancer --name=nfs-pvc-deploy-svc1  --port=80
'df -h'명령어를 통해 worker1,2가 'docker'와 마운트 됐음을 알 수 있다.

## docker에서
# 마운트 시킨 폴더에 웹 파일을 만들어준다.
tar xvf food.tar -C /nfs_shared/
docker에서 nfs 마운트 폴더에 웹사이트 파일을 만들어준다.
로드 밸런서의 외부 아이피로 접속하면 웹 사이트가 변한 것을 확인할 수 있다.

 


configMap

configMap이란?

컨피그맵은 키-값 쌍으로 기밀이 아닌 데이터를 저장하는 데 사용하는 API 오브젝트이다. 파드는 볼륨에서 환경 변수, 커맨드-라인 인수 또는 구성 파일로 컨피그맵을 사용할 수 있다.
컨피그맵을 사용하면 컨테이너 이미지에서 환경별 구성을 분리하여, 애플리케이션을 쉽게 이식할 수 있다.

configMap 관리

컨피그맵은 컨테이너를 필요한 환경 설정을 컨테이너와 분리해서 제공하는 기능이다.

개발용과 상용 서비스에서는 서로 다른 설정이 필요할 때가 많다. 사용하는 데이터베이스가 다를 수도 있고, 실제 개발할 때는 디버그 모드로 로그를 출력하는데, 서비스용에서는 시스템 정보를 나타내는 모드로 로그를 출력해야 하는 등의 차이가있다. 이렇게 다른 설정으로 컨테이너를 실행해야할 때 사용하는 것이 컨피그맵이다.

컨피그맵을 컨테이너와 분리하면 컨테이너 하나를 개발용, 상용 서비스를 운영하기 전 보안이나 성능 장애 등을 검증하는 스테이지용, 상용 서비스용으로 사용할 수 있다.


개발용 configMap

# master1에서 폴더 생성 후 이동
mkdir configmap && cd $_

# 개발용 컨피그맵 템플릿 생성
vi configmap-dev.yaml
//
apiVersion: v1
kind: ConfigMap
metadata:
  name: config-dev
  namespace: default
data:
  DB_URL: localhost
  DB_USER: myuser
  DB_PASS: mypass
  DEBUG_INFO: debug
//

# kubectl apply -f configmap-dev.yaml
# kubectl describe configmaps config-dev
DB_URL: localhost / DB_USER: myuser / DEBUG_INF: debug / DB_PASS: mypass

# deployment-config01 템플릿 생성
vi deployment-config01.yaml
//
apiVersion: apps/v1
kind: Deployment
metadata:
  name: configapp
  labels:
    app: configapp
spec:
  replicas: 1
  selector:
    matchLabels:
      app: configapp

  template:
    metadata:
      labels:
        app: configapp
    spec:
      containers:
      - name: testapp
        image: nginx
        ports:
        - containerPort: 8080
        env:
        - name: DEBUG_LEVEL    # 변수명
          valueFrom:           #
            configMapKeyRef:
              name: config-dev
              key: DEBUG_INFO
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: configapp
  name: configapp-svc
  namespace: default
spec:
  type: NodePort
  ports:
  - nodePort: 30800
    port: 8080
    protocol: TCP
    targetPort: 80
  selector:
    app: configapp
//

# kubectl apply -f deployment-config01.yaml
# kubectl exec -it configapp-64d4554b68-v55g5 -- bash

컨테이너에 접속해서 환경변수를 확인. 지정한 대로 잘 되어있다.

 워드프레스에서의 configMap

# 워드프레스용 configMap 템플릿 생성
vi configmap-wordpress.yaml
//
apiVersion: v1
kind: ConfigMap
metadata:
  name: config-wordpress
  namespace: default
data:
  MYSQL_ROOT_HOST: '%'
  MYSQL_ROOT_PASSWORD: mode1752
  MYSQL_DATABASE: wordpress
  MYSQL_USER: wpuser
  MYSQL_PASSWORD: wppass
//

# kubectl apply -f configmap-wordpress.yaml
# kubectl describe configmaps config-wordpress
정의한 환경변수가 보인다.

# 워드프레스 mysql 템플릿 생성.
vi mysql-pod-svc.yaml
//
apiVersion: v1
kind: Pod
metadata:
  name: mysql-pod
  labels:
    app: mysql-pod
spec:
  containers:
  - name: mysql-container
    image: mysql:5.7
    envFrom:
    - configMapRef:
        name: config-wordpress    # configMap 참조
    ports:
    - containerPort: 3306
---
apiVersion: v1
kind: Service
metadata:
  name: mysql-svc
spec:
  type: ClusterIP
  selector:
    app: mysql-pod
  ports:
  - protocol: TCP
    port: 3306
    targetPort: 3306
//

# kubectl apply -f mysql-pod-svc.yaml
mysql 파드와 서비스 생성.

## mysql 확인
# master1에 mysql 설치
yum install -y mysql
접속해서 데이터베이스가 정상적으로 생성된 것을 확인.

# 워드프레스 웹서버 파드 템플릿 생성 
vi wordpress-pod-svc.yaml
//
apiVersion: v1
kind: Pod
metadata:
  name: wordpress-pod
  labels:
    app: wordpress-pod
spec:
  containers:
  - name: wordpress-container
    image: wordpress
    env:
    - name: WORDPRESS_DB_HOST
      value: mysql-svc:3306      # 아이피 대신 서비스 명을 도메인처럼 사용
    - name: WORDPRESS_DB_USER
      valueFrom:
        configMapKeyRef:
          name: config-wordpress    # 컨피그맵에서 키 값을 통해 밸류를 참조
          key: MYSQL_USER
    - name: WORDPRESS_DB_PASSWORD
      valueFrom:
        configMapKeyRef:
          name: config-wordpress
          key: MYSQL_PASSWORD
    - name: WORDPRESS_DB_NAME
      valueFrom:
        configMapKeyRef:
          name: config-wordpress
          key: MYSQL_DATABASE
    ports:
    - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: wordpress-svc
spec:
  type: LoadBalancer
#  externalIPs:
#  - 192.168.56.103
  selector:
    app: wordpress-pod
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
//

# kubectl apply -f wordpress-pod-svc.yaml

파드와 서비스 생성완료.
접속하면 워드프레스 창이 뜬다. 만일 '503'에러가 뜨는 경우, 다른 네임 스페이스에 80포트가 있는지 확인

여담으로 사진 처럼 없는 VM 아이피로 하는 경우 작동하지 않는다. 외부 아이피로 부여되는 아이피는 무조건 VM의 아이피로 존재햐아만 가능하다.

 Deployment 사용하여 워드프레스 구축

## 만일을 위해 모두 삭제
# kubectl delete all --all

# mysql deployment, 서비스 템플릿 생성
vi mysql-deploy-svc.yaml
//
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql-deploy
  labels:
    app: mysql-deploy
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mysql-deploy
  template:
    metadata:
      labels:
        app: mysql-deploy
    spec:
      containers:
      - name: mysql-container
        image: mysql:5.7
        envFrom:
        - configMapRef:
            name: config-wordpress
        ports:
        - containerPort: 3306
---
apiVersion: v1
kind: Service
metadata:
  name: mysql-svc
spec:
  type: ClusterIP
  selector:
    app: mysql-deploy
  ports:
  - protocol: TCP
    port: 3306
    targetPort: 3306
//

# 워드프레스 deployment 웹 서버 템플릿 생성
vi wordpress-deploy-svc.yaml
//
apiVersion: apps/v1
kind: Deployment
metadata:
  name: wordpress-deploy
  labels:
    app: wordpress-deploy
spec:
  replicas: 1
  selector:
    matchLabels:
      app: wordpress-deploy
  template:
    metadata:
      labels:
        app: wordpress-deploy
    spec:
      containers:
      - name: wordpress-container
        image: 192.168.1.158:5000/wordpress
        env:
        - name: WORDPRESS_DB_HOST
          value: mysql-svc:3306
        - name: WORDPRESS_DB_USER
          valueFrom:
            configMapKeyRef:
              name: config-wordpress
              key: MYSQL_USER
        - name: WORDPRESS_DB_PASSWORD
          valueFrom:
            configMapKeyRef:
              name: config-wordpress
              key: MYSQL_PASSWORD
        - name: WORDPRESS_DB_NAME
          valueFrom:
            configMapKeyRef:
              name: config-wordpress
              key: MYSQL_DATABASE
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: wordpress-svc
spec:
  type: LoadBalancer
#  externalIPs:
#  - 192.168.1.102
  selector:
    app: wordpress-deploy
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
//

# kubectl apply -f wordpress-deploy-svc.yaml

 

 


Namespace

namespace 관리 

 네임스페이스는 쿠버네티스 클러스터 하나를 여러 개 논리적인 단위로 나눠서 사용하는 것이다.

네임스페이스 덕분에 쿠버네티스 클러스터 하나를 여러 개 팀이나 사용자가 함께 공유할 수 있다. 또한 클러스터 안에서 용도에 따라 실행해야 하는 앱을 구분할 때도 네임스페이스를 사용한다.

네임스페이스별로 별도의 쿼터(할당량)을 설정해서 특정 네임스페이스의 사용량을 제한할 수 도 있다.


namespace 명령어

# 네임 스페이스 리스트 확인
kubectl get ns

# 해당 네임스페이스의 서비스, 파드 확인
kubectl -n metallb-system get svc,pod

# context들의 정보 확인
kubectl config get-contexts

# 네임 스페이스 생성
kubectl create namespace test-namespace

# context의 네임 스페이스 변경
kubectl config set-context kubernetes-admin@kubernetes --namespace test-namespace
네임 스페이스 수정.

 


ResourceQuota

ResourceQuota 관리

리소스 쿼터를 사용하여 각 네임스페이스마다, 즉 가상 쿠버네티스 클러스터마다 사용 가능한 리소스를 제한할 수 있다.

리소스 쿼터는 생성이나 변경으로 그 시점에 제한이 걸린 상태가 되어도 이미 생성된 리소스에는 영향을 주지 않기 때문에 주의해야 한다.

리소스 쿼터는 크게 '생성 가능한 리소스 수 제한'과 '리소스 사용량 제한'으로 나눌 수 있다.


ResourceQuota - 파드 제한

# resourceQuota 템플릿 생성
vi sample-resourcequota.yaml
//
apiVersion: v1
kind: ResourceQuota
metadata:
  name: sample-resourcequota
  namespace: test-namespace
spec:
  hard:
    count/pods: 5    # 파드 최대 5개 제한
//

# kubectl apply -f sample-resourcequota.yaml

# 파드 상세 정보
kubectl describe quota sample-resourcequota

# 테스트용 파드 생성
kubectl run new-nginx -n test-namespace --image=192.168.1.158:5000/nginx:latest

## 이름을 달리하여 총 6개의 파드를 생성

리소스 제한에 의해 6번째 파드는 생성이 안된다.

ResourceQuota - 자원 제한

# 새 네임스페이스 생성
kubectl create ns kyounggu

# 폴더 생성 후 이동
mkdir quotas && cd $_

# 자원 제한 resourceQuota 템플릿 생성
vi sample-resourcequota-usable.yaml
//
apiVersion: v1
kind: ResourceQuota
metadata:
  name: sample-resourcequota-usable
  namespace: kyounggu
spec:
  hard:
    requests.cpu: 1    # request:요구 / 메모리 용량 최소 제한 / 코어 1 = 1000m
    requests.memory: 1Gi    # 스토리지 용량 최소 제한
    requests.ephemeral-storage: 5Gi    # 로컬 임시 스토리지
    requests.nvidia.com/gpu: 2    # gpu
    limits.cpu: 4                 # limit: 최대 제한 / cpu 개수 최대 제한
    limits.memory: 2Gi
    limits.ephemeral-storage: 10Gi
    limits.nvidia.com/gpu: 4
//

# kubectl apply -f sample-resourcequota-usable.yaml
# kubectl -n kyounggu describe resourcequotas sample-resourcequota-usable
자원 제한 상황을 볼 수 있다.

# 테스트용 파드 생성 템플릿 (자원 생략)
vi sample-pod.yaml
//
apiVersion: v1
kind: Pod
metadata:
  name: sample-pod
  namespace: kyounggu
spec:
  containers:
  - name: nginx-container
    image: 192.168.1.158:5000/nginx:latest
//

## 에러 발생. (최소 제한이 걸린 경우, 파드 템플릿에 자원 제한을 넣어줘야함)
kubectl apply -f sample-pod.yaml
ResourceQuota가 있는 상태에서 자원 제한을 세팅하지 않으면 오류.

# 테스트용 파드 생성 (자원 할당)
vi sample-resource.yaml
//
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-resource
  namespace: kyounggu
spec:
  replicas: 4
  selector:
    matchLabels:
      app: sample-app
  template:
    metadata:
      labels:
        app: sample-app
    spec:
      containers:
      - name: nginx-container
        image: 192.168.1.158:5000/nginx:latest
        resources:  # ResourceQuota에 자원 제한이 걸린 경우 최소/최대 메모리, cpu를 꼭 넣어야 한다.
          requests:
            memory: "250Mi"
            cpu: "250m"
          limits:
            memory: "500Mi"
            cpu: "1000m"
//

# kubectl apply -f sample-resource.yaml
# kubectl -n kyounggu get pod
# kubectl -n kyounggu describe resourcequotas sample-resourcequota-usable

리소스 사용량과 한도를 할 수 있다.

 


LimitRange

LimitRange

리소스 제한 정보를 넣지 않아도 생성 가능

# 샘플 파드 생성
vi sample-pod.yaml
//
apiVersion: v1
kind: Pod
metadata:
  name: sample-pod
  namespace: kyounggu
spec:
  containers:
  - name: nginx-container
    image: nginx:1.16
//

# 원활한 테스트를 위해 삭제
kubectl delete -f sample-resource.yaml
]해당 파드는 리소스 정보가 없기 때문에 오류가 난다.

# LimitRange 템플릿 생성
vi sample-limitrange-container.yaml
//
apiVersion: v1
kind: LimitRange
metadata:
  name: sample-limitrange-container
  namespace: kyounggu
spec:
  limits:
  - type: Container
    default:    # 리소스 정보가 정의되지 않을 경우의 limit
      memory: 500Mi
      cpu: 1000m
    defaultRequest:    # 리소스 정보가 정의되지 않을 경우의 request
      memory: 250Mi
      cpu: 250m
    max:        # 리소스 정보가 정의됐을 때의 limit
      memory: 500Mi
      cpu: 1000m
    min:        # 리소스 정보가 정의됐을 때의 request
      memory: 250Mi
      cpu: 250m
    maxLimitRequestRatio:    # 최소/최대 요청 비율
      memory: 2      # 메모리는 최대가 최소의 2배
      cpu: 4        # cpu는 최대가 최소의 4배
//

# kubectl apply -f sample-limitrange-container.yaml
# kubectl -n kyounggu describe limitranges sample-limitrange-container

# kubectl apply -f sample-pod.yaml
# kubectl -n kyounggu describe limitranges sample-limitrange-container


LimitRange 덕에 리소스 정보가 없어도 오류 없이 생성이 된다.
LimitRange의 디폴트 값으로 설정됐다.

# 테스트 위해 템플릿 복사
cp sample-resource.yaml test-resource.yaml

# 리소스 부분 주석 처리 (default값을 사용하도록)
vi test-resource.yaml
//
#        resources:  # ResourceQuota에 자원 제한이 걸린 경우 최소/최대 메모리, cpu를 꼭 넣어야 한다.
#          requests:
#            memory: "250Mi"
#            cpu: "250m"
#          limits:
#            memory: "500Mi"
#            cpu: "1000m"
//

# kubectl -n kyounggu get all
리소스 최대 제한 때문에 리소스가 부족하여 3개까지 밖에 생성 불가.