[{"data":1,"prerenderedAt":1047},["ShallowReactive",2],{"post-document:\u002Fci-cd-docker\u002Fdocker\u002F2026\u002F08\u002F24\u002Fsigterm\u002F":3},{"id":4,"title":5,"body":6,"categories":1032,"date":1035,"description":1036,"extension":1037,"image":1038,"key_concepts":1038,"last_modified_at":1038,"legacyPath":1039,"meta":1040,"navigation":63,"part":1038,"path":1042,"published":63,"robots":1038,"seo":1043,"series":1038,"stem":1044,"strengths":1038,"summary":1038,"tags":1045,"tradeoffs":1038,"__hash__":1046},"posts\u002Fposts\u002FCI-CD-Docker\u002FDocker\u002Fsigterm.md","sigterm",{"type":7,"value":8,"toc":999},"minimark",[9,14,23,26,30,35,105,109,117,120,137,143,150,154,171,177,180,186,190,193,196,218,221,229,231,235,238,247,254,257,266,269,272,278,284,290,310,313,325,328,334,337,364,367,372,376,382,388,391,394,397,400,409,418,421,450,453,455,459,462,471,478,482,488,491,509,513,519,525,529,534,537,543,546,549,552,555,564,569,583,591,593,597,670,674,677,685,688,696,699,707,709,716,729,734,741,747,750,752,756,759,765,768,772,799,803,825,829,851,854,900,903,929,932,948,951,963,978,995],[10,11,13],"h2",{"id":12},"세-가지-cmd-실행-방식-비교","세 가지 CMD 실행 방식 비교",[15,16,17,18,22],"p",{},"Docker 컨테이너가 종료될 때 Docker는 컨테이너의 ",[19,20,21],"strong",{},"PID 1 프로세스에 SIGTERM","을 보냅니다. 따라서 어떤 프로세스가 PID 1인지가 Graceful Shutdown의 핵심입니다.",[24,25],"hr",{},[10,27,29],{"id":28},"실습-1-exec-form-python-직접-실행","실습 1. Exec Form, Python 직접 실행",[31,32,34],"h3",{"id":33},"dockerfile","Dockerfile",[36,37,41],"pre",{"className":38,"code":39,"language":33,"meta":40,"style":40},"language-dockerfile shiki shiki-themes github-light github-dark","ARG UBUNTU_VERSION=22.04\nFROM ubuntu:${UBUNTU_VERSION}\n\nRUN apt-get update && \\\n    apt-get install -y python3 python3-pip\n\nWORKDIR \u002Fapp\nCOPY webserver.py .\n\nCMD [\"python3\", \"-u\", \"webserver.py\"]\n","",[42,43,44,52,58,65,71,77,82,88,94,99],"code",{"__ignoreMap":40},[45,46,49],"span",{"class":47,"line":48},"line",1,[45,50,51],{},"ARG UBUNTU_VERSION=22.04\n",[45,53,55],{"class":47,"line":54},2,[45,56,57],{},"FROM ubuntu:${UBUNTU_VERSION}\n",[45,59,61],{"class":47,"line":60},3,[45,62,64],{"emptyLinePlaceholder":63},true,"\n",[45,66,68],{"class":47,"line":67},4,[45,69,70],{},"RUN apt-get update && \\\n",[45,72,74],{"class":47,"line":73},5,[45,75,76],{},"    apt-get install -y python3 python3-pip\n",[45,78,80],{"class":47,"line":79},6,[45,81,64],{"emptyLinePlaceholder":63},[45,83,85],{"class":47,"line":84},7,[45,86,87],{},"WORKDIR \u002Fapp\n",[45,89,91],{"class":47,"line":90},8,[45,92,93],{},"COPY webserver.py .\n",[45,95,97],{"class":47,"line":96},9,[45,98,64],{"emptyLinePlaceholder":63},[45,100,102],{"class":47,"line":101},10,[45,103,104],{},"CMD [\"python3\", \"-u\", \"webserver.py\"]\n",[31,106,108],{"id":107},"프로세스-구조","프로세스 구조",[36,110,115],{"className":111,"code":113,"language":114,"meta":40},[112],"language-text","Docker\n└── PID 1: python3 -u webserver.py\n","text",[42,116,113],{"__ignoreMap":40},[15,118,119],{},"컨테이너 내부에서 확인하면:",[36,121,125],{"className":122,"code":123,"language":124,"meta":40,"style":40},"language-bash shiki shiki-themes github-light github-dark","ps -ef\n","bash",[42,126,127],{"__ignoreMap":40},[45,128,129,133],{"class":47,"line":48},[45,130,132],{"class":131},"sScJk","ps",[45,134,136],{"class":135},"sj4cs"," -ef\n",[36,138,141],{"className":139,"code":140,"language":114,"meta":40},[112],"UID    PID  PPID  CMD\nroot     1     0  python3 -u webserver.py\nroot     7     0  \u002Fbin\u002Fbash\nroot    15     7  ps -ef\n",[42,142,140],{"__ignoreMap":40},[15,144,145,146,149],{},"Python이 직접 ",[42,147,148],{},"PID 1","로 실행됩니다.",[31,151,153],{"id":152},"종료-과정","종료 과정",[36,155,157],{"className":122,"code":156,"language":124,"meta":40,"style":40},"docker stop linux-container\n",[42,158,159],{"__ignoreMap":40},[45,160,161,164,168],{"class":47,"line":48},[45,162,163],{"class":131},"docker",[45,165,167],{"class":166},"sZZnC"," stop",[45,169,170],{"class":166}," linux-container\n",[36,172,175],{"className":173,"code":174,"language":114,"meta":40},[112],"Docker\n  │\n  │ SIGTERM\n  ▼\nPID 1: Python\n  │\n  ▼\nhandle_sigterm() 실행\n  │\n  ▼\n서버와 자원 정리 후 종료\n",[42,176,174],{"__ignoreMap":40},[15,178,179],{},"따라서 다음 로그가 바로 출력됩니다.",[36,181,184],{"className":182,"code":183,"language":114,"meta":40},[112],"SIGTERM 신호 수신\nSIGTERM 처리 종료\n",[42,185,183],{"__ignoreMap":40},[31,187,189],{"id":188},"왜-사용하는가","왜 사용하는가?",[15,191,192],{},"Python, Spring Boot, FastAPI 같은 애플리케이션이 SIGTERM을 직접 받을 수 있기 때문입니다.",[15,194,195],{},"SIGTERM을 받은 애플리케이션은 다음 작업을 수행할 수 있습니다.",[197,198,199,203,206,209,212,215],"ul",{},[200,201,202],"li",{},"처리 중인 요청 마무리",[200,204,205],{},"HTTP 서버 종료",[200,207,208],{},"데이터베이스 연결 해제",[200,210,211],{},"파일과 네트워크 자원 정리",[200,213,214],{},"로그 저장",[200,216,217],{},"Graceful Shutdown 수행",[15,219,220],{},"별도의 셸 기능이 필요 없다면 가장 권장되는 방식입니다.",[36,222,223],{"className":38,"code":104,"language":33,"meta":40,"style":40},[42,224,225],{"__ignoreMap":40},[45,226,227],{"class":47,"line":48},[45,228,104],{},[24,230],{},[10,232,234],{"id":233},"실습-2-shell을-거쳐-자식-프로세스로-실행","실습 2. Shell을 거쳐 자식 프로세스로 실행",[31,236,34],{"id":237},"dockerfile-1",[36,239,241],{"className":38,"code":240,"language":33,"meta":40,"style":40},"CMD [\"\u002Fbin\u002Fsh\", \"-c\", \"python3 -u webserver.py\"]\n",[42,242,243],{"__ignoreMap":40},[45,244,245],{"class":47,"line":48},[45,246,240],{},[15,248,249,250,253],{},"엄밀히 말하면 Dockerfile 문법 자체는 JSON 배열을 사용한 Exec Form입니다. 하지만 ",[42,251,252],{},"\u002Fbin\u002Fsh -c","를 직접 실행하므로 실제 동작은 셸을 거치는 Shell Form과 비슷합니다.",[15,255,256],{},"일반적인 Shell Form으로 작성하면 다음과 같습니다.",[36,258,260],{"className":38,"code":259,"language":33,"meta":40,"style":40},"CMD python3 -u webserver.py\n",[42,261,262],{"__ignoreMap":40},[45,263,264],{"class":47,"line":48},[45,265,259],{},[15,267,268],{},"두 방식 모두 셸이 중간에 들어갈 수 있습니다.",[31,270,108],{"id":271},"프로세스-구조-1",[36,273,276],{"className":274,"code":275,"language":114,"meta":40},[112],"Docker\n└── PID 1: \u002Fbin\u002Fsh\n    └── PID 7: python3 -u webserver.py\n",[42,277,275],{"__ignoreMap":40},[15,279,280,283],{},[42,281,282],{},"ps -ef"," 결과:",[36,285,288],{"className":286,"code":287,"language":114,"meta":40},[112],"UID    PID  PPID  CMD\nroot     1     0  \u002Fbin\u002Fsh -c python3 -u webserver.py\nroot     7     1  python3 -u webserver.py\n",[42,289,287],{"__ignoreMap":40},[197,291,292,298,304],{},[200,293,294,297],{},[42,295,296],{},"\u002Fbin\u002Fsh",": PID 1",[200,299,300,303],{},[42,301,302],{},"python3",": 셸이 생성한 자식 프로세스",[200,305,306,307],{},"Python의 PPID: 셸의 PID인 ",[42,308,309],{},"1",[31,311,153],{"id":312},"종료-과정-1",[36,314,315],{"className":122,"code":156,"language":124,"meta":40,"style":40},[42,316,317],{"__ignoreMap":40},[45,318,319,321,323],{"class":47,"line":48},[45,320,163],{"class":131},[45,322,167],{"class":166},[45,324,170],{"class":166},[15,326,327],{},"Docker는 Python이 아니라 PID 1인 셸에 SIGTERM을 보냅니다.",[36,329,332],{"className":330,"code":331,"language":114,"meta":40},[112],"Docker\n  │\n  │ SIGTERM\n  ▼\nPID 1: \u002Fbin\u002Fsh\n  │\n  │ Python에 전달되지 않을 수 있음\n  ▼\nPID 7: Python\n",[42,333,331],{"__ignoreMap":40},[15,335,336],{},"셸이 SIGTERM을 Python에 전달하지 않으면 Python의 신호 처리 함수가 실행되지 않습니다.",[36,338,342],{"className":339,"code":340,"language":341,"meta":40,"style":40},"language-python shiki shiki-themes github-light github-dark","def handle_sigterm(signum, frame):\n    print(\"SIGTERM 신호 수신\")\n    httpd.server_close()\n    sys.exit(0)\n","python",[42,343,344,349,354,359],{"__ignoreMap":40},[45,345,346],{"class":47,"line":48},[45,347,348],{},"def handle_sigterm(signum, frame):\n",[45,350,351],{"class":47,"line":54},[45,352,353],{},"    print(\"SIGTERM 신호 수신\")\n",[45,355,356],{"class":47,"line":60},[45,357,358],{},"    httpd.server_close()\n",[45,360,361],{"class":47,"line":67},[45,362,363],{},"    sys.exit(0)\n",[15,365,366],{},"따라서 다음 로그가 나오지 않을 수 있습니다.",[36,368,370],{"className":369,"code":183,"language":114,"meta":40},[112],[42,371,183],{"__ignoreMap":40},[31,373,375],{"id":374},"docker의-실제-종료-동작","Docker의 실제 종료 동작",[15,377,378,381],{},[42,379,380],{},"docker stop","이 곧바로 SIGKILL을 보내는 것은 아닙니다.",[36,383,386],{"className":384,"code":385,"language":114,"meta":40},[112],"SIGTERM 전송\n    ↓\n기본 10초 동안 종료 대기\n    ↓\n종료되지 않으면 SIGKILL 전송\n",[42,387,385],{"__ignoreMap":40},[15,389,390],{},"Kubernetes에서는 일반적으로 종료 유예 시간이 기본 30초입니다. 이 시간이 지나도 종료되지 않으면 강제 종료될 수 있습니다.",[31,392,189],{"id":393},"왜-사용하는가-1",[15,395,396],{},"셸 기능이 필요할 때 사용할 수 있습니다.",[15,398,399],{},"예를 들면:",[36,401,403],{"className":38,"code":402,"language":33,"meta":40,"style":40},"CMD [\"\u002Fbin\u002Fsh\", \"-c\", \"python3 $APP_FILE\"]\n",[42,404,405],{"__ignoreMap":40},[45,406,407],{"class":47,"line":48},[45,408,402],{},[36,410,412],{"className":38,"code":411,"language":33,"meta":40,"style":40},"CMD [\"\u002Fbin\u002Fsh\", \"-c\", \"python3 webserver.py > server.log 2>&1\"]\n",[42,413,414],{"__ignoreMap":40},[45,415,416],{"class":47,"line":48},[45,417,411],{},[15,419,420],{},"셸은 다음 기능을 사용할 때 필요합니다.",[197,422,423,426,432,438,444],{},[200,424,425],{},"환경변수 치환",[200,427,428,429],{},"파이프 ",[42,430,431],{},"|",[200,433,434,435],{},"출력 리다이렉션 ",[42,436,437],{},">",[200,439,440,441],{},"여러 명령 연결 ",[42,442,443],{},"&&",[200,445,446,447],{},"와일드카드 ",[42,448,449],{},"*",[15,451,452],{},"하지만 셸을 단순히 Python 실행용으로만 사용하면 신호 전달과 프로세스 관리가 복잡해집니다.",[24,454],{},[10,456,458],{"id":457},"실습-3-shell-with-exec-프로세스-치환","실습 3. Shell with Exec, 프로세스 치환",[31,460,34],{"id":461},"dockerfile-2",[36,463,465],{"className":38,"code":464,"language":33,"meta":40,"style":40},"CMD [\"\u002Fbin\u002Fsh\", \"-c\", \"exec python3 -u webserver.py\"]\n",[42,466,467],{"__ignoreMap":40},[45,468,469],{"class":47,"line":48},[45,470,464],{},[15,472,473,474,477],{},"처음에는 셸이 실행되지만, ",[42,475,476],{},"exec","가 셸을 Python 프로세스로 교체합니다.",[31,479,481],{"id":480},"실행-직후","실행 직후",[36,483,486],{"className":484,"code":485,"language":114,"meta":40},[112],"PID 1: \u002Fbin\u002Fsh\n",[42,487,485],{"__ignoreMap":40},[15,489,490],{},"셸이 다음 명령을 처리합니다.",[36,492,494],{"className":122,"code":493,"language":124,"meta":40,"style":40},"exec python3 -u webserver.py\n",[42,495,496],{"__ignoreMap":40},[45,497,498,500,503,506],{"class":47,"line":48},[45,499,476],{"class":135},[45,501,502],{"class":166}," python3",[45,504,505],{"class":135}," -u",[45,507,508],{"class":166}," webserver.py\n",[31,510,512],{"id":511},"exec-실행-후","exec 실행 후",[36,514,517],{"className":515,"code":516,"language":114,"meta":40},[112],"PID 1: python3 -u webserver.py\n",[42,518,516],{"__ignoreMap":40},[15,520,521,522,524],{},"새로운 자식 프로세스를 만드는 것이 아니라, 기존 셸 프로세스가 Python으로 바뀝니다. PID는 그대로 ",[42,523,309],{},"입니다.",[15,526,527,283],{},[42,528,282],{},[36,530,532],{"className":531,"code":140,"language":114,"meta":40},[112],[42,533,140],{"__ignoreMap":40},[31,535,153],{"id":536},"종료-과정-2",[36,538,541],{"className":539,"code":540,"language":114,"meta":40},[112],"Docker\n  │\n  │ SIGTERM\n  ▼\nPID 1: Python\n  │\n  ▼\nhandle_sigterm() 실행\n  │\n  ▼\nGraceful Shutdown\n",[42,542,540],{"__ignoreMap":40},[15,544,545],{},"따라서 실습 1과 마찬가지로 Python이 SIGTERM을 직접 받습니다.",[31,547,189],{"id":548},"왜-사용하는가-2",[15,550,551],{},"셸 기능이 필요하지만, 최종 애플리케이션이 PID 1이 되어야 할 때 사용합니다.",[15,553,554],{},"예를 들어 환경변수를 조합하거나 실행 전 작업이 필요할 수 있습니다.",[36,556,558],{"className":38,"code":557,"language":33,"meta":40,"style":40},"CMD [\"\u002Fbin\u002Fsh\", \"-c\", \"echo '서버 시작' && exec python3 -u webserver.py\"]\n",[42,559,560],{"__ignoreMap":40},[45,561,562],{"class":47,"line":48},[45,563,557],{},[15,565,566,567,524],{},"여기서 중요한 부분은 마지막의 ",[42,568,476],{},[36,570,571],{"className":122,"code":493,"language":124,"meta":40,"style":40},[42,572,573],{"__ignoreMap":40},[45,574,575,577,579,581],{"class":47,"line":48},[45,576,476],{"class":135},[45,578,502],{"class":166},[45,580,505],{"class":135},[45,582,508],{"class":166},[15,584,585,587,588,590],{},[42,586,476],{},"가 없으면 Python은 셸의 자식 프로세스가 됩니다. ",[42,589,476],{},"가 있으면 셸이 Python으로 교체됩니다.",[24,592],{},[10,594,596],{"id":595},"세-방식-요약","세 방식 요약",[598,599,600,619],"table",{},[601,602,603],"thead",{},[604,605,606,610,612,616],"tr",{},[607,608,609],"th",{},"방식",[607,611,148],{},[607,613,615],{"align":614},"right","Python의 SIGTERM 수신",[607,617,618],{},"주요 용도",[620,621,622,639,655],"tbody",{},[604,623,624,630,633,636],{},[625,626,627],"td",{},[42,628,629],{},"CMD [\"python3\", \"-u\", \"webserver.py\"]",[625,631,632],{},"Python",[625,634,635],{"align":614},"직접 수신",[625,637,638],{},"일반적으로 가장 권장",[604,640,641,646,649,652],{},[625,642,643],{},[42,644,645],{},"CMD [\"\u002Fbin\u002Fsh\", \"-c\", \"python3 -u webserver.py\"]",[625,647,648],{},"Shell",[625,650,651],{"align":614},"전달되지 않을 수 있음",[625,653,654],{},"셸 기능이 필요하지만 신호 처리에 주의",[604,656,657,662,665,667],{},[625,658,659],{},[42,660,661],{},"CMD [\"\u002Fbin\u002Fsh\", \"-c\", \"exec python3 -u webserver.py\"]",[625,663,664],{},"최종적으로 Python",[625,666,635],{"align":614},[625,668,669],{},"셸 처리 후 애플리케이션을 PID 1로 실행",[31,671,673],{"id":672},"선택-기준","선택 기준",[15,675,676],{},"단순히 프로그램 하나만 실행한다면:",[36,678,679],{"className":38,"code":104,"language":33,"meta":40,"style":40},[42,680,681],{"__ignoreMap":40},[45,682,683],{"class":47,"line":48},[45,684,104],{},[15,686,687],{},"셸 기능이 반드시 필요하다면:",[36,689,690],{"className":38,"code":464,"language":33,"meta":40,"style":40},[42,691,692],{"__ignoreMap":40},[45,693,694],{"class":47,"line":48},[45,695,464],{},[15,697,698],{},"피하는 편이 좋은 구조:",[36,700,701],{"className":38,"code":240,"language":33,"meta":40,"style":40},[42,702,703],{"__ignoreMap":40},[45,704,705],{"class":47,"line":48},[45,706,240],{},[24,708],{},[10,710,712,715],{"id":711},"u-옵션의-의미",[42,713,714],{},"-u"," 옵션의 의미",[36,717,719],{"className":122,"code":718,"language":124,"meta":40,"style":40},"python3 -u webserver.py\n",[42,720,721],{"__ignoreMap":40},[45,722,723,725,727],{"class":47,"line":48},[45,724,302],{"class":131},[45,726,505],{"class":135},[45,728,508],{"class":166},[15,730,731,733],{},[42,732,714],{},"는 SIGTERM과 직접 관계가 없습니다. Python의 표준 출력과 표준 오류를 버퍼링하지 않도록 설정합니다.",[15,735,736,737,740],{},"따라서 다음 로그가 바로 ",[42,738,739],{},"docker logs","에 나타납니다.",[36,742,745],{"className":743,"code":744,"language":114,"meta":40},[112],"Starting server on port 8080...\nSIGTERM 신호 수신\nSIGTERM 처리 종료\n",[42,746,744],{"__ignoreMap":40},[15,748,749],{},"컨테이너 환경에서는 로그를 즉시 확인하기 위해 자주 사용합니다.",[24,751],{},[10,753,755],{"id":754},"현재-폴더-구조에서-실습하는-명령어","현재 폴더 구조에서 실습하는 명령어",[15,757,758],{},"현재 파일 위치가 다음과 같기 때문에:",[36,760,763],{"className":761,"code":762,"language":114,"meta":40},[112],"ubuntu\u002F\n├── dockerfile\n└── mydata\u002F\n    └── webserver.py\n",[42,764,762],{"__ignoreMap":40},[15,766,767],{},"각 버전의 Dockerfile을 수정한 다음 프로젝트 루트에서 빌드합니다.",[31,769,771],{"id":770},"_10-exec-form","1.0, Exec Form",[36,773,775],{"className":122,"code":774,"language":124,"meta":40,"style":40},"docker build -f ubuntu\u002Fdockerfile -t linux-container:1.0 ubuntu\u002Fmydata\n",[42,776,777],{"__ignoreMap":40},[45,778,779,781,784,787,790,793,796],{"class":47,"line":48},[45,780,163],{"class":131},[45,782,783],{"class":166}," build",[45,785,786],{"class":135}," -f",[45,788,789],{"class":166}," ubuntu\u002Fdockerfile",[45,791,792],{"class":135}," -t",[45,794,795],{"class":166}," linux-container:1.0",[45,797,798],{"class":166}," ubuntu\u002Fmydata\n",[31,800,802],{"id":801},"_11-shell-실행","1.1, Shell 실행",[36,804,806],{"className":122,"code":805,"language":124,"meta":40,"style":40},"docker build -f ubuntu\u002Fdockerfile -t linux-container:1.1 ubuntu\u002Fmydata\n",[42,807,808],{"__ignoreMap":40},[45,809,810,812,814,816,818,820,823],{"class":47,"line":48},[45,811,163],{"class":131},[45,813,783],{"class":166},[45,815,786],{"class":135},[45,817,789],{"class":166},[45,819,792],{"class":135},[45,821,822],{"class":166}," linux-container:1.1",[45,824,798],{"class":166},[31,826,828],{"id":827},"_12-shell-with-exec","1.2, Shell with Exec",[36,830,832],{"className":122,"code":831,"language":124,"meta":40,"style":40},"docker build -f ubuntu\u002Fdockerfile -t linux-container:1.2 ubuntu\u002Fmydata\n",[42,833,834],{"__ignoreMap":40},[45,835,836,838,840,842,844,846,849],{"class":47,"line":48},[45,837,163],{"class":131},[45,839,783],{"class":166},[45,841,786],{"class":135},[45,843,789],{"class":166},[45,845,792],{"class":135},[45,847,848],{"class":166}," linux-container:1.2",[45,850,798],{"class":166},[15,852,853],{},"실행:",[36,855,857],{"className":122,"code":856,"language":124,"meta":40,"style":40},"docker run --rm -d \\\n  --name linux-container \\\n  -p 8080:8080 \\\n  linux-container:1.2\n",[42,858,859,875,885,895],{"__ignoreMap":40},[45,860,861,863,866,869,872],{"class":47,"line":48},[45,862,163],{"class":131},[45,864,865],{"class":166}," run",[45,867,868],{"class":135}," --rm",[45,870,871],{"class":135}," -d",[45,873,874],{"class":135}," \\\n",[45,876,877,880,883],{"class":47,"line":54},[45,878,879],{"class":135},"  --name",[45,881,882],{"class":166}," linux-container",[45,884,874],{"class":135},[45,886,887,890,893],{"class":47,"line":60},[45,888,889],{"class":135},"  -p",[45,891,892],{"class":166}," 8080:8080",[45,894,874],{"class":135},[45,896,897],{"class":47,"line":67},[45,898,899],{"class":166},"  linux-container:1.2\n",[15,901,902],{},"프로세스 확인:",[36,904,906],{"className":122,"code":905,"language":124,"meta":40,"style":40},"docker exec -it linux-container \u002Fbin\u002Fbash\nps -ef\n",[42,907,908,923],{"__ignoreMap":40},[45,909,910,912,915,918,920],{"class":47,"line":48},[45,911,163],{"class":131},[45,913,914],{"class":166}," exec",[45,916,917],{"class":135}," -it",[45,919,882],{"class":166},[45,921,922],{"class":166}," \u002Fbin\u002Fbash\n",[45,924,925,927],{"class":47,"line":54},[45,926,132],{"class":131},[45,928,136],{"class":135},[15,930,931],{},"로그를 띄운 상태에서:",[36,933,935],{"className":122,"code":934,"language":124,"meta":40,"style":40},"docker logs -f linux-container\n",[42,936,937],{"__ignoreMap":40},[45,938,939,941,944,946],{"class":47,"line":48},[45,940,163],{"class":131},[45,942,943],{"class":166}," logs",[45,945,786],{"class":135},[45,947,170],{"class":166},[15,949,950],{},"다른 터미널에서 종료합니다.",[36,952,953],{"className":122,"code":156,"language":124,"meta":40,"style":40},[42,954,955],{"__ignoreMap":40},[45,956,957,959,961],{"class":47,"line":48},[45,958,163],{"class":131},[45,960,167],{"class":166},[45,962,170],{"class":166},[15,964,965,966,969,970,973,974,977],{},"참고로 ",[42,967,968],{},"--rm","으로 실행한 컨테이너는 종료 후 자동으로 삭제됩니다. 따라서 이후의 ",[42,971,972],{},"docker rm linux-container","는 필요하지 않습니다. 또한 자료의 ",[42,975,976],{},"docker exec -it python-container","는 컨테이너 이름이 잘못된 것으로 보이며, 다음이 맞습니다.",[36,979,981],{"className":122,"code":980,"language":124,"meta":40,"style":40},"docker exec -it linux-container \u002Fbin\u002Fbash\n",[42,982,983],{"__ignoreMap":40},[45,984,985,987,989,991,993],{"class":47,"line":48},[45,986,163],{"class":131},[45,988,914],{"class":166},[45,990,917],{"class":135},[45,992,882],{"class":166},[45,994,922],{"class":166},[996,997,998],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}",{"title":40,"searchDepth":54,"depth":54,"links":1000},[1001,1002,1008,1015,1022,1025,1027],{"id":12,"depth":54,"text":13},{"id":28,"depth":54,"text":29,"children":1003},[1004,1005,1006,1007],{"id":33,"depth":60,"text":34},{"id":107,"depth":60,"text":108},{"id":152,"depth":60,"text":153},{"id":188,"depth":60,"text":189},{"id":233,"depth":54,"text":234,"children":1009},[1010,1011,1012,1013,1014],{"id":237,"depth":60,"text":34},{"id":271,"depth":60,"text":108},{"id":312,"depth":60,"text":153},{"id":374,"depth":60,"text":375},{"id":393,"depth":60,"text":189},{"id":457,"depth":54,"text":458,"children":1016},[1017,1018,1019,1020,1021],{"id":461,"depth":60,"text":34},{"id":480,"depth":60,"text":481},{"id":511,"depth":60,"text":512},{"id":536,"depth":60,"text":153},{"id":548,"depth":60,"text":189},{"id":595,"depth":54,"text":596,"children":1023},[1024],{"id":672,"depth":60,"text":673},{"id":711,"depth":54,"text":1026},"-u 옵션의 의미",{"id":754,"depth":54,"text":755,"children":1028},[1029,1030,1031],{"id":770,"depth":60,"text":771},{"id":801,"depth":60,"text":802},{"id":827,"depth":60,"text":828},[1033,1034],"CI-CD-Docker","Docker","2026-08-24 13:57:58 +0900","Docker 컨테이너가 종료될 때 Docker는 컨테이너의 PID 1 프로세스에 SIGTERM을 보냅니다. 따라서 어떤 프로세스가 PID 1인지가 Graceful Shutdown의 핵심입니다.","md",null,"\u002Fci-cd-docker\u002Fdocker\u002F2026\u002F08\u002F24\u002Fsigterm\u002F",{"layout":1041},"post","\u002Fposts\u002Fci-cd-docker\u002Fdocker\u002Fsigterm",{"title":5,"description":1036},"posts\u002FCI-CD-Docker\u002FDocker\u002Fsigterm",[],"J6B3wqCQRd-25WL4epeUJY1sZtkcJW9YDcJXNn92taU",1788744788036]