3장 - 컨테이너를 다루는 표준 아키텍처, 쿠버네티스
- Created
- 2022년 9월 3일 PM 8:24

컨테이너 인프라 환경이란? 리눅스 운영 체제의 커널 하나에서 여러 개의 컨테이너가 격리된 상태로 실행되는 인프라 환경을 말합니다.
- 여기서 컨테이너는 하나 이상의 목적을 위하 독립적으로 작동하는 프로세스 입니다.
- 컨테이너 인프라 환경을 구성하면 눈송이 서버를 방지하는데 효과적 임
- 눈송이 서버 = 여러 사람이 만져서 설정의 일관성이 떨어진 서버
- 가상화 환경에서는 각각의 가상머신이 모두 독립적인 운영 체제 커널을 가지고 있어야 하기 때문에 그만큼 자원을 더 소모해야 하고 성능이 떨어질 수밖에 없다.
- But. 컨테이너 인프라 환경은 운영 체제 커널 하나에 컨테이너 여러 개가 격리된 형태로 실행 때문에 자원의 효율적 사용, 거치는 단계가 적어 속도도 훨씬 빠름!

컨테이너 인프라 환경이 성장하게 된 결정적 계기는 구글이 쿠버네티스를 오픈소스로 공개한데 있다.
- 이를 통해 쿠버네티스를 누구나 자유롭게 이용하게 되면서 컨테이너 인프라 환경을 좀 더 효율적으로 관리할 수 있게 되었음
- 여러 기능이 추가되며 쿠버네티스는 컨테이너 인프라 관리 솔루션의 표준으로 자리잡게 됨
3.1 쿠버네티스 이해하기#
쿠버네티스를 컨테이너 관리 도구라고 설명했지만, 실제로 쿠버네티스는 컨테이너 오케스트레이션을 위한 솔루션입니다.
- 오케스트레이션이란? 복잡한 단계를 관리하고 요소들의 유기적인 관계를 미리 정의해 손쉽게 사용하도록 서비스를 제공하는 것을 의미합니다.
3.1.1 왜 쿠버네티스일까#
| 구분 | 도커 스웜 | 메소드 | 노매드 | 쿠버네티스 |
| 설치 난이도 | 쉬움 | 매우 어려움 | 쉬움 | 어려움 |
| 사용 편의성 | 매우 좋음 | 좋음 | 매우 좋음 | 좋음 |
| 세부 설정 지원 | 거의 없음 | 있음 | 거의 없음 | 다양하게 있음 |
| 안정성 | 매우 안정적인 | 안정적임 | 안정적임 | 매우 안정적임 |
| 확장성 | 어려움 | 매우 잘 됨 | 어려움 | 매우 잘 됨 |
| 정보량 | 많음 | 적음 | 적음 | 매우 많음 |
| 에코파트너 | 없음 | 거의 없움 | 있음 | 매우 많음 |
| 학습 곡선 | 쉬움 | 매우 어려움 | 어려움 | 어려움 |
- k8s의 의미
- 쿠버네티스는 그 이름 자체가 긴 단어이기 때문에 문자 수를 표기하는 방법으로 약어를 만들었습니다.
- k8(ubernete = 8글자)s
3.1.2 쿠버네티스 구성 방법#
쿠버네티스를 구성하는 방법은 크게 3가지로 구분됩니다.
- 퍼블릭 클라우드 업체에서 제공하는 관리형 쿠버네티스인 EKS, AKS, GKE 등을 사용합니다.
- 구성이 이미 다 갖춰져 있고 마스터 노드를 클라우드 업체에서 관리하기 때문에 학습용으로는 적합하지 않음
- 수세의 Rancher, 레드햇의 OpenShift와 같은 플랫폼에서 제공하는 설치형 쿠버네티스를 사용합니다.
- 유료이기 때문에 쉽게 접근이 어렵다.
- 사용하는 시스템에 쿠버네티스 클러스터를 자동으로 구성해주는 솔루션을 사용한다.
- kubeadm, kops, KRIB, kubespray가 대표적
- 위 4가지 솔루션중 kubeadm가 가장 널리 알려져 있다.
- 사용자 변경이 수월
- 온프레미스와 클라우드를 모두 지원
- 배우기도 쉬움

