Shim Won

December 31, 2014 6:52 am

번역 “본격적으로” 쓰는 Docker

Docker Advent Calendar 2014 12/25의 글, 본격적으로 쓰는 Docker입니다.

실제 저희 회사에서 Docker를 사용해 운용을 시작했을 때, 고생했던 것과, 고민했던 것, 어떻게 사용했는지를 샤샤샥 적어 보겠습니다.

“본격적으로”

저는 왜 Docker를 써야하는 이유를 이렇게 생각합니다.

  • 모든 어플리케이션을 (인프라적인 측면에서) 같은 방법으로 디플로이, 관리하고싶음.
  • 특정 서버/인스턴스의 상대를 보존하지 않고, 어플리케이션의 보존과 인프라부분의 보존을 따로 관리하고 싶음.
  • Docker는 뭔가 멋져 보이니까 쓰고 싶음.

위의 이유로 부터 어떻게 사용할 지를 적어보겠습니다. 기본적으로 1번과 2번의 이유가 중요합니다.

Docker 컨테이너의 장점

어떤 Rails 어플리케이션을 디플로이하기 하려면 서버에 이미 nginx가 들어있고, 그 nginx의 설정이 기대한 대로 설정되어있고, 디플로이 용 유저 어카운트가 있고….등등 여러가지로 힘듭니다.

이런 설정이 어플리케이션 엔지니어에서 인프라 엔지니어에게 전달되지 않는 경우도 있고, 그 설정을 실수 없이하고 싶기도 합니다.

개인적으로 더 중요하게 생각하는 것은 어플리케이션의 의존 라이브러리와 서버 상태를 분리할 수 있는 것입니다. ImageMagick의 버전을 올리고 싶을때 전 서버에서 작업하는것은 좀 두근두근한 일이니까요.

Docker 컨테이너의 좋은 점도 설명했고, 이제부터 본격적으로 Docker를 써보겠습니다.

docker-registry 선정

Docker 컨테이너를 만드는 것 뿐이라면 여기저기있는 투토리얼을 보면 알 수 있기 때문에 건너뛰고, 실제로 docker-registry부터 선정하겠습니다. 개인적으로 추천하는 registry는 quay.io입니다. 물론, 직접 docker-registry를 운용하고 싶다면 막지는 않겠습니다만, 힘드니까 각오하셔야 합니다. 제 경우 시험적으로 운영한 결과, 엄청 고생 했습니다. 느리고 느리고 느려서요.

quay.io에서는 bot 어카운트의 발행이 되고, 저장소에 억세스 권한도 설정 되어있기때문에, 그것들을 사용해 운용할 것을 추천합니다. 이런 기능들은 Docker Hub 쪽에서는 보이지 않았지만, 비슷하게 설정 할 수 있나요? 자세히 알고 계신분은 코맨트쪽에라도 가볍게 적어주시면 감사하겠습니다.

여담으로 quay.io의 가장 작은 플랜(Personal을 재외하고)은 현재 SKIFF로 $25/m입니다. 이것은 t2.medium을 1개월간 빌리는 가격인 $37.44/m 보다 싸고, GitHub와의 연동으로 Auto build도 quay.io에서는 해주는 것을 생각하면, 어느쪽이 비용이 적게드는지는 말할 필요도 없을 것이라 생각합니다.

(조금 생각 해 봤는데, 보다 권장되는 환경은 quay.io에 master를 두고 직접 docker-registry를 t2정도 어딘가에 만들어두어 mirroring하는게 좋지않을까 싶습니다.)

컨테이너 보존처의 설정

docker 컨테이너의 배포처로, /var/lib/docker 이하의 보존하는건이 기본 설정 입니다만, EC2하고 EBS-Backend라면, 이 보존처는 Ephemeral Disk등으로 해놓으면 좋습니다. 8GB의 EBS으로 해두면, 꽤 간단히 Disk가 full나 버리므로, docker컨테이너가 기동안되거나, pull이 안되거나 하는 문제가 발생합니다. docker 기동시에는 -g /epdisk/var/lib/docker 등의 옵션을 넘겨, 보존처의 디스크를 변경해두는 것이 좋습니다. 그때의 파일시스템도 꼼꼼히 채크해 둡시다.

Docker daemon의 기동시의 옵션은 공식 문서 를 구멍이 날 정도로 보시면 됩니다.

Dockerfile 의 작성법

