컨테이너, 짐을 상자에 담아 옮기는 일
컨테이너에는 무엇이 들어가고 무엇은 남을까요? 이미지와 실행 중인 컨테이너를 구별하고, 커널 공유와 데이터 보관의 경계를 알아봐요.
이 글의 목차항구를 바꾼 것은 상자가 아니라 규격이었다4
이사할 때 짐을 상자에 담는 이유는 짐이 상자를 좋아해서가 아니라 옮기는 사람이 편하기 때문이에요. 안에 그릇이 들었든 책이 들었든 크기가 같으면 쌓는 방법도, 나르는 손도, 트럭에 넣는 순서도 같아요. 상자는 내용물을 감추는 대신 다루는 방법을 하나로 만들어요.
소프트웨어의 컨테이너도 프로그램을 일정한 방식으로 실행하고 옮기게 해 줘요. 다만 상자 안에 컴퓨터 한 대가 통째로 들어가는 것은 아니에요. 무엇을 함께 담고 무엇을 실행할 곳에 맡기는지 알면, ‘내 컴퓨터에서는 됐는데’라는 문제를 어디까지 줄일 수 있는지도 보여요.
항구를 바꾼 것은 상자가 아니라 규격이었다
컨테이너 이전의 항구는 사람의 손으로 돌아갔어요. 자루와 나무 상자와 통이 제각각인 짐을 인부들이 하나씩 들어 실었어요. 크기가 다르니 쌓는 방법도 매번 달랐고, 배가 항구에 묶여 있는 시간이 바다를 건너는 시간보다 긴 경우도 흔했어요. 비용의 상당 부분이 항해가 아니라 싣고 내리는 데서 나왔어요.
1956년 뉴어크 항에서 트럭 운송업을 하던 Malcom McLean이 다른 방식을 시도했어요. 짐을 배에 옮겨 싣는 대신 짐이 담긴 화물칸을 통째로 실어 보내는 것이었어요. 그가 띄운 배가 Ideal-X였고 뉴저지에서 텍사스까지 갔어요.
여기서 실제로 판을 바꾼 것은 상자 자체가 아니라 규격이었어요. 치수가 통일되자 크레인과 트럭과 기차가 같은 물건을 다룰 수 있게 됐고, 항구마다 다른 장비를 갖출 이유가 사라졌어요. 부두에서 짐을 풀었다 다시 싸는 과정이 없어졌고, 그와 함께 그 일을 하던 직업도 사라졌어요. 표준이 만들어 낸 효율과 표준이 지운 노동이 같은 사건의 양면이었어요.
무엇을 격리하고 무엇을 공유하는가
프로그램을 다른 컴퓨터로 옮기면 자주 말썽이 났어요. 프로그램은 혼자 도는 것이 아니라 언어 버전, 라이브러리, 설정, 운영체제의 잔가지까지 딸려 있는데 그것들이 기계마다 조금씩 달랐기 때문이에요.
2013년 3월 Solomon Hykes가 개발자 행사에서 Docker를 처음 공개했어요. 무대에서 그가 한 말은 문제를 그대로 요약해요. 개발자에게는 서버로 배송하는 일이 어렵다는 것이었어요.
프로그램과 필요한 파일을 묶어 둔 실행 원본을 이미지라고 해요. 그 이미지에서 실제로 실행한 것이 컨테이너예요. 일반적인 리눅스 컨테이너는 운영체제의 핵심인 커널을 실행 호스트와 공유해요. 리눅스의 이름공간(namespace)은 각 프로세스에 별도의 파일·프로세스·네트워크 시야를 주고, 자원 제한은 별도 설정이 맡아요. 제한값을 정하지 않았는데 자원이 저절로 균등 분배되는 것은 아니에요.
같은 이유로 격리의 성질도 달라요. 커널을 공유한다는 것은 커널에서 문제가 생기면 그 위의 컨테이너가 함께 영향을 받는다는 뜻이에요. 서로 신뢰하는 내 프로그램들을 묶는 데는 충분하지만, 신뢰할 수 없는 코드를 남의 것과 나란히 돌리는 경계로 삼기에는 약해요.
사라져도 되는 것과 남아야 하는 것
컨테이너의 가장 큰 장점은 언제든 버리고 새로 만들 수 있다는 것이에요. 그런데 이 성질은 데이터에는 재앙이에요. 그래서 무엇을 상자에 넣을지 가르는 기준은 사실상 하나로 좁혀져요.
| 무엇 | 어디에 두나 | 잘못 두면 |
|---|---|---|
| 프로그램과 라이브러리 | 이미지 안 | 밖에 두면 기계마다 달라진다 |
| 환경별 설정과 비밀 값 | 실행할 때 주입 | 이미지에 넣으면 환경마다 다시 빌드해야 한다 |
| 데이터와 업로드 파일 | 이미지 밖의 별도 저장소 | 안에 두면 컨테이너를 지울 때 함께 사라진다 |
두 번째 줄이 자주 어긋나요. 설정을 이미지에 구워 넣으면 개발용과 운영용 이미지가 서로 다른 물건이 되고, 검증한 것과 배포한 것이 달라져요. 앞 시리즈에서 다룬 승격 구조가 성립하려면 이미지는 환경에 대해 중립이어야 해요.
데이터는 컨테이너를 멈추는 것과 지우는 것을 구별해야 해요. 안에 새로 쓴 파일은 단순 재시작에는 남지만, 컨테이너를 삭제하면 함께 사라져요. 볼륨(volume)은 컨테이너와 따로 보관하는 저장 공간이에요. Docker의 데이터 보관 설명처럼 볼륨을 남겨 두고 새 컨테이너에 다시 연결하면 같은 파일을 읽을 수 있어요.
실행 중에 저장한 사진 한 장을 두 위치에서 비교해요.
컨테이너 안
교체하면 삭제
별도 볼륨
교체해도 유지
컨테이너를 지우면 안에 새로 쓴 파일도 사라져요. 같은 볼륨에 연결한 새 컨테이너는 보관된 파일을 다시 읽어요.
두 곳에 사진.jpg를 저장했어요. 컨테이너를 교체해 보세요.
실제 파일을 다루지 않는 예시예요. 볼륨은 함께 삭제하지 않아요.
저는 무엇을 상자에 담았나
제가 만드는 앱에서는 서비스를 지켜보는 도구들을 컨테이너로 묶었어요. 로그를 모으고 지표를 보관하고 화면으로 보여 주는 것들은 함께 떠 있어야 의미가 있고, 설정이 꼬이면 통째로 내렸다 다시 올리는 편이 빨라요. 버리고 새로 만들 수 있다는 장점이 가장 잘 맞는 자리였어요.
반면 앱 자체는 컨테이너 밖에 두었어요. 혼자 운영하면서 자주 손보는 부분은 한 겹 덜 감싸 두는 편이 제게 편했거든요. 환경을 일정하게 묶는 이득과 실행 과정을 살펴보는 비용을 같이 봤어요. 다른 사람이 함께 운영하거나 배포할 곳이 늘면 다시 판단할 수 있는 선택이에요.
경계를 어디에 그을지 정답이 하나라고 믿었을 때는 이 결정이 어려웠어요. 사라져도 되는 것과 남아야 하는 것, 환경에 따라 달라지는 것과 어디서나 같아야 하는 것을 먼저 나누고 나니 상자의 자리는 저절로 정해졌어요.