3.1.3 쿠버네티스 구성하기#
- 학습을 위해 사용자 설정이 많이 필요한 kubeadm으로 쿠버네티스를 구성
- 쿠버네티스가 설치되는 서버 노드는 가상 머신을 이용해 실제 온프레미스에 가깝게 구성
3.1.4 파드 배포를 중심으로 쿠버네티스 구성요소 살펴보기#
# kubectl get pods --all-namespaces--all-namespaces는 기본 네임스페이스인 default외에 모든 것을 표시하겠다는 의미- 쿠버네티스 클러스터를 이루는 구성요소들은 파드 형태로 이루어져 있음을 알 수 있음
관리자나 개발자가 파드를 배포할 때#

통신 순서가 있어 흐름을 이해할 수 있지만, 각각의 기능을 파악하기는 어려움
파드를 배포하는 순서에 따라 요소들의 역할을 정리
- kubectl : 쿠버네티스 클러스터에 명령을 내리는 역할
- 다른 구성요소들과 다르게 바로 실행되는 명령 형태인 바이너리로 배포되기 때문에 마스터 노드에 있을 필요는 없다.
- 통상적으로 API 서버와 주로 통신
- API 서버 : 주로 상태 값을 저장하는 etcd와 통신
- 그 밖의 요소들 또한 API 서버를 중심으로 통신
- 때문에 API 서버의 역할이 매우 중요
- etcd : 구성 요소들의 상태 값이 모두 저장되는 곳
- 회사의 관리자가 모든 보고 내용을 기록하는 노트라고 생각하면 됨
- 실제로 etcd외 다른 구성요소는 상태 값을 관리하지 않는다.
- 때문에 etcd의 정보만 백업돼 있다면 긴습한 장애 상황에서도 쿠버네티스 클러스터를 복구할 수 있음
- 또한 etcd는 분산 저장이 가능한 key-value 저장소로서 복제해 여러 곳에 저장해 두면 하나의 etcd에서 장애가 나도 시스템 가용성을 확보할 수 있음
- etcd(엣시디)는 리눅스 구성 정보를 주로 가지는 etc 디렉터리와 distributed(퍼뜨렸다)의 합성어 = 구성 정보를 퍼뜨려 저장하겠다는 의미
- 컨트롤러 매니저 : 쿠버네티스 클러스터의 오브젝트 상태를 관리
- 워커 노드에서 통신이 되지 않는 경우. 상태 체크와 복구는 컨트롤러 매니저에 속한 노드 컨트롤러에서 이루어짐
- 서비스와 파드를 연결하는 역할을 하는 엔드 포인트 컨트롤러 또한 컨트롤러 매니저임
- 이와 같이 다양한 상태 값을 관리하는 주체들이 컨트롤러 매니저에 소속돼 각자의 역할을 수행
- 스케줄러 : 노드의 상태와 자원, 레이블, 요구 조건 등을 고려해 어떤 워커 노드에 파드를 생성할 것인지 결정하고 할당하는 역할
- 이름에 걸맞게 파드를 조건에 맞는 워커 노드에 지정하고, 파드가 워커 노드에 할당되는 일정을 관리하는 역할을 담당
- kubelet : 파드의 구성 내용(PodSpec)을 받아 컨테이너 런타임에 전달, 파드 안의 컨테이너들이 정상적으로 작동하는지 모니터링 함
- 컨테이너 런타임 : 파드를 이루는 컨테이너 실행을 담당
- 파드 안에서 다양한 종류의 컨테이너가 문제 없이 작동하게 만드는 표준 인터페이스
- 파드(Pod) : 한 개 이상의 컨테이너로 단일 목적의 일을 하기 위해 모인 단위
- 파드는 언제라도 죽을 수 있는 존재
- 쿠버네티스를 처음 배울 때 가장 이해하기 어려운 부분
- 가상 머신은 언제라도 죽을 수 있다고 가정하고 디자인하지 않지만, 파드는 언제라도 죽을 수 있다고 가정하고 설계되었음
- 때문에 쿠버네티스는 여러 대안을 디자인했음

