Windows 환경의 C++ 프로젝트의 컨테이너 이미지 관리
혹자는 Linux 환경에서 C++ 빌드도 되는데, 그냥 리눅스로 도커 이미지 빌드하면 안되냐고 할 것이다.
하지만 제목에서 말해주듯 IOCP 게임서버에 관한 내용으로, IO Completion Port는 윈도우 OS의 커널 오브젝트이다.
Overlapped IO를 통해 OS에 종속될 수 밖에 없는 Proactor 비동기 기술의 비애라고 볼 수 있겠다.
어쩔 수 없이 Windows 플랫폼을 고집해야하는 상황이고, k8s 환경에서 다른 마이크로서비스들과 함께 관리하기 위해서라도 컨테이너화 빌드도 필요한 상황이다.
핵심 : Visual Studio 빌드 시스템 사용 (.vcsproj 프로젝트 파일)
FROM mcr.microsoft.com/windows/servercore:ltsc2022
# Visual Studio Build Tools
RUN powershell -Command "Invoke-WebRequest -Uri 'https://aka.ms/vs/16/release/vs_BuildTools.exe' -OutFile 'C:\vs_BuildTools.exe'; Start-Process -FilePath 'C:\vs_BuildTools.exe' -ArgumentList '--quiet', '--wait', '--add', 'Microsoft.VisualStudio.Workload.VCTools' -NoNewWindow -Wait; Remove-Item -Force 'C:\vs_BuildTools.exe'"
COPY ./ /app
WORKDIR /app
RUN "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin\MSBuild.exe" <ProjectName>.vcxproj /p:Configuration=Release /p:Platform=x64
CMD ["Release/<ProjectName>.exe"]
해당 Dockerfile을 간단하게 요약하면 다음과 같다.
1. Windows OS 선택 (Windows Server 2022)
Windows 컨테이너에서 최소한의 OS 환경 제공
2. Visual Studio Build Tools 설치
백그라운드에서 C++ 컴파일러와 빌드 도구를 설치하고, 불필요한 Installer 파일을 삭제
3. 프로젝트 파일 복사
현재 디렉토리(./)의 모든 파일을 컨테이너 내부 /app 디렉토리로 복사, 이후 작업 디렉토리를 /app으로 설정
4. MSBuild를 이용해서 프로젝트 빌드
MSBuild.exe를 사용하여 프로젝트(.vcxproj) 빌드
최적화를 적용하여 x64 Release 빌드 (Configuration=Release, Platform=x64)
참고로 MSBuild.exe 실행시 경로에 있는 vcsproj 파일의 경로는 프로젝트 구조에 따라 변경해야한다.
Windows 컨테이너의 호환성 문제
ERROR: failed to solve: mcr.microsoft.com/windows/servercore:ltsc2022: no match for platform in manifest
도커를 리눅스 컨테이너 모드로 실행중이라서 Windows 이미지를 찾을 수 없는 상태
윈도우 컨테이너 모드로 실행하면 되는 쉬운 문제이다.
Windows 10/11 Home 에디션은 Windows 컨테이너를 지원하지 않습...네?
Windows Home에서는 Hyper-V가 완전히 지원되지 않아서 Windows 컨테이너를 구동할 수 없다.
Windows 컨테이너를 실행하려면 Pro / Enterprise / Education 버전이 필요하다는 말인데, 난 당연히 가정용 노트북이라 팔다리가 잘린 기분이다.
가장 먼저 생각난 해결책은 Windows Server OS의 클라우드 컴퓨터에 원격 접속해서 도커 빌드하는 방법이었다.
근데.. 배포 한두번 할거도 아니고.. 자동화 없이 날 것그대로의 빌드 과정을 매번.... 난 못한다.
머리를 써보자
Github Actions을 이용한 Windows 이미지 빌드 (feat. AWS ECR)
CI/CD 파이프라인을 구축할때 나는 주로 Github Actions을 통해서 통합된 프로젝트를 도커 이미지로 빌드, AWS ECR로 Push하는 구조를 즐겨 사용했다.
workflows 파일을 실행하는 runs-on 환경을 Windows로 지정하면 도커 이미지 빌드시 Windows 컨테이너 모드로 전환되지 않을까?
빌드 환경 오류가 몇번 뜨기도 하고, 리눅스 기반과 명령어나 줄바꿈 명령같은 체계가 조금씩 달라서 삽질이 조금 필요했다.
Windows 도커라이징은 모르면 시간박으면서 당할 수 밖에 없는거같다.
Docekrfile에서 외부 라이브러리에 대한 의존성 추가
외부 의존성(헤더 파일)과 Windows SDK 누락
error C1083: Cannot open include file: 'winsock2.h': No such file or directory
error C1083: Cannot open include file: 'mysql.h': No such file or directory
Github Actions 상에서 도커 이미지로 빌드하는 과정에서 MSBuild의 결과를 컴파일할때 나는 오류이다.
외부 라이브러리 설정을 가져오지 않아서 생긴 문제인데 직접 추가해보겠다.
외부 라이브러리에 대한 의존성
사용한 외부 라이브러리들의 경로를 옮기는게 번거로울 예정
- mysql :
- C:\Program Files\MySQL\MySQL Server 8.0\include;
- C:\Program Files\MySQL\MySQL Server 8.0\lib;
- rdkafka :
- C:\Users\User\Downloads\modern-cpp-kafka-main\modern-cpp-kafka-main\include;
- C:\Users\User\Downloads\librdkafka.redist.2.3.0\build\native\include\librdkafka;
- C:\Users\User\Downloads\librdkafka.redist.2.3.0\build\native\lib\win\x64\win-x64-Release\v142;
개발 환경에서의 vcxproj 프로젝트 (Debug 모드)
<AdditionalIncludeDirectories>
C:\Users\Downloads\modern-cpp-kafka-main\modern-cpp-kafka-main\include;
C:\Users\Downloads\boost_1_84_0\boost_1_84_0;
C:\Users\Downloads\librdkafka.redist.2.3.0\build\native\include\librdkafka;
C:\Program Files\MySQL\MySQL Server 8.0\include;%(AdditionalIncludeDirectories);
$(SolutionDir)\wargame\libs</AdditionalIncludeDirectories>
이런 식으로 여러 외부 라이브러리를 사용하고 있었다.
배포 환경에서는 다음과 같이 로컬 경로에 라이브러리를 포함하고 있어서 환경변수를 주입해줘야한다.
ENV INCLUDE="C:\\app\\libs\\MYSQL_Server_8.0\\include;
ENV LIB="C:\\app\\libs\\MYSQL_Server_8.0\\lib"
RUN powershell -Command "Write-Host $Env:INCLUDE"
RUN powershell -Command "Write-Host $Env:LIB"
RUN cmd /C ""C:\Program ...\MSBuild.exe" C:\app\<ProjectName>.vcxproj /p:Configuration=Release /p:Platform=x64 /p:AdditionalIncludeDirectories="%INCLUDE%" /p:AdditionalLibraryDirectories="%LIB%" /p:AdditionalDependencies=libmysql.lib"
Write-Host를 통해서 환경변수로 주입한 경로가 잘 있는지나 해당 경로에 파일들이 잘 복사되었는지 확인하는 절차가 중요하다.
MSBuild 커맨드 가장 뒤에 %INCLUDE%와 %LIB%을 통해서 AdditionalLibraries나 라이브러리에 대한 디렉토리도 물론 설정해야한다.
MSB1009: Project file does not exist.
MSBuild는 기본적으로 공백을 인식안하는데 파일 경로를 지정할때 너무 삽질이 많아서 화난다.
심지어 한번 빌드하는데 거진 20분가까이 드는데 이 경로 인식때문에 10시간동안 30번은 한거같다.
개선전 :
RUN cmd /C ""C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin\MSBuild.exe" \"C:\\app\\<ProjectName>.vcxproj\" /p:Configuration=Release /p:Platform=x64"
개선후 ;
RUN cmd /C ""C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin\MSBuild.exe" C:\app\<ProjectName>.vcxproj /p:Configuration=Release /p:Platform=x64"
MSB8020: The build tools for v143 (Platform Toolset = 'v143') cannot be found
Github Actions 상에서 다음과 같은 오류가 났다.
error MSB8020: The build tools for v143 (Platform Toolset = 'v143') cannot be found. To build using the v143 build tools, please install v143 build tools. Alternatively, you may upgrade to the current Visual Studio tools by selecting the Project menu or right-click the solution, and then selecting "Retarget solution". [C:\app\<projectName>.vcxproj]
Done Building Project "C:\app\<projectName>.vcxproj" (default targets) -- FAILED.
Build FAILED.
0 Warning(s)
1 Error(s)
Time Elapsed 00:00:01.12
The command 'cmd ...' returned a non-zero code: 1
vcxproj에서 Platform Toolset='v143'을 요구하는 경우 설치를 해줘야한다.
Dockerfile에서 VS BuilTools를 설치할때 v143 빌드 도구를 함께 넣어서 해결했다.
RUN powershell -Command "Invoke-WebRequest -Uri 'https://aka.ms/vs/16/release/vs_BuildTools.exe' -OutFile 'C:\\vs_BuildTools.exe'; Start-Process -FilePath 'C:\\vs_BuildTools.exe' -ArgumentList '--quiet', '--wait', '--add', 'Microsoft.VisualStudio.Workload.VCTools', '--add', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64' -NoNewWindow -Wait; Remove-Item -Force 'C:\\vs_BuildTools.exe'"
주의사항) 윈도우 환경의 shell에서는 줄바꿈에 민감해서 그냥 맘편하게 한줄로 쫙 내리쓰는게 오류도 안난다.
Windows Container In Kubernetes
빌드하고자 하는 게임 서버는 MSA 환경에서 동작하는 마이크로 서비스 단위로 배포할 계획이다.
백엔드를 공부하면서 리눅스 환경 배포에 더 익숙하지만 사실 Docker같은 컨테이너 기술은 윈도우도 지원하니 말이다!
당연히 쿠버네티스에서는 윈도우 컨테이너도 함께 지원하고 있으며, 윈도우 기반과 리눅스 기반의 애플리케이션을 모두 사용하는 조직에 대해 별도의 오케스트레이터가 필요없다.
한마디로, OS에 관계없이 배포 전반에 걸쳐 Kubernetes로 해결되는 셈이다.
k8s의 Windows Node 지원
Kuberentes에서 Pod 내의 윈도우 컨테이너를 스케줄링하는 것은 리눅스 기반과 유사하다.
k8s의 Controll Plane은 리눅스에서만 실행할 수 있지만, Worker Node들은 윈도우도 지원한다.(Windows Server 2019)
참고로 Hyper-V 격리 기반의 컨테이너는 지원하지 않고, 프로세스 격리 기반의 컨테이너만 해당.
윈도우 OS 버전 호환성
윈도우 컨테이너에서는 일부 노드 기능을 이용할 수 없다.
내가 프로젝트에 적용하기에는 크게 무리는 없다고 생각하지만 자세한 내용은 아래에서 확인할 수 있다.
쿠버네티스에서의 윈도우 컨테이너
윈도우 애플리케이션은 많은 조직에서 실행되는 서비스 및 애플리케이션의 상당 부분을 구성한다. 윈도우 컨테이너는 프로세스와 패키지 종속성을 캡슐화하는 현대적인 방법을 제공하여, 데브
kubernetes.io
Kubernetes(EKS 환경)에서 Windows 노드 그룹을 생성하면 혼용 가능
- nodeSelector를 사용하여 Windows 노드에서만 이 Pod가 실행되도록 지정
출처 및 인용.
'windows' 카테고리의 다른 글
토이프로젝트 - IOCP 서버와 유니티 클라이언트 구현(winsock2, cpp) (0) | 2024.11.22 |
---|---|
IOCP(IO Completion Port) 쉽게 이해하기 (0) | 2024.11.22 |
토이프로젝트 - winsock으로 구현한 프록시 서버(winsock2, cpp) (0) | 2024.11.22 |
IOCP GetQueuedCompletionStatus, CreateloCompletionPort 함수의 변경점 (0) | 2024.11.22 |
게임서버 매치메이킹 구현과 기술 세미나 발표 (0) | 2024.11.22 |