# patches/ — 현장에서 이미지 일부만 바꾸기 폐쇄망에서는 이미지를 다시 빌드할 수 없다. 여기에 바꾼 파일을 두고 `bin/apply-patches.sh` 를 돌리면, 컨테이너의 같은 경로 위에 **파일 단위로** 덮어쓴다. 나머지 파일은 이미지 것을 그대로 쓰고, 컨테이너를 다시 만들어도 유지된다. ``` patches/app/<경로> → /app/<경로> bootstrap · web · worker-* · scheduler patches/processing/<경로> → /www/alpha-processing/<경로> alpha-processing ``` ## 절차 ```bash # 1. 이미지에서 원본을 꺼낸다 (없는 파일을 만들 수는 없다 — 덮어쓰기만 된다) mkdir -p patches/app/prompts docker run --rm --entrypoint sh pi-continuum:76d67d4 \ -c 'cat /app/prompts/interview_system.md' > patches/app/prompts/interview_system.md # 2. 고친다 vi patches/app/prompts/interview_system.md # 3. 적용 ./bin/apply-patches.sh --list # 무엇이 어디에 붙는지 먼저 확인 ./bin/apply-patches.sh # compose.patches.yml 생성 # 4. 반영 ./bin/up-compose.sh # up-docker-run.sh / up-podman-run.sh 도 자동으로 읽는다 ./bin/verify.sh ``` 해제: ```bash ./bin/apply-patches.sh --clear # compose.patches.yml 삭제 → 다음 기동부터 이미지 원본 ``` `compose.patches.yml` 은 생성물이다. 직접 고치지 말고 `patches/` 를 고친 뒤 다시 돌린다. ## 권한 (uid/gid) bind mount 는 호스트의 uid/gid 를 그대로 컨테이너에 넘긴다. 컨테이너는 앱 이미지와 처리 이미지 모두 uid 10001 로 도는데 호스트 파일은 보통 다른 uid 소유다. 읽기 전용 마운트라 **쓰기 권한은 필요 없고, 다른 사용자에게 읽히기만 하면 된다.** 파일 단위로 마운트하므로 디렉터리 권한은 무관하다 (데몬이 root 로 경로를 해석한다). 문제가 되는 경우는 하나다 — `umask 077` 인 호스트에서 파일을 만들면 `0600` 이 되어 컨테이너가 열지 못한다. 컨테이너는 정상으로 뜨고 그 파일을 **읽는 순간** Permission denied 로 실패하므로 알아채기 어렵다. `apply-patches.sh` 가 이걸 대신 처리한다. 1. 패치 파일 모드를 `a+r` 로 맞추고 무엇을 바꿨는지 출력한다. 2. 모드만 보고 넘기지 않고, **실제 이미지로 컨테이너를 띄워 그 사용자로 읽어 본다.** 못 읽으면 override 를 만들지 않고 멈춘다. 소유자가 달라 `chmod` 가 통하지 않으면(예: root 소유 파일) 경고 후 읽기 확인에서 멈춘다. 그럴 때는 소유권을 옮기거나 직접 `chmod a+r` 한다. SELinux enforcing 호스트라면 `SELINUX_LABEL=Z ./bin/apply-patches.sh` 로 마운트에 라벨을 붙인다 (`:ro` → `:ro,Z`). ## 주의 - **파일 단위로만** 덮어쓴다. 디렉터리를 통째로 마운트하면 이미지의 나머지 파일이 가려진다. 스크립트가 파일마다 마운트를 만들어 주므로 `patches/` 아래에 바꿀 파일만 두면 된다. - 프롬프트는 web·worker·scheduler 가 모두 읽는다. 스크립트가 앱 이미지를 쓰는 서비스 전체에 같은 마운트를 붙이므로 따로 신경 쓸 것은 없다. - 파이썬 코드를 바꿨다면 컨테이너가 새로 뜨면서 반영된다. --- ## 급할 때: 컨테이너 안에서 직접 고치기 **컨테이너를 다시 만들면 사라진다.** 장애 대응용 임시 조치로만 쓴다. ```bash docker exec -i pi-continuum-web-1 sed -i 's/old/new/' /app/prompts/interview_system.md docker restart pi-continuum-web-1 # 파이썬 코드를 고쳤다면 반드시 재시작 ``` - `/app` 최상위는 root 소유라 **새 파일은 못 만든다.** 하위 디렉터리(`prompts/`, `alpha/`, `apps_pi_continuum/` 등)는 실행 사용자(uid 10001) 소유라 수정된다. - 이미지에 `vi`·`nano`·`patch` 가 없다. `sed` 와 `python` 은 있다. 편집기가 필요하면 호스트에서 고쳐 `docker cp` 로 넣는다. - 파이썬 코드는 프로세스가 이미 import 한 뒤라 **재시작해야** 반영된다. `.pyc` 는 만들지 않으므로(`PYTHONDONTWRITEBYTECODE=1`) 캐시가 남을 걱정은 없다. - `docker restart` 는 유지되지만 `up --force-recreate`·`rm` 은 되돌린다. ## 바꿀 수 없는 것 프런트엔드는 Vite 가 **빌드 시점에** 번들로 굽는다. `.vue`·`.js` 소스를 고쳐도 화면은 바뀌지 않는다. `VITE_ENCRYPTION_KEY` 도 마찬가지다. 둘 다 폐쇄망 밖에서 이미지를 다시 빌드해 반입해야 한다. nginx 설정과 `postgres/init.sql` 은 이미지가 아니라 번들의 `conf/` 에서 마운트된다. 그 둘은 여기가 아니라 `conf/` 를 직접 고친다.