041214_1147_WindowsMedi37.png

Windows Media Service를 Microsoft Azure에서 실행하기

Windows Media Service는 Windows Server 2008 R2를 마지막으로 현재는 더 이상 업데이트되지 않고 있는 레거시 미디어 서비스입니다. 현재는 IIS Media Service를 IIS에 추가로 설치하여 Progressive Download 또는 Smooth Streaming 형태로 기존 미디어를 다시 인코딩하여 서비스하는 것을 권장하고 있는 상황입니다.

그러나 만약 필요에 따라 Windows Media Service를 Microsoft Azure로 옮겨서 실행해야 할 필요가 있다면, 거의 모든 구성이나 설정은 기존의 레거시 서버 설정과 동일하게 구성하면 큰 무리는 없습니다. 이번 블로그 포스트의 전반부는 Microsoft Azure에서 Windows Media Service를 실행할 수 있도록 Windows Server 2008 R2를 프로비저닝하는 방법을 살펴보고, 후반부에서는 네트워크 포트 설정 등을 구성하여 단일 미디어 서버가 정상적으로 Microsoft Azure 환경에서 잘 실행될 수 있도록 한 다음 테스트하는 방법을 살펴보도록 하겠습니다.

주의 사항

Microsoft Azure의 방화벽 특성 상 일부 시나리오 (UDP 멀티캐스트)는 구성에 문제가 있습니다. 이 블로그 포스트는 TCP 방식의 유니캐스트를 기준으로만 설명을 진행하고 있음을 미리 말씀드립니다.

Windows Server 2008 R2 프로비저닝하기

Windows Media Service의 가장 최신 버전은 Windows Server 2008 R2와 함께 사용할 수 있습니다. 다음 순서에 따라 Windows Server 2008 R2를 프로비저닝합니다. 블로그에서 소개하는 방법은 Microsoft Azure Management Portal을 사용하는 방법을 기준으로 하는 것으로, 다른 사용 방법을 택하더라도 무관합니다.

다른 설정은 적절히 설정을 지정하시면 됩니다. 여기서 중요한 것은 이미지에 대한 설정으로 Windows Server 2008 R2 SP1을 기본 이미지로 사용하도록 택해야 합니다. 설정을 모두 구성한 다음 가상 컴퓨터 만들기 버튼을 클릭하고 잠시 기다리면 자동으로 프로비저닝이 완료되어 접속 가능한 상태로 전환될 것입니다.

또한 DNS 이름은 여러분이 입력한 ID값 다음에 .cloudapp.net이 오는 형태의 주소이며 이 주소는 인터넷 상에서 고유한 주소가 됩니다. 이 주소를 기준으로 MMS 서버 주소가 완성됩니다.

가상 컴퓨터가 준비되면 새로 만든 컴퓨터를 선택하고 하단의 연결 버튼을 클릭하여 원격 데스크톱 연결을 시작합니다.

IE 보안 강화 구성 완화하기

아시다시피 Windows Media Service는 Windows Server 2008부터는 기본 제공 기능이 아닌 별도 분리된 확장 기능으로 Microsoft 웹 사이트에서 언어 별, 버전 별로 패키지가 별도로 분리되어 제공되고 있습니다. 원격 데스크톱에 접속한 다음, Microsoft 웹 사이트에서 해당 패키지를 내려 받아 설치하기 위하여 인터넷 보안 강화 설정을 잠시 완화해야 합니다.

최초에 다음과 같이 화면이 나타나면 Close 버튼을 클릭합니다.

이어서 Server Manager 화면에서 Configure IE ESC (한글 명칭은 보안 강화 구성) 링크를 클릭합니다.

다음 그림과 같이 관리자 계정들에 대해서만 Off로 설정하도록 라디오 버튼을 체크하고 OK 버튼을 클릭합니다. 만약 이보다 앞서 Internet Explorer 창을 열어 놓은 것이 있을 경우 모두 닫고 다시 열어야 설정이 반영됩니다.

Windows Media Services 설치 패키지 받아서 설치하기

현재 영어 버전의 Windows Server를 사용 중이므로, 아래 주소에서 해당 언어 버전의 Windows Media Services 패키지를 받아 설치해야 합니다.

http://www.microsoft.com/en-us/download/details.aspx?id=20424

만약 한국어 버전의 Windows Server 2008 R2 SP1 이미지를 VHD로 게시하여 VM을 프로비저닝한 경우 한국어 버전의 Windows Media Services 패키지를 받아 설치하면 됩니다.

http://www.microsoft.com/ko-kr/download/details.aspx?id=20424

웹 브라우저로 사이트를 열어보면 다음과 같이 Download 버튼이 보일 것입니다. 경고 창이 많이 나타나거나 Download 버튼이 보이지 않으면 보안 강화 구성 완화가 아직 반영되지 않은 것이므로 앞 단계로 되돌아가서 다시 설정을 검토하거나, 필요한 경우 로그아웃 한 다음 다시 로그인하면 됩니다.

패키지를 내려 받아 설치를 시도하면 Windows Update Standalone Installer가 나타나며 다음과 같이 설치 여부를 묻는 대화 상자가 나타납니다. Yes 버튼을 클릭하여 설치를 진행합니다.

업데이트 제공 및 사용에 관한 동의 여부를 확인하는 창이 나타납니다. 내용을 검토한 후 동의해야 설치를 진행할 수 있으며 동의하는 경우 I Accept 버튼을 클릭합니다.

설치는 보통 2~3분 이내에 마무리됩니다. 다음과 같이 설치 완료 대화 상자가 나타나면 Close 버튼을 클릭합니다.

보안 강화 구성 복원 및 Windows Media Service 역할 설치

이제 필요한 파일을 내려 받아 설치를 마무리하였으므로 보안 강화 구성을 원래대로 복원하고, 실제로 Windows Media Service 역할을 설치해야 합니다. 작업 표시줄 하단의 서버 관리자 아이콘을 클릭합니다.

다시 보안 강화 구성 대화 상자로 들어가서 Administrators에 대해 보안 강화 구성을 다시 사용하도록 On으로 라디오 버튼을 체크하도록 합니다. 이 설정 전후로 모든 Internet Explorer 창을 닫아야 합니다.

대화 상자를 닫고, 이번에는 좌측 트리 뷰에서 Roles 노드를 클릭한 다음 새 역할 추가 링크를 클릭합니다.

어떤 역할을 설치할 것인지 묻는 부분에서 Streaming Media Services가 보이면 앞의 패키지 설치가 잘 완료된 것입니다. 해당 항목을 선택하고 다음 버튼을 클릭합니다.

이 블로그 포스트에서는 최소한의 기본 시나리오를 설명하기 위한 것이므로 다른 추가 구성 요소를 선택하지 않고 Windows Media Service 항목만을 설치하는 것으로 진행해보겠습니다. 다음 버튼을 클릭합니다.

이 블로그 포스트에서는 RTSP 스트리밍과 HTTP 프로그레시브 다운로드를 사용하는 시나리오를 택하여 설치를 진행하도록 하겠습니다. 다음 버튼을 클릭합니다.

설치 내역 확인을 묻는 단계입니다. Install 버튼을 클릭하여 설치를 계속 진행합니다.

설치가 마무리되면 다음과 같이 화면이 나타나게 됩니다. Close 버튼을 클릭합니다.

Windows Media Service 게시 지점 만들고 구성하기

이제 Microsoft Azure에서 Windows Media Service 스트리밍을 구성할 수 있게 되었습니다. 테스트를 위하여 VOD 서비스를 각각 RTSP 버전과 HTTP 버전으로 나누어서 만들어보도록 하겠습니다. 서버 관리자에서 아래 그림에 나타난 것 과같이 트리 뷰 노드를 펼쳐서 Publishing Points 항목을 오른쪽 버튼으로 클릭하여 Add Publishing Point (Wizard) 항목을 클릭합니다.

적당한 게시지점 이름을 입력합니다. 여기서는 이해를 돕기 위하여 Sample1 이라고 입력하고 Next 버튼을 클릭하겠습니다.

디렉터리 단위로 게시지점을 설정하여 일반적인 동영상 호스팅을 시작해보도록 하겠습니다. 네 번째 라디오 버튼을 클릭하고 Next 버튼을 클릭합니다.

주문형 게시 지점 구현을 위하여 두 번째 라디오 버튼을 클릭하고 Next 버튼을 클릭하겠습니다.

%SYSTEMROOT%\WMPUB\WMROOT 디렉터리에 샘플 동영상들이 다수 포함되어있습니다. 필요한 경우 다른 디렉터리를 선택합니다. Next 버튼을 클릭합니다.

재생 목록에 관한 정책으로 기본값을 유지한 상태에서 일단 Next 버튼을 클릭하겠습니다.

발생하는 이벤트 및 오류에 대한 기록을 수행할 지의 여부를 선택할 수 있습니다. 기본 값으로 설정하고 Next 버튼을 클릭하겠습니다.

구성 내역 확인 페이지입니다. Next 버튼을 클릭하겠습니다.

