본문 바로가기

Docker

Docker와 mySQL 컨테이너 만들기

안녕하세요, 이번 포스팅에서는 Docker가 무엇인지에 대해 먼저 알아보겠습니다. Docker는 컨테이너 기반의 가상화 플랫폼으로, 애플리케이션을 쉽게 개발, 배포 및 실행할 수 있도록 지원합니다. 그리고 Docker를 활용하여 MySQL 컨테이너를 만드는 방법에 대해 알아보겠습니다.

 

DockerCon에 가다.


아래 대화는 Docker에 대한 이해를 돕기 위한 가상의 인물 간 대화 내용입니다.

 

 

(Dall-e 2 Generated)

 

(차차와 브루니는 DockerCon 2023을 소개하는 전광판 옆을 걸어갑니다.)

 

차차 : 어, 브루니. 이게 뭐죠? DockerCon 2023?🤣

 

브루니 : 아, DockerCon요? Docker란 가상화 기술이에요. 이제 많은 개발자들이 이걸 이용해서 애플리케이션을 배포하고 운영하고 있어요. Docker를 잘 활용하는 능력이 점점 개발자로서 중요한 소양이 되어가고 있어요.

 

차차 : 정말요?  😮‍💨 그러면 Docker를 개발한 사람은 누구인가요?

 

브루니 : Docker를 만든 사람은 도트클라우드(DotCloud)라는 회사의 CTO인 솔로몬 하익스(Solomon Hykes)래요. 도커가 세상에 공개된지는 무려 10년밖에 안되었어요. 2013년에 Docker를 공개하면서 컨테이너 기술의 발전에 기여하게 되었습니다.

 

차차 : 어라, 컨테이너 기술은 JK도 얘기했듯이 Docker 이전부터 있었던 기술이라고 들었는데요..🙀

 

브루니 : 맞아요, 컨테이너 기술은 이미 2000년대 초반에 리눅스 컨테이너와 Solaris Zones와 같은 기술로 존재했지만, 그 당시에는 사용성이 좋지 않았어요. 그리고 컨테이너 기술을 사용하는 것이 복잡하고 어려웠기 때문에, 상용 가상머신이 더 많이 사용되고 있었죠. 지금으로 따지면 VMWare와 같은 가상 환경을 사용하는 것이죠. 하지만 Docker는 이 기술을 더욱 발전시켜 개발자들이 더 쉽게 사용할 수 있도록 만들었다는데 의의가 있어요.

 

차차 : 컨테이너가 정확히 무엇인가요? JK의 설명을 듣긴 했지만 아직 개념이 구름 속을 떠다니는 것 같아요.

 

브루니 : 도커는 컨테이너 기술을 기반으로 하고 있어요. 컨테이너는 운영체제에서 실행되는 프로세스를 격리된 환경에서 실행시키는 기술이에요. 이를 통해 여러 개의 프로세스를 하나의 운영체제에서 실행시킬 수 있고, 각각의 프로세스는 다른 프로세스와 격리된 환경에서 동작하게 되죠. 이런 컨테이너 기술의 구현은 운영체제의 시스템콜을 통해서 지원되기 때문에 쉽게 구현이 가능했다고 해요.

 

차차 : 음.. 그렇군요. 정리하자면, 도커는 컨테이너 기술을 이용해서 프로세스를 격리된 환경에서 실행하도록 해주는 기술인거군요. 아직은 잘 모르겠는데요. 구체적으로 Docker를 이용하면 어떤 장점이 있나요?🥶

 

브루니 : Docker는 애플리케이션의 개발, 테스트, 배포, 운영 등의 프로세스를 훨씬 더 간단하게 만들어줘요. 개발환경 구성도 쉽고, 애플리케이션을 빠르게 배포할 수도 있고, 확장성도 뛰어나서 많은 개발자들이 이용하고 있어요.

 

차차 : 음.. 조금은 알 것 같아요. Docker가 개발자들에게 더욱 편리한 개발환경을 제공해주는 거네요!🧑‍🚀 이러한 장점이 도커의 인기가 급부상한 이유이겠죠?

 