그외 추가적으로 선택 가능한 구성요소
- 네트워크 플러그인 : 쿠버네티스 클러스터의 통신을 위해 네트워크 플러그인을 선택하고 구성할 수 있음
- 네트워크 플러그인은 일반적으로 CNI로 구성
- CNI(Container Network Interface, 컨테이너 네트워크 인터페이스)
- 클라우드 네이티브 컴퓨팅 재단의 프로젝트
- 컨테이너의 네트워크 안정성과 확장성을 보장하기 위해 개발 됨
- 네트워크 프로토콜인 BGP와 VXLAN의 지원, ACL 지원, 보안 기능 제공 등 살펴보고 필요한 조건을 가지고 있는 네트워크 플러그인을 선택할 수 있어 설계 유연성이 매우 높음
- CoreDNS : 클라우드 네이티브 컴퓨팅 재단에서 보증하는 프로젝트
- 빠르고 유연한 DNS 서버
- 클러스터 구성시 IP보다 도메인 네임을 편리하게 관리해주는 CoreDNS를 사용하는게 일반적
사용자가 배포된 파드에 접속할 때#
- kube-proxy : 쿠버네티스 클러스터는 파드가 위치한 노드에 kube-proxy를 통해 파드가 통신할 수 있는 네트워크를 설정함
- 이때 실제 통신은 br_netfilter과 iptables로 관리
- 파드 : 이미 배포된 파드에 접속하고 필요한 내용을 전달받음
- 이때 대부분 사용자는 파드가 어느 워커노드에 위치하든지 신경 쓰지 않아도 됨
3.1.5 파드의 생명주기로 쿠버네티스 구성 요소 살펴보기#

쿠버네티스의 구성요소를 개별적으로 기능만 나열해서는 이해하기가 어렵다.
따라서 파드가 배포되는 과정을 하나하나 자세히 살펴보면서 쿠버네티스의 구성요소들이 어떤 역할을 담당하는지 정리해보자
- kubectl을 통해 API 서버에 파드 생성을 요청한다.
- (업데이트가 있을 때마다 매번) API 서버에 전달된 내용이 있으면 API 서버는 etcd에 전달된 내용을 모두 기록해 클러스터의 상태 값을 최신으로 유지한다.
- API 서버에 파드 생성이 요청된 것을 컨트롤러 매니저가 인지
- 컨트롤러 매니저는 파드를 생성
- 아직 어떤 워커노드에 파드를 적용할지는 결정되지 않는 상태로 파드를 생성
- API 서버에 파드가 생성됐다는 정보를 스케줄러가 인지한다.
- 스케줄러는 생성된 파드를 어떤 워커 노드에 적용할지 조건을 고려해 결정하고 해당 워커노드에 파드를 띄우도록 요청한다.
- API 서버에 전달된 정보대로 지정한 워커 노드에 파드가 속해있는지 스케줄러가 kubelet으로 확인한다.
- kebelet에서 컨테이너 런타임으로 파드 생성을 요청한다.
- 파드가 생성된다.
- 파드가 사용 가능한 상태가 된다.
3.1.6 쿠버네티스 구성 요소의 기능 검증하기#
kubectl#
kubectl은 꼭 마스터 노드에 위치할 필요가 없다. 실제로 쿠버네티스 클러스터의 외부에서 쿠버네티스 클러스터에 명령을 내릴 수도 있다.
어느 곳에서든지 kubectl을 실행하려면 어떤 부분이 필요한지 확인해보자.
- 슈퍼푸티 세션 창에서 w3-k8s를 더블클릭해 터미널에 접속
kubectl get nodes를 실행- 쿠버네티스 클러스터 정보를 마스터노드에서 scp명령으로 w3-k8s의 현재 디렉터리에 받아옴
- 이때 접속기록이 없기 때문에 known_hosts로 저장하도록 함
- kubectl get nodes 명령에 추가로 쿠버네티스 클러스터 정보를 입력받는 옵션(
--kubeconfig)과 마스터 노드에서 받아온admin.conf를 입력하고 실행
kubelet#
kubelet으 쿠버네티스에서 파드의 생성과 상태 관리 및 복구 등을 담당하는 매우 중요한 구성요소
따라서 kubelet에 문제가 생기면 파드가 정상적으로 관리되지 않음
- 기능 검증을 위해서는 실제 파드를 배포해야함
kubectl create -f ~/_Book_k8sInfra/ch3/3.1.6/nginx-pod.yaml명령으로 nginx 파드를 배포
kubectl get pod명령으로 배포된 파드가 정상적으로 작동중(Running)인지 확인kubectl get pods -o wide명령을 실행해 파드가 배포된 워커 노드를 확인- -o느 output의 약어로 출력을 특정 형식으로 해주는 옵션
- wide는 재공되는 출력 형식 중에서 출력 정보를 더 많이 표시해 주는 옵션
- 배포된 노드에 접속해
systemctl stop kubelet으로 kubelet 서비스를 멈춘다. - m-k8s에서
kubectl get pod로 상태를 확인하고,kubectl delete pod nginx-pod로 파드를 삭제 - 이후 명령어가 Terminating 상태에서 진행되지 않는것을 확인
- 다시 노드에 접속해
systemctl start kubelet명령어를 통해서 kubelet을 복구 - 잠시 후
kubelet get pod명령어를 통해 파드가 삭제되었는지 확인
kebe-proxy#
kubelet이 파드 상태를 관리한다면 kube-proxy는 파드의 통신을 담당합니다.
- 테스트하기 위해 마스터 노드인 m-k8s에서 다시 파드를 배포합니다.
- kubectl get pod -o wide 명령으로 파드의 IP와 워커 노드를 확인합니다.
- curl로 파드의 전 단계에서 파드의 전 단계에서 확인한 파드의 IP
3.2 쿠버네티스의 기본 사용법#
쿠버네티스를 사용한다는 것은 결국 사용자에게 효과적으로 파드를 제공한다는 뜻
kubectl run nginx-pod --image=nginx
kubectl create deployment dpy-nginx --image=nginx두 명령어의 차이는?