이제 마지막 단계입니다. 여기서 주소는 컴퓨터의 NETBIOS 이름으로 되어있지만 실제로는 정규 도메인 이름 (FQDN)으로 변경하여 외부에 공개하면 됩니다. 마침 버튼을 클릭합니다.

기능 테스트를 위하여 만든 것이므로 유니캐스트 알림 마법사 창이 다음과 같이 나타나면 Cancel 버튼을 눌러 마법사를 취소합니다.

새로 만들어진 게시 지점 디렉터리 아래에 사용 가능한 동영상들을 확인하기 위하여 새 게시지점 항목을 선택하고 Source 탭을 클릭합니다.

그리고 Announce 탭을 클릭하면 실제 서비스를 위하여 어떻게 주소를 지정하면 되는지 알려줍니다. 컴퓨터 이름 대신 실제 .cloudapp.net 주소로 바꾸도록 하고, insert_file_name_here.즘 부분은 앞에서 본 파일 들 중 하나로 이름을 지정하면 됩니다.

Microsoft Azure 방화벽 구성하기

역할 설치와 동시에 Windows 방화벽은 자동으로 구성되므로 별도로 변경할 것이 없습니다. 그러나 RTSP 서비스를 실제로 밖에서 사용할 수 있도록 하려면 Microsoft Azure의 방화벽 구성을 변경해주어야 합니다. RTSP 서비스를 위하여 변경해야 할 방화벽 요소는 다음과 같습니다.

다시 Microsoft Azure 가상 컴퓨터 콘솔로 되돌아와서 지금 작업한 가상 컴퓨터 인스턴스의 상세 페이지로 이동한 다음 끝점 항목을 클릭합니다.

현재 개방되어있는 TCP/UDP 포트들의 내역이 나타납니다. 이제 여기에 TCP 유니캐스트 포트와 HTTP 포트를 개방해야 합니다. 다음 그림과 같이 구성이 나타나도록 만들면 됩니다.

새 포트를 추가하기 위하여, 하단의 추가 버튼을 클릭합니다.

독립형 끝점 추가 라디오 버튼을 클릭하고 다음 버튼을 클릭합니다.

다음 화면에 WMS TCP유니캐스트 및 HTTP 항목을 추가하기 위하여 따로 항목을 입력합니다. 한 번에 한 항목만 마법사를 통하여 등록할 수 있으며 등록에는 일정 시간이 소요됩니다.

TCP UNICAST

  • 이름: TCP UNICAST (일치하는 기본 항목이 없으므로 직접 입력합니다.)
  • 프로토콜: TCP
  • 공용 포트: 1755
  • 개인 포트: 1755

HTTP

  • 이름: HTTP (드롭 다운 상자에서 선택하면 자동으로 아래 항목들이 입력됩니다.)
  • 프로토콜: TCP
  • 공용 포트: 80
  • 개인 포트: 80

위의 설정 내역은 http://support.microsoft.com/kb/189416/en 에서 발췌하였습니다.

동영상 테스트해보기

재생이 잘 되는지 이제 확인해볼 차례입니다. Windows Media Player를 실행하고, URL 열기 (Ctrl + U를 눌러 단축키로 실행할 수 있습니다.) 에서 다음과 같이 주소를 입력합니다.

mms://<VM DNS 이름>.cloudapp.net/<게시 지점 이름>/<샘플 동영상 파일 이름>

예를 들어, 위의 설정에 따라 저는 다음과 같이 입력할 수 있습니다.

mms://rkttu-wms.cloudapp.net/Sample1/snowboard_300.wmv

그러면 다음과 같이 동영상이 재생되는 것을 볼 수 있습니다.

HTTP 포트도 개방하였기 때문에, 위의 주소 규칙에서 mms:// 대신 http:// 로 바꾸어 접속해도 재생이 잘 될 것입니다.

마무리

Windows Media Service를 Microsoft Azure를 통해서 구성하는 방법을 살펴보았습니다. 클라우드 환경의 이점을 충분히 이용한다면 다음과 같은 확장 방안을 고려해 볼 수도 있습니다.

  • 가상 컴퓨터 인스턴스 간 데이터 공유를 위하여 Network Attached Storage 역할을 수행할 수 있는 가상 컴퓨터를 Microsoft Azure Virtual Network 상에 배치하여 동영상 파일을 가상 컴퓨터 간에 공유하도록 게시 지점을 구성한 후, 부하 분산 로드 밸런싱을 구성하면 확장성 있는 동영상 스트리밍 서비스 구성이 가능합니다.
  • IIS와 동시에 같은 서비스를 구성하기 위하여 NAT 방화벽 설정을 이용하면 MMS만을 중개하도록 하고 HTTP 포트는 IIS로 연결이 되도록 구성할 수 있습니다.

그러나 한 가지 염두에 두어야 할 것이 있습니다. Windows Media Service는 현재 최신 버전의 Windows Server에서는 더 이상 지원되지 않는 기술이기 때문에, 최신 버전의 Windows Server로 업그레이드를 수행하려면 동영상 스트리밍 서비스 방식을 변경해야 하는 문제가 있습니다. 이 점에 대한 적절한 대비책을 마련한 후 지속적으로 서비스 운영 여부를 결정하도록 하는 것이 좋겠습니다.

041114_1628_CHTML1.jpg

C#에서 HTML 문서 분석 때문에 고민하지 마세요 – HtmlAgilityPack

흔히 소프트웨어 개발 과정에서 나타나는 요구 사항들 중에서, 시간 투자 대비 효율이 가장 떨어지는 요구 사항으로 HTML 문서 분석에 대한 것이 있습니다. 이 요구 사항을 해결하기 위해서, 보통 택하는 방안으로는 Windows 환경에서 Internet Explorer의 MSHTML을 이용하는 방안을 고민하게 됩니다. 그러나 익히 알려져 있는 바, 메모리 누수나 무거운 런타임 크기, 더 나아가서는 제한된 수준의 해석 등 이점보다는 단점이 더 많은 방식이라는 것이 큰 문제입니다. 물론 이 이후로도 오픈 소스 브라우저를 활용하거나 WebKit 바인딩을 이용하는 방법도 흔히 검토가 가능하긴 하지만 전체 브라우저 스택을 완전히 불러들여야 하고 HTML 문서의 계산 과정이 동반된다는 점이 성능 상의 이슈가 됩니다.

HtmlAgilityPack은 순수하게 .NET Framework의 코드 만으로 HTML 문서를 온전하게 분석하는 것은 기본이고, System.Xml 네임스페이스에서 제공하는 XPATH 식 관련 인터페이스와 해석기를 충실하게 지원하고 있어서, 복잡하고 까다로운 HTML 문서 구조 탐색을 매우 손쉽게 처리해 준다는 큰 장점이 있습니다. 무엇보다도 중요한 것은, NuGet에서 쉽게 설치해서 사용할 수 있으므로 HTML 문서 분석에 관한 고민에 시달리고 계시다면 지금 당장 테스트해보시기를 강력히 권할 수 있을 만큼, 훌륭한 기능을 제공합니다. 강력한 기능 덕분에 몇몇 상용 솔루션에서는 이미 절찬리에 채택되어 사용 중에 있습니다.

패키지/프로젝트 소개

HtmlAgilityPack은 2014년 4월 현재 다음과 같이 두 패키지로 구분되어있습니다.

처음의 패키지는 Desktop 버전의 .NET Framework (Mono 포함)에서 이용할 수 있도록 패키징된 버전으로, XPATH 식에 대한 지원을 포함하고 있습니다. 그리고 두 번째 패키지는 Windows Phone, Windows Store App 등의 환경에서도 사용 가능하도록 Portable Class Library 프로필에 맞게 리패키징한 버전입니다. 이 글에서 설명하고자 하는 버전은 첫 번째 버전입니다.

샘플 코드

테스트하려는 프로젝트를 여신 다음, HtmlAgilityPack을 NuGet 패키지 관리자로 프로젝트에 설치하고, 실제로 HTML 페이지 분석이 잘 이루어지는지 확인해보기 위하여, 다음과 같이 코드를 작성해보도록 하겠습니다.

using System;
using System.IO;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml.XPath;

class Program
{
    static void Main(string[] args)
    {
        Uri targetUri = new Uri("http://www.youtube.com/watch?v=8YkbeycRa2A"); HttpWebRequest webRequest = HttpWebRequest.Create(targetUri) as HttpWebRequest;
        using (HttpWebResponse webResponse = webRequest.GetResponse() as HttpWebResponse)
        using (Stream webResponseStream = webResponse.GetResponseStream())
        {
            HtmlDocument s = new HtmlDocument();
            Encoding targetEncoding = Encoding.UTF8;

            s.Load(webResponseStream, targetEncoding, true);
            IXPathNavigable nav = s;

            string title = WebUtility.HtmlDecode(nav.CreateNavigator().SelectSingleNode("/html/head/meta[@property='og:title']/@content").ToString());
            string description = WebUtility.HtmlDecode(nav.CreateNavigator().SelectSingleNode("/html/head/meta[@property='og:description']/@content").ToString());
            string fullDescription = WebUtility.HtmlDecode(s.GetElementbyId("eow-description").InnerHtml);
            fullDescription = Regex.Replace(fullDescription, @"<(br|hr)[^>]*>", Environment.NewLine);
            fullDescription = Regex.Replace(fullDescription, @"<[^>]*>", String.Empty).Trim();

            Console.WriteLine(title);
            Console.WriteLine(description);
            Console.WriteLine(fullDescription);
        }
    }
}