브루니 : 맞아요. 도커의 장점이 많지만 그 중에서도 가장 큰 이유는 개발자들이 개발환경을 쉽게 구축할 수 있다는 것이었어요. 예를 들어, 이번 주에 자자의 새 컴퓨터로 체스 게임을 구현하는 프로젝트를 진행한다고 해봐요. 그럼 자바 개발환경, 라이브러리, 기타 개발환경 등을 모두 설치해야 할 거에요. 이걸 일일이 컴퓨터가 바뀔 때마다 설치해야 한다면 상당히 번거롭겠죠? 하지만 도커를 사용하면 이미지를 만들어서 필요한 모든 것을 담아놓고, 그 이미지를 이용해 개발환경을 쉽게 구축할 수 있어요.

 

차차 : 오오, 도커는 정말 엄청난 것이군요!🙀

 

브루니 : 도커를 통해서 배포도 매우 쉽게 할 수 있어요. 예를 들어, 체스 게임을 배포한다고 해봐요. 만약 도커를 사용하지 않는다면, 개발 환경과 서버 환경이 다를 수 있으니, 서버 환경에 따라서 의존성을 고려해야하고, 애플리케이션을 다시 구성해야 할 수도 있겠죠? 하지만 도커를 사용하면 모든 것을 이미지로 만들어서 배포할 수 있기 때문에, 서버 환경과 개발 환경을 완전히 동일하게 구성할 수 있어요. 즉, 서버 환경에 따라서 애플리케이션을 다시 구성할 필요가 없다는 장점이죠.

 

차차 : 그렇군요. 종합하면, 도커를 사용하면 개발환경 구성도 쉽고, 애플리케이션을 빠르게 배포할 수 있고, 확장성도 뛰어나다는 거네요.

 

브루니 : 맞아요, 요즘은 Docker 없이는 현대적인 애플리케이션 개발이나 운영이 어려워졌어요. 이제는 Docker가 없이는 상상할 수 없는 시대가 되었죠!

 

차차 : 그렇군요.👋 브루니와 Docker에 대해 이야기하니까 더욱 이해하기 쉽네요. 이제 DockerCon에 가서 더 자세히 배워봐야겠어요!


Docker와 Container


 

Docker는 컨테이너 기반의 가상화 플랫폼으로, 애플리케이션을 컨테이너라는 격리된 환경에서 실행시킴으로써 서로 다른 환경에서 실행되는 애플리케이션을 쉽게 배포하고 실행할 수 있게 해줍니다. Docker는 컨테이너 내부에서 필요한 모든 라이브러리와 애플리케이션을 가지고 있기 때문에 호스트 시스템과는 독립적으로 실행됩니다.

 

 

다시 말하면, 도커는 컨테이너로 가상화를 구현하는 가상화 기술입니다. 도커의 특징은, 컨테이너가 각각 가상화를 구현하는 기본 단위가 된다는 것입니다. 위의 Docker의 로고처럼, 하나의 시스템에서 많은 수의 컨테이너를 만들 수 있습니다. 그리고 컨테이너마다 다른 종류의 데이터, 프로그램이 격리되어서 작동하고 있는 것이죠. 도커와 우리가 일반적으로 사용하는 환경의 차이는, 컨테이너 외부와 격리 여부라고 볼 수 있겠습니다. 여러분도 지금 컴퓨터에서 엑셀, 인터넷 익스플로러를 같이 사용할 수 있고, 인터넷에서 다운로드 받은 파일을 엑셀에서 불러올 수 있죠. 보통은 이처럼 여러 프로그램이 동시에 격리되지 않은 채로 함께 돌아갑니다. 

 

도커는, 이러한 프로그램 각각을 컨테이너 속에 격리하는 기능을 합니다. 여기에서 컨테이너의 개념을 설명하겠습니다.

 

박스안에 프로그램과 데이터를 격리시키는 것

컨테이너는 도커에서 가상화를 구현하는 가장 기본적인 단위이며, 도커의 핵심 개념 중 하나입니다. 비유적으로 설명하면, 컨테이너는 택배 박스를 사용하는 것과 비슷합니다.

 

예를 들어 보겠습니다. 박스는 컨테이너에 비유되고, 박스에 들어가는 내용물은 컨테이너에 격리되는 데이터와 프로그램입니다.

우리가 데스크탑을 사용하는 것은 마치 이사짐을 보내는 것처럼 한 박스에 모든 프로그램과 데이터를 담는 것과 비슷합니다. 한 박스에 수많은 내용물을 담다보니, 나중에 찾기도 어렵고 보관하는 물건이 파손되는 경우도 발생하죠.

