본문 바로가기

KOSA 클라우드 솔루션즈 아키텍트 양성과정

[7.20] kubernetes(도커 이미지 pull 횟수 제한, ResourceQuota, taint, labels)

** 쿠버네티스에서 도커 이미지  pull 횟수 제한 문제 해결 **

# kubectl patch -n default serviceaccount/default -p '{"imagePullSecrets":[{"name": "skk2022"}]}'
=> default 부분에는 사용하고자 하는 namespace명을 입력
# kubectl describe serviceaccount default -n default
# kubectl create secret generic skk2022 --from-file=.dockerconfigjson=/root/.docker/config.json --type=kubernetes.io/dockerconfigjson
=> skk2022부분에는 docker 허브의 ID입력
# 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

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 exec -it configapp-64d4554b68-v55g5 -- bash

 

configapp-c ~~~ pod로 접속하여 환경변수 설정 내용 확인 해보기
configmap]# kubectl exec -it configapp-c9bb7b748-zdqn7 -- bash를 통해 pod에 접속
env 명령어를 통해 pod 내의 환경설정 내역 확인 가능


# vi configmap-wordpress.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: config-wordpress
  namespace: default
data:
  MYSQL_ROOT_HOST: '%'
=> 누구나 접근할 수 있도록 % 사용
  MYSQL_ROOT_PASSWORD: kosa0401
  MYSQL_DATABASE: wordpress
  MYSQL_USER: wpuser
  MYSQL_PASSWORD: wppass

=> 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:
=> ' MYSQL_ROOT_PASSWORD: kosa0401
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wpuser
      MYSQL_PASSWORD: wppass '
=> 위와 같은 환경 변수 내용을 그대로 가져오는 환경변수 필드
    - configMapRef:
        name: config-wordpress
    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

 

# 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:
=> env 다음에 나오는 name은 변수명
    - name: WORDPRESS_DB_HOST
      value: mysql-svc:3306
=> - name: WORDPRESS_DB_HOST=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
=> configmap에서 MYSQL_PASSWORD라는 이름의 키를 찾아서 해당 키의 값을 WORDPRESS_DB_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.2.0
  selector:
    app: wordpress-pod
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

# 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

 

#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: 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.104
=> worker노드의 IP를 주거나 주석처리를 하고 metallb-l2config.yaml 에 등록된 IP 범위 이용
  selector:
    app: wordpress-deploy
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

* namespace

  •  GCP의 프로젝트나 AZURE의 리소스 그룹과 동일한 개념
  • 특정 목적을 가진 팀단위로 namespace를 만들어서 작업
  • 쿠버네티스의 클러스터 하나를 여러 개의 논리적 단위로 나눠 사용하는 것(워크스페이스의 역할)
  • 네임스페이스 생성 후 해당 네임스페이스를 default로 지정할 수 있음

 

네임스페이스 개념도

--- namespace

kubectl get namespaces
=> 현재 존재하는 네임스페이스 확인
kubectl config get-contexts kubernetes-admin@kubernetes
NAMESPACE가 비어 있음

kubectl config set-context kubernetes-admin@kubernetes --namespace=kube-system
kubectl config get-contexts kubernetes-admin@kubernetes
kubectl config set-context kubernetes-admin@kubernetes --namespace=default
kubectl create namespace test-namespace
=> test-namespace라는 이름의 namespace를 생성
kubectl get namespace
kubectl  set-context kubernetes-admin@kubernetes --namespace=test-namespace
=> 직접 만든 namespace를 default namespace로 설정하는 명령어
kubectl config set-context kubernetes-admin@kubernetes --namespace=default

특정 namespace 확인
kubectl run nginx-pod1 --image=nginx -n test-namespace 로 test-namespace에 nginx 이미지 생성
default namespace를 test-namespace로 변경
default가 test-namespace로 변경된 것 확인
아무 서비스(여기서는 로드밸런서) 생성하고 namespace 확인하기
namespace를 따로 지정하지 않아도 test-namespace로 들어간 것 확인


--- ResourceQuota

# vi sample-resourcequota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: sample-resourcequota
  namespace: default
=> 기입된 네임스페이스는 ResourceQuota에 따라 리소스 사용량에 제한을 받게 됨
spec:
  hard:
    count/pods: 5
=> pod가 5개를 초과할 수 없도록 지정

# kubectl apply -f sample-resourcequota.yaml
my-ns 네임스페이스에 apply된 리소스쿼터 확인

# kubectl describe resourcequotas sample-resourcequota
# kubectl run pod new-nginx --image=nginx
pod가 다섯 개를 초과하려고 하면 애러 발생

 

# vi sample-resourcequota-usable.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: sample-resourcequota-usable
  namespace: default
spec:
  hard:
    requests.memory: 2Gi
    requests.storage: 5Gi
    sample-storageclass.storageclass.storage.k8s.io/requests.storage: 5Gi
    requests.ephemeral-storage: 5Gi
    requests.nvidia.com/gpu: 2
    limits.cpu: 4
    limits.ephemeral-storage: 10Gi