여기서 설명한 코드는 YouTube의 메타 태그 속성을 이용하여 동영상에 대한 기본적인 정보를 가져오는 코드입니다. 여기서 주목할 것은 XPATH 식을 사용하여 HTML DOM 모델에 정확하게 접근하고 있다는 점입니다. Property 속성이 og:title인 META 태그의 Content 속성을 가져와서 YouTube에 정확하게 등록한 원래 동영상 제목을 추출하거나, 동영상의 설명을 같은 방법으로 가져오고 있습니다. 여기서 그치지 않고, eow-description이라는 ID를 가진 HTML 태그를 찾아 그 태그의 내용을 통째로 가져와서 축약되지 않은 원래 설명도 특별한 API 없이 가져오고 있습니다.

System.Xml.XPath 호환

위의 코드에서 HtmlDocument 클래스를 IXPathNavigable 형식의 변수 s로 캐스팅한 것을 볼 수 있습니다. 이 코드가 의미하는 바는 실로 큰데, IXPathNavigable은 .NET Framework BCL의 System.Xml 안에 들어있는 인터페이스를 실제로 대응하여 구현한 것입니다. 이 기능을 사용하면 다루는 대상이 XML이든 HTML이든 혹은 XHTML이든 일반화하여 다루는 것이 가능하여 의존성 주입의 차원을 고도화하는 것이 가능합니다.

IXPathNavigable 인터페이스는 다른 메서드를 제공하지 않고 오로지 CreateNavigator() 메서드만을 제공하는데, 이 메서드를 이용하여 만드는 객체는 XPathNavigator 클래스입니다. 이 클래스의 인스턴스는 상대적 접근 경로를 인식하여 해당 객체를 만들기 위하여 어떤 DOM 노드 객체를 활용하였는지에 따라 경로가 달라집니다. 이 기능을 사용하면 XPATH 식으로 선택이 어려운 노드를 근처의 형제 노드 (Sibling Node)를 통해서 전/후 탐색 메서드를 사용하여 접근이 가능합니다. XPathNavigator 클래스는 한 번 생성된 이후에는 자신이 스스로 상태를 관리하도록 되어있으므로 일종의 커서처럼 탐색이 가능합니다.

실제 활용 사례