만약 물건을 잘 관리하고 싶다면, 각각의 제품을 개별적으로 포장해서 여러 개의 박스에 담아 배송합니다. 이렇게 포장된 박스들은 각각의 제품을 보호하고, 다른 박스와 구분되어야 합니다. 그렇지만, 컨테이너 하나에 한 물건만 담을 필요는 없겠죠? 연관된 기능을 수행하는 물건들은 같은 박스에 담아도 괜찮을 것입니다.

 

컨테이너도 마찬가지입니다. 컨테이너 안에는 하나 이상의 프로세스가 실행되고, 각 컨테이너는 독립적인 환경에서 실행됩니다. 이렇게 컨테이너를 사용하면, 여러 개의 애플리케이션을 하나의 서버에서 실행시키더라도, 각 애플리케이션은 서로 독립적인 환경에서 실행됩니다. 그리고, 서버와 데이터베이스와 같이 밀접하게 연관된 프로그램의 경우 한 컨테이너에 담을 수도 있고 다른 컨테이너로 분리할 수도 있겠죠? 이는 개발자의 선택의 문제일 것입니다. 어찌 되었든, 선택을 할 수 있다는 것이 장점입니다. 이렇게 컨테이너를 사용하면, 애플리케이션의 실행 환경을 간편하게 구축하고, 배포할 수 있습니다. 그리고 도커는 이 컨테이너를 다루는 기능을 제공하는 소프트웨어라고 정의할 수 있겠습니다.

 

도커의 동작원리


도커의 동작원리를 가볍게 살펴보겠습니다. 도커의 기반 기술은 리눅스 시스템 콜으로 구현됩니다. 

 

리눅스 시스템콜은 프로그램이 운영체제(OS)와 상호작용하기 위해 사용하는 인터페이스입니다. 우리가 Command Line에 exit을 입력해서 프로세스를 종료하거나, 혹은 GUI를 강제종료할 때 종료 아이콘을 누르는 행위도 프로세스 내부적으로는 exit 시스템콜을 호출하는 것과 동일할겁니다. 이렇게 프로그램이 운영체제의 도움을 받아 수행할 수 있는 요청들을 시스템 콜이라고 합니다. 도커는 컨테이너화된 애플리케이션을 실행하기 위해 많은 시스템콜을 사용합니다. 

그 중, 대표적으로 namespace와 CGroup이 있습니다.

 

네임스페이스는 프로세스, 파일 시스템, 네트워크, IPC 등을 격리하는 기능을 제공합니다. 도커는 이를 활용하여 호스트 시스템과 독립된 파일 시스템, 네트워크 등을 제공하여 컨테이너 내에서 실행되는 애플리케이션들이 호스트 시스템과 격리된 환경에서 동작할 수 있도록 합니다. 예를 들어, 컨테이너 내부에서 /etc/passwd 파일에 접근하면, 이는 컨테이너 내부의 /etc/passwd 파일이며, 호스트 시스템의 /etc/passwd 파일과는 별개의 파일입니다.

 

CGroup은 프로세스 그룹을 관리하는 기능을 제공합니다. 도커는 이를 활용하여 컨테이너 내의 리소스(CPU, 메모리, 디스크 I/O 등) 사용량을 제한하고 관리할 수 있습니다. 예를 들어, 도커는 컨테이너 내의 프로세스가 사용하는 메모리 양을 제한할 수 있으며, 이를 통해 호스트 시스템의 메모리 사용량을 제어하고 안정적인 서비스 운영을 할 수 있습니다.

또한, 도커는 네트워크 네임스페이스를 활용하여 각 컨테이너마다 고유한 IP 주소를 할당하고, 가상 네트워크를 구성하여 여러 개의 컨테이너 간에 네트워크 통신이 가능하도록 합니다.

 

따라서, 네임스페이스와 CGroup은 도커에서 컨테이너의 격리와 리소스 관리를 위한 핵심적인 기술이며, 이를 통해 도커는 가상화 기술을 효과적으로 활용하여 애플리케이션의 실행 환경을 관리할 수 있게 됩니다.

