기본 콘텐츠로 건너뛰기

추천 가젯

MCP 도입 전에 먼저 정해야 하는 것: 개발팀 에이전트 권한·로그·실패 대응 체크리스트

개발 생산성 MCP 도입 전에 먼저 정해야 하는 것: 개발팀 에이전트 권한·로그·실패 대응 체크리스트 에이전트 성능보다 먼저 필요한 운영 설계를 다룹니다. MCP 도입 시 권한 범위, 실행 로그, 롤백 기준을 어떻게 정해야 팀이 안전하게 자동화를 확장할 수 있는지 실무 관점으로 정리합니다. #MCP #AI 에이전트 #권한 설계 #감사 로그 #실패 복구 #개발 생산성 Focus MCP Audience 현업 백엔드·플랫폼 개발자와 테크리드 Angle MCP 서버를 붙이기 전에 팀 단위로 합의해야 할 최소 운영 원칙을 실무 체크리스트로 제시 왜 지금 이 주제를 봐야 할까 코드 작성뿐 아니라 배포·운영 자동화까지 에이전트 적용 범위가 넓어지면서, 기능 데모보다 거버넌스와 책임 경계 설계가 팀 리스크를 좌우하는 시점입니다. MCP 서버를 붙이기 전에 팀 단위로 합의해야 할 최소 운영 원칙을 실무 체크리스트로 제시라는 질문은 이제 특정 팀만의 고민이 아닙니다. 현업 백엔드·플랫폼 개발자와 테크리드 입장에서 보면 기술 선택은 곧 생산성과 연결되고, 작은 의사결정 하나가 유지보수 비용까지 바꿉니다. 특히 MCP 같은 키워드...

파이썬 subprocess 완전 정복 ⚙️ — 외부 명령 실행·입출력 캡처·타임아웃

파이썬 subprocess 완전 정복 ⚙️ — 외부 명령 실행·입출력 캡처·타임아웃 subprocess 아이콘

파이썬 subprocess 완전 정복 ⚙️

subprocess는 외부 프로그램 실행을 위한 표준 모듈입니다. 안전한 호출(shell=False), 출력 캡처, 타임아웃, 파이프, 환경/작업폴더 제어까지 운영에 필요한 기능을 모두 제공합니다.

1) 가장 쉬운 방법: subprocess.run

import subprocess

# 리스트 인자 + shell=False (기본) → 안전
result = subprocess.run(
    ["python", "--version"],
    capture_output=True, text=True, check=False
)
print(result.stdout.strip())  # Python 3.x.x
print(result.returncode)
text=True로 자동 디코딩(기본 UTF-8)을 사용하고, 실패 시 예외를 원하면 check=True.

2) 표준출력/표준에러 캡처

import subprocess

res = subprocess.run(
    ["git", "status"],
    stdout=subprocess.PIPE, stderr=subprocess.PIPE,
    text=True
)
print("STDOUT:", res.stdout)
print("STDERR:", res.stderr)

3) 타임아웃과 에러 처리

import subprocess

try:
    subprocess.run(["ping", "-c", "3", "example.com"], timeout=5, check=True)
except subprocess.TimeoutExpired as e:
    print("타임아웃:", e)
except subprocess.CalledProcessError as e:
    print("비정상 종료:", e.returncode, e.stderr)
팁: 타임아웃 시 하위 프로세스가 좀비로 남지 않도록 Popen을 쓰는 경우 proc.kill(); proc.communicate()로 버퍼를 비워 정리하세요.

4) 스트리밍/파이프: Popen

4-1. 실시간 출력 읽기

import subprocess

with subprocess.Popen(
    ["ping", "-c", "3", "example.com"],
    stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, bufsize=1
) as proc:
    for line in proc.stdout:
        print(">>", line.strip())
    code = proc.wait()
print("returncode:", code)

4-2. 두 명령 파이프 연결(UNIX 스타일)

import subprocess

p1 = subprocess.Popen(["ps", "aux"], stdout=subprocess.PIPE)
p2 = subprocess.Popen(["grep", "python"], stdin=p1.stdout, stdout=subprocess.PIPE, text=True)
p1.stdout.close()  # 파이프 종단 닫기(좀비 방지)
out, _ = p2.communicate()
print(out)