- run = 단일 파드로 생성되고 관리 (초코파이 단일품)
- create deployment = deployment라는 관리 그룹 내세엇 파드가 생성됨 (초코파이 한상자)
오브젝트란#
쿠버네티스를 사용하는 관점에서 파드와 디플로이먼트는 스펙과 상태 등을 가지고 있다.

- 기본 오브젝트
- 파드 = 쿠버네티스에서 실행되는 최소 단위, 웹 서비스를 구동하는데 필요한 최소 단위
- 네임스페이스 = 쿠버네티스 클러스터에서 사용되는 리소스들을 구분해 관리하는 그룹
- 볼륨 = 파드가 생성될 때 파드에서 사용할 수 있는 디렉터리를 제공
- 파드가 사라지더라도 저장과 보존이 가능한 디렉터리 볼륨 오브젝트를 생성/사용 가능
- 서비스 = 파드는 클러스터 내에서 유동적이기 때문에 접속 정보가 고정일 수 없음
- 파드 접속을 안정적으로 유지하도록 서비스를 통해 내/외부로 연결됨


- 디플로이먼트
- 기본 오브젝트만으로도 쿠버네티스를 사용할 수 있지만, 좀 더 효율적인 사용을 위해 구현된것이 바로 디플로이먼트
- 이 외에도 데몬셋, 컨피그맵, 레플리카셋, PV, PVC, 스테이트풀셋, 등이 있으며 요구사항에 따라 목적에 맞는 오브젝트들이 추가될 것
- 쿠버네티스에서 가장 많이 쓰이는 디플로이먼트 오브젝트는 파드에 기반을 두고 있다.
- 레플리카셋 오브젝트를 합쳐 놓은 형태
- 실제로 API 서버와 컨트롤러 매니저는 단순히 파드가 생성되는 것을 감시하는 것이 아니라 디플로이먼트처럼 레플리카셋을 포함하는 오브젝트의 생성을 감시
3.2.3 레플리카셋으로 파드 수 관리하기#