위와 같이, 도커는 많은 시스템콜을 사용하여 컨테이너의 환경을 구성하고 관리합니다. 시스템콜은 운영체제의 기능을 호출하므로, 도커를 사용하여 애플리케이션을 컨테이너화할 때 사용되는 운영체제의 종류에 따라 시스템콜이 달라지겠죠? 그래서 도커 엔진은 리눅스 기반 운영체제에서만 구동된다고 보면 될 것 같습니다. 

 

그렇다면, 도커는 컴퓨터가 구동할 때 어디 쯤에서 위치해서 작동되는 걸까요? 운영체제에 따라 다릅니다. 윈도우에서는 일반적으로 사용하는 도커 데스크탑으로 설명하겠습니다. 아래 그림의 오른쪽 처럼, 운영체제가 리눅스라면 위에 도커엔진이 작동될 수 있고, 도커엔진 상에서 컨테이너가 각각 구동되는 형태가 됩니다. 그렇지만 보통 윈도우/Mac의 경우는 왼쪽과 같습니다. 한 쪽에는 운영체제 윈도우가 존재하고, 다른 쪽에는 윈도우에서 가상환경을 지원하기 위해 제공하는 시스템인 Hyper-V나 WSL2(Window Subsystem for Linux 2)가 존재합니다. 가상 환경 위에 리눅스 운영체제, 도커엔진, 컨테이너 순서로 위치하게 되는 것입니다.

 

도커 엔진이 구동되기 위해서 어떤 형태로든 리눅스 운영체제가 필요합니다.

 

자, 이제 도커가 무엇인지 알았으니, 도커를 설치하고 mySQL을 담은 컨테이너를 구동시켜보겠습니다.


Docker Desktop 설치


위에서 설명했듯이 도커는 리눅스 상에서 호환되는 소프트웨어입니다. 리눅스 운영체제에서 도커를 사용하기 위해서는 도커를 설치하기만 하면됩니다. 그러나 다른 운영체제에서는 도커를 구동하기 위해서는 리눅스 OS가 필요합니다. 윈도우, macOS에서는 리눅스 운영체제를 포함한 소프트웨어 패키지를 Docker Desktop이라고 합니다. 도커 데스크톱은 리눅스 운영체제를 구동시키기 위한 가상환경 지원을 필요로 합니다. 윈도우에서는 WSL2(Window Subsystem for Linux 2)나 프로페셔널에서 지원하는 Hyper-V를 통해서 가상 환경을 지원합니다. 이 글에서는 윈도우를 기준으로 설명합니다.

 

제일 먼저, 도커 데스크톱을 다운받고 설치해주세요.

https://docs.docker.com/desktop/release-notes/

 

Docker Desktop release notes

 

docs.docker.com

 

설치가 완료되었다면, 도커를 사용할 준비가 되었습니다.

커맨드 라인에 docker를 입력했을 때 아래와 같이 동작한다면 설치가 잘 된 것입니다.

 


도커 허브에서 이미지 다운로드 받기


이미지란, 컨테이너를 생성하기 위해 필요한 프로그램과 데이터를 포함한 파일입니다. 아까 택배 박스 비유에서는 박스가 컨테이너를 의미하고, 내용물이 이미지를 의미한다고 볼 수 있습니다. 다른 점은 이미지 한 장으로 수많은 컨테이너를 생산할 수 있다는 것이 다릅니다.

 

원하는 이미지는 도커 허브에서 다운로드 받을 수 있습니다. 우리는 mySQL을 컨테이너에 담을 것이기 때문에 mySQL의 이미지를 찾으면 됩니다. 다만 저는 ubuntu의 운영체제에서 작동하는 mySQL을 원하기 때문에, ubuntu/mySQL 이미지를 검색했습니다.

 

도커 허브에서 아래처럼 ubuntu/mysql을 검색합니다.

https://hub.docker.com/search?q=ubuntu%2Fmysql 

 

Docker

 

hub.docker.com

 

이미지가 있는 것을 확인하고, 들어가서 버전과 pull command를 확인합니다.

 

오른쪽의 pull command를 Command Line에 입력하면 이미지를 다운 받을 수 있고, 왼쪽의 tag를 이미지 이름 뒤에 입력해서 이미지에서 제공하는 버전의 다른 조합으로도 다운로드 받을 수 있습니다. 아무것도 입력하지 않고 pull tag만 입력한다면 latest(최신 버전)으로 다운로드 됩니다.

 

