도커를 사용하다 생긴 궁금증
도커를 공부하다가 docker run -it ubuntu /bin/bash
명령어를 보게 되었다.
여기서 -it
라는 옵션에 대해서 궁금해서 무엇인지 찾아보았는데, -i
는 -interactive
의 의미로 터미널을 통해 도커와 상호작용하겠다는 의미였다.
그렇다면, -t
는 무엇일까 했는데, -tty
로 설명에는 Allocate a pseudo-tty 라고 적혀있었다.
스택 오버플로 답변 1
스택 오버플로의 친절한 답변에서 답을 찾을 수 있었다.
-t
옵션은 Unix/Linux 가 어떻게 터미널에 접근하는지에 대한 것이다. 과거에는 터미널이 물리적인 선으로 연결되어(hard line connection) 있었다. 그리고 이후엔 모뎀을 기반으로 한 연결이 되었다. 이 때는 물리적인 디바이스 드라이버를 가지고 있었고 당연히 실제 장비도 있었다. 일단 일반화된 네트워크가 사용되기 시작하면, pseudo-terminal 드라이버가 개발되었다. 프로그램에 직접 터미널과 관련된 것을 작성할 필요 없이 터미널의 어떤 기능이 사용될 수 있는지를 알도록 분리하기 위해서였다. (stty
와 curses
의 매뉴얼 페이지를 읽어보라.)
위와 같은 배경 지식을 가지고 접근해보자. 옵션을 주지 않고 기본 값으로 컨테이너를 실행하면, stdout
스트림을 얻게 된다 (docker run | <cmd>)
. -i
옵션을 추가하면, stdin
스트림이 추가된다 (<cmd> | docker run -i)
. 마지막으로 -t
를 사용해서 -it
옵션을 붙여서 사용하면, 드라이버가 추가된 터미널을 갖게 된다. 만일 프로세스와 상호작용하고 있다면, 아마 이게 우리가 원하던 일일 것이다. 이는 컨테이너를 터미널 커넥션 세션처럼 보이도록 만들어준다.
스택 오버플로 답변 2
먼저 -i
에 대해 알아보자. docker run/exec -i
는 커멘드의 컨테이너 내부의 stdin
을 docker run/exec
자체의 stdin
과 연결해준다.
그래서
docker run -i alpine cat
은 입력을 기다리는 빈 라인을 제공한다."hello"
를 입력하면"hello"
가 나올 것이다.CTRD
+D
를 입력할 때까지 컨테이너는 종료되지 않는다. 왜냐하면, 메인 프로세스인cat
은 infinite stream 에서docker run
의 터미널 입력을 기다리기 때문이다.- 반면에,
echo "hello" | docker run -i alpine cat
은"hello"
를 출력하고 즉시 종료된다. 왜냐하면cat
은 인풋 스트림이 끝났다는 것을 인지하고 자신을 종료하기 때문이다.
만일 위의 과정이 끝난 후 docker ps
를 입력하면, 실행중인 컨테이너를 찾아볼 수 없을 것이다. 두 경우 모두 cat
이 자체적으로 종료된다. 그래서 도커도 컨테이너를 종료시킨다.
이제 -t
에 대해 알아보자. -t
는 도커 내부에 있는 메인 프로세스에게 입력이 터미널 디바이스를 통해 들어온다는 것을 알린다.
그래서
docker run -t alpine cat
은 빈 라인을 제공하지만,"hello"
를 타이핑해도 어떠한 응답도 받지 못한다.cat
은 터미널 입력과 연결되었다. 하지만 우리가 입력하는 것과는 연결되지 않았다. 우리가 타이핑한"hello"
는cat
에게 도착하지 못한다.cat
은 영영 도착하지 않을 입력을 기다리게 된다.echo "hello" | docker run -t alpine cat
은 빈 라인을 제공할 것이고,CTRL
+D
명령으로도 종료되지 않을 것이다. 또한"hello"
라는 응답도 받지 못한다. 왜냐하면-i
옵션을 넘기지 않았기 때문에 입력 자체가 전달되지 않기 때문이다.
CTRL
+ C
를 입력하면, 쉘을 돌려받는다. 하지만 docker ps
를 입력해보았을 때, cat
컨테이너가 여전히 돌아가는 중임을 볼 수 있다. cat
은 종료 명령을 정상적으로 입력받지 못했고, 입력 스트림이 끝나지도 않았기 때문에 아직 기다리고 있다.
-t
옵션은 혼자써서는 별 의미가 없고, -i
와 함께 써야 의미를 갖는다.
이번엔, -it
를 함께 썼을 때를 생각해보자. 이는 cat
에게 인풋이 터미널이라고 알리고 동시에 이 터미널을 docker run
터미널의 입력에 연결시킨다. docker run/exec
은 cat
으로 넘기기 전의 tty
가 입력 이라는 것을 보장할 것이다. echo "hello" | docker run -it alpine cat
명령을 시도했을 때, input device is not a TTY
라는 응답을 받는 것은 이 때문이다. 위 경우엔, docker run
의 입력이 터미널이 아닌 이전 echo
로부터의 파이프이다. 그래서 docker run
이 실행되는 곳이 터미널이 아니게 된다.
마지막으로, -i
가 우리가 터미널에서 입력하는 것을 cat
으로 넘긴다면, 왜 -t
를 또 넘겨야 하는 걸까? 이는 터미널이라면, 커멘드가 입력을 다루는 방식이 달라지기 때문이다. 아래의 예를 보자.
docker run -e MYSQL_ROOT_PASSWORD=123 -i mariadb mysql -u root -p
명령어는 패스워드 프롬프트를 제공한다. 이 프롬프트에서 패스워드를 입력하면, 문자들이 그대로 나타날 것이다.docker run -i alpine sh
는 빈 라인을 제공한다.ls
와 같은 커멘드를 입력하면, 출력값을 받는다. 하지만, 프롬프트나 색이 입혀진 출력값은 받지 못한다.
마지막 두 경우에, mysql
과 shell
은 입력을 tty
로 다루지 않기에 인풋을 마스킹하거나 색상을 주는 것과 같이 tty
에 맞춰진 행위를 하지 않는다.
결론
-i
는 stdin
을 연결시켜 우리의 입력이 무사히 도커의 프로세스까지 닿게 한다. 단, 터미널이 연결된 것은 아니어서 터미널에 특화된 행위인 글씨색 제공, 프롬프트 제공, 마스킹 제공 등을 받지 못한다. 단순히 stdout
을 통해 오는 문자열을 볼 수 있을 뿐이다. -t
옵션까지 함께 주어야 터미널에 특화된 기능까지 함께 제공받을 수 있다.
레퍼런스
스택오버플로우 답변 - Confused about Docker -t option to Allocate a pseudo-TTY
'인프라 > 도커' 카테고리의 다른 글
하이퍼바이저 (Hypervisor) 란 무엇인가? (1) | 2024.02.04 |
---|---|
도커 실무 - Mariadb 를 사용하는 스프링부트 프로젝트 배포해보기 (0) | 2022.06.07 |
도커 자주 쓰이는 명령어 정리 (Docker Cheat Sheet) (0) | 2022.06.03 |
도커 소개 (Docker overview - get started 공식문서 번역) (0) | 2022.05.28 |
도커 (Docker) 가 무엇인지 알아보자. (0) | 2022.05.24 |