=> ephemeral : persistent volume(pv)과 반대의 개념, 컨테이너가 지워지면 함께 지워짐
    limits.nvidia.com/gpu: 4
- requests : 최소한 requests 에 지정된 만큼은 사용하겠다는 의미
- limits : 최대치는 limits를 넘지 않겠다는 의미
# vi sample-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: sample-pod
spec:
  containers:
  - name: nginx-container
    image: nginx:1.16
    resources:
      requests:
        memory: "64Mi"
        cpu: "50m"
       limits:
         memory: "128Mi"
         cpu: "100m"
=> 1000m(milicore) = 1core

 

새로운 파드를 생성하려고 했지만, request, limits 용량을 별도로 지정하지 않으면 생성되지 않음..

 

따라서 이 부분을 넣어주고 apply해야 함

   


--- LimitRange

vi sample-limitrange-container.yaml
apiVersion: v1
kind: LimitRange
metadata:
  name: sample-limitrange-container
  namespace: 
=> namespace를 입력하지 않으면 현재 default로 설정되어 있는 my-ns로 자동 지정됨
spec:
  limits:
  - type: Container
    default:
=> 여기서의 default는 limit을 의미
      memory: 512Mi
      cpu: 500m
    defaultRequest:
=> 직접 정하지 않은 경우 최소 용량, 최소 확보 용량
      memory: 256Mi
      cpu: 250m
    max:
=> max와 min은 사용자가 정해줘야 하는 용량, max가 limit(상한선)
      memory: 1024Mi
      cpu: 1000m
    min:
=> min이 하한선 requests를 의미
      memory: 128Mi
      cpu: 125m
    maxLimitRequestRatio:
=> Requests와 Limit의 차이 허용 비율이 2배, 오버 커밋을 피할 수 있음
=> 위의 default와 defaultRequest 필드의 차이 의미
      memory: 2
      cpu: 2

 

# vi sample-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: sample-pod-limitrange
spec:
  containers:
  - name: nginx-container
    image: nginx:1.16

# vi sample-pod-overratio.yaml
apiVersion: v1
kind: Pod
metadata:
  name: sample-pod-overratio
spec:
  containers:
  - name: nginx-container
    image: nginx:1.16
    resources:
      requests:
        cpu: 125m
      limits:
        cpu: 500m

@@ 파드 스케줄(자동 배치)

=> worker1,2 중 랜덤으로 배치

# vi pod-schedule.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-schedule-metadata
  labels:
    app: pod-schedule-labels
spec:
  containers:
  - name: pod-schedule-containers
    image: nginx
    ports:
    - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: pod-schedule-service
spec:
  type: NodePort
  selector:
    app: pod-schedule-labels
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

@@ 파드 노드네임(수동 배치)

# vi pod-nodename.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-nodename-metadata
  labels:
    app: pod-nodename-labels
spec:
  containers:
  - name: pod-nodename-containers
    image: nginx
    ports:
    - containerPort: 80
  nodeName: worker2
=> 수동배치로 새로 만들어진 pod가 worker2에 만들어지도록 지정
---
apiVersion: v1
kind: Service
metadata:
  name: pod-nodename-service
spec:
  type: NodePort
  selector:
    app: pod-nodename-labels
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

@@ 노드 셀렉터(수동 배치)

=> 노드에 라벨을 부여하는 것

# kubectl label nodes worker1 tier=dev
=> tier라는 키와 dev라는 value를 worker1에게 라벨로 부여
# kubectl get nodes --show-labels
tier=dev 라벨 부여된 것 확인

# vi pod-nodeselector.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-nodeselector-metadata
  labels:
    app: pod-nodeselector-labels
spec:
  containers:
  - name: pod-nodeselector-containers
    image: nginx
    ports:
    - containerPort: 80
  nodeSelector:
    tier: dev
---
apiVersion: v1
kind: Service
metadata:
  name: pod-nodeselector-service
spec:
  type: NodePort
  selector:
    app: pod-nodeselector-labels
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
# kubectl label nodes worker1 tier-
=> tier=dev라는 라벨을 지우는 명령어
# kubectl get nodes --show-labels

@@ taint와 toleration

=> taint는 특정 노드가 pod를 생산하지 않도록 하여 수동으로 스케쥴해야 함

# kubectl taint node worker1 tier=dev:NoSchedule
# kubectl describe nodes worker1
describe했을 때 taints 된 것 확인 가능

# vi pod-taint.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-taint-metadata
  labels:
    app: pod-taint-labels
spec:
  containers:
  - name: pod-taint-containers
    image: nginx
    ports:
    - containerPort: 80
  tolerations:
  - key: “tier”
    operator: “Equal”
    value: “dev”
    effect: “NoSchedule”
---
apiVersion: v1
kind: Service
metadata:
  name: pod-taint-service
spec:
  type: NodePort
  selector:
    app: pod-taint-labels
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80