정상적으로 다운로드 되었다면, 아래처럼 이미지가 GUI 이미지에서 확인됩니다. 혹은, Command Line에서 docker image ls 명령어로 확인 가능합니다.


mySQL 컨테이너 생성


이제, 컨테이너를 생성해보겠습니다.

 

Command Line에 아래 명령어를 입력합니다. 참고로, 컨테이너의 생성 사이클은 아래와 같습니다.

 

Image Pull(이미지 다운로드) - Create Container(컨테이너 생성) - Start Container(컨테이너 가동)

원래는 pull - create - start를 각각 입력해야하지만, 이 세 가지를 합쳐놓은 명령어가 docker run입니다. 이미 이미지는 다운 받았지만, 나머지를 run으로 수행해보겠습니다.

$ docker run -dit --name porosql -e MYSQL_ROOT_PASSWORD=(password) ubuntu/mysql
  • Options
    • -dit : dit 옵션은 보통 Non-blocking Background 실행에 사용됩니다.
    • -e MYSQL_ROOT_PASSWORD : root의 패스워드를 설정합니다.

 

정상적으로 생성이 되었다면, 컨테이너에 접속해줍니다. 접속 명령어는 아래와 같습니다. 컨테이너의 bash shell에 연결한다는 의미입니다.

docker exec -it porosql /bin/bash

 

docker 컨테이너 접속 성공

 

다음으로, 로케일 설정을 해볼텐데요, 로케일은 운영체제에서 어떤 문자열을 사용할지 정의하는 것이라고 이해하시면 됩니다. 기본적으로 한글이 입력이 안되는 상태일겁니다. 마찬가지로, mySQL에서 한글을 사용하기 위해서도 ubuntu의 로케일 설정이 선행되어야 가능합니다.

 

로케일 설정


로케일이란?

사용자 인터페이스에서 사용되는 언어, 지역 설정, 출력 형식 등을 정의하는 문자열입니다. 유닉스와 리눅스 같은 POSIX 기반 시스템에서는 같은 형식을 사용합니다.

 

(참고) POSIX?

POSIX (Portable Operating System Interface)은 다양한 유닉스(Unix) 기반 운영체제에서 호환성과 이식성을 강화하기 위해 개발된 표준 인터페이스입니다. POSIX 표준은 미국 표준기술연구소(NIST)와 IEEE에 의해 개발되었습니다. POSIX가 필요한 이유는 유닉스 계열 OS가 굉장히 많은데, 공통 API를 정리해서 유닉스 응용 프로그램 개발 시 이식성을 높이는 것이 목적입니다. LINUX도 POSIX 규격을 준수하기 때문에 Unix-like(유닉스 호환) 운영체제라고 부릅니다.
POSIX는 유닉스 운영체제에서 사용되는 API 시스템 호출(System Calls)을 규정하며, 프로세스 환경, 파일과 디렉터리,시스템 데이터베이스(암호 파일 등), tar 압축 포맷 등 다양한 분야를 아우릅니다. 이러한 표준화는 소프트웨어 개발자들이 다양한 운영체제에서 프로그램을 개발하고 이식성을 높일 수 있도록 도와줍니다.

로케일 형식

로케일의 형식은 아래와 같습니다. 한글을 지원하는 로케일은 ko_kr.UTF-8을 사용하면 됩니다.

더보기

language[_territory][.codeset][@modifier] 

로케일 설정

기본적으로 C Locale로 설정되어있습니다.

  • C 로켈(POSIX 로켈이라고도 함)은 모든 POSIX 준수 시스템에 대한 POSIX 시스템 기본 로켈입니다.

어떤 로케일을 사용할 지는 환경 변수(시스템의 환경 설정 값)를 설정하면 간단하게 정할 수 있습니다. 그러나, 로케일이 우선 있어야 환경 변수 설정을 해도 사용할 수 있겠죠? locale -a로 사용가능한 로케일을 조회할 수 있습니다. 일반적인 리눅스나 맥OS 환경의 경우 자주 사용되는 로케일이 설치되어있습니다. 하지만 도커 이미지와 같이 최소화된 환경에서는 로케일이 기본적으로 설치되어있지 않습니다. 

 

로케일 다운로드

