Skip to content

기획서: Frappe Docker 커스텀 이미지(Frappe + ERPNext + HRMS) 로컬 빌드

목적: 공식 frappe_docker는 ERPNext만 포함하므로, HRMS 등 추가 앱을 포함한 커스텀 이미지로컬에서 bench get-app(또는 apps.json) 방식으로 재빌드할 수 있도록, 그 구현 코드를 만들기 위한 기획·범위·경로·단계를 정의한다.
코드 생성 없음 — 기획·요구사항·산출물만 정리.

  • 배경: 공식 이미지 = Frappe Framework + ERPNext. HRMS·Payments 등은 앱 추가 후 이미지 재빌드로만 포함 가능.
  • 실행 환경: 로컬 머신(Mac/Linux)에서 Docker 빌드·태그·(선택) 레지스트리 푸시까지.

1. 공식 frappe_docker 구조 요약

구분설명
공식 이미지frappe/erpnext, frappe/bench 등 — Frappe + ERPNext 조합. HRMS 미포함.
앱 추가 방식프로덕션에서는 컨테이너 런타임에 bench get-app 불가. 빌드 시점에 앱을 포함해 이미지로 만들어야 함.
빌드 경로frappe_docker 리포의 images/custom/ 또는 images/layered/ + APPS_JSON_BASE64 (Base64 인코딩된 apps.json).
의존성HRMS는 ERPNext에 의존. apps.json에 ERPNext → HRMS 순으로 명시 필요.

2. Base 경로·산출물 위치 제안

구분경로용도
frappe_docker 클론로컬 작업 디렉터리 (예: ~/frappe_docker 또는 Prego 하위 tools/frappe_docker)공식 리포 클론 — custom/layered Containerfile 재사용.
앱 정의·빌드 스크립트동일 리포 내 apps.json, build.sh(또는 Makefile/docker build 래퍼)HRMS 포함 앱 목록·로컬 빌드 실행.
생성 이미지 태그로컬: prego-frappe-erpnext-hrms:VERSION (또는 프로젝트 네이밍 규칙에 맞게)Ansible 등에서 frappe_bench_image 변수로 참조.
  • 선택: Prego 레포에 tools/frappe-docker-build/ 같은 디렉터리를 두고, apps.json + 빌드 스크립트만 두고 frappe_docker는 git submodule 또는 문서상 “클론 경로”로 안내할 수 있음.

3. 기술 요구사항

3.1 apps.json 형식 (frappe_docker 공식)

  • JSON 배열. 각 요소: url(Git HTTPS), branch.
  • 순서: Frappe는 이미 bench init에 포함되므로, 추가 앱만 나열. ERPNext → HRMS 순 (의존성 순).
  • 예시 (ERPNext + HRMS):
    • ERPNext: https://github.com/frappe/erpnext, version-15 (또는 version-16)
    • HRMS: https://github.com/frappe/hrms, version-15 (또는 version-16)
  • Private 리포: HTTPS URL에 Personal Access Token 포함. 예: https://${GITHUB_TOKEN}@github.com/org/repo.git. 토큰은 환경변수로만 전달·빌드 로그에 노출되지 않도록.

3.2 빌드 인자 (Build Args)

인자설명예시
APPS_JSON_BASE64apps.json 내용을 Base64 인코딩한 문자열.echo -n "$(cat apps.json)" | base64 (macOS: base64 -i apps.json -o - 등)
FRAPPE_BRANCHFrappe 프레임워크 브랜치.version-15, version-16
FRAPPE_PATH(선택) Frappe 리포 URL. 커스텀 fork 시 사용.기본: https://github.com/frappe/frappe

3.3 이미지 빌드 방식 두 가지

방식경로특징
customimages/custom/Containerfile베이스가 python:3.x-slim부터 시작. 전체 툴체인 포함. 빌드 시간 길고 이미지 크기 큼.
layeredimages/layered/Containerfilefrappe/build, frappe/base 사용. 공식 빌드 캐시 활용. 빌드 시간·크기 유리.
  • 권장: 로컬에서 재현성·속도 고려 시 layered 우선. custom은 Frappe 버전·툴체인을 완전히 자체 제어할 때.

4. 로컬 빌드 단계 (구현 시 코드가 수행할 흐름)