이 즈음되면, 정말 특이한 상황을 제외하고 HTML 페이지를 수집하러 돌아다니는 크롤러를 얼마든지 만들 수도 있겠다는 예상도 해볼 수 있습니다. 실제로 이 라이브러리를 사용하여 크롤링 기술을 구현하고 있는 Arachnode.net이라는 Lucene.net 기반의 상용 검색 엔진 프로젝트도 많은 주목을 받고 있습니다. (http://arachnode.net/)

필자 개인적으로는 HTML 구문 분석이 필요한 프로젝트에서 상당히 큰 도움을 받았으며 해당 프로젝트의 주요 기능으로 적극적으로 채택하는데 큰 도움을 받았습니다.

도입 시 고려할 사항

HTML을 분석할 수 있다는 전무후무한 강력한 장점이 있음에도 불구하고, 한 가지 주의 사항이 있습니다. HtmlAgilityPack으로 처리할 수 있는 HTML은 파일 시스템 상의 고정된 정적 페이지나 네트워크를 통해서 서버가 정적 또는 동적으로 제공하는 HTML 페이지만 정확하게 처리가 가능하며, CSS나 JavaScript, 혹은 다른 Rich Internet Application (Flash나 Silverlight 등)이 나중에 가공하는 HTML 페이지의 변경 사항은 반영되지 않는다는 점입니다. 이것은 라이브러리의 문제가 아니며, 라이브러리가 취하고자 하는 기능의 명확한 한계입니다.

Rich Internet Application에 의한 후 처리를 제외하고 CSS나 JavaScript에 대한 처리가 완료된 웹 페이지에 대한 분석이 필요한 상황인 경우, Headless Browser를 사용하여 계산이 완료된 웹 페이지를 처리하거나 더 복잡한 작업을 수행할 수도 있습니다. 이를 위하여 PhantomJS (http://phantomjs.org/) 를 사용하는 것이 유용합니다. PhantomJS는 NuGet 패키지로도 제공됩니다. (http://www.nuget.org/packages/PhantomJS/)

만약 Rich Internet Application에 의한 후 처리까지 필요한 경우에는 Chrome이나 Internet Explorer를 해석 엔진으로 안정적으로 사용할 수 있도록 도움을 주는 Selenium Web Driver에 의한 간접적 처리도 고려해볼 수 있습니다. (NuGet 패키지: http://www.nuget.org/packages/Selenium.WebDriver/) PhantomJS와 Selenium Web Driver에 관한 이야기는 이 블로그 포스트 범위 밖에 있는 이야기이므로 존재에 대해서만 언급을 하는 것으로 갈무리하겠습니다.

041014_1618_SystemNetHt1.jpg

System.Net.Http.HttpClient에 대한 경험담

System.Net.Http.HttpClient는 ASP.NET 웹 API의 REST API 호출을 위해서도 요긴하게 사용하지만, 다양한 상황에서 사용 가능한 HTTP 송수신을 담당하는데 특화된 클래스입니다. 최근에 이 클래스를 사용하여 개발한 소프트웨어 프로젝트에서 예기치 않은 문제가 하나 있었는데, TIME_WAIT 상태로 연결 대기가 유지되는 소켓 연결의 수가 급증하여 서버에서 실행 중인 다른 데이터베이스나 웹 서비스의 연결이 WSAENOBUF WinSock 오류 코드를 반환하며 거부되는 일이었습니다.

이 클래스는 기본적으로 IDisposable 인터페이스를 구현하고 있고, 원래의 의도는 사용하지 않을 때 적시에 제거하는 것이 올바른 방식이라고 생각하였습니다. 그러나 실제로 이 클래스를 Dispose() 메서드를 사용하여 소거한다고 하더라도 클라이언트 측 연결이 끊어지지 않고 TIME_WAIT 상태로 변경되는데, 이러한 상황에서 계속 HttpClient 인스턴스를 반복적으로 만들고 연결을 다시 시도하다보면, 접속하는 클라이언트 측의 잔여 TCP 포트의 수가 부족해지는 문제가 발생하게 됩니다.

이 문제를 해결하기 위하여 취한 방법은 해당 인스턴스를 싱글턴 인스턴스로 만들어 사용하는 것이었으며, 실제로 문제를 해결할 수 있었습니다. 하지만 남아있는 문제는 이 인스턴스를 Thread-Safe 인스턴스로 만들어야 하는 것이며 이를 위해서 보강해야 할 것이 있다고 보고 있습니다.

f137c4ccb68681c17301b3c53d7628dd.jpg

(주)자이닉스 윈도우, 모바일, 웹 어플리케이션 경력직 개발자 모집 채용 공고

안녕하세요. Windows Azure MVP 남정현입니다.


제가 현재 근무하고 있는 (주)자이닉스에서 Windows 응용프로그램 개발, Mobile 개발 및 웹 어플리케이션 부문 경력직 개발자를 채용하고 있습니다. 상세한 채용 모집 공고는 다음과 같습니다. 관심있으신 분들께서는 아래 링크를 통하여 온라인으로 지원서를 제출해주시고, 추천해 주실 만한 분이 있으시다면 역시 많은 홍보 부탁드리겠습니다.



 


㈜ 자이닉스 윈도우, 모바일, 웹 어플리케이션 

경력직 개발자 모집 채용 공고


 

자이닉스는 리치미디어 기반의 소프트웨어 개발 전문 기업으로 이러닝/프레젠테이션 콘텐츠 저작도구 및 지식 공유 플랫폼 솔루션을 개발하여, 국내 유수의 대학/기업 및 일본 시장에서 비즈니스를 전개하고 있습니다.

자이닉스는 데스크톱 기반의 어플리케이션 개발 기술, DirectX 및 Windows Media 기반의 미디어 변환 및 저작 기술, 웹 어플리케이션 개발 기술 등을 보유하고 있으며, 최근 모바일 어플리케이션 부문의 개발까지 확대하여 다양한 콘텐츠 저작 도구 및 공유 솔루션을 개발/공급하고 있습니다.


자이닉스는 윈도우, 모바일, 웹 어플리케이션 경력직 개발자 인력을 다음과 같이 채용 하고자 합니다.

관련 분야의 전문성을 가지고 새로운 영역을 개척하려는 자기 개발 의지와 도전 의지를 가지고 계신 분들의 많은 지원을 바랍니다.
















Exciting


즐겁게, 신나게, 그렇지만 치열하게 일합니다.


평범하고 좋은 사람이 되기 보다, 특별한 가치를 지향하는, 세상의 변화를 꿈꾸는 회사이고자 합니다.


고객의 꿈을 실현할 수 있도록, 우리가 먼저 꿈꾸고 우리가 먼저 실천하고자 합니다.

그것이 바로 자이닉스가 말하는 Exciting입니다. 




096_110228.jpg




  1.png



Technology


이미 주어진 것을 개발하여
결과만 내는 개발자를 원하지 않습니다.


무엇을, 왜 만드는 것인지,
어떻게 만드는 것이 최선인지 고민하고,

더디더라도 사용성과 품질을 생각하여 

진정한 가치있는 상품을 만들 수 있는 개발을 지향합니다.


 다양한 웹, 윈도우 어플리케이션 기반의 디지털 커뮤니케이션 솔루션에 대한 경험을 토대로,

모바일 영역까지 확장하여,
이제는 글로벌 시장에서 겨루고자 합니다.

Companions


자이닉스 일원들이 서로 하나의
생활 공동체를 이루는 동반자입니다.


또한 우리는 고객에게 기술을 통해 가치를 전달하고, 

함께 성장해 가는 기술 동반자입니다.


같이 하기 때문에 더 큰 꿈을 이룰 수 있는
진정한 동반자가 되는 것,


그것이 자이닉스가 꿈꾸는 비전입니다.





 3.png


 




▼ 자이닉스 소개 슬라이드  (클릭해서 슬라이드를 넘겨보세요)








▼ 자이닉스 근무환경이 궁금하시다고요?






 



모집 인원


o      윈도우 및 모바일 어플리케이션 개발 부문 1~2명
o      웹 어플리케이션 개발 부문 1~2명



모집 분야

o      모바일 환경에서의 프레젠테이션 및 콘텐츠 제작 어플리케이션 개발
o      웹 기반 콘텐츠 관리 시스템(CMS) 및 서비스 플랫폼 개발




담당 업무

= 콘텐츠 제작 플랫폼(Contents Creation Platform)
           콘텐츠 제작 플랫폼은 사용자의 상황 및 의도에 가장 적합한 콘텐츠 생산 도구의 제공을 목표로 합니다.
       • 어플리케이션 개발 부문
                [Windows 및 Mobile 어플리케이션 개발 부문]
                     # 업무 영역: 윈도우 및 모바일 콘텐츠 제작용 어플리케이션 개발
                     # 전문 영역:
                               – iOS/Android 등 주류 모바일 플랫폼에 대한 어플리케이션 개발
                                        -    Objective-C, Java
                               – HTML5 기술을 이용한 어플리케이션 융합
                               – 윈도우 어플리케이션 개발
                                        -    Visual C++, C#, .NET Framework, WPF



= 콘텐츠 관리 및 서비스 플랫폼
       • 웹 CMS/서비스 플랫폼 개발 부문
                     # 업무 영역: 웹 기반 콘텐츠 관리 시스템(CMS) 및 서비스 플랫폼 개발
                     # 전문 영역:
                               – 웹 기반의 콘텐츠 관리 및 서비스 플랫폼 개발
                                        -    PHP, JavaScript, CSS, Ajax, jQuery, HTML5, XML
                               – Open CMS를 활용한 서비스 플랫폼 개발
                                        -    WordPress
                               – 클라우드 환경을 기반으로 한 웹 서비스 개발


지원 자격 조건



o      전문대 졸 이상 
o      모집 분야 및 담당 업무 관련 경력 2~3년 (*)  

심사 시 주안점 및 우대 조건



o      관련 업무에 대해 적극적인 참여를 통한 개발 경험이 있으신 분
o      활발한 커뮤니케이션에 익숙하고 팀 단위 활동에 적극적이신 분
o      영어, 일본어 등 외국어 능통자 우대

 

근무 조건 및 복리후생


o      연봉 – 사내 규정에 따름, 퇴직금 별도
o      주 5일 (월~금) 근무, 연차 12일
o      4대 보험 (국민연금, 고용보험, 산재보험, 건강보험), 퇴직금
o      각종 경조금, 경조 휴가
o      우수 사원 포상
o      도서구입비 지원
o      역량 강화를 위한 교육, 세미나, 전시회 등 적극 지원


전형 절차

 


o      1차: 서류 전형 (1차에 합격하신 분에 한해서 개별 통보)

o      2차: 기술 면접

o      3차: 인성 면접

o      4차: 최종 면접



제출 서류

o      이력서 (연락처/사진 포함) 및 자기소개서 
        ※  이력서는 제공해 드리는 양식을 참고해 주시고, 자기소개서는 자유 양식으로 작성하시기 바랍니다.
             (이력서 양식 다운로드 – http://link.rkttu.com/xinics-resume-form)
o      경력 및 참여 부문별 개발 경험 및 관심사 위주로 작성 


접수 방법

o      이메일 접수 : recruit@xinics.com 


전형 일정

o      서류 접수: 채용 완료 전 까지
o      서류 전형 결과 발표: 서류 접수 후 서류 심사 통과자에게 개별 통보
o      면접: 서류 심사 합격자 개별 연락하여 일정 확인
        ※ 지원자 규모 및 여부에 따라 변동 가능


문의 및 연락처



o      이메일 : recruit@xinics.com

o      전화: 02-2109-8801 (311)

o      담당자: 박진궁 차장
 

회사 위치 

o      서울시 구로구 구로동 197-22 에이스테크노타워 5차 610호 (주)자이닉스
o      회사로 오시는 길 (네이버 지도) – http://link.rkttu.com/xinics-map 

002.png

Visual Studio 2013에서 ASP.NET 프로젝트가 만들어지지 않는 경우

Visual Studio 2013에서는 One ASP.NET이라는 새로운 형태의 프로젝트 생성 방식을 제공하고 있습니다. 이전에는 ASP.NET MVC, Web Form, Web Page, Web API가 각기 다른 프로젝트로 분리되어있어서 구성하기에 불편한 점이 많았습니다만 2013부터는 한 위치에서 동시에 여러 ASP.NET 웹 스택을 선택하고 조합할 수 있게 되었으며, 인증 시나리오도 Windows Identity Foundation, 기본 인증, 소셜 네트워크 기반 인증 등을 지원할 수 있는 옵션이 추가되었습니다.


그런데 이러한 특성 때문에, 처음부터 NuGet 패키지 관리자에 대한 의존성이 필수가 되었습니다. 그래서 간혹 어떤 컴퓨터에서는 Visual Studio 2013으로 ASP.NET 프로젝트를 생성하려 할 때 다음과 같은 오류 메시지가 나타나기도 합니다.


지정된 파일을 찾을 수 없습니다. (예외가 발생한 HRESULT: 0×80070002) 



오류: 이 템플릿에서 구성 요소 어셈블리 ‘NuGet.VisualStudio.Interop, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a’을(를) 로드하려고 했습니다. 이 문제에 대한 자세한 정보 및 이 템플릿을 활성화하는 방법에 대한 정보는 “프로젝트 템플릿 사용자 지정”의 설명서를 참조하십시오. 



위와 같은 오류 메시지가 나타나는 것은 NuGet Package Manager 애드인이 설치되어있지 않기 때문이며, ASP.NET 프로젝트 생성과 동시에 인터넷 상에서 NuGet Package Manager를 이용하여 프로젝트 구성에 필요한 각종 라이브러리들 (jQuery, ANTLRv3 등)을 내려받으려고 시도하기 때문입니다.


문제를 진단하기 위하여, Visual Studio에 현재 설치된 확장 및 업데이트 내역을 확인합니다. 메뉴에서 아래와 같이 실행하면 해당 항목을 찾을 수 있습니다.


도구(T) – 확장 및 업데이트(U) 클릭 



온라인 – Visual Studio 갤러리 선택 – 검색어에 nuget 입력 후 Enter 키 누름 – “NuGet Package Manager for Visual Studio” 선택 – 다운로드 버튼 클릭 



다운로드 진행 – EULA 동의 - 설치 – 아래와 같이 화면이 나타나면 하단의 “지금 다시 시작(R)” 버튼 클릭



이제 ASP.NET 프로젝트를 다시 생성하면 정상적으로 생성이 완료될 것입니다.

001.png

NUnit Runner를 대신하는 간편한 Self Runner 구현하기

NUnit의 GUI Runner는 여러 개의 테스트 유닛 프로젝트를 로드하여 동시에 테스트 결과를 시각적으로 확인할 수 있는 매우 유용한 유틸리티입니다. 그러나 한 가지 아쉬운 점이 있다면, Visual Studio와 완벽하게 통합되어있지는 않아서 단위 테스트 도중 변수의 상태를 확인하거나 디버깅을 하기에는 불편한 구조로 제작되어있다는 점입니다. 그래서 개인적으로 자주 애용하는 대안으로 Reflection을 사용하여 Test Fixture와 Test Case를 검색하여 자동으로 호출하는 유틸리티 클래스의 소스 코드를 https://github.com/rkttu/nunit-self-runner 에 게시하였습니다.


이 프로그램 코드는 NUnit Framework 어셈블리 외에 특별한 종속성이 없고 어떤 코드에서든 쉽게 붙여넣어 시작할 수 있습니다. 그러나 기능 상의 제약이 있는데 다음과 같은 유형의 Test Fixture나 Test Case에서는 작동하지 않습니다.



  • Test Fixture 생성 시 별도의 생성자 매개 변수가 필요한 경우

  • Test Method 실행 시 별도의 호출 매개 변수가 필요한 경우

  • private이나 protected, internal 멤버

이 소스 코드를 NUnit 클래스 라이브러리 프로젝트에 추가하고, 해당 NUnit 클래스 라이브러리를 컴파일하여 실행하면 다음과 같은 형태로 단위 테스트가 전개될 것입니다.



테스트에 실패하는 케이스, 즉 Exception이 발생하면 위와 같이 적색의 Test case failed 라는 문구가 나타나고 자세한 Stack Trace 결과가 노란색의 텍스트로 표시되어 시각적으로 구분을 쉽게 해줍니다. 그리고 실패했다는 사실을 알리기 위하여 테스트가 일시 중단되고, Enter 키를 누르면 계속 실행됩니다. 이 메시지를 확인하고 적절한 위치에 중단점을 설정하면 디버거가 해당 위치에서 중지되므로 좀 더 쉽게 문제를 진단할 수 있습니다.



반면 예외 없이 정상적으로 실행되는 테스트 케이스는 초록색의 Test case succeed 메시지를 표시하고 중단없이 계속 다음 테스트를 진행합니다. 그리고 한 Test Fixture의 실행이 완료되면 다시 사용자의 입력을 대기하는 상태로 들어가며, Enter 키를 누르면 다음 Test Fixture로 진행할 수 있으므로 인터랙티브하게 단위 테스트 결과를 확인할 수 있습니다. 



모든 테스트 Fixture의 실행이 끝난 이후에도 한 번 더 사용자의 입력을 기다립니다. 콘솔에 표시된 전체 내용을 리뷰하고 마지막으로 Enter 키를 누르면 프로그램이 완료됩니다.

003.png

Windows Forms용 Async/Await 프로그래밍 보조 라이브러리

Windows Forms는 오랜 시간이 지난 지금 매우 잘 정착하여 성공적으로 여러 시스템과 플랫폼에 걸쳐 사용되고있는 훌륭한 프레임워크입니다. 하지만 최신 프로그래밍 기법과는 잘 어울리지 못한다는 문제점이 있어서 점진적으로 사장되어가고 있다는 것은 개인적으로 참 안타깝게 생각하는 부분입니다.


여러가지 이슈들이 있을 수 있지만, Windows Forms 개발자들에게 있어 가장 근본적이면서도 가장 어려운 문제는 단일 UI 스레드 안에서 모든 코드를 처리하도록 만든 프레임워크의 특성 상 다중 스레드에서의 프로그래밍 기법이 친숙하지 않다는 것입니다. 코드를 잘못 풀어서 정리할 경우 매우 파악하기 어렵고 까다로운 코드가 되기 쉽습니다. 그리고 이러한 문제는 UI 스레드가 아닌 스레드 문맥에서 UI 요소를 제어하려고 할 때 가장 큰 문제가 됩니다.


모든 경우의 수를 다 고려할 수는 없습니다. 그렇지만 빈번하게 사용되는 속성과 메서드들에 대해서만이라도 비동기 프로그래밍이 쉬워진다면 확실한 이점이 있을 것입니다. 이번에 개인적으로 런칭한 라이브러리는 그런 부분에 있어 큰 도움을 줄 수 있을 것이라 기대합니다.


라이브러리 설치 방법


이 라이브러리는 .NET Framework 4.0 Client Profile 이상의 Desktop App을 대상으로 합니다. 따라서 최소한 Visual Studio 2010 이상의 IDE 또는 Visual C#/Basic Express IDE가 필요하며, async/await 프로그래밍을 사용하기 위해서는 Visual Studio 2012 이상의 IDE 또는 Visual Studio 2012 for Desktop Express가 필요합니다. 그리고 이 글을 작성하는 현 시점에서 가장 최신 버전은 Visual Studio 2013 또는 Visual Studio 2013 for Desktop Express입니다. Express 버전의 IDE는 http://www.microsoft.com/express 에서 무료로 다운로드할 수 있습니다.


적절한 버전의 IDE를 다운로드하여 Windows Forms 프로젝트를 열거나 새로 만든 다음, NuGet 패키지 관리자를 열어 온라인에서 검색 키워드로 wfasync를 입력하면 다음과 같이 검색 결과가 나타납니다. 검색 결과 상의 패키지를 설치합니다.


 



기능 시험해보기


이 라이브러리는 System.Windows.Forms를 기본 네임스페이스로 사용하고 있으므로, 자동으로 기존 Windows Forms 프로젝트 상의 주요 컨트롤에 관련된 확장 메서드들이 추가됩니다. Control 클래스를 기준으로 구현되는 거의 모든 속성, 메서드들에 대해서 다음의 사항들에 대한 Wrapper Method가 제공됩니다.



  • Control 클래스의 주요 인스턴스 메서드의 경우 Begin~, End~, ~Async Wrapper 메서드가 추가됩니다. 만약 메서드가 여러 버전의 오버로드를 가지고 있는 경우 정확한 구분을 위하여 Begin과 End 시리즈 메서드에는 접미사로 순번이 붙습니다. 이것은 설계에 따른 기본 설정입니다.

  • Control 클래스의 주요 속성 (인덱서 제외)의 경우 getter/setter 사용 가능 여부에 따라 GetXXX, SetXXX, BeginGetXXX, BeginSetXXX, EndGetXXX, EndSetXXX, GetXXXAsync, SetXXXAsync 확장 메서드가 자동으로 추가됩니다.

  • 해당 Form이나 Control을 Parent Window로 지정하는 MessageBox.Show 메서드에 대한 10가지 오버로드에 대한 확장 메서드가 제공됩니다.

위의 사항들 중 일부를 간단히 시험해볼 수 있는 예제는 다음과 같습니다.


아래 화면과 같이 간단한 Form을 하나 생성하고, 적당한 크기의 RichTextBox 컨트롤을 추가한 다음, 비동기 작업 분리를 위하여 BackgroundWorker 컴포넌트를 하나 추가합니다. 그리고 Form의 Load 이벤트와 BackgroundWorker 컴포넌트의 DoWork 이벤트를 다음과 같이 구현하고 연결합니다.



private void Form1_Load(object sender, EventArgs e)
{
    this.backgroundWorker1.RunWorkerAsync();
}


private async void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    using (System.Net.WebClient wc = new System.Net.WebClient())
    using (System.Threading.AutoResetEvent are = new System.Threading.AutoResetEvent(false))
    {
        wc.Encoding = Encoding.UTF8;
        await this.richTextBox1.SetTextAsync(“Performing downloads.”);
        string content = await wc.DownloadStringTaskAsync(
            new Uri(“http://support.xinics.com/support/index.php?document_srl=23783“));
        await this.ShowMessageBoxAsync(
            String.Format(“Downloaded {0} bytes.”, content.Length));
        await this.richTextBox1.SetTextAsync(“Waiting five seconds.”);
        are.WaitOne(5000);
        await this.richTextBox1.SetTextAsync(content);
    }
}


코드의 내용은 단순합니다. UI 스레드가 메시지 처리에만 집중할 수 있도록, 추가 스레드를 쉽게 관리할 수 있도록 해주는 BackgroundWorker 컴포넌트를 Form 시작 시 실행하도록 코드를 추가하였습니다. 그 후, DoWork 이벤트 처리기를 만났을 때 비로소 이 라이브러리의 진가가 발휘됩니다.


결과를 반환하는 메서드가 아니기 때문에, 다행히 async/await 프로그래밍 때문에 이벤트 처리기의 메서드 시그니처와 이벤트 선언 사이의 임피던스 불일치는 일어나지 않습니다. 간편하게 DoWork 이벤트 핸들러 메서드에 async 키워드를 붙여주기만 하면 async/await 프로그래밍 준비는 끝납니다.


그 다음에는 RichTextBox 컨트롤의 텍스트를 변경하도록 요청하고 있고, WebClient 클래스를 초기화하고 using 블록 안에서만 사용하도록 코드를 시작합니다. WebClient의 기본 송수신 인코딩을 UTF8로 정하고, 지정된 URL로부터 문자열을 다운로드하여 해당 인코딩 방식으로 데이터를 디코딩하여 문자열로 가져옵니다.


그리고 다운로드한 문자의 갯수를 보여주기 위하여 ShowMessageBoxAsync 메서드를 사용하였습니다. 이 메서드 안에는 많은 내용이 숨겨져 있는데, 일단은 현재 스레드가 UI 스레드가 아니라는 점을 인지하여 메시지 박스를 UI 스레드를 통해 호출하도록 하고 있으며, 따라서 메시지 박스를 닫기 전까지는 모달 상태이므로 UI는 작업이 중단됩니다. 여기에 한 가지 더, 메시지 박스를 닫을 때까지 이 비동기 스레드 역시 동결 상태가 됩니다. 이것이 이 라이브러리의 역할인데, UI 스레드와 무관하게 전개가 되어야 할 때에는 작업을 독립적으로 수행하다가도, 사용자의 입력이 필요할 때 이와 같이 현재 스레드의 상태를 동결하는 것이 가능하다는 것입니다.


그 다음으로 RichTextBox 컨트롤을 대상으로 UI 스레드가 아닌 위치에서 표시할 문자열 변경을 요청하고 있습니다. 당연히 이 작업도 UI 스레드에 의하여 온전히 처리되도록 관리되며, UI 스레드가 작업을 마무리하기 전까지 현재 스레드는 역시 동결됩니다.


위의 코드를 실행했을 때 처음 얼마간 다운로드 작업이 이루어지는 동안에도 창에 대한 이벤트나 응답이 정상적으로 처리됨을 확인할 수 있습니다. 그리고 메시지 박스를 확인하고 난 다음에 5초의 시간이 지나서 RichTextBox의 내용이 갱신될 때 까지 UI가 전혀 얼어붙지 않음을 쉽게 확인할 수 있습니다.


 



라이선스에 대하여


이 프로젝트의 라이선스는 Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0)을 따릅니다. 상업적 이용에 제한을 두지 않으며, 소스 코드 공개 의무를 지니지 않으므로 편리하게 이용할 수 있습니다. 소스 코드에 대한 검토 및 의견 제안은 github를 통해서 받고 있으니 언제든 자유롭게 의견 부탁드리겠습니다.


주요 프로젝트 URL



 

001.png

Windows Azure Linux Virtual Machine과 docker를 이용한 Linux 기반의 C# 개발 환경 구축

Windows Azure의 Virtual Machine 서비스는 Windows와 Linux를 Guest OS로 지원하는 전형적인 IaaS 플랫폼입니다. 그리고 Linux는 다양한 오픈 소스 소프트웨어와 결합할 수 있는 매우 이상적인 소프트웨어 개발 환경이기도 합니다.


Linux에서 사용할 수 있는 매력적인 소프트웨어들 중 최근 큰 주목을 받고 있는 프로젝트로 docker 프로젝트가 있는데, 이 프로젝트는 기본적으로 Hypervisor 없이 Linux 실행 환경을 가상화하고 서로 격리된 상태로 실행할 수 있도록 도와주는 Linux Container (LXC)를 조금 더 실용적이고 사용하기 편리하게 만들어주는 컴패니언 소프트웨어로, 이미지를 공유하거나, 이미지로부터 생성하는 컨테이너를 만들기 위해 필요한 명령을 자동으로 등록하거나, 컨테이너를 이미지로 변환하는 등의 작업을 단순화합니다.


docker 프로젝트를 설치하고 사용하는 방법에 대한 가이드는 인터넷 상에 이미 다양한 자료로 게시된 적이 있고, 최근에 열린 NAVER 개발자 행사인 DeVIEW 2013에서도 다루어진 적이 있습니다. (http://www.slideshare.net/modestjude/docker-in-deview-2013)


오늘 살펴보려는 내용은 docker 프로젝트를 Windows Azure Virtual Machine 상에서 설치하고 이용하는 방법과 함께, docker Index에 게시되어있는 최신 버전의 Mono 이미지를 다운로드하고 활용하는 방법을 간단히 살펴보려고 합니다. 지금 소개하는 방법을 통해서 쉽고 빠르게 리눅스 기반의 다중 개발 환경을 손쉽고 빠르게 프로토타이핑할 수 있습니다.


시작하기 전에 – Hypervisor 안에서 또다른 가상 환경을 만드는 것은 불가능하지 않습니까?


docker를 일반적인 PC나 서버 환경이 아닌 곳에서 사용할 때 가장 먼저 드는 의문점이 바로 이것입니다. 기본적으로 Hypervisor 위에서 실행하는 OS는 또 다시 가상 환경을 만들어낼 능력이나 여건이 되지 못합니다. 가능하도록 설정했다고 해도 결국 물리적인 한계에 부딪힐 가능성이 커집니다.


사실, docker는 Hypervisor가 아니기 때문에 Hypervisor 고유의 CPU 기능을 활용하는 일은 거의 없고, 호스트가 되는 리눅스의 커널의 재량에 따라 그 안에서 실행되는 독립적인 프로세스일 뿐입니다. 그러나, 제아무리 docker가 유용하다고 해도, 시스템이나 VM에 할당된 자원의 밀도나 품질을 생각해보았을 때 docker가 실제 처리할 수 있는 작업의 양이 항상 효율적이라고는 할 수 없습니다. 따라서, docker를 사용한 시스템 구축은 전적으로 충분한 시나리오 테스트와 QA를 거쳐야만 함을 염두에 두어야 할 것입니다.


docker로 할 수 있는 일


docker는 단순히 프로세스만을 격리하는 것이 아니라 일정 수준의 가상 환경을 다룹니다. 즉, 자체적으로 이용할 수 있는 파일 시스템, 네트워크 어댑터, 가용 메모리 크기 등이 있고, 상황에 따라 이들 자원의 크기가 동적으로 변화하게 됩니다. 그러나 우리가 일반적으로 사용하는 완전한 Hypervisor와는 다르게 자원을 명시적으로 제한할 수 있는 방법이 2013년 10월 현재 기준으로 특별히 없습니다. 그리고 네트워크는 사설 IP로만 할당되기 때문에, docker가 자체적으로 구성하는 NAT를 이용하여 외부로부터 들어오는 네트워크 요청을 특정 컨테이너 앞으로 도착하도록 연결해주는 것이 꼭 필요합니다.


그럼에도 불구하고, docker는 리눅스 기반의 환경에서 항상 있을 수 있는 파일 시스템, 커널, 잘못된 라이브러리나 패키지 설치로 인한 시스템의 중단으로부터 안전하게 지켜줄 수 있고, 신뢰할 수 있을만한 수준을 제공하면서도, 가볍게 다룰 수 있는 가상 환경을 제공한다는 점에서 큰 주목을 받고 있으며, 심지어 Hypervisor 기반의 실행 환경 위에서 전혀 다른 Linux Guest를 추가 실행할 수 있을만큼 유연합니다.


docker Index (https://index.docker.io/)에 게시된 이미지들을 살펴보면 알겠지만 호스트의 Linux OS와 아무 관련이 없는 busybox 같은 응급 이미지도 존재하고, Ubuntu가 호스트인 시스템에서 CentOS를 컨테이너 OS로도 택하는 것이 가능합니다. 즉, docker 환경에 맞추어 개발된 OS이기만하면 docker와의 상호작용을 전제로 호스트 OS와 완전히 분리된 환경에서 실행이 가능하므로 독립적인 환경 구성이 가능함을 뜻합니다.


docker를 Azure Linux VM 위에 설치하기


docker는 LXC 프로젝트를 기반으로 하기 때문에, 커널 버전에 대한 의존성이 크고, 사용할 수 있는 Host OS의 종류에도 제한이 있습니다. 현 시점에서는 Ubuntu Linux 13.04에서의 실행이 가장 안정적이기 때문에, Windows Azure Virtual Machine 갤러리에서 다음 그림과 같이 Ubuntu Linux 13.04 기반의 VM을 하나 추가해서 시작하셔야 합니다. 만약 Ubuntu Linux 12.04나 12.10 버전을 실행 중인 경우 Secure Shell 터미널 환경을 통하여 원격으로 13.04로 업그레이드하는 명령을 실행할 수도 있지만, libcurse 기반의 UI 실행이 일부 필요하기 때문에 putty 등에서는 정상적으로 보이지 않을 수 있고, 또한 잘못 선택할 경우 VM에 원격 접속이 불가능한 상황이 올 수 있으므로 추천하지 않습니다.


http://manage.windowsazure.com/ 으로 접속하여 새 VM을 갤러리로부터 생성하도록 시작합니다. 아래와 같은 대화 상자가 나타나는지 확인한 후 Ubuntu Linux 13.04를 선택합니다.


 



다음 버튼을 클릭한 다음 기본 VM 설정을 입력합니다.


 



PuttyGen을 이용하여 키 체인을 만들어 업로드하거나, 사용자 암호를 지정하고 다음 버튼을 클릭합니다.


 



클라우드 서비스는 네트워크 연결 및 중재를 위한 기본 단위이자 실행 환경을 정의하는 단위 환경입니다. docker 환경과 연결하려는 클라우드 서비스나 다른 VM이 있을 경우 같이 소속되도록 설정해주시고, 가용성 설정 등을 확인한 다음 다음 버튼을 클릭합니다.


 



기본적으로 SSH 포트가 열려있습니다. 그러나 docker container와의 연결을 허용하고 외부에서 접속을 받아들이려면 Windows Azure의 방화벽 설정도 수정해야 합니다. 외부에서 docker container 서비스로의 접속이 안된다면 이쪽의 방화벽 설정을 꼭 확인하셔야 합니다. 마침 버튼을 클릭하여 VM 생성을 시작합니다.


 



VM의 외부 DNS 주소를 확인하고, putty로 접속을 시작합니다.


 



접속이 완료되었다면 이제부터 명령어 입력을 진행합니다. 설치 가이드의 내용은 http://docs.docker.io/en/latest/installation/ubuntulinux/#ubuntu-raring-13-04-64-bit 에서 발췌하였습니다.


우선 최신 패키지 목록을 가져오기 위하여 다음 명령을 수행합니다. 최신 릴리즈를 사용하여 VM을 만들었다면 별 다른 업데이트는 발생하지 않을 것입니다.


sudo apt-get update


그리고 Ubuntu 13.04 시스템들 중 일부 릴리즈에서 누락되어있을 수 있는 AUFS 파일 시스템에 대한 지원 (LXC 실행을 위해 꼭 필요합니다.)을 추가하기 위하여 아래 명령어를 수행합니다. 참고로 Azure Virtual Machine을 통하여 최신 릴리즈를 사용하도록 VM을 생성했다면 역시 AUFS에 대한 지원이 이미 포함되어있어서 아래 명령어로 시스템에 변화가 발생하지는 않을 것입니다.


sudo apt-get install linux-image-extra-`uname -r`


이제 docker 리포지터리에 접근하여 패키지를 설치할 차례입니다. 우선 키 체인을 다운로드하여 시스템에 등록하여 docker 패키지를 인터넷으로부터 다운로드할 수 있도록 허가합니다.


sudo sh -c “wget -qO- https://get.docker.io/gpg | apt-key add -”


OK라는 메시지를 확인하였으면 이어서 리포지터리 목록에 docker 리포지터리를 추가하기 위하여 다음 명령어를 실행합니다.


sudo sh -c “echo deb http://get.docker.io/ubuntu docker main > /etc/apt/sources.list.d/docker.list”


이제 패키지 업데이트를 다시 수행하여 사용 가능한 패키지 목록을 갱신합니다.


sudo apt-get update


출력 중에서 다음과 비슷한 메시지가 들어있는지 확인합니다.


Get:3 http://get.docker.io docker/main amd64 Packages [1,395 B]


이제 패키지 목록을 업데이트하였으므로 lxc-docker 패키지가 사용 가능한 상태가 되었을 것입니다. lxc-docker 패키지를 아래 명령으로 설치합니다.


sudo apt-get install lxc-docker


종속 패키지들을 다수 설치해야 함을 알리는 메시지가 나타나면 y 키를 눌러 진행합니다.


설치가 잘 되었는지 확인해보기 위하여 docker Index 사이트로부터 ubuntu 게스트 OS 이미지를 다운로드해보겠습니다. 아래 명령어를 실행합니다.


sudo docker run -i -t ubuntu /bin/bash


아래와 같이 다운로드 메시지가 나타나고 콘솔이 바뀌는 것을 확인하기 바랍니다.


rkttu@dockertest:~$ sudo docker run -i -t ubuntu /bin/bash
Unable to find image ‘ubuntu’ (tag: latest) locally
Pulling repository ubuntu
8dbd9e392a96: Download complete
b750fe79269d: Download complete
27cf78414709: Download complete
root@f45ee37cf476:/#


호스트 이름이 Azure VM의 dockertest가 아니라 임의로 작명한 f45ee37cf476이라는 이름으로 바뀐 것을 볼 수 있습니다. 그리고 IP 주소 대역도 다르다는 것을 쉽게 파악할 수 있는데, ifconfig을 비롯한 네트워킹 도구가 이 버전의 이미지에는 들어있지 않기 때문에 다음 명령어를 실행하여 net-tools 패키지를 설치합니다.


apt-get install net-tools


격리 환경 상에서 자동으로 root 권한을 얻었으므로 sudo를 덧붙일 필요가 없습니다. 설치가 끝난 다음, ifconfig eth0 명령을 실행하면 다음과 같이 나타납니다.


eth0      Link encap:Ethernet  HWaddr fa:b2:4f:b9:15:84
          inet addr:172.17.0.2  Bcast:172.17.255.255  Mask:255.255.0.0
          inet6 addr: fe80::f8b2:4fff:feb9:1584/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:192 errors:0 dropped:0 overruns:0 frame:0
          TX packets:81 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:267507 (267.5 KB)  TX bytes:5591 (5.5 KB)


굵게 강조 표시한대로 사설 IPv4 주소가 할당되어있습니다. 그리고 패키지 업데이트와 업그레이드를 진행하여 인터넷 연결 상태를 다시 한 번 확인해봅니다.


apt-get update
apt-get upgrade


가상 환경에서 나가기 위하여 exit 명령을 입력하면 다음과 같이 원래의 Host OS로 프롬프트가 바뀌는 것을 볼 수 있습니다.


root@f45ee37cf476:/# exit
exit
rkttu@dockertest:~$


이제 방화벽 설정을 확인합니다. 기본적으로 Ubuntu는 ufw라는 방화벽 프로그램을 이용합니다. 그리고 Windows Azure 기본 구성 이미지에서는 ufw가 비활성화되어있고, Windows Azure의 방화벽이 외부로부터의 연결을 차단하며, Windows Azure 간 네트워크에는 제한이 없습니다. 아래 명령어를 입력하여 방화벽 상태를 확인합니다.


rkttu@dockertest:~$ sudo ufw status
Status: inactive
rkttu@dockertest:~$


그리고 방금 전 테스트를 위하여 받은 이미지와 그 이미지를 기반으로 실행한 컨테이너가 잘 등록되었는지 확인하여 설치 프로세스를 마무리합니다.


rkttu@dockertest:~$ sudo docker images -a
REPOSITORY          TAG                 ID                  CREATED             SIZE
ubuntu              12.04               8dbd9e392a96        6 months ago        131.5 MB (virtual 131.5 MB)
ubuntu              latest              8dbd9e392a96        6 months ago        131.5 MB (virtual 131.5 MB)
ubuntu              precise             8dbd9e392a96        6 months ago        131.5 MB (virtual 131.5 MB)
ubuntu              12.10               b750fe79269d        7 months ago        24.65 kB (virtual 180.1 MB)
ubuntu              quantal             b750fe79269d        7 months ago        24.65 kB (virtual 180.1 MB)
<none>              <none>              27cf78414709        7 months ago        180.1 MB (virtual 180.1 MB)


rkttu@dockertest:~$ sudo docker ps -a
ID                  IMAGE               COMMAND             CREATED             STATUS              PORTS
f45ee37cf476        ubuntu:12.04        /bin/bash           8 minutes ago       Exit 0


예상한 대로 이미지가 다운로드되어있고, 해당 이미지를 기반으로 /bin/bash 앱에 대한 컨테이너가 생성 후 실행되었으며 종료 코드 0으로 종료되었다는 결과 표가 보입니다.


mono 개발 환경 빠르게 구축하기


mono 개발 환경을 입맛에 맞게 구축하는 방법은 여러가지가 있습니다. 방금 전처럼 base image를 받아서 수작업으로 설치하거나, 그 과정을 서술하는 Dockerfile을 만들어 한 번에 일괄 실행하여 시스템의 설치를 전개하는 방식도 있을 수 있습니다. 그렇지만 docker를 개발 환경으로 이용하기 위해서 취할 수 있는 가장 좋은 방법은 docker Index 사이트에 게시된 최신 이미지를 확인하여 해당 이미지를 직접 로컬 시스템으로 Pull 하는 것입니다.


편의를 위하여 잠시 리눅스 콘솔에서 윈도 화면으로 되돌아온 다음 https://index.docker.io/ 로 접속하여 키워드로 mono를 지정하고 검색합니다.




 

 

Ubuntu 이미지를 이용하여 Mono 3.2.3을 설치하여 배포하는 이미지가 Docker Index에 올라와있습니다. 그 외에도, 닷넷 기반의 SOA 실행 및 개발 환경 구축을 편리하게 할 수 있도록 Service Stack과 연계한 리눅스 이미지도 보입니다. 우리가 사용하려는 것은 rwentzel/ubuntu-mono 이미지이므로 이 이미지의 이름을 기록합니다.


이제 다시 리눅스 콘솔로 되돌아가서 해당 이미지를 로컬 리포지터리로 다운로드하겠습니다. 다음 명령어를 실행하여 동기화를 시작합니다. 해당 이미지는 여러 차례 수정을 거쳐 만들어진 것이기 때문에 다운로드에 다소 시간이 걸리니 조금 오래 기다리셔야 합니다.


sudo docker pull rwentzel/ubuntu-mono


이미지 다운로드가 완료되었다면, 이제 이 이미지를 이용하여 컨테이너를 만들고 정말 안에 mono 개발 환경이 들어있는지 확인해볼 차례입니다. 아래 명령어로 이미지를 우선 확인합니다.


sudo docker images -a


설치한 이미지의 갯수가 매우 많아졌습니다. 그런데 주의할 것이 하나 있습니다. docker rmi 명령으로 이미지를 제거하는 것이 가능하지만, 꼭 필요한 경우가 아니라면 가급적 리포지터리나 TAG가 none으로 설정된 이미지를 임의로 삭제하는 일은 피해야 합니다. 콘솔에서는 잘 드러나지 않지만 이미지는 차이점 보관 방식으로 생성되어있고 일종의 트리 계층을 형성하기 때문입니다. 그래서 docker로 이미지를 만들 때 정말 중요하게 관리되어야 하는 이미지는 REPOSITORY나 TAG에 정확한 속성을 지정하여 쉽게 찾을 수 있도록 해주는 것이 중요합니다.


REPOSITORY             TAG                 ID                  CREATED             SIZE
rwentzel/ubuntu-mono   latest              2e8ec476cfd1        3 weeks ago         12.29 kB (virtual 2.627 GB)
<none>                 <none>              866ee2ba174c        3 weeks ago         12.29 kB (virtual 2.627 GB)
<none>                 <none>              9d58fdd1f145        3 weeks ago         28.67 kB (virtual 2.627 GB)
<none>                 <none>              48d313d93277        3 weeks ago         194.1 kB (virtual 2.627 GB)
<none>                 <none>              a6f3f7d033e8        3 weeks ago         1.151 GB (virtual 2.627 GB)
<none>                 <none>              0063533722a2        3 weeks ago         486.2 MB (virtual 1.476 GB)
<none>                 <none>              563cc9ce1df7        3 weeks ago         43.2 MB (virtual 989.9 MB)
<none>                 <none>              d963202bdca8        3 weeks ago         62.24 MB (virtual 946.7 MB)
<none>                 <none>              fa1d9d247e8a        3 weeks ago         27.46 MB (virtual 884.5 MB)
<none>                 <none>              e01eae29dae1        3 weeks ago         32.86 kB (virtual 857 MB)
<none>                 <none>              eb5606044c61        3 weeks ago         70.23 MB (virtual 857 MB)
<none>                 <none>              519b96c9a701        3 weeks ago         29.08 MB (virtual 786.8 MB)
<none>                 <none>              552c68e56d9a        3 weeks ago         46.38 MB (virtual 757.7 MB)
<none>                 <none>              17f3c8064eb6        3 weeks ago         25.59 MB (virtual 711.3 MB)
<none>                 <none>              0cb9cc3fc7b8        3 weeks ago         144.5 MB (virtual 685.7 MB)
<none>                 <none>              898780b65670        3 weeks ago         12.29 kB (virtual 541.2 MB)
<none>                 <none>              de6790a79ec8        3 weeks ago         158.2 MB (virtual 541.2 MB)
<none>                 <none>              29002fa46318        3 weeks ago         24.58 MB (virtual 383 MB)
<none>                 <none>              270acf4d2474        3 weeks ago         96.52 MB (virtual 358.5 MB)
<none>                 <none>              1d4aaea09576        3 weeks ago         81.83 MB (virtual 261.9 MB)
ubuntu                 12.04               8dbd9e392a96        6 months ago        131.5 MB (virtual 131.5 MB)
ubuntu                 latest              8dbd9e392a96        6 months ago        131.5 MB (virtual 131.5 MB)
ubuntu                 precise             8dbd9e392a96        6 months ago        131.5 MB (virtual 131.5 MB)
ubuntu                 12.10               b750fe79269d        7 months ago        24.65 kB (virtual 180.1 MB)
ubuntu                 quantal             b750fe79269d        7 months ago        24.65 kB (virtual 180.1 MB)
<none>                 <none>              27cf78414709        7 months ago        180.1 MB (virtual 180.1 MB)


위의 rwentzel/ubuntu-mono 이미지를 사용하여 내부에 들어있는 /bin/bash를 컨테이너로 실행하기 위하여 아래 명령을 실행합니다.


sudo docker run -i -t rwentzel/ubuntu-mono /bin/bash


그러면 다음과 같이 프롬프트가 변경되는 것을 볼 수 있습니다.


rkttu@dockertest:~$ sudo docker run -i -t rwentzel/ubuntu-mono /bin/bash
root@f739c613d0ae:/#


이제 간단한 C# 소스 코드를 작성하여 프로그램으로 컴파일하고 잘 작동하는지 확인해보겠습니다. vi를 사용해도 좋고, vi 사용에 익숙하지 않은 경우 아래와 같이 명령을 실행하여 pico/nano 에디터를 추가 설치할 수 도 있습니다.


apt-get install nano


Hello.cs 라는 소스 코드를 원하는 에디터로 아래와 같이 작성합니다.


using System;
using System.Linq;
using System.Collections.Generic;


public static class Program {
        [STAThread]
        public static void Main(string[] args) {
                var count = args.Count();
                List<string> options = args.Where(x => x.StartsWith(“-”)).ToList();
                Console.Out.WriteLine(“Hello, World!”);
                Console.Out.WriteLine(“Total Args: {0}, Option Args: {1}”, count, options.Count);
        }
}


Mono 3.2.3은 LINQ와 제네릭을 모두 잘 지원하므로 위의 코드를 아래와 같이 컴파일하였을 때 문제없이 컴파일이 완료될 것입니다.


mcs Hello.cs


그리고 JVM과 마찬가지로 Mono VM을 실행하여 컴파일한 어셈블리 파일을 실행해봅니다.


root@f739c613d0ae:/# mono Hello.exe
Hello, World!
Total Args: 0, Option Args: 0
root@f739c613d0ae:/# mono Hello.exe a b c
Hello, World!
Total Args: 3, Option Args: 0
root@f739c613d0ae:/# mono Hello.exe a b -c
Hello, World!
Total Args: 3, Option Args: 1


의도한 대로 LINQ와 제네릭을 잘 받아서 처리하고 있습니다.


mono 실행 속도 개선하기


최신 버전의 mono는 실행 속도를 개선하기 위하여 가비지 컬렉터를 새롭게 디자인하였고, 전처리 컴파일을 미리 수행하는 방법을 제공합니다. 특히, Microsoft .NET Framework와 마찬가지로 GAC에 대해 ngen을 수행하는 것과 비슷하게 AOT 컴파일을 미리 수행하도록 명령어를 한 번 실행해주면 실행 속도 개선에 큰 도움이 됩니다. 아래 명령어를 실행하여 GAC 내부의 모든 어셈블리에 대해 AOT 컴파일을 실행합니다.


for i in /usr/local/lib/mono/*/mscorlib.dll; do mono –aot $i; done
for i in /usr/local/lib/mono/gac/*/*/*.dll; do mono –aot $i; done


위의 이미지 환경 내에서의 mono 설치 경로는 /usr/local에 있으므로 경로는 mono 실행 파일의 위치를 which 명령으로 확인하여 적절하게 변경해야 합니다. 참고로 GAC에 대한 AOT 컴파일은 시간이 오래 걸릴 수 있으며, 이 버전의 가상 환경에서는 .NET Framework 1.0이나 1.1 기준으로는 개발이 불가능하므로 버전을 업그레이드 하거나 base image로부터 구 버전의 mono를 설치하도록 수동 구성해야 합니다.


그리고 개별 어셈블리에 대한 AOT 컴파일은 다음과 같이 실행할 수 있으며, 실행 결과로 .so 파일이 생성되므로 AOT 컴파일의 효과를 위하여 항상 같은 위치에 배포될 수 있도록 배포합니다.


mono –aot Hello.exe
mono Hello.exe


마무리


지금까지 Windows Azure Linux VM에서 docker를 이용한 mono 개발 환경의 구축 방법을 살펴보았습니다. 언제든 원하는 때에 즉시 Linux VM을 만들 수 있다는 것 말고도, 한 번 만든 VM을 손상시키지 않으면서 환경을 독립적으로 구성할 수 있도록 하는 환경 상의 완결성을 제공하는 docker를 이용함으로서 최상의 리눅스 개발 환경을 체험할 수 있게 된 것은 참 좋은 일입니다.


그리고 한 가지 더 덧붙이면, docker를 이용하여 컨테이너를 만들 때 -v 스위치를 사용하여 호스트 파일 시스템과 링크를 연결할 수 있으므로, 컨테이너 셸 상에서 만든 파일을 쉽게 호스트로 반출하거나 반입할 수 있습니다. -p 스위치는 가상 NAT를 통하여 포트 리디렉션을 할 수 있는 방법을 제공하며, 양쪽 스위치의 자세한 사용법은 http://blog.docker.io/2013/07/docker-0-5-0-external-volumes-advanced-networking-self-hosted-registry/ 의 내용을 확인하기 바랍니다.