Microsoft MVP성태의 닷넷 이야기
오류 유형: 934. Azure - rm: cannot remove '...': Directory not empty [링크 복사], [링크+제목 복사],
조회: 5123
글쓴 사람
정성태 (seongtaejeong at gmail.com)
홈페이지
첨부 파일
 

Azure - rm: cannot remove '...': Directory not empty

Azure Web App 환경의 경우, 예를 들어 Python 앱이라면,

파이썬 웹 앱을 Azure App Service에 배포하기
; https://www.sysnet.pe.kr/2/0/13830

리눅스 환경에서 호스팅하게 되는데요, 여기서 임의의 데이터를 지속하고 싶다면 반드시 /home 디렉터리 하위에 위치시켜야 합니다.

예를 들어, 파이썬 앱에서 사용하는 패키지를 다음과 같이 설치하면,

$ pip install test-app

Scale-out이 된 경우, 저 SSH로 들어간 환경에서만 test-app 패키지를 사용할 수 있는 데다, 만약 해당 Web App 인스턴스가 재시작하면 저 test-app을 설치한 디렉터리는 다시 초기화되므로 사라지게 됩니다.

따라서, 이런 경우 반드시 /home 디렉터리 하위에 설치해야 합니다.

$ pip install test-app -t /home/test_pacakge

/home 디렉터리 외에도, Azure는 이를 우회할 수 있는 자동화 스크립트 방법을 제공하는데요,

Customize build automation
; https://learn.microsoft.com/en-us/azure/app-service/configure-language-python#customize-build-automation

정리하면 SCM_DO_BUILD_DURING_DEPLOYMENT 환경변수를 1로 설정하고, 원하는 스크립트를 PRE_BUILD_COMMAND / POST_BUILD_COMMAND 환경변수에 설정하거나, 보유하고 있는 requirements.txt에 해당 패키지를 추가하는 식으로 처리할 수 있습니다.




여기서는 /home 디렉터리 하위에 직접 사용자가 설치한 경우를 예로 들어 보겠습니다.

$ pip install test-app -t /home/test_pacakge

이런 상태에서 Python Web App이 실행 중일 때, /home/test_pacakge 디렉터리 하위에 있는 "실행 파일"을 함께 구동했다고 가정하면, 그 실행 파일은 Web App이 Scale-out하면 그 인스턴스 수만큼 실행이 될 것입니다.

재미있는 건, 그 상태에서 해당 패키지가 업그레이드돼 다시 설치하게 되면,

# pip install test-app -U -t /home/test_pacakge
Collecting test-app
...[생략]...