쿠버네티스에서는 다수의 파드를 만드는 레플리카셋 오브젝트를 제공함
파드를 3개 만들겠다고 선언하면 컨트롤러 매니저와 스케줄러가 워커 노드에 파드 3개를 만들도록 선언, 레플리카셋은 파드 수를 보장하는 기능만 제공
- 롤링 업데이트 등이 추가된 디플로이먼트를 사용해 파드수를 관리하는것을 권장
3.2.4 스펙을 지정해 오브젝트 생성#
디플로이먼트를 생성하면서 한꺼번에 여러개의 파드를 생성하는 방법
- 야믈문법으로 작성한 오브젝트 스펙을 이용하는 방법
apiVersion: apps/v1 # API 버전
kind: Deployment # 오브젝트 종류
metadata:
name: echo-hname
labels:
app: nginx
spec:
replicas: 3 # 몇 개의 파드를 생성할지 결정
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: echo-hname
image: sysnet4admin/echo-hname # 사용되는 이미지
3.2.5 apply로 오브젝트 생성하고 관리하기#
run은 파드를 생성하는 매우 편리한 방법 But 단일 파드만 생성 가능
create로 디플로이먼트를 생성하면 파일의 변경 사항을 바로 적용할 수 없음
이럴 때를 위해 apply를 통해서 오브젝트 관리가 가능함
| 구분 | Run | Create | Apply |
| 명령 실행 | 제한적 | 가능 | 안 됨 |
| 파일 실행 | 안 됨 | 가능 | 가능 |
| 변경 가능 | 안 됨 | 안 됨 | 가능 |
| 실행 편의성 | 매우 좋음 | 매우 좋음 | 좋음 |
| 기능 유지 | 제한적 | 지원됨 | 다양하게 지원됨 |
- 오브젝트 생성 명령어 비교
3.2.6 파드의 컨테이너 자동 복구 방법#
쿠버네티스는 거의 모든 부분이 자동 복구되도록 설계되어있음
특히 파드의 자동 복구 기술을 셀프 힐링이라 하는데, 제대로 작동하지 않는 컨테이너를 다시 시작/교체해 파드가 정상적으로 작동하게 함
3.2.7 파드의 동작 보증 기능#

3.2.8 노드 자원 보호하기#
- 여러 상황 속에서도 쿠버네티스는 파드를 안정적으로 작동하도록 관리 함
- 노드는 쿠버네티스 스케줄러에서 파드를 할당받고 처리하는 역할을 함
- 지속적으로 문제가 생기는 노드의 경우 cordon을 통해서 노드를 관리할 수 있음
3.2.9 노드 유지보수하기#
쿠버네티스를 사용하다 보면 정기 또는 비정기적 유지보수를 위해 노드를 꺼야하는 상황이 발생할 수 있음
이때 drain을 통해서 지정된 노드의 파드를 다른 곳으로 이동시켜 해당 노드를 유지보수할 수 있게 함
3.3 쿠버네티스 연결을 담당하는 서비스#
외부에서 크버네티스 클러스터에 접속하는 방법을 서비스라고 함
3.3.1 가장 간단하게 연결하는 노드포트#

외부에서 클러스터의 내부에 접속하는 가장 쉬운 방법은 노드포트 서비스를 이용하는 것
노드포트 서비스를 설정하면 모든 워커 노드의 특정 포트를 열고 여기로 오는 모든 요청을 노드포트 서비스로 전달함
apiVersion: v1
kind: Service
metadata:
name: np-svc
spec:
selector:
app: np-pods
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
nodePort: 30000 # 30000번의 노드포트를 허용함
type: NodePort3.3.2 사용 목적별로 연결하는 인그레스#

노드포트 서비스는 포트의 중복사용이 불가하여 1개의 노드포트에 1개의 디플로이먼트만 적용이 가능함
인그레스는 고유한 주소를 제공해 사용 목적에 따라 다른 응답을 제공할 수 있고, 트래픽에 대한 L4/L7 로드밸런서와 보안 인증서를 처리하는 기능을 제공
- 인그레스 컨트롤러는 파드와 직접 통신할 수 없어서 노드포트 또는 로드밸런서 서비스와 연동되어야 함
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: ingress-nginx
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- path:
backend:
serviceName: hname-svc-default
servicePort: 80
- path: /ip
backend:
serviceName: ip-svc
servicePort: 80
- path: /your-directory
backend:
serviceName: your-svc
servicePort: 803.3.3 클라우드에서 쉽게 구성 가능한 로드밸런서#