bash shell에서 아래 명령어를 입력해서 다운로드 받을 수 있습니다.

 
$ apt-get update
$ apt-get upgrade
$ apt-get install locales
$ apt-get install language-pack-ko
$ locale-gen ko_KR.utf8

로케일 설정은 아래 명령어로 가능합니다.

 
$ update-locale LANG=ko_KR.utf8 LC_MESSAGES=POSIX

 

이미지 저장하기

다음에 mySQL 컨테이너를 재생성할 때, 로케일 설정까지 완료된 상태인 컨테이너를 만들고 싶다면, 이 상태로 commit을 통해서 이미지를 생성해주면 됩니다. 다음에, 이 이미지로 컨테이너를 생성하면 설정 그대로 사용할 수 있습니다. 일종의 중간 저장 개념입니다.

# 로케일 설정한 컨테이너로 Image 만들기(commit)

$ docker commit 컨테이너이름 생성할이미지이름

혹은, Dockerfile 스크립트를 작성해도 됩니다. 스크립트는 이미지를 불러와서 스크립트 안의 내용을 순차적으로 실행한 후, 그 결과물을 이미지로 다시 만들어줍니다.

# 이미지 가져오기
FROM ubuntu/mysql

# 로케일 다운로드
RUN apt-get update
RUN apt-get -y upgrade
RUN apt-get install locales
RUN apt-get install language-pack-ko
RUN locale-gen ko_KR.utf8

# 로케일 설정 업데이트
ENV LANG ko_KR.utf8
ENV LANGUAGE ko_KR.utf
ENV LC_MESSAGES POSIX
RUN update-locale LANG=ko_KR.utf8 LC_MESSAGES=POSIX

로컬 환경에서 위의 스크립트를 작성한 후, 아래 명령어로 이미지를 생성할 수 있습니다.

> docker build -t 빌드할이미지이름 스크립트를담고있는파일경로

이미지로 컨테이너를 만들어서 locale을 확인하면 아래처럼 설정이 되어있음을 확인할 수 있습니다.

 
root@5339e90082e5:/# locale
LANG=ko_KR.utf8
LANGUAGE=
LC_CTYPE="ko_KR.utf8"
LC_NUMERIC="ko_KR.utf8"
LC_TIME="ko_KR.utf8"
LC_COLLATE="ko_KR.utf8"
LC_MONETARY="ko_KR.utf8"
LC_MESSAGES=POSIX
LC_PAPER="ko_KR.utf8"
LC_NAME="ko_KR.utf8"
LC_ADDRESS="ko_KR.utf8"
LC_TELEPHONE="ko_KR.utf8"
LC_MEASUREMENT="ko_KR.utf8"
LC_IDENTIFICATION="ko_KR.utf8"
LC_ALL=

locale 설정을 완료했으니 mySQL에서도 적용되었는지 확인해보겠습니다. CLI에서 mysql -u root -p을 입력해서 접속하고, status로 조회합니다. 리눅스의 경우 초기 설정이 latin1로 설정되는데, 로케일이 설정되어있는 경우 아래처럼 자동으로 설정됩니다.

 
mysql> status
--------------
mysql  Ver 8.0.32-0ubuntu0.22.04.2 for Linux on x86_64 ((Ubuntu))

Connection id:          8
Current database:
Current user:           root@localhost
SSL:                    Not in use
Current pager:          stdout
Using outfile:          ''
Using delimiter:        ;
Server version:         8.0.32-0ubuntu0.22.04.2 (Ubuntu)
Protocol version:       10
Connection:             Localhost via UNIX socket
Server characterset:    utf8mb4
Db     characterset:    utf8mb4
Client characterset:    utf8mb4
Conn.  characterset:    utf8mb4
UNIX socket:            /var/run/mysqld/mysqld.sock
Binary data as:         Hexadecimal
Uptime:                 7 min 56 sec

Threads: 2  Questions: 5  Slow queries: 0  Opens: 119  Flush tables: 3  Open tables: 38  Queries per second avg: 0.010
--------------

도커가 무엇인지, 도커가 어떻게 작동하는지에 대해서 간단히 살펴보았습니다. 그리고 도커로 ubuntu의 mySQL 컨테이너를 생성하여 로케일 설정까지 완료해보았습니다. 처음에 설정은 어려울 수 있지만 잘 사용하게 된다면 정말 편리한 툴이라는 생각이 많이 듭니다.