ERROR: Exception:
Traceback (most recent call last):
  File "/tmp/8dd0d13008cfbf9/antenv/lib/python3.12/site-packages/pip/_internal/cli/base_command.py", line 105, in _run_wrapper
    status = _inner_run()
             ^^^^^^^^^^^^
  File "/tmp/8dd0d13008cfbf9/antenv/lib/python3.12/site-packages/pip/_internal/cli/base_command.py", line 96, in _inner_run
    return self.run(options, args)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/8dd0d13008cfbf9/antenv/lib/python3.12/site-packages/pip/_internal/cli/req_command.py", line 67, in wrapper
    return func(self, options, args)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/8dd0d13008cfbf9/antenv/lib/python3.12/site-packages/pip/_internal/commands/install.py", line 519, in run
    self._handle_target_dir(
  File "/tmp/8dd0d13008cfbf9/antenv/lib/python3.12/site-packages/pip/_internal/commands/install.py", line 574, in _handle_target_dir
    shutil.rmtree(target_item_dir)
  File "/opt/python/3.12.2/lib/python3.12/shutil.py", line 785, in rmtree
    _rmtree_safe_fd(fd, path, onexc)
  File "/opt/python/3.12.2/lib/python3.12/shutil.py", line 686, in _rmtree_safe_fd
    _rmtree_safe_fd(dirfd, fullname, onexc)
  File "/opt/python/3.12.2/lib/python3.12/shutil.py", line 686, in _rmtree_safe_fd
    _rmtree_safe_fd(dirfd, fullname, onexc)
  File "/opt/python/3.12.2/lib/python3.12/shutil.py", line 697, in _rmtree_safe_fd
    onexc(os.rmdir, fullname, err)
  File "/opt/python/3.12.2/lib/python3.12/shutil.py", line 695, in _rmtree_safe_fd
    os.rmdir(entry.name, dir_fd=topfd)
OSError: [Errno 39] Directory not empty: 'amd64'

이런 식의 오류가 발생합니다. 실제로 해당 경로를 직접 삭제하려고 하면 문제가 되는 디렉터리가 밝혀지는데요,

# rm -rf /home/test_pacakge
rm: cannot remove '/home/test_pacakge/bin/linux/amd64': Directory not empty

저 amd64에는 실행 파일이 있고, 그 실행 파일이 사용 중이라 삭제가 안 되는 것입니다. 따라서, 저 디렉터리가 삭제될 수 있어야 하는데요, 만약 Web App 재시작으로 가능하다면 그렇게 하면 됩니다.

혹은, SSH 환경에서 직접 저 실행 파일을 kill 하면 되는데요,

# ps aux | grep test-app
root          65  0.1  0.2 714036  4920 ?        SNl  01:34   0:13 /home/test_package/bin/linux/amd64/test-app
root         139  0.0  0.0   6240   620 pts/1    SN+  04:31   0:00 grep test-app

# kill 65

# ps aux | grep test-app
root         141  0.0  0.0   6240   652 pts/1    SN+  04:31   0:00 grep test-app

Scale-out 환경이라면 저렇게 했어도 여전히 디렉터리 삭제가 안 될 것입니다. 왜냐하면, 저렇게 실행 중인 프로세스를 모든 인스턴스에서 종료해야 하기 때문입니다.




한 가지 재미있는 점이 있는데요, Azure Web App 환경의 SSH 접속으로 설치한 파일들의 소유자를 보면,

# pip install test-app -t /home/test_pacakge

# ls /home/test_pacakge/ -l
total 0
drwxrwxrwx 2 nobody nogroup 0 Dec  2 01:19 bin
drwxrwxrwx 2 nobody nogroup 0 Dec  2 01:19 test_app
drwxrwxrwx 2 nobody nogroup 0 Dec  2 01:19 test_app-1.0.0.0.dist-info

저렇게 nobody, nogroup이 있습니다. 검색해 보면,

Debian change owner of nobody:nogroup
; https://unix.stackexchange.com/questions/563942/debian-change-owner-of-nobodynogroup

이게 컨테이너 내에서 볼 수 없는 상위 네임스페이스에서 설정된 파일 권한이어서 그렇다고 합니다.

# ls -n 
total 3064
-rwxrwxrwx 1 65534 65534 3137536 Nov 29 01:46 test-app

이런 경우 저렇게 uid/gid도 65534로 나온다고. ^^




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 12/3/2024]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... [166]  167  168  169  170  171  172  173  174  175  176  177  178  179  180  ...
NoWriterDateCnt.TitleFile(s)
889정성태7/5/201026567.NET Framework: 179. Dictionary.Get(A) 대신 Dictionary.Get(A.GetHashCode())를 사용해서는 안 되는 이유 [1]
888정성태6/30/201024363오류 유형: 96. Hyper-V 연결 오류 - A connection will not be made because credentials may not be sent to the remote computer
887정성태6/23/201034199개발 환경 구성: 79. Hyper-V의 가상 머신에서 소리 재생 방법 [2]
886정성태6/23/201022402제니퍼 .NET: 14. ASMX, WCF 호출 모니터링 및 누수 확인
885정성태6/20/201023952개발 환경 구성: 78. COM+ 서버에서 COM+ 서버를 호출하는 방법
884정성태6/20/201026908제니퍼 .NET: 13. COM+ 서버 모니터링 [2]
883정성태6/18/201028782개발 환경 구성: 77. Appinit_Dlls로 구현한 환경 변수 설정 DLL [5]파일 다운로드1
882정성태6/17/201031614개발 환경 구성: 76. JKS(Java Key Store)에 저장된 인증서를 ActiveX 코드 서명에 사용하는 방법 [1]
881정성태6/14/201021036제니퍼 .NET: 12. COM+ 호출 모니터링 및 누수 확인
879정성태6/10/201023707제니퍼 .NET: 11. 소켓 모니터링 기능으로 본 ASP.NET의 소켓 풀링 기능 [1]
878정성태6/6/201023496제니퍼 .NET: 10. 소켓 모니터링 기능으로 본 WCF의 WSDualHttpBinding 성능 부하
877정성태5/31/201020231제니퍼 .NET: 9. 성능 관리 퀴즈 세 번째 문제 (닷넷 개발자 컨퍼런스)
876정성태5/31/201019680제니퍼 .NET: 8. 성능 관리 퀴즈 두 번째 문제 (닷넷 개발자 컨퍼런스) [2]
875정성태5/30/201021410제니퍼 .NET: 7. 성능 관리 퀴즈 첫 번째 문제 (닷넷 개발자 컨퍼런스)
873정성태5/19/201028274제니퍼 .NET: 6. 제니퍼를 위한 방화벽 설정
872정성태5/15/201027610제니퍼 .NET: 5. 제니퍼 서버 - NT 서비스로 구동시키는 방법
871정성태5/13/201034188VC++: 40. MSBuild를 이용한 VC++ 프로젝트 빌드파일 다운로드1
870정성태5/12/201025202제니퍼 .NET: 4. 닷넷 APM 솔루션 - 제니퍼 닷넷의 기능 요약 [2]
869정성태11/8/201926671오류 유형 : 95. WCF 인증서 설정 관련 오류 정리 [4]
865정성태5/5/201028964개발 환경 구성: 75. 인증서의 개인키를 담은 물리 파일 위치 알아내는 방법파일 다운로드1
864정성태5/4/201032828.NET Framework: 178. WCF - 사용자 정의 인증 구현 예제 [4]파일 다운로드1
863정성태5/4/201058726개발 환경 구성: 74. 인증서 관련(CER, PVK, SPC, PFX) 파일 만드는 방법 [1]파일 다운로드1
862정성태5/3/201020611제니퍼 .NET: 3. 제2회 닷넷 개발자 컨퍼런스에서 뵙겠습니다. ^^
861정성태5/1/201021208.NET Framework: 177. .NET 2.0 Profiler에 .NET 4.0 지원 추가
860정성태4/30/201026295오류 유형: 95. .NET 4.0 설치 오류 - 0x800c0005 [1]
858정성태4/29/201030177제니퍼 .NET: 2. JENNIFER .NET을 이용한 .NET 웹 사이트 모니터링 (2) - 설치 [3]
... [166]  167  168  169  170  171  172  173  174  175  176  177  178  179  180  ...