WinSock 서버를 Dockerizing 하기

0_JegtvL5rZPmMxxqe
WinSock을 추억하며… (이미지 출처: https://www.cedps.net/windows-socket-winsock/)

Docker가 Windows 컨테이너를 지원하도록 릴리스된지 꽤 되었지만, 의외로 Windows Server에서 실행되는 애플리케이션을 Dockerizing 하려는 시도에 대해서는 잘 알려진 내용이 거의 없습니다.

이 아티클에서는 MSDN에 공개되어있는 간단한 WinSock 서버와 클라이언트 코드를 이용하여 Dockerizing을 하는 방법을 살펴보려고 합니다. Windows 기반 Docker에 대해 막연한 느낌을 가지셨다면 한 번 즈음 재미있게 살펴보시면 좋을 것 같습니다.

준비물

간편한 진행을 위해서 저는 다음의 개발 환경을 미리 준비하여 테스트했습니다. VM을 사용할 여건이 되지 않는 경우 다른 대체 환경이나 클라우드를 사용하여도 무방합니다.

  • Visual Studio 2017에 C++ 지원 추가
  • 가상 PC 환경 (VMware Workstation)에 Windows Server 1709 설치

만약 Windows Server 2016을 사용할 수 있는 환경인 경우, 아래 Dockerfile에 관한 설명을 참조하여 Base Image를 Windows Server 2016으로 변경하시면 되겠습니다.

코드 샘플 준비 및 컴파일

WinSock 서버 코드를 Dockerizing 해서 잘 동작하는지를 보고 싶은 것이 목표이므로, 기능 상으로 서버 역할을 해낼 수 있는 샘플 코드를 찾아보았습니다. 마침 MSDN에 적절한 예제 코드가 있어 해당 코드를 발췌하였습니다.

https://msdn.microsoft.com/en-us/library/windows/desktop/ms737593%28v=vs.85%29.aspx

위의 코드를 복사하여 server.cpp 파일로 저장하고, Visual Studio 2017 개발자용 Command Prompt 창을 열어 다음과 같이 C++ 컴파일러로 server.cpp 파일을 컴파일하도록 호출합니다.
Windows SDK에 포함되어있는 라이브러리 파일을 사용할 것이고, 코드 내에서 #pragma 지시자로 어떤 라이브러리 파일과 링크하게 할 것인지 코드 상으로 미리 선언할 수 있어 아래 명령어만으로 바로 exe 파일을 생성할 수 있습니다.

cl server.cpp

이어서 테스트를 위한 클라이언트 프로그램도 빌드해야 하겠습니다.

https://msdn.microsoft.com/en-us/library/windows/desktop/ms737591%28v=vs.85%29.aspx

마찬가지로 아래 명령어만으로 EXE 파일을 바로 만들어낼 수 있습니다.

cl client.cpp

기능이 정상적으로 작동하는지 확인해보기 위하여, server.exe 파일을 실행하고, client.exe 파일에는 접속할 호스트 주소를 넣습니다. 로컬에서 테스트해볼 것이므로 127.0.0.1 이나 localhost 를 호스트 주소로 넣으면 테스트할 수 있습니다.

샘플 프로그램이므로 서버는 첫 연결만 처리하고 바로 종료되는 것을 볼 수 있습니다.

Dockerfile 작성하기

Dockerfile을 만들어야 Docker 이미지를 생성할 수 있는 것을 잘 알고 계실 것입니다. 그런데 리눅스에서 Dockerfile을 만들던 것과 얼마나 다를까요? 제가 만들려고 하는 Dockerfile을 한 줄씩 따라가보며 완성해보겠습니다.

FROM microsoft/windowsservercore:1709_KB4056892

기본적인 시놉시스는 크게 다르지 않습니다. FROM 지시자를 사용하여 어떤 이미지를 기본 이미지로 사용할 것인지 지정해야 합니다. 당연하게도 지정할 수 있는 이미지가 Windows Server 이미지로 한정됩니다. 이 글을 작성하는 시점에서 최신 버전의 Windows Server는 반기 릴리스인 1709에 KB4056892 핫 픽스가 적용된 버전이므로 해당 이미지를 사용하도록 지정했습니다.

앞의 글에서 Windows Server 2016을 사용하는 경우에 대한 언급도 했었는데, 이 때에는 1709 대신 Docker를 설치한 Windows Server 2016 서버 컴퓨터의 빌드 넘버와 일치하는 이미지를 지정하면 됩니다. 예를 들어, 빌드 2007을 사용 중인 경우 10.0.14393.2007 을 1709 대신 지정하면 됩니다.

COPY server.exe /app/

COPY 지시자는 하는 일도 많고 중요한 부분입니다. Dockerfile이 들어있는 폴더가 기준 작업 폴더이며, 이 폴더에 들어있는 파일 중 server.exe 파일을 만들어질 이미지의 루트\app 폴더에 복사하여 넣겠다는 의미로 지시자를 작성한 것입니다.

여기서 알아둘 부분은, Dockerfile을 해석하는 프로그램 자체는 Windows를 고려하지 않았기 때문에 디렉터리 구분자를 유닉스의 / 로 사용해야만 하는 제약이 있고, C 드라이브만이 존재한다고 가정합니다. 그래서 C:\app이 아닌 /app/ 가 대상 경로가 됩니다. 그리고 디렉터리임을 정확히 표현하려면 끝에 / 구분자를 한 번 더 기재해야 합니다.

또한 Docker 이미지 안에 들어있는 Windows Server는 보통의 Windows 환경처럼 UAC로 제약이 걸려있는 환경보다는 훨씬 자유도가 높습니다. Docker 자체가 하나의 샌드 박스 역할을 하기 때문이라고 봐도 좋습니다. 따라서 %USERPROFILE% 같은 환경 변수에 종속되거나 구속되어 생각하지 않고 작업을 해야 합니다.

WORKDIR /app
CMD server.exe

다음으로 WORKDIR은 이미지를 실행하는 Docker 엔진이 기준으로 삼을 경로를 지정하는 부분입니다. 그 다음은 당연히 WORKDIR에 들어있는 EXE 파일을 “진입점”으로서 실행하는 CMD 지시자가 나타나게 될 것입니다.

EXPOSE 27015

마지막으로 EXPOSE 지시자로 어떤 포트가 대외적으로 서비스되어야 하는가를 지정하게 됩니다. 따로 언급하지 않으면 기본적으로 TCP 포트라고 가정하며, UDP 포트로 개방하기 원하는 경우 번호 뒤에 /udp 접미사를 붙이면 됩니다.

전체 코드를 다시 보면 아래와 같습니다.

FROM microsoft/windowsservercore:1709_KB4056892

COPY server.exe /app/

WORKDIR /app
CMD server.exe

EXPOSE 27015

Docker 이미지 빌드하고 테스트하기

이제 Windows Server로 파일들을 복사하여 의도한대로 잘 동작하는지 테스트해보겠습니다.
Docker 기반 인프라가 구축이 되어있다면, Docker Private Registry를 대상으로 이미지를 빌드하여 Push하고, Docker 서버에서 이미지를 Pull 하여 사용할 수 있습니다. 여기서는 그러한 인프라가 없는 초기 테스트 환경에서의 진행을 가정하였습니다.

이미지 빌드를 위하여 다음의 파일들이 서버로 복사되어야 합니다.

  • Dockerfile
  • server.exe
  • client.exe

서버로 파일을 복사한 다음, 아래의 명령어를 실행합니다. wsdock 대신 원하는 다른 이미지 이름을 지정해도 됩니다.

docker build -t wsdock .

Base Image를 다운로드하고 추출하는데 시간이 많이 소요될 수 있고, 만약 네트워크 환경이 종량제인 경우에는 패킷 요금이 과다청구될 수 있으니 주의해야 합니다.

이미지를 빌드한 다음 정상적으로 저장이 되었는지 확인하기 위하여 아래 명령을 실행해봅니다.

docker images

위에서 지정한 이미지가 목록에 나타나면 정상적으로 처리가 된 것입니다.

이제 만들어진 이미지로 컨테이너를 띄워보겠습니다.

docker run -it wsdock

wsdock 대신 다른 이름을 지정하였다면 해당 이름을 정확히 지정하도록 합니다. -it 의 의미는 컨테이너 실행 후 콘솔을 모니터링하고 직접 입력을 할 수 있게 연결하라는 의미입니다.

서버 측 실행 모습을 보기 위하여 콘솔을 점유하였으니, 새 콘솔을 띄워서 client.exe 파일이 있는 곳으로 현재 디렉터리 경로를 변경합니다. 만약 서버 코어 환경인 경우에는 Ctrl + Alt + Delete (RDP인 경우 Delete 대신 End, VMware인 경우 Insert)를 눌러 작업 관리자를 통해 새 콘솔을 시작하도록 합니다.

접속할 서버 주소를 확인하기 위하여 컨테이너의 IP 주소를 알아야 하는데, 그러려면 컨테이너 인스턴스의 이름을 먼저 알아야 합니다. 두 번째 띄운 콘솔에서 다음의 명령을 실행하여 컨테이너의 별칭을 확인합니다.

docker ps

그 다음, 확인한 별칭을 아래의 부분 대신 넣습니다.

docker inspect <Instance Name>

JSON으로 데이터가 표시되는데, 이 중에서 IP 주소를 찾아 아래와 같이 client.exe에 인수로 넣어줍니다.

client.exe <IP Address>

서버 측 컨테이너가 첫 연결을 받은 후 종료되는 모습이 보이면 의도한대로 여러분의 WinSock 샘플 서버가 Dockerizing이 잘 된 것입니다.

결론

Docker 자체에 대해서는 사용법과 활용 방법을 따로 익혀야 하는 부분이 있지만, 기본 원리만 이해한다면 Windows 서버 환경에서도 어렵지 않게 Dockerizing 기법을 적용할 수 있습니다.
당연하게도, Azure의 Docker 레지스트리에 이렇게 만들어진 이미지를 Push하고, Container Instance 등에서 Pull 할 수 있으면 쉽게 서버를 Azure 클라우드에서 프로비져닝 할 수 있는 것입니다.

실제 서버 운영 환경에서는 여러 컨테이너를 하나의 네트워크에 배치하여 서로 참조하도록 만들어야 하며, 이 경우에는 여러 개의 Dockerfile을 만들고, 한 번에 컨테이너를 띄우고 연결시킬 목적으로 Docker Compose 유틸리티와 스크립트를 만들게 됩니다.

여기서는 기본 사용법과 시나리오를 이해하기 위한 목적으로 기본적인 내용만을 기재하였으니, 더 관심있으신 분들께서는 관련 리소스를 찾아보시기를 권합니다.

커버 이미지 출처: http://www.rob-r.co.uk/other/UKphonecatwiring.htm

글쓴이: 남정현

http://www.rkttu.com

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

%s에 연결하는 중

This site uses Akismet to reduce spam. Learn how your comment data is processed.