앞서 배운 방식은 들어오는 요청을 모두 워커 노드의 노드포트를 통해 노드포트 서비스로 이동하고 이를 다시 쿠버네티스의 파드로 보내는 구조
- 이 방식은 매우 비효율적
- 때문에 쿠버네티스에서는 로그밸런서라는 서비스 타입을 제공해 간단하 구조로 파드를 외부에 노출시키고 부하를 분산
kubectl expose deployment ex-lb --type=LoadBalance --name=ex-svc3.3.4 온프레미스에서 로드밸런서를 제공하는 MetalLB#

- MetalLB는 베어메탈로 구성된 쿠버네티스에서도 로드밸러서를 사용할 수 있게 고안된 프로젝트
- 특별한 네트워크 설정이나 구성이 있는 것이 아닌 기존의 L2 네트워크와 L3 네트워크로 로드밸런서를 구현함
- 때문에 네트워크를 새로 배워야 할 부담도 적으며 연동하기도 쉬움
- MetalLB의 컨트롤러는 작동 방식을 정의하고 EXTERNAL-IP를 부여해 관리한다.
- MetalLB 스피커는 정해진 작동 방식(L2/ARP, L3/BGP)에 따라 경로를 만들 수 있도록 네트워크 정보를 광고하고 수집해 각 파드의 경로를 제공
apiVersion: v1
kind: ConfigMap
metadata:
namespace: metallb-system
name: config
data:
config: |
address-pools:
- name: nginx-ip-range
protocol: layer2
addresses:
- 192.168.1.11-192.168.1.13
3.3.5 부하에 따라 자동으로 파드 수를 조절하는 HPA#
사용자가 갑자기 늘어난다면 파드가 더 이상 감당할 수 없어 서비스 불가라는 결과를 초래할 수 있음
이런 경우를 대비해 부하량에 따라 디플로이먼트의 파드 수를 유동적으로 관리하는 기능을 제공함
- 이를 HPA(Horizontal Pod Autoscaler)라고 함

HPA가 작동하려면 자원을 요청할 때 메트릭 서버를 통해 계측값을 전달 받아야함
- HPA를 통해서 늘어나는 파드 수 계산 방법
- 디플로이먼트 스펙에서 resources의 CPU를 10m으로 설정하고, autoscale에서 cpu-percent를 50%로 했다고 가정
- 파드가 29m 라는 부하를 받을 때 한개의 파드가 처리할 수 있는 부하량은 10m으로 CPU 부하량의 50%가 넘으면 자동으로 파드를 생성해야 하기 때문에 5m이 넘으면 파드를 증설
- 29/5를 한뒤 올림하면 6이라는 숫자가 나오고, 결국 증가하는 파드는6임
3.4 알아두면 쓸모 있는 쿠버네티스 오브젝트#
데몬셋#
데몬셋은 디플로이먼트의 replicas가 노드 수만큼 정해져 있는 형태, 노드 하나당 파드 한 개만을 생성
노드를 관리하는 파드라면 데몬셋이 가장 효율적
컨피그맵#
컨피그맵은 이름 그대로 설정을 목적으로 사용하는 오브젝트
PV와 PVC#
때때로 파드에서 생성한 내용을 기록하고 보관하거나 모든 파드가 동일한 설정을 유지하고 관리하기 위해 공유된 볼륨으로부터 공통된 설정을 가지고 올 수 있도록 설계할 때 이용
- 임시: emptyDir
- 로컬: host Path, local
- 원격: persistentVolumeClaim, cephfs, csi, fc 등등
- 특수목적: downwardAPI, configMap, secret 등등
- 클라우드: awsElasticBlockStore, azureDisk
PVC는 준비될 볼륨에서 일정 공간을 할당 받는 것
PV는 볼륨을 사용할 수 있게 준비하는 단계
스테이트풀셋#
지금까지는 파드가 replicas에 선언된 만큼 무작위로 생성될 뿐이었음. 하지만 파드가 만들어지는 이름과 순서를 예측해야 할 때가 있다.
주로 레디스, 주키퍼, 카산드라, 몽고DB 등 마스터-슬레이브 구조 시스템에서 필요
레플리카풀셋은 volumeClaimTemplates기능을 사용해 PVC를 자동으로 생성할 수 있고, 각 파드가 순서대로 생성되기 때문에 고정된 이름과 볼륨, 설정 등을 가질 수 있음
다만 효율성 측면에서 좋지 않기 때문에 요구사항에 맞게 적절히 사용하는게 좋음