4-3. 입력을 프로그램에 전달

import subprocess

p = subprocess.Popen(["python", "-c", "print(input()[::-1])"],
                     stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
out, _ = p.communicate("abcde\n")
print(out.strip())  # edcba

5) 환경변수/작업 디렉터리/권한

import os, subprocess

env = dict(os.environ)
env["API_TOKEN"] = "masked"

res = subprocess.run(
    ["python", "script.py"],
    cwd="/path/to/project",   # 작업 디렉터리
    env=env,                  # 환경변수 오버라이드
    capture_output=True, text=True
)
print(res.stdout)

6) Windows & POSIX 차이

  • Windows는 dir, copy 같은 내장은 cmd 전용이므로 shell=True가 필요합니다. 대안: 파워셸 ["powershell","-Command","Get-ChildItem"].
  • 백그라운드/콘솔 창 숨김은 creationflags=subprocess.CREATE_NO_WINDOW (Windows 전용)로 제어.
  • POSIX에서 세션 분리는 preexec_fn=os.setsid 또는 start_new_session=True 사용.

7) 실전 레시피

7-1. JSON 출력 파싱

import subprocess, json

res = subprocess.run(["python","-c",'import json; print(json.dumps({"ok":1}))'],
                     capture_output=True, text=True, check=True)
payload = json.loads(res.stdout)
print(payload["ok"])

7-2. 안전한 사용자 입력 인자화

import subprocess

def grep_safe(pattern, path):
    # 쉘 미사용, 리스트 인자화 → 쉘 인젝션 방지
    return subprocess.run(["grep", "-R", pattern, path],
                          capture_output=True, text=True)

print(grep_safe("TODO", "."))

7-3. 타임아웃 + 강제 종료 정석 패턴

import subprocess

proc = subprocess.Popen(["sleep","10"])
try:
    proc.wait(timeout=3)
except subprocess.TimeoutExpired:
    proc.kill()
    proc.wait()  # 버퍼 비우기/정리

7-4. 대용량 출력 안전 처리(메모리 폭주 방지)

import subprocess

# communicate는 전부 메모리에 적재될 수 있음 → 라인 스트리밍
with subprocess.Popen(["find","/","-maxdepth","1"], stdout=subprocess.PIPE, text=True) as p:
    for line in p.stdout:
        # 라인 단위 처리/저장/전송
        pass

8) 보안 & 베스트 프랙티스

  • shell=False를 기본으로. 정말 필요할 때만 shell=True (그리고 사용자 입력을 절대 그대로 넘기지 않기).
  • 명령·인자는 리스트로 전달. 공백/특수문자 자동 이스케이프.
  • 입력 데이터는 stdin으로 전달하고, 명령 인자에는 로직상 필요한 값만 주입.
  • 타임아웃을 항상 고려하고, 예외 처리로 종료/정리 보장.
  • 로그에 전체 명령행과 시크릿을 그대로 남기지 않기(마스킹).

요약

  • run은 간단 실행/캡처, Popen은 스트리밍·파이프 등 고급 제어.
  • shell=False + 리스트 인자가 보안 기본값.
  • 타임아웃/에러 처리/환경·작업폴더 제어로 운영 신뢰성 확보.

자주 묻는 질문(FAQ)

Q1. UTF-8이 아닌 출력은 어떻게 디코딩하나요?
A. text=True, encoding="cp949" 같이 인코딩을 지정하거나, res.stdout.encode().decode("cp949")로 변환하세요.

Q2. 비동기 병렬 실행은?
A. asyncio.create_subprocess_exec 또는 concurrent.futures.ThreadPoolExecutorPopen 호출을 병렬화하세요.

Q3. sudo가 필요한 명령은?
A. 권한 분리 원칙을 우선 적용하고, 필요한 경우에만 최소 범위로 승격하세요. 자동화 시엔 전용 사용자/권한을 분리하는 것이 안전합니다.

댓글

가장 많이 본 글

Icons by Flaticon