Dockerfile를 작성법에 관해서는 언급은 하지만 이미 나와있는 좋은 글이 넘치므로 간략하게 말하면,

  • 팀별 베이스 컨테이너 (루비가 들어있거나, go가 들어있거나)
    • 어플 A
      • ImageMagick 6.7
      • 어플 B
      • ImageMagick 6.8
      • 어플 B의 다음버전

이런 식으로 구성하시면, 편리하게 쓰실 수 있으므로 추천합니다.

자동으로 기동하는 컨테이너

예를들면, EC2 인스턴스 기동시에 붙여둔 테그에서 Docker 컨테이너를 pull 해 자동으로 기동하는, 등등의 스크립트를 짤 때, 저는 단순히 rc.local의 마지막 커맨드를 적었습니다만, rc.local에서 기동하면, root의 홈 디랙토리가 설정되어있지 않은(? 이부분은 잘 모르겠네요)등의 이유로 ~/.dockercfg가 읽히지 않고, quay.io나 docker-registry의 설정에 실패해 pull이 실행되지 않는 문제가 발생합니다. 제경우 하루정도 해맸습니다. 조심하세요.

외부와 통신하는 컨테이너

저희 회사에서 운용하는 Docker 컨테이너는 호스트 쪽의 포트를 고정하지 않고 EXPOSE 80으로 80번 포트를 HTTP통신을 받을수 있도록 할것이라는 규칙을 새워두고 있습니다.

이 규칙을 바탕으로 밑에 있는 것처럼 컨테이너가 받는 HTTP 포트를 뽑아 nginx의 config를 덮어쓰는 운용을 하고 있습니다.

# 실제 코드에서 핵심부분만 뽑은 것
cid=$(docker run -d -P ${CONTAINE_NAME} | cut -c1-12)
port=$(docker port ${cid} 80 | sed -e -e 's/.*://')
config-updater ${port}

docker run 해서 만든 컨테이너 ID를 사용해 docker port 커맨드로 실제 포트를 뽑는 형태입니다. 이런 규칙으로, 모든 컨테이너를 같은 방법으로 관리할 수 있습니다. 컨테이너 내에 nginx를 동봉하는 설정의 경우는 haproxy의 tcp 모드로 나누면서, graceful로 컨피그를 바꿔치기해서, 낡은 컨테이너를 중지해서 등등의 것도 가능합니다.

이런 설정 덕분에, 어떤 언어든 어떤 구조의 어플리케이션이든, graceful하게 디플로이가 가능해져, 상당히 편해졌습니다.

Docker 컨테이너의 클린업

이건 특별히 고민할 것 없이

docker rm $(docker ps -a -q)
docker rmi $(docker images -a | grep none | awk '{print $3}')

를 실행하면 될 것 같습니다. 주의할 점은 커맨드의 앞뒤가 바뀌어버리면, stop된 컨테이너의 이미지가 먼저 삭제되어서 참조가 삭제되 docker의 행동이 이상해 질 수도 모른다는 점입니다. (또 재현될지는 모르겠지만, rmi를 전혀할수 없었던 때가 있습니다.)

기동중의 컨테이너는 rm으로 삭제되는 경우도 없고, 기동중의 컨테이너를 참조하고 있는 이미지는 rmi로 삭제되지 않기 때문에, 마음껏 해도 상관 없습니다.

k8s 등

Docker를 베이스로한 PaaS 환경 구축툴들은 여러가지 개발되어 있어, 군웅할거의 시대같은 느낌도 있습니다만, 기본적으로 그런 툴을 이용하지 않고, 평범~하게 bash 스크립트나, 낡고 좋은 awk에 의한 변환으로, 현제 운용하고 있습니다. 그냥 단순히, 너무 복잡한 툴은 운용할 때도 시작할 때도 비용이 든다는 이유 뿐입니다.

개인적으로 1컨테이너 1호스트만으로도 충분 최소의 이점을 얻고 있고, 이 이상 복잡해지는것은 원하지 않아서긴합니다만, 이렇게 생각하면, AWS의 ECS는 굉장히 기대됩니다. 좀 더 편해졌으면 좋겠어요!

정리

특히 새로울것도 없는 내용이라 생각하지만, 어떠셨습니까? 사실은 아침에 쓸 생각이었습니다만, 크리스마스의 분위기에 취해 단것을 처묵처묵하거나, 새로운 포켓몬을 하다가 완전히 늦어지고 말았습니다. 죄송합니다.

이것으로 올해의 Docker Advent Calendar는 끝입니다. 여러분, 수고하셨습니다. 좋은 연말 되세요.