순서단계담당(구현 시)비고
1frappe_docker 클론/업데이트스크립트 또는 수동git clone / git pull (동일 경로 재사용 시).
2apps.json 작성/배치코드 또는 수동ERPNext + HRMS (및 필요 시 payments 등) 정의. 버전(브랜치)은 변수/설정으로.
3APPS_JSON_BASE64 생성스크립트apps.json → Base64. 환경변수 또는 빌드 시 --build-arg로 전달.
4Docker 빌드 실행스크립트docker build --build-arg FRAPPE_BRANCH=version-15 --build-arg APPS_JSON_BASE64=... -f images/layered/Containerfile -t prego-frappe-erpnext-hrms:15 . (실제 태그는 네이밍 규칙에 맞게).
5(선택) 로컬 실행 검증수동/스크립트docker run 또는 기존 docker-compose에서 해당 이미지로 사이트 생성·HRMS 설치 확인.
6(선택) 레지스트리 푸시스크립트Private 레지스트리 사용 시 docker push. CI에서 할 경우 GitHub Actions 등에서 수행.

5. 사전 조건 (로컬 환경)

항목설명확인 방법
DockerDocker Engine (Docker Desktop 포함) 설치.docker version
Gitfrappe_docker 클론용.git --version
디스크 공간이미지 빌드 시 수 GB 이상 필요.df -h
네트워크GitHub 등 Git 접근. Private 리포 시 토큰.git ls-remote https://github.com/frappe/hrms
(선택) FRAPPE_BRANCH 일치ERPNext·HRMS·Frappe 브랜치 버전 일치 권장.예: 모두 version-15 또는 모두 version-16.

6. 산출물 (구현 후 기대)

산출물설명
apps.jsonERPNext, HRMS( 및 필요 시 기타 앱)의 url/branch 정의. 버전은 한 곳에서 관리 가능하도록.
빌드 스크립트build.sh 또는 유사. APPS_JSON_BASE64 생성 → docker build 실행. 인자: FRAPPE_BRANCH, 이미지 태그 등.
(선택) Makefilemake build, make push 타깃.
(선택) README로컬에서 빌드하는 방법, 사전 조건, 환경변수(GITHUB_TOKEN 등), Ansible에서 이미지 교체 방법 요약.
Docker 이미지로컬에 prego-frappe-erpnext-hrms:<tag> (또는 합의된 이름). Ansible frappe_bench_image 에서 이 태그 사용 가능.

7. Ansible·운영 연계

항목내용
이미지 교체prego-ansible의 roles/frappe_bench/defaults/main.yml 등에서 frappe_bench_image를 커스텀 이미지 태그로 변경. (예: prego-frappe-erpnext-hrms:15.)
사이트 생성 시 앱bench new-sitebench --site <site> install-app hrms 등은 이미 이미지에 포함된 앱이므로 설치만 하면 됨.
버전 고정동일 브랜치(예: version-15)로 이미지 빌드 시, 배포·롤백은 동일 이미지 태그로 일관 유지.

8. 트러블슈팅·참고

