폐쇄망에 배포하는 당신, 이 글 한 번은 보면 좋을지도
요즘 누가 USB로 배포해요? ???: 안녕하세요? 제가 바로 그 ‘누’입니다.
요즘 누가 USB로 배포해요? ???: 안녕하세요? 제가 바로 그 ‘누’입니다.
웹 어플리케이션을 운영하는 데 있어 컨테이너 배포와 CI/CD 자동화가 기본인 요즘이다. 코드가 main에 머지되는 순간, 꽤 짧은 시간에 동작하는 복잡한 배포 워크플로우는 이젠 당연한 것처럼 느껴진다.
하지만 인터넷이 연결되지 않은 곳, 즉 ‘폐쇄망’에 배포할 땐 이런 것이 가능할까?
여기서 말하는 폐쇄망은 단순한 기업 내부망을 말하려는 것이 아니다. 사내에 구성한 배포 파이프라인조차 접근할 수 없는, 외부와 완전히 단절된 독립 네트워크 환경을 의미한다. 워낙 연결이 되어 있는 세상이라 폐쇄망은 다소 특수한 상황처럼 느껴질 수 있다.
네트워크가 단절되었다는 의미는 우리가 사용해오던 자동화된 파이프라인과 배포 전략의 일부는 사용할 수 없다는 의미이기도 하다. 완전하게 단절된 환경에서 배포를 한다는 것은 생각보다 세세한 단계를 따져 진행해야 된다.
이 글은 웹 어플리케이션을 배포하는 데에 있어 컨테이너와 배포 프로세스에 대한 지식과 경험은 있지만, 폐쇄망에 배포를 처음 해보는 사람들에게 도움이 되고자 하는 마음으로 작성하였다.
필자는 병원의 폐쇄망에 배포를 진행해본 바가 있다. 병원은 우리 서비스를 이용하는 ‘고객’이었고 병원 사이트 단위로 어플리케이션을 배포해야 했다.
물론 클라우드를 적극 도입하는 병원도 존재하지만, 병원마다 보안 규정은 다르기에 인터넷이 연결되지 않는 서버에 on-premise 배포를 요청 받은 경우도 적지 않았다. VPN 조차 연결이 되지 않은 경우에는 물리적으로 병원에 직접 방문해서 배포를 진행해야 했다. 완전히 분리된 망에서의 배포는 의외로 있을 수 있다는 사실을 절실히 깨달았던 경험이었다. (그리고 아주 중요한 것은 USB가 필수라는 것이다. 하나는 꼭 갖고 있자)
비단 병원 도메인 만의 이야기가 아닐 수 있다. 보안 정책이 강력한 곳이라면 어디든 폐쇄망으로 어플리케이션 배포를 요청 받을 수 있다.
제공된 서버의 사양을 확인해야 한다. 이 때는 다음의 3개를 꼭 체크한다.
필수 패키지의 설치를 요청해야 한다.
제공된 서버가 정말 아무것도 없는 pure한 경우일 때가 많다. 고객사에서 임의의 서버를 주는 경우이거나 새로운 서버를 사서 제공한 경우는 더더욱 그렇다. 그러니 적어도 컨테이너로 배포를 하기 위한 ‘docker’ 설치는 꼭 요청하자.
하지만 정말 드물게도 docker 설치를 제공하지 않는 경우도 있다. 그런 경우에는 직접 docker 공식 홈페이지에서 바이너리 파일을 다운 받아 가져간다.
다만 필자가 주니어 시절에 겪었던 경험에 의하면 docker 바이너리 파일만 가지고는 설치가 불가능하기도 했다. 제공된 ubuntu 컴퓨터가 너무 pure한 나머지 추가적으로 apt 패키지를 설치해야 했던 사례였다. apt 패키지 또한 인터넷이 열려 있어야 쉽게 설치 가능하다. 만약 폐쇄망에서 추가로 패키지를 설치해야 한다면 패키지 바이너리 파일을 하나하나 찾아 옮겨야 하는 고통을 받을 수 있다. 상황을 설명하고 인터넷을 잠시 열어달라고 요청하는 것도 때론 가능하지만 고객사의 정책상 불가한 경우는 언제나 존재한다.
물론 설치로만 끝나는 것이 아니다. ubuntu 컴퓨터라면 바이너리든 apt든 설치만 잘 하면 추가 설정이 거의 없지만 window 컴퓨터라면 WSL 등의 설정도 필요하다. 점점 골치가 아파질 수 밖에 없다.
(참고 사항) docker 뿐만이 아니라 어플리케이션을 사용하기 위해 설치되어야 하는 서드파티 프로그램은 모두 미리 설치 해달라고 요청해야 한다.
AI 모델을 배포해야 하는 경우에는 CUDA 설치, 분석 프로그램을 써야할 경우에는 R 설치, DB를 도커 컨테이너로 띄우지 않을 거라면 DB 설치, DB 뷰어 설치 등이 때로는 필요하여 사전에 요청을 해야 했다.
(그렇지 않으면 2.에서 작성한 이유와 마찬가지로 패키지 설치 지옥에 빠지기 쉽다. 😇)
프로젝트에서 사용한 패키지는 모두 인터넷이 되는 환경에서 설치가 가능하므로, 인터넷이 열려있는 곳에서 미리 빌드한다.
dockerFROM python:3.11-slim WORKDIR /app COPY requirements.txt . # 파이썬의 pip 패키지 설치도 마찬가지로 인터넷 가능한 환경에서 빌드해야 함 RUN pip install --no-cache-dir -r requirements.txt COPY . . EXPOSE 8000 CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
또한 이미지를 빌드할 때 꼭 linux/amd64 플랫폼 환경에서 빌드해야 한다. (예를 들어, 회사에 있는 linux 서버에서 빌드). 로컬 컴퓨터로 이미지 빌드를 할 수 있다고 해도, 당신이 쓰는 컴퓨터가 맥북이라면 한 번 더 생각해봐야 한다. MacOS 환경에서 빌드를 하면 도커 이미지의 platform 정보가 달라져 병원 환경(window 컴퓨터)에서는 load 자체가 안될 수 있다.
폐쇄망에 배포하기 위해서는 로컬 컴퓨터, 이미지 빌드를 위한 서버, 폐쇄망 서버 내에서의 액션들을 고려한다. 지금까지 해왔던 폐쇄망 배포는 보통은 다음의 절차대로 진행되었다.
렌더링 중...
렌더링 중...
docker save -o target_image_file_name.tar target_image_name
docker load -i target_image_file_name.tar
사내에 CI/CD 파이프라인을 구성해서 클라우드 스토리지 등에 tar 파일을 올려놓는 경우라면 다음과 같은 시퀀스 다이어그램으로 행동해도 된다.
렌더링 중...
폐쇄망 서버에서의 tar파일, 이미지, env 등의 관리에 대한 전략을 미리 고민하는 것이 좋다.
그렇지 않으면 기존 파일을 덮어 씌우거나 사용해야 할 파일이 유실되어 USB로 여러 번 옮기게 되고 여간 귀찮은 일이 아닐 수 없다.
우리가 CI/CD로 배포할 때 버전 관리를 어떻게 하는지를 생각하고 이를 온프렘 환경에 어떻게 적용시켜볼 수 있을지를 고민해보자. (굉장히 구시대적 생각처럼 느낄지도 모르겠지만, 결국엔 폴더 관리 잘하는 게 짱일 수도 있다. 로컬 레지스트리라도 있으면 다행…)
폐쇄망 배포할 때 생기는 모든 작업과 트러블슈팅 과정을 잘 작성해두는 게 매우 필요하다.
로컬 및 사내 개발기 환경과 폐쇄망 환경의 간극을 최대한 줄이고자 최선을 다해 미리미리 환경 세팅을 잘 요청한다고 해도 예상치 못하게 문제가 터질 수 있다.
외부에 있는 서버를 사내 서버의 환경과 100% 맞추기란 절대 쉬운 것이 아니다. 외부 서버의 관리 주체는 자기 자신 또는 회사가 아니니 당연한 얘기다. 그래서 완벽하게 한 번에 배포하겠다는 마음은 스스로를 더 괴롭게 할 수 있다.
생긴 문제는 진단하고 기록하자. 그것이 서버 사양의 문제인지, 서버 프로그램의 문제인지, 도커 설정의 문제인지, 어플리케이션 코드의 문제인지 알아야 다음 온프렘 배포 시 미리 대응이 가능해진다.
앞서 말한 두 포인트는 결국 미래의 나와 타인의 작업을 위한 것임을 잊지 말자.
여타 프로젝트를 하다보면 일정 상황에서는 대무자가 생기거나 R&R이 바뀌기 마련이다. 이런 상황에선 서로의 컨텍스트를 최대한 맞추는 게 중요하다. 이게 어긋나면 회사 내에서도 작업의 병목이 생기기 마련인데 외부 망의 상황조차 정리가 안되어 있으면 모두가 고통 받을 수 있다.
그러므로 고객사 별 배포 현황 및 트러블 슈팅 기록 문서를 꼼꼼히 챙기도록 하자. 당신은 팀의 평화에 일조할 수 있다.
(참고 사항) 배포를 했으나 어플리케이션 레벨에서 문제가 생겼을 시, 외근지에서 빠른 탈출(?)을 하기 위한 약간의 꿀팁
만약 배포를 하고 운영 테스트를 하는 과정에서 에러가 났는데 코드 레벨에서 수정을 해야만 디버깅이 가능했던 경우 또는 즉각적인 반영과 대응이 필요한 경우에는(예. 개발기에서 확인하기 어려웠던 데이터를 폐쇄망 쪽 운영기에서 확인하게 되어 query가 원하는대로 작동하지 않을 때, orm에서 대응이 가능할 때가 있었음) 다음의 방법을 사용할 수'는' 있다.
plain1. docker exec -it container_name bash로 컨테이너 내부 소스 코드에 접근 2. vim으로 수정할 코드를 직접 수정 후 저장(이미지 빌드 시 vim을 설치 하지 않았다면 vi로 코드 수정) 3. exit로 컨테이너 환경 탈출 4. docker commit container_name image_name:tag 로 변경된 코드를 이미지에 커밋 -> 이미지 해시가 변경되며 이미지 형상이 바뀜 5. docker rm container_name && docker run {{필요한 옵션들}}로 컨테이너 재실행(docker-compose 사용시 docker compose up으로 재실행)
다만 권장하는 사항이 아니다. 이는 관리하던 배포 이미지 형상이 깨지는 행위이기 때문이다.
그저 '빠른 해결'에 초점을 맞춘다면 가능한 방법이지만, 이 방법을 사용한다면 회사 복귀 후 바로 코드 수정을 하고 다음 방문 시 배포 이미지를 꼭 교체하도록 한다.
폐쇄망 배포는, 편의에 익숙해져 불편을 감수해야 하는 일처럼 느껴질 수도 있다. 필자 또한 그런 생각을 해본 적이 있다. 그래도 관점을 바꿔 생각해보면, 배포를 하기 위한 step by step은 자동화된 파이프라인을 사용하든 폐쇄망에 직접 배포하든 크게 다르지 않다. step마다의 작업 형태나 사용하는 기술이 달라졌고 사람이 하던 일을 컴퓨터가 할 수 있게 변경이 되어 왔을 뿐. 단계별 과정을 직접 습득하는 길이라 생각한다면 그저 파워성장러가 되는 것이니, 그게 곧 마음 편해지는 길이라 여겼다.
폐쇄망 배포를 하면서 가장 쉽지 않았던 것은 이미지 빌드와 USB로 옮기는 과정을 무한 반복해야 했던 것이다. 현대적인 CI/CD 워크플로우가 갖춰진 상태라면 버튼 하나로 '딸깍'하며 재배포를 하면 되지만 폐쇄망에선 이를 인간이 직접해야 하니 말이다. 어쩌면 스스로가 고통을 줄이기 위한 방향으로 진화(?)하려고 했을지도 모른다.
이 글만으로는 모든 폐쇄망 배포의 상황을 커버할 수는 없을 것이다. 워낙 다양한 배포 환경 케이스가 있고 조직 간의 소통 방법 및 이해 관계, 각 조직의 워크 플로우 또한 다양하기 때문이다. 따라서 이 글을 통해서는 폐쇄망 배포를 할 때 가장 근본적으로 고민하면 좋을 게 무엇인지를 안내 받아 고민의 가짓수를 줄이길 바란다. 그리고 그 기준을 가지고 상황에 따라 적절히 대응하는 것이 조금 더 쉬워지길 바라는 바다. (폐쇄망 배포하시는 분들 모두 화이팅!)