이슈대응
빌드 중 메모리 부족Docker Desktop 메모리 상향, 또는 layered 빌드 사용으로 단계별 캐시 활용.
HRMS 설치 실패(의존성)apps.json에 ERPNext가 HRMS보다 먼저 오는지 확인.
Private 리포 403HTTPS URL에 PAT 포함, 빌드 로그에 토큰이 안 나오도록 스크립트에서만 환경변수로 전달.
macOS base64base64 -i apps.json 출력 시 줄바꿈 제거. `base64 -i apps.json
공식 문서frappe_docker custom-apps, images/custom, images/layered.

9. 구현 시 체크리스트 (코드 작성 단계용)

  • frappe_docker 클론/경로 결정 (Prego 하위 vs 별도 디렉터리).
  • apps.json 템플릿 작성 (ERPNext + HRMS, 브랜치 변수화 가능 여부).
  • Base64 생성 로직 (로컬 스크립트·macOS/Linux 호환).
  • docker build 호출 (custom vs layered 선택, build-arg 전달).
  • 이미지 태그 네이밍 (naming-conventions.md와 통일: 예 prego-frappe-erpnext-hrms:15).
  • (선택) CI에서 빌드·푸시 시 Docker 레지스트리 인증·태그 전략.
  • docs/runbook 또는 README에 “로컬에서 HRMS 포함 이미지 빌드” 절 추가.

10. 멀티플랫폼 빌드 및 Docker Hub 업로드 가이드

로컬 환경에서 Intel/AMD(amd64)와 ARM(arm64) 두 아키텍처만 지원하는 Frappe/ERPNext v15 Docker 이미지를 만들고, Docker Hub에 하나의 매니페스트로 푸시하는 절차·설계 원칙을 정리한다. linux/386(32비트) 등 레거시는 지원하지 않으며, AWS·Oracle Ampere·GCP 등 실제 클라우드 환경에서 즉시 가동 가능한 Production-Ready 표준을 따른다. 코드는 생성하지 않고 가이드만 기술.


10.1 목적 및 범위

항목내용
목적단일 아키텍처가 아닌 멀티플랫폼(amd64 + arm64) 이미지를 빌드해, x86_64 서버(Intel Xeon 등)·ARM 서버(Ampere Altra, Mac M1/M2 등)에서 동일 태그로 풀 받아 사용할 수 있게 한다.
지원 플랫폼linux/amd64, linux/arm64만. 32비트(linux/386)는 미지원.
범위Dockerfile 구조 전략(Multi-stage·멀티 아키텍처 최적화), docker buildx를 이용한 로컬 빌드·푸시, Docker Hub 인증·매니페스트 검증.
비범위Dockerfile·스크립트 본문(구현 시 별도 작성).

10.2 Dockerfile 설계 원칙 (Multi-Arch 최적화, 권한 문제 해결 최종 버전)

다양한 CPU 아키텍처에서 빌드 시 발생할 수 있는 바이너리 호환성 문제와 Frappe bench 권한 정책을 반영한 구조를 따른다.

원칙내용
2단계 빌드 (Builder / Final)Stage 1 (Builder): 베이스 --platform=$BUILDPLATFORM. rootmkdir -p sites, common_site_config.json(socketio_port 등) 생성 후 **chown -R frappe:frappe /home/frappe/frappe-bench**로 소유권 부여. 그 다음 반드시 USER frappe로 전환한 뒤 bench get-app hrms ..., bench build --app hrms 실행. Builder 결과물(apps/hrms, sites/assets)만 Final로 복사. Stage 2 (Final): root로 COPY·mkdir -p sites·chown -R frappe:frappe sitesUSER frappe, HEALTHCHECK, EXPOSE 8000.
권한(USER) 전환 — 필수bench 명령은 root에서 실행하면 안 된다. Frappe는 “You should not run this command as root” 경고 후 exit code 1로 종료한다. Builder에서 설정 파일·디렉터리 생성은 root로 수행해도 되지만, **bench 실행 전에 반드시 USER frappe**를 선언해야 빌드가 성공한다.
경량화·보안(Hardening)최종 이미지에 빌드 도구를 넣지 않아 이미지 크기·요새화를 유지한다.
권한·헬스체크Final 스테이지에서 USER frappe(최소 권한), HEALTHCHECK(예: curl -f http://localhost:8000/api/method/ping || exit 1)로 가용성 확인.

SRE 인사이트 (권한 실패 원인)
Frappe는 **방어적 설계(Defensive Design)**로 root에서의 bench 실행을 금지한다. root로 앱을 설치해 두면, 런타임에 frappe 일반 사용자가 로그·캐시를 쓸 때 Permission Denied가 나와 서비스가 멈출 수 있다. 이를 막기 위해 빌드 단계에서부터 frappe 사용자로 bench를 실행하도록 해야 한다.

  • 구현 시 Dockerfile: Builder에서 root 작업 후 chown -R frappe:frappe ...USER frappe → 그 다음에만 RUN bench get-app ... && bench build --app hrms. Final에서는 COPY 후 권한 정리·USER frappe·HEALTHCHECK·EXPOSE.

10.3 지원 플랫폼 및 이식성

플랫폼용도
linux/amd64Intel/AMD x86_64 서버(Hetzner, AWS, GCP 등).
linux/arm64ARM 기반 서버(Oracle Ampere, AWS Graviton, Mac M1/M2 등).
  • 미지원: **linux/386(32비트 x86)**은 레거시로 간주하여 지원하지 않는다. 실제 클라우드·프로덕션 환경에서 널리 쓰이는 amd64·arm64만 대상으로 한다.
  • 이식성(Portability): 사용자는 docker pull USER/repo:TAG아키텍처를 지정하지 않아도 Docker가 매니페스트를 보고 현재 CPU에 맞는 이미지를 받는다. Intel Xeon(x86) 서버에서도, Ampere Altra(ARM) 서버에서도 별도 수정 없이 동일 태그로 최적화되어 실행된다(인프라 유연성).

10.4 로컬 빌드 절차 (buildx)

멀티 아키텍처 이미지는 로컬 Docker 엔진에 한 번에 저장할 수 없으므로, 빌드와 동시에 Docker Hub로 푸시하는 것이 표준 방식이다. 순서대로 진행한다.

순서단계요약
1빌더 엔진 초기화 (최초 1회)docker buildx create --name prego-builder --use, 이어서 docker buildx inspect --bootstrap. 멀티 플랫폼 지원용 전용 빌더 생성·활성화. 이미 있으면 생략 가능.
2Docker Hub 로그인docker login -u <Docker_Hub_아이디> (예: iamfork). Password 입력란에 Personal Access Token(PAT) 붙여넣기.
3통합 빌드 및 자동 푸시아래 최종 빌드 명령 실행. --push로 빌드 성공 시 바로 Docker Hub로 전송.
4결과 확인(Verification)푸미널: docker buildx imagetools inspect iamfork/prego-erpnext:v1.1.0두 아키텍처(amd64, arm64)의 Digest가 출력되면 성공. Docker Hub 웹: 해당 레포 → Tags → 해당 태그에서 OS/ARCHlinux/amd64linux/arm64 두 가지로 표시되는지 확인.

최종 빌드 명령 (권한 수정 Dockerfile 적용 후)
Dockerfile을 저장한 뒤, 프로젝트 루트에서 다음을 실행한다. 기존 빌드 캐시가 꼬였을 수 있으므로 동일 명령으로 재실행하면 된다.

docker buildx build \
--platform linux/amd64,linux/arm64 \
-t iamfork/prego-erpnext:v1.1.0 \
--push .
  • 재빌드 가이드: 수정된 Dockerfile(USER frappe 전환) 적용 후 위 명령을 그대로 다시 실행. 한 번 성공하면 이후 빌드는 캐시가 작동하여 수십 초 내에 끝날 수 있다. (첫 빌드 시 베이스 이미지 다운로드로 수 분 소요 가능.)
  • 주의: 일반 docker build + docker push는 단일 아키텍처만 푸시한다. 멀티 아키텍처는 buildx로 여러 플랫폼을 하나의 **매니페스트 리스트(Manifest List)**로 묶어 푸시해야 한다.

10.5 매니페스트 리스트의 의미 (Principal Engineer 인사이트)

항목내용
사용자 경험사용자가 docker pull iamfork/prego-erpnext:v1.1.0을 실행할 때, 아키텍처를 고민할 필요가 없다. Docker 엔진이 Docker Hub에 저장된 매니페스트 리스트를 보고, 현재 CPU에 맞는 레이어만 골라 내려받는다.
인프라 유연성동일 이미지 태그로 Intel Xeon(x86) 서버와 Ampere Altra(ARM) 서버 등에서 별도 수정 없이 docker pull만으로 최적화되어 실행된다. Production-Ready 표준.
설계 원칙구글 SRE가 지향하는 **“인프라의 복잡성을 사용자로부터 추상화하는 설계”**에 부합한다.

10.6 기획서·운영과의 연계

문서연동
§1~8 본 기획서apps.json·layered/custom 빌드·로컬 단계는 그대로 두고, 빌드 실행 단계에서 buildx·—platform·—push를 사용하는 것으로 확장.
docker-hub-stack-ansible-deploy-plan.mdAnsible에서 사용할 이미지가 iamfork/prego-erpnext:v1.1.0 등 멀티플랫폼 태그일 때, 배포 대상 서버(amd64/arm64 등)에 맞는 레이어가 자동으로 풀된다.
naming-conventions.md이미지 이름·태그 규칙과 통일.

다음 단계: 이 기획서를 바탕으로 실제 apps.json, 빌드 스크립트, (선택) Makefile·README를 구현한다. 멀티플랫폼 적용 시 Dockerfile을 2단계(Builder/Final)로 구성하고, 빌드 명령은 docker buildx build --platform ... --push를 사용한다.
관련 문서: naming-conventions.md, ansible-frappe-bench-rc127-resolution-plan.md(이미지·bench 경로), docker-hub-stack-ansible-deploy-plan.md, IMPLEMENTATION_INDEX.md.

Help