BizCoder 온프렘 설치·사용 가이드

ENTERPRISE AI CODING AGENT

BizCoder 온프렘 설치·사용 가이드

사내 Kubernetes · Helm 위에 BizCoder 를 올리고, 사내 onpod · 사내 GitLab · Azure OpenAI 와 연결해 직원이 쓰기까지

번들 버전
번들 안 bundle.env 참고
설치·운영 대상
시스템 아키텍처팀 · 플랫폼 운영자
사용 대상
직원 · 조직 관리자
작성일
2026-10-27 · 주식회사 AI3
지원 문의
support@onpod.ai

스크린샷을 누르면 원본 크기로 열려요. 표·코드·구성도는 좌우로 밀어서 볼 수 있어요.

목차 보기

독자별 안내

누가어디를 읽나요
플랫폼 운영자 (설치)2장 준비물 → 3장 설치 → 4장 첫 로그인·SSO → 7장 업그레이드 → 8장 보안 → 9장 문제 해결
조직 관리자4장 초기 설정 → 6장 관리자 운영(멤버·좌석·배포 승인·감사 로그)
직원5장 직원 사용법 (GitLab 연결 → 새 작업 → 결과 확인 → 배포)

이 가이드는 번들과 별도로 제공돼요. 번들 안의 MANUAL.ko.md 는 같은 설치 절차의 텍스트 판이에요. 화면 캡처는 예시 회사 「예시 주식회사」, 도메인 corp.example 로 구성한 실제 구동 화면이에요.

1. 개요와 구성도

1.1 BizCoder 온프렘이 하는 일

사내 Kubernetes 에 BizCoder 를 올리면, 직원이 사내 브라우저로 접속해 AI 코딩 에이전트에게 일을 시킬 수 있어요. 코딩 작업은 사내 onpod 가 띄우는 샌드박스에서 실행되고, 결과물은 사내 GitLab 에 커밋·푸시·MR 로 쌓여요. 배포하면 사내 onpod 가 https://<앱 이름>.<onpod 도메인> 주소를 만들어 줘요. LLM 은 Azure OpenAI(또는 OpenAI 호환 사내 게이트웨이)를 쓰고, 인터넷으로 나가는 호출은 없어요.

  1. 직원이 사내 브라우저로 BizCoder 웹 화면에 접속해 저장소 주소와 하고 싶은 일을 적어요.
  2. BizCoder 가 사내 onpod 에 샌드박스 Pod 를 만들어요. 코딩 에이전트는 이 Pod 안에서 일하고, 샌드박스는 소스 파일만 받아요.
  3. LLM 호출은 BizCoder 의 LLM 프록시를 거쳐 Azure OpenAI 로 가요. LLM 키와 Git 토큰은 BizCoder 서버에만 있어요.
  4. 결과는 사내 GitLab 에 브랜치로 커밋·푸시되고 Merge Request 가 자동으로 만들어져요. 클론·푸시·MR 은 BizCoder 가 대신해요.
  5. 「배포까지 한 번에」를 켜면 사내 onpod 에 배포돼 https://<이름>.<onpod 도메인> 주소가 나와요. 기본 공개 범위는 「우리 회사 사람만」(로그인 필요)이에요.
인터넷으로 나가는 호출은 없어요 BizCoder 파드의 송신을 클러스터와 사내망으로만 제한한 상태에서도 코딩 → MR → 배포 전체가 끝까지 동작해요. 외부 SaaS 에 기대는 기능(GitHub·구글 로그인, 결제, 이미지·영상 생성 등)은 설치본에서 꺼져 있어요(8.4절).

1.2 구성도

직원 브라우저 사내망 ALB / Ingress HTTPS 사내 Kubernetes 클러스터 namespace: bizcoder BizCoder Deployment · :8077 웹 UI · API LLM 프록시 Git 중계 (클론 · 푸시 · MR) onpod 클라이언트 1 PostgreSQL 번들 StatefulSet 또는 사내 DB 2 Azure OpenAI 또는 OpenAI 호환 사내 게이트웨이 엔드포인트·키·모델은 values 로 지정 LLM 호출 3 사내 onpod (온프렘) 샌드박스 Pod 비밀키 없음 · 소스 파일만 서버 빌드 샌드박스 이미지 · 앱 빌드 앱 배포 https://<앱>.<onpod 도메인> 기본 공개 범위: 우리 회사 사람만 onpod API 호출 :8077 로만 호출 4 사내 GitLab 클론 · 푸시 · MR · 웹훅 git 클론·푸시·MR 웹훅(push) 배포된 앱은 직원 브라우저가 https://<앱>.<onpod 도메인> 주소로 직접 접속해요 인터넷 호출 없음 모든 연결은 사내망·클러스터 안에서만 이어져요. 샌드박스는 BizCoder :8077 만 불러요.

실선은 BizCoder 가 거는 호출, 점선은 샌드박스 Pod 가 BizCoder 로 거는 호출이에요. GitLab 과는 양방향이에요(웹훅은 GitLab → BizCoder).

구성 요소하는 일위치
BizCoder웹 화면·API, LLM 프록시, git 중계(클론·푸시·MR), onpod 호출. LLM 키·Git 토큰은 여기에만 있어요.네임스페이스 bizcoder 의 Deployment bizcoder (포트 8077)
1 PostgreSQLBizCoder 가 쓰는 데이터베이스. 번들 PostgreSQL 은 소규모·PoC 용이고, 운영은 사내 DB 를 권장해요.번들 StatefulSet 또는 사내 DB
2 Azure OpenAILLM. BizCoder 의 LLM 프록시만 호출해요. 엔드포인트·키·모델 매핑은 values 로 지정해요.사내 또는 Azure (사내망에서 도달 가능해야 해요)
3 사내 onpod샌드박스 Pod 실행, 서버 빌드(샌드박스 이미지·앱 빌드), 앱 배포. BizCoder 는 회사 조직의 서비스용 API 키 1개로 호출해요.Kubernetes 앱 서버가 등록된 사내 onpod
4 사내 GitLab저장소. 푸시 자동 배포를 쓰면 push 때 GitLab 이 BizCoder 로 웹훅을 보내요.사내 GitLab
샌드박스 Pod코딩 에이전트가 실행되는 곳. 비밀키가 없고 클러스터 안에서 BizCoder :8077 만 불러요.onpod 가 띄우는 Pod

2. 준비물과 용량 산정

2.1 준비물

항목내용
Kubernetes1.25 이상. Ingress 컨트롤러(예: AWS Load Balancer Controller) 또는 LoadBalancer. 번들 DB 를 쓰면 기본 StorageClass 가 있어야 해요.
사내 onpod (온프렘)Kubernetes 앱 서버가 등록돼 있고, 컨트롤플레인에 ONPOD_SANDBOX_API_ENABLED=1 과 서버 빌드 API(ONPOD_BUILD_API_ENABLED=1)가 켜져 있어야 해요. 꺼져 있으면 3장의 provision.sh 가 알려 주고 켜는 방법을 출력해요.
회사 조직onpod 에 회사 조직(org)이 있고 관리자 토큰이 있어야 해요. BizCoder 는 이 조직의 서비스용 API 키 1개로 onpod 를 호출해요.
이미지 저장소번들의 앱 이미지·DB 이미지를 올릴 사내 레지스트리 (또는 각 노드에 미리 로드).
LLMAzure OpenAI 리소스 + 모델 배포 이름 + 키. 또는 /v1/chat/completions 호환 사내 게이트웨이.
사내 CAALB·GitLab·onpod 의 인증서를 발급한 사내 루트 CA(PEM). 공인 인증서만 쓰면 필요 없어요.
라이선스도입 시 받은 .lic 파일(서명된 JSON).
관리자 PC 도구helm 3.12+, kubectl, curl, python3(라이선스 서명 검증을 쓰려면 python cryptography 도). 이미지를 올릴 때만 docker.
직원 쪽사내 브라우저, 사내 SSO 계정(OIDC), 사내 GitLab 개인 액세스 토큰(5장).

2.2 설치 전에 꼭 확인할 세 가지

이 세 가지는 나중에 알게 되면 설치가 멈춰요
  1. onpod 의 샌드박스 API·서버 빌드 API 가 켜져 있나요? onpod 차트 values 의 controlplane.extraEnv 에 ONPOD_SANDBOX_API_ENABLED: "1" 을 넣어요. 꺼져 있으면 provision.sh 가 501 로 알리고 켜는 법을 출력한 뒤 멈춰요(3.3절).
  2. 코딩 에이전트(CLI)는 x86-64 에서 AVX2 를 지원하는 CPU 가 필요해요. 가상머신이면 호스트 CPU 기능 전달 설정을 확인하세요. 3.6절의 preflight.sh --smoke-sandbox 에서 「샌드박스 CLI 실행」 항목이 미리 알려 줘요.
  3. onpod 회사 조직과 관리자 토큰이 있어야 해요. 조직이 없으면 provision.sh --create-org "회사 이름" 으로 만들 수 있어요. 토큰을 따로 주지 않으면 provision.sh 가 kubectl 로 onpod 컨트롤플레인에서 읽어요.

2.3 용량 산정 — 동시에 몇 건까지 코딩할 수 있나요

코딩 작업 1건은 onpod 샌드박스 1개를 써요. 그래서 동시 코딩 작업 수는 onpod 가 가진 해당 크기 슬롯의 수예요. 샌드박스 크기는 values 의 onpod.sandbox.class(nano | micro | small | medium)로 정하고, 기본값 small 은 2 vCPU · 4 GiB 한도로 onpod 의 cpu_medium 슬롯 1개를 써요.

온프렘 onpod 는 호스트(클러스터)의 RAM 에서 슬롯을 잘라 내요.

사용 가능 RAM = 전체 RAM × (100 − 예약%)  (기본 예약 20%)
크기별 슬롯 수 = 사용 가능 RAM × 크기별 비율 ÷ 슬라이스 크기  (RAM 이 작아도 각 크기 최소 1개)
슬라이스 크기microsmallmediumlarge
한 슬롯의 RAM512 MiB2 GiB4 GiB8 GiB
기본 비율 (ONPOD_ONPREM_SLOT_MIX)20%40%25%15%

예) RAM 16 GiB 서버 — 사용 가능 12.8 GiB 중 medium 몫은 3.2 GiB 이고 슬롯 하나가 4 GiB 라서 계산상 1개에 못 미치지만 최소 1개가 보장돼요. 그래서 medium 슬롯 1개, 곧 동시 코딩 1건이에요.

용량은 넉넉히 잡으세요
  • 슬롯이 없으면 작업이 잠시 대기(최대 약 4분)하다 실패할 수 있어요. 직원이 몰리는 시간대 동시 작업 수를 기준으로 슬롯을 계산하세요.
  • 배포된 앱도 같은 슬롯을 써요. 배포 앱의 기본 크기는 cpu_2c_4g(= medium)이고, values 의 deploy.appShape 로 cpu_small 등으로 낮출 수 있어요. 정적 사이트가 대부분이면 낮추는 것을 권장해요.

BizCoder 자체 요구량(차트 기본값)

대상requestslimits비고
BizCoderCPU 500m · 메모리 1Gi메모리 4Gi/tmp 최대 10Gi (저장소 클론·빌드 컨텍스트 임시 공간), 레플리카 1
번들 PostgreSQLCPU 250m · 메모리 512Mi메모리 2GiPVC 20Gi (postgres.persistence.size)

3. 설치 (5단계)

설치는 번들 폴더 안에서 실행해요. 예시의 bizcoder 는 네임스페이스이자 릴리스 이름이에요. 아래 5단계를 순서대로 하면 끝나요.

1단계번들 확인 · 이미지 올리기
2단계provision.sh
키 · Secret · 샌드박스 이미지
3단계values 작성
my-values.yaml
4단계helm 설치
helm upgrade --install
5단계preflight 점검
첫 로그인

3.1 번들 구성

bizcoder-onprem-<태그>-amd64/
├─ images/
│   ├─ bizcoder-app.tar                  앱 이미지
│   ├─ bizcoder-sandbox-rootfs.tar.gz    샌드박스 이미지의 rootfs
│   └─ postgres.tar                      번들 DB 이미지
├─ Dockerfile.sandbox                    샌드박스 이미지 정의 (FROM scratch + ADD rootfs)
├─ helm/bizcoder/                        Helm 차트
├─ scripts/                              provision.sh · preflight.sh · seed-sandbox-image.sh · lib.sh
├─ argocd/                               Application · ExternalSecret · SealedSecret 안내
├─ values.example.yaml                   OpenAI 호환 게이트웨이용 예시 values
├─ values.azure.example.yaml             Azure OpenAI 용 예시 values
└─ bundle.env · SHA256SUMS · MANUAL.ko.md

3.2 1단계 — 번들 확인 · 이미지 올리기

sha256sum -c bizcoder-onprem-<태그>-amd64.tar.gz.sha256        # macOS: shasum -a 256 -c …
tar xzf bizcoder-onprem-<태그>-amd64.tar.gz && cd bizcoder-onprem-<태그>-amd64
sha256sum -c SHA256SUMS                                          # 모든 파일이 OK 여야 해요
docker load -i images/bizcoder-app.tar                           # 앱 이미지
docker load -i images/postgres.tar                               # 번들 DB 를 쓸 때만
# 사내 레지스트리로 재태그해서 push (노드에 직접 로드하는 환경이면 건너뛰어도 돼요)
docker tag  $(sed -n 's/^APP_IMAGE=//p' bundle.env) registry.corp.example/bizcoder/wrks-code:$(sed -n 's/^APP_TAG=//p' bundle.env)
docker push registry.corp.example/bizcoder/wrks-code:$(sed -n 's/^APP_TAG=//p' bundle.env)

3.3 2단계 — 서비스 키 · Secret · 샌드박스 이미지 만들기 (provision.sh)

scripts/provision.sh \
  --onpod-url https://api.onpod.corp.example --cacert ca.crt \
  --license bizcoder.lic --azure-key-from-stdin \
  --public-base-url https://bizcoder.corp.example

이 한 번으로 아래 8단계가 끝나요. 여러 번 실행해도 이미 만든 비밀은 건드리지 않아요. Azure 키는 표준입력(없으면 프롬프트)에서 읽어요.

scripts/provision.sh 실행 화면 — [1/8]~[8/8] 단계가 차례로 끝나요
그림 1. scripts/provision.sh 실행 화면 — [1/8]~[8/8] 단계가 차례로 끝나요
단계하는 일
[1/8] onpod 확인onpod 에 연결해 에디션(onprem)·앱 주소 규칙·라이선스 상태를 확인해요.
[2/8] 샌드박스 API / 서버 빌드 API둘 다 켜져 있는지 확인해요. 꺼져 있으면(501) 켜는 방법을 정확히 출력하고 멈춰요.
[3/8] 회사 조직 확인이 토큰이 속한 조직과 역할을 확인해요. 조직이 없으면 안내만 하고 만들지 않아요(--create-org 를 줄 때만 만들어요).
[4/8] 서비스용 org API 키서비스 키를 발급해 Secret bizcoder-onpod 에 저장하고(값은 화면에 나오지 않아요) 스코프별로 점검해요.
[5/8] 앱 비밀WRKS_SECRET_KEY·DB 비밀번호·로그인 접근 코드를 만들어 Secret bizcoder-app·bizcoder-db·bizcoder-dev-login 에 저장해요.
[6/8] 라이선스 · 사내 CA · LLM 키Secret bizcoder-license·bizcoder-ca·bizcoder-azure 를 만들어요.
[7/8] 샌드박스 이미지번들의 rootfs 로 사내 onpod 서버 빌드를 실행해 샌드박스 이미지를 만들어요. 외부 레지스트리·인터넷이 필요 없어요. 결과 별칭은 onpod://bizcoder-sandbox:<버전>.
[8/8] values 조각위 값들을 담은 values.generated.yaml 을 출력해요(비밀값 없음 — Secret 이름만 참조).

만들어지는 Secret

Secret키내용
bizcoder-onpodtoken서비스용 org API 키 (BizCoder → onpod 호출용)
bizcoder-appWRKS_SECRET_KEY저장값 암호화 키(Fernet). 한 번 정하면 바꾸지 마세요 — 저장된 암호화 값이 읽히지 않게 돼요.
bizcoder-dbpassword번들 PostgreSQL 비밀번호
bizcoder-dev-logincode첫 관리자 로그인 접근 코드
bizcoder-licenselicense.json서명된 라이선스
bizcoder-caca.crt사내 CA(PEM) — 공개 인증서
bizcoder-azureapi-keyAzure OpenAI 키

서비스 키 스코프

org:read · org:write 가 들어 있는 이유 서비스 키의 스코프는 sandboxes:* builds:* pods:* static:* 에 더해 org:read org:write 예요. 배포물을 「사내 전용」으로 걸고, 승인제에서 승인 전까지 잠그는 데 필요해요. onpod 는 키 발급·초대·멤버 변경·조직 삭제를 스코프 키로는 못 하게 막아 두었어요(계정 관리급). --without-site-access 로 이 둘을 뺄 수 있지만, 배포 정책이 「자유」이고 공개 범위를 BizCoder 가 걸 필요가 없는 환경에서만 쓰세요. 승인제에서는 배포가 되돌려져요(9장).

자주 쓰는 옵션

옵션설명
--onpod-url URL(필수) 사내 onpod API 주소
--admin-token-file · --admin-token-env · --admin-token-stdin관리자 토큰 전달(하나만). 안 주면 kubectl 로 onpod 컨트롤플레인(기본 네임스페이스 onpod)에서 읽어요.
--cacert FILE사내 CA PEM. BizCoder 파드도 이 CA 를 신뢰하도록 Secret 으로 저장해요.
--create-org NAME회사 조직이 아직 없을 때만 이 이름으로 만들어요.
--org-key-name NAME · --rotate-key같은 이름의 서비스 키(기본 bizcoder-service)가 이미 있을 때 — 다른 이름을 주거나, 기존 키를 회수하고 새로 발급해요.
--azure-key-from-stdin · --azure-key-file FILEAzure OpenAI 키를 읽어 Secret bizcoder-azure 에 저장해요. OpenAI 호환 게이트웨이면 --openai-key-from-stdin, APIM 등 추가 헤더는 --llm-extra-headers-file.
--namespace NS · --kube-context CTX대상 네임스페이스(기본 bizcoder)와 kubectl 컨텍스트
--sandbox-class C · --skip-sandbox-imagevalues 에 넣을 샌드박스 크기(기본 small) / 샌드박스 이미지 빌드 건너뛰기
--dry-run읽기 조회만 하고 조직·키·Secret·빌드는 바꾸지 않아요. 계획만 확인할 때 써요.
--emit-yaml DIR클러스터에 적용하지 않고 Secret 매니페스트를 파일(권한 600)로 저장해요. SealedSecret·ExternalSecret 을 쓰는 GitOps 용이에요(7.3절).
--ignore-sandbox-api샌드박스·빌드 API 가 꺼져 있어도 계속 진행해요(나중에 켤 계획일 때). 켜기 전에는 샌드박스 이미지를 만들 수 없어요.
샌드박스 API 가 꺼져 있으면 (501) provision.sh 가 「샌드박스 API 가 꺼져 있어요 (GET /v1/sandboxes → 501)」를 출력하고 멈춰요. onpod 컨트롤플레인에 환경변수를 켜세요. 서버 빌드가 꺼져 있으면 ONPOD_BUILD_API_ENABLED=1 도 같은 방법으로 켜요.
# onpod 차트 values — Helm/Argo 로 운영하면 이 방법을 권장해요 (재배포해도 유지돼요)
controlplane:
  extraEnv:
    ONPOD_SANDBOX_API_ENABLED: "1"
그 뒤 helm upgrade 또는 Argo CD 동기화를 하고, 컨트롤플레인이 다시 뜨면 provision.sh 를 다시 실행하세요. 임시로 바로 켜려면 kubectl -n onpod set env deploy/onpod-controlplane ONPOD_SANDBOX_API_ENABLED=1 뒤 rollout restart 를 하면 되지만 Argo CD 가 되돌릴 수 있어요.

출력: values.generated.yaml

3단계에서 my-values.yaml 과 함께 쓰는 값 조각이에요. 비밀값은 없고 Secret 이름만 들어 있어요.

publicBaseUrl: https://bizcoder.corp.example
onpod:
  apiUrl: https://api.onpod.corp.example
  tokenSecret: {name: bizcoder-onpod, key: token}
  caSecret: {name: bizcoder-ca, key: ca.crt}
  sandbox: {image: "onpod://bizcoder-sandbox:<버전>", class: small}   # 샌드박스 이미지 별칭
secretKey: {existingSecret: bizcoder-app, key: WRKS_SECRET_KEY}
postgres:
  auth: {existingSecret: bizcoder-db, passwordKey: password}
license: {existingSecret: bizcoder-license, key: license.json}
llm:
  azure: {existingSecret: bizcoder-azure, keyKey: api-key}
auth:
  devLogin:
    secretRef: {name: bizcoder-dev-login, key: code}

3.4 3단계 — values 작성

번들의 values.azure.example.yaml(OpenAI 호환 게이트웨이는 values.example.yaml)을 복사해 my-values.yaml 로 고쳐요. values.generated.yaml 이 채워 준 값은 다시 적지 않아도 돼요.

꼭 채울 곳값
image.repository · image.tag1단계에서 이미지를 올린 사내 레지스트리 주소 / bundle.env 의 APP_TAG
publicBaseUrl직원이 접속하는 HTTPS 주소(ALB). 끝에 / 를 붙이지 않아요. 쿠키·초대 링크·Git 웹훅이 이 주소를 써요.
llm.*LLM 종류(azure 또는 openai)·엔드포인트·모델·단가
ingress.*className, ALB 어노테이션(annotations), TLS
빠뜨려도 반쯤 설치되지는 않아요 필수 값이 비어 있으면 helm install 이 BizCoder 차트 값 검증 실패 와 함께 어느 값이 비었는지 알려 주며 실패해요. 알 수 없는 키나 잘못된 값도 values.schema.json 이 거절해요.

Azure OpenAI 예시 (my-values.yaml 의 핵심)

image:
  repository: registry.corp.example/bizcoder/wrks-code   # 1단계에서 올린 사내 레지스트리 주소
  tag: <bundle.env 의 APP_TAG>

publicBaseUrl: https://bizcoder.corp.example             # 직원이 접속하는 HTTPS 주소(ALB)

llm:
  kind: azure
  azure:
    endpoint: https://<리소스 이름>.openai.azure.com    # Azure OpenAI 리소스 주소
    apiVersion: v1                  # GA v1 API. 날짜 버전이면 클래식(배포 이름) 주소
    auth: api-key                   # api-key | bearer | both
    existingSecret: bizcoder-azure  # provision.sh 가 만든 Secret
    keyKey: api-key
  models:
    main: gpt-4.1                   # 사용자 화면의 모델 id (= Azure 배포 이름)
    fallback: gpt-4.1-mini
    curated: [gpt-4.1, gpt-4.1-mini]
  modelMap: {}                      # 배포 이름이 다르면 매핑. 예: {gpt-4.1: my-gpt41-deployment}
  prices:                           # KRW / 1M tokens — 예산·사용액 집계 기준
    gpt-4.1:      {input_krw_per_1m: <입력 단가>, output_krw_per_1m: <출력 단가>}
    gpt-4.1-mini: {input_krw_per_1m: <입력 단가>, output_krw_per_1m: <출력 단가>}
  sidecallModel: gpt-4.1-mini       # 제목·요약 같은 보조 호출용

auth:
  devLogin:
    enabled: true
    allowlist: [admin@corp.example] # 첫 관리자 한 명만
    secretRef: {name: bizcoder-dev-login, key: code}
  superadminEmails: [admin@corp.example]

ingress:
  enabled: true
  className: alb
  annotations:                      # AWS Load Balancer Controller 예 — 환경에 맞게 조정
    alb.ingress.kubernetes.io/scheme: internal
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]'
    alb.ingress.kubernetes.io/certificate-arn: <ACM 인증서 ARN>
    alb.ingress.kubernetes.io/healthcheck-path: /api/auth/mode
    alb.ingress.kubernetes.io/load-balancer-attributes: idle_timeout.timeout_seconds=300   # 스트리밍 응답이 끊기지 않게

환경에 따라 더 채우는 값

상황값
사내 PostgreSQL 사용(운영 권장)postgres.enabled: false + database.urlSecret.{name,key}(DATABASE_URL 이 든 Secret)
OpenAI 호환 사내 게이트웨이llm.kind: openai + llm.openai.baseUrl·existingSecret (values.example.yaml 참고)
모델 id 와 Azure 배포 이름이 다름llm.modelMap (예: {gpt-4.1: my-gpt41-deployment})
APIM 등이 추가 헤더를 요구llm.extraHeaders.existingSecret (JSON, Secret 으로만 받아요)
사내 CA 로 서명된 GitLab·onpodonpod.caSecret (provision.sh 가 만든 bizcoder-ca)
생성된 앱의 빌드가 npm/PyPI 를 씀build.npmRegistry · build.pipIndexUrl 에 사내 미러 주소
정적 사이트가 많아 배포 앱을 작게deploy.appShape: cpu_small (2.3절)
샌드박스 크기 변경onpod.sandbox.class (nano | micro | small | medium)

3.5 4단계 — helm 으로 설치

helm upgrade --install bizcoder ./helm/bizcoder -n bizcoder --create-namespace \
  -f values.generated.yaml -f my-values.yaml
kubectl -n bizcoder rollout status deploy/bizcoder

앱은 시작할 때 DB 마이그레이션을 실행해서 첫 기동에 시간이 걸릴 수 있어요(시작 프로브는 최대 약 6분을 기다려요). 설치가 끝나면 NOTES 로 접속 주소와 확인 명령, 첫 관리자 로그인 방법이 나와요.

helm upgrade --install 뒤에 나오는 NOTES — 접속 주소와 첫 관리자 로그인 안내
그림 2. helm upgrade --install 뒤에 나오는 NOTES — 접속 주소와 첫 관리자 로그인 안내
kubectl -n bizcoder logs deploy/bizcoder --tail=50
curl -sS https://bizcoder.corp.example/api/auth/mode

3.6 5단계 — 점검(preflight.sh)과 첫 로그인

scripts/preflight.sh --from-release bizcoder/bizcoder --cacert ca.crt \
  --gitlab-url https://gitlab.corp.example --license bizcoder.lic --smoke-sandbox
scripts/preflight.sh --smoke-sandbox 점검 표 — 모두 PASS 면 준비 끝이에요
그림 3. scripts/preflight.sh --smoke-sandbox 점검 표 — 모두 PASS 면 준비 끝이에요
점검 항목확인하는 것
onpod 도달·TLS 신뢰 / 에디션onpod API 에 닿고 사내 CA 로 인증서를 검증할 수 있는지, 온프렘 에디션과 앱 주소 규칙·라이선스 상태
샌드박스 API / 서버 빌드 API두 API 가 켜져 있는지(GET /v1/sandboxes·/v1/builds 가 200)
샌드박스 이미지 · 서비스 키 스코프onpod://bizcoder-sandbox:<버전> 의 빌드 성공 기록, 서비스 키에 필요한 스코프
Azure 엔드포인트 도달 / 최소 호출LLM 엔드포인트에 닿고, 모델(배포) 1토큰 호출이 200 으로 돌아오는지
GitLab 도달·TLS사내 GitLab 에 닿고 인증서를 신뢰하는지
BizCoder 주소 DNS · ALB/Ingress → 앱접속 주소가 풀리고, /api/auth/mode 가 JSON 으로 응답하는지
라이선스서명·만료·좌석을 오프라인으로 검증
샌드박스 생성 / 도구 / CLI 실행샌드박스가 뜨는지, 안에 git·Python·코딩 에이전트(CLI)가 있는지, CLI 가 실제로 실행되는지(x86-64 는 AVX2 필요)
샌드박스 → BizCoder샌드박스에서 BizCoder 내부 주소(:8077)에 닿는지 — LLM 프록시·파일 전송 경로

4. 첫 로그인과 초기 설정

4.1 첫 관리자 로그인

  1. 접근 코드를 확인해요. 코드는 화면에 직접 출력되지 않아요.
    kubectl -n bizcoder get secret bizcoder-dev-login -o jsonpath='{.data.code}' | base64 --decode; echo
  2. 브라우저로 https://<BizCoder 주소>/?dev=1 에 접속해요(주소 뒤에 ?dev=1). 일반 주소(/)에는 「사내 SSO로 로그인」 단추만 보여요.
  3. 「이메일로 시작」 칸에 auth.devLogin.allowlist 에 적은 이메일을 넣고 단추를 눌러요. 접근 코드를 물으면 1번의 값을 입력해요.
  4. 첫 관리자는 조직 소유자가 돼요.
일반 주소(/) — 「사내 SSO로 로그인」 단추만 보여요
그림 4. 일반 주소(/) — 「사내 SSO로 로그인」 단추만 보여요
/?dev=1 주소 — 「이메일로 시작」 칸이 함께 보여요 (첫 관리자용)
그림 5. /?dev=1 주소 — 「이메일로 시작」 칸이 함께 보여요 (첫 관리자용)
allowlist 에는 첫 관리자 한 명만 이메일마다 별도 조직이 만들어져요. 다른 관리자는 이 방식으로 추가하지 말고 멤버 초대로 추가하세요(6.1절). 접속은 되는데 로그인이 안 되면 /?dev=1 주소·allowlist 이메일·접근 코드를 확인하고, publicBaseUrl 이 https 인지도 확인하세요(9장).

4.2 회사 이름 입력 (처음 한 번)

첫 관리자가 처음 들어오면 「회사 이름을 알려주세요」 창이 떠요. 직원을 초대할 때, 만든 사이트를 공유할 때, 사용 내역서에 이 이름이 보여요.

처음에는 임시 이름으로 되어 있고, 나중에 조직 관리에서 바꿀 수 있어요. 이름을 적고 「저장하고 시작하기」를 누르면 콘솔로 들어가요.

처음 한 번 — 첫 관리자가 처음 들어오면 뜨는 「회사 이름을 알려주세요」 창
그림 6. 처음 한 번 — 첫 관리자가 처음 들어오면 뜨는 「회사 이름을 알려주세요」 창

4.3 라이선스 확인

콘솔에서 조직 관리 → 라이선스 로 가서 사용 중 좌석 / 전체, 만료일, 상태를 확인해요. 좌석은 활성 멤버 + 아직 합류하지 않은 초대를 합한 수예요. 좌석이 다 차면 새 멤버를 초대하거나 회사 SSO 로 새로 들어올 수 없어요(6.1절).

조직 관리 → 라이선스. 「사용 중 좌석 / 전체」·만료일·상태를 보여줘요
그림 7. 조직 관리 → 라이선스. 「사용 중 좌석 / 전체」·만료일·상태를 보여줘요

캡처의 좌석 수·만료일은 예시예요.

4.4 회사 SSO(OIDC) 설정

SSO 를 설정하면 직원은 별도 가입 없이 회사 계정으로 들어와요. 퇴사자는 IdP 에서 계정을 끊는 즉시 차단돼요. OIDC 가 기준이고, SAML 전용 IdP 는 도입 문의가 필요해요(설정 화면 안내).

  1. 사내 IdP(Okta·Entra 등)에 OIDC 앱(클라이언트)을 만들고, 리디렉션 URI 로 https://<BizCoder 주소>/api/auth/oidc/callback 을 등록해요. SSO 설정 화면의 「리디렉션 URI (IdP 앱에 등록)」에 표시되는 값이에요.
  2. BizCoder 에서 조직 관리 → 정책 → 「회사 SSO」 로 가서 발급자(issuer, https), 클라이언트 ID / 시크릿, 회사 이메일 도메인을 입력해요.
  3. 저장하면 「연결됨 · 도메인」으로 바뀌고 직원 로그인 주소(…/api/auth/oidc/start?domain=<이메일 도메인>)가 표시돼요. 「변경」·「해제」 단추로 바꾸거나 끌 수 있어요.
조직 관리 → 정책 → 회사 SSO. 「직원 로그인 주소」와 「리디렉션 URI (IdP 앱에 등록)」가 표시돼요
그림 8. 조직 관리 → 정책 → 회사 SSO. 「직원 로그인 주소」와 「리디렉션 URI (IdP 앱에 등록)」가 표시돼요

직원이 로그인하는 모습 — 직원은 일반 주소의 「사내 SSO로 로그인」 → 회사 이메일 입력 → 사내 IdP 로그인 순서로 들어오고, 자동으로 조직 멤버로 합류해요.

직원 로그인 ① — 「사내 SSO로 로그인」을 누르면 뜨는 회사 이메일 입력 창
그림 9. 직원 로그인 ① — 「사내 SSO로 로그인」을 누르면 뜨는 회사 이메일 입력 창
직원 로그인 ② — 사내 IdP 로그인이 끝나면 조직 멤버로 합류하고 콘솔이 열려요
그림 10. 직원 로그인 ② — 사내 IdP 로그인이 끝나면 조직 멤버로 합류하고 콘솔이 열려요

4.5 초기 설정 체크리스트

5. 직원 사용법

직원이 BizCoder 로 코딩을 맡기고 결과를 받는 순서예요. 필요한 것은 사내 SSO 계정과 사내 GitLab 개인 액세스 토큰이에요.

GitLab 연결처음 한 번
새 작업저장소 + 하고 싶은 일
진행 보기실시간
결과 확인MR · 바뀐 곳
사이트 열기배포 주소
Git 자동 배포선택

5.1 콘솔 둘러보기

로그인하면 콘솔이 열려요. 왼쪽 위의 「새 작업」으로 작업을 시작하고, 아래로 내 작업 목록이 쌓여요. 「내 배포 사이트」에서 내가 올린 사이트를 볼 수 있고, 왼쪽 아래에는 연결된 저장소 계정이 표시돼요.

콘솔(작업 시작 화면). 왼쪽은 작업 목록과 메뉴, 가운데는 요청 입력창이에요
그림 11. 콘솔(작업 시작 화면). 왼쪽은 작업 목록과 메뉴, 가운데는 요청 입력창이에요

5.2 GitLab 연결 (처음 한 번)

작업 결과를 사내 GitLab 에 푸시하고 MR 을 만들려면 직원마다 개인 액세스 토큰을 한 번 등록해요.

  1. 사내 GitLab 에서 개인 액세스 토큰(Personal Access Token)을 만들어요. 권장 범위는 api · read_repository · write_repository 예요.
  2. BizCoder 에서 내 계정 → 연결 계정 으로 가서 GitLab 줄의 「연결」을 눌러요.
  3. GitLab 호스트(예: gitlab.corp.example)와 Personal Access Token 을 입력하고 「연결」을 눌러요.
  4. GitLab 줄에 초록 점이 켜지고 서버 주소가 보이면 끝이에요. 끊으려면 「해제」를 눌러요.
GitLab 연결 창 — GitLab 호스트와 Personal Access Token 을 입력해요
그림 12. GitLab 연결 창 — GitLab 호스트와 Personal Access Token 을 입력해요
연결이 끝나면 GitLab 줄에 초록 점이 켜지고 서버 주소가 보여요
그림 13. 연결이 끝나면 GitLab 줄에 초록 점이 켜지고 서버 주소가 보여요
내 계정 → 연결 계정. 저장소 계정(GitLab)을 연결·해제해요
그림 14. 내 계정 → 연결 계정. 저장소 계정(GitLab)을 연결·해제해요
토큰은 안전하게 보관돼요 토큰은 서버에 암호화되어 저장되고, 코드가 실행되는 샌드박스에는 전달되지 않아요. 토큰에 api 권한이 없으면(read_api·write_repository 만 고르면) 커밋 화면의 배포 결과(✓·×) 표시가 실패해요(연결 창 안내). 사내 CA 로 서명된 GitLab 이면 관리자가 onpod.caSecret 에 그 CA 를 포함해야 해요(3.4절).

5.3 새 작업 시작

  1. 왼쪽 위 「새 작업」(단축키 N)을 눌러요.
  2. 입력창에 하고 싶은 일을 평소 말투로 적어요. 예: 「팀 회식 장소를 투표로 정하는 간단한 한 페이지 웹앱을 index.html 하나로 만들어 줘. 장소를 추가하고 항목마다 투표 수를 올릴 수 있게, 결과는 막대로. 외부 CDN 없이.」
  3. 아래 줄에 저장소 URL을 적어요. 예: https://gitlab.corp.example/dev/hello.git. 저장소 없이도 작업할 수 있고, 이때는 결과를 내려받아요.
  4. 결과를 바로 사내 서버에 올리려면 「배포까지 한 번에」 스위치를 켜요. 「완성되면 사내 서버에 자동 배포돼요. 결과가 웹앱일 때만요」라고 안내돼요.
  5. 「코딩 시작」을 눌러요. 모델 선택 칸에는 관리자가 values 의 llm.models 로 정한 모델이 나와요.
새 작업 — 요청, 「배포까지 한 번에」 스위치, 저장소 URL 을 채우고 「코딩 시작」을 눌러요
그림 15. 새 작업 — 요청, 「배포까지 한 번에」 스위치, 저장소 URL 을 채우고 「코딩 시작」을 눌러요

5.4 진행 보기

작업이 시작되면 가운데에 샌드박스 준비됨 → 툴체인 설치됨 → 리포 클론됨 → 에이전트 시작 → 에이전트가 작업 중 순서로 단계가 쌓이고, 도구 실행과 테스트가 실시간으로 보여요. 이 창을 닫거나 다른 일을 해도 작업은 서버에서 계속되고, 나중에 다시 들어오면 이어서 볼 수 있어요. 중간에 말을 걸려면 아래 입력창에 후속 메시지를 보내고(Enter 전송 · Shift+Enter 줄바꿈), 멈추려면 위쪽 「작업 중단」을 눌러요.

작업 진행 화면 — 가운데에 진행 단계가, 오른쪽에 파일·바뀐 곳·작업 기록·GitLab 탭이 있어요
그림 16. 작업 진행 화면 — 가운데에 진행 단계가, 오른쪽에 파일·바뀐 곳·작업 기록·GitLab 탭이 있어요

오른쪽 탭은 파일(만든·고친 파일), 바뀐 곳(줄 단위 변경), 작업 기록, GitLab(MR) 이에요.

5.5 결과 확인 — MR 과 바뀐 곳

작업이 끝나면 위쪽에 「완료」와 함께 「PR」·「사이트 열기」·「다시 배포」·「결과 다운로드」 단추가 생겨요. 가운데에는 MR 링크와 라이브 사이트 주소가 나와요. 카드에는 「Merge Request 생성됨」과 주소(…/-/merge_requests/<번호>), 「GitLab에서 열기」 단추가 나와요.

작업 완료 — Merge Request 주소와 라이브 사이트 주소(「우리 회사 사람만」)가 나와요
그림 17. 작업 완료 — Merge Request 주소와 라이브 사이트 주소(「우리 회사 사람만」)가 나와요

「바뀐 곳」 탭에서는 무엇이 달라졌는지 파일별·줄 단위로 볼 수 있어요. 새로 추가된 줄은 초록, 지워진 줄은 빨강이에요. 파일 이름 옆의 +264 −0 같은 숫자는 추가·삭제된 줄 수예요.

사내 GitLab 에서도 같은 MR 을 볼 수 있어요. 작업마다 MR 이 하나씩 생기고, 제목에는 요청한 내용이 들어가요. 검토와 머지는 평소 쓰는 GitLab 방식으로 하면 돼요.

「바뀐 곳」 탭 — 새로 추가된 줄은 초록, 지워진 줄은 빨강으로 보여요
그림 18. 「바뀐 곳」 탭 — 새로 추가된 줄은 초록, 지워진 줄은 빨강으로 보여요
사내 GitLab 의 Merge requests 목록 — 작업마다 MR 이 하나씩 생겨요
그림 19. 사내 GitLab 의 Merge requests 목록 — 작업마다 MR 이 하나씩 생겨요

5.6 배포된 사이트 열기

「배포까지 한 번에」를 켰다면 결과 화면의 「사이트 열기」로 https://<이름>.<onpod 도메인> 주소를 열어요. 기본 공개 범위는 「우리 회사 사람만」이라 사내 로그인이 필요해요.

이미 올린 사이트는 콘솔 왼쪽 위 「내 배포 사이트」에서 다시 열고 관리해요. 사이트마다 주소·상태(「실행 중」)·작업 이름·공개 범위가 보이고, 줄 끝에 「수정하기」 등의 단추가 있어요.

콘솔의 「내 배포 사이트」 — 내가 올린 사이트와 공개 범위(「우리 회사만」)가 보여요
그림 20. 콘솔의 「내 배포 사이트」 — 내가 올린 사이트와 공개 범위(「우리 회사만」)가 보여요
배포된 사이트 화면 예 — 작업에서 만든 「팀 회식 장소 투표」 앱(사내 로그인 후 열려요)
그림 21. 배포된 사이트 화면 예 — 작업에서 만든 「팀 회식 장소 투표」 앱(사내 로그인 후 열려요)

조직 배포 정책이 승인제(기본)이면 사이트는 올라가지만 관리자가 승인하기 전에는 다른 직원에게 열리지 않아요. 결과 화면에 「관리자 승인 대기 — 아직 아무도 볼 수 없어요」가 표시되고, 승인 요청은 관리자에게 자동으로 가요. 승인되면 다시 올릴 필요 없이 곧바로 열려요(6.3절).

승인제에서 직원이 올린 사이트 — 「관리자 승인 대기 — 아직 아무도 볼 수 없어요」로 잠겨 있어요
그림 22. 승인제에서 직원이 올린 사이트 — 「관리자 승인 대기 — 아직 아무도 볼 수 없어요」로 잠겨 있어요

5.7 Git 자동 배포 (push 하면 사이트가 갱신)

저장소의 한 브랜치에 push 할 때마다 사이트를 다시 올리고 싶을 때 써요.

  1. 「내 배포 사이트」에서 사이트의 Git 아이콘을 눌러 「Git 자동 배포」 창을 열어요.
  2. 「저장소 연결」 탭에서 연결된 계정(GitLab)을 고르고, 저장소 목록에서 저장소·브랜치를 골라 「연결하기」를 눌러요.
  3. 저장소에 웹훅이 자동으로 등록돼요. 연결한 다음 push 부터 자동으로 올라가요.
Git 자동 배포 창 — 연결할 계정과 저장소를 고르고 「연결하기」를 눌러요 (「CI 배포 토큰」 탭도 있어요)
그림 23. Git 자동 배포 창 — 연결할 계정과 저장소를 고르고 「연결하기」를 눌러요 (「CI 배포 토큰」 탭도 있어요)
배포 정책그 브랜치에 push 하면
자유 (「모두 허용」)약 5초 안에 사이트가 갱신돼요.
승인제 (「관리자 승인」)검토용 주소에 먼저 올라가고, 관리자가 승인(커밋 확인)하면 실제 사이트에 반영돼요. 그동안 기존 사이트는 그대로예요.
연결하기 전에 확인하세요
  • 그 브랜치에 push 할 수 있는 사람은 누구나 이 사이트를 바꿀 수 있어요. 보호 브랜치를 권해요(연결 창 안내).
  • 웹훅이 동작하려면 GitLab 이 BizCoder 주소의 인증서를 신뢰해야 해요(ALB 인증서의 발급 CA 를 GitLab 에 등록). 웹훅이 사내 IP 로 가는 경우에는 GitLab 관리자 설정의 「로컬 네트워크 요청 허용」도 켜야 해요.
  • 파이프라인에서 테스트를 통과한 뒤에만 올리고 싶다면 「Git 자동 배포」 창의 「CI 배포 토큰」 탭을 써요.

6. 관리자 운영

소유자·관리자 역할은 콘솔에서 조직 관리 화면을 쓸 수 있어요. 왼쪽 메뉴는 아래처럼 구성돼 있고, 이 장은 굵게 표시한 항목을 다뤄요.

그룹메뉴
워크스페이스개요 · 사용량·비용 · 성과 리포트 · 프로젝트
조직멤버 · 부서
거버넌스정책(회사 SSO·배포 통제 등) · 배포 사이트 · 예산 관리 · 공용 하네스 · 감사 로그
결제라이선스 · 조직 설정

6.1 멤버와 좌석

조직 관리 → 멤버 에서 멤버별 작업 수·누적 비용·최근 로그인을 보고 역할을 바꿔요. 역할은 세 가지예요.

역할권한
소유자조직 전체 통제 · 예산 한도 · 소유권 이전 (조직당 보통 1명)
관리자멤버·정책·예산·하네스·감사 관리
멤버코딩 작업 수행 (조직 관리 화면은 안 보여요)
조직 관리 → 멤버. 역할(소유자·관리자·멤버)과 초대 단추(「메일로 초대」·「초대 링크 만들기」)가 있어요
그림 24. 조직 관리 → 멤버. 역할(소유자·관리자·멤버)과 초대 단추(「메일로 초대」·「초대 링크 만들기」)가 있어요

좌석이 가득 찬 상태에서 새 직원이 SSO 로 로그인하면 로그인 화면에 「라이선스 좌석이 모두 사용 중이거나 라이선스가 유효하지 않아 새로 들어올 수 없어요. 관리자에게 문의해 주세요.」가 뜨고, 주소에 ?sso_error=license_seats 가 붙어요.

좌석을 비우거나 라이선스를 늘려야 해요.

좌석이 가득 찼을 때 새 직원의 SSO 로그인 화면
그림 25. 좌석이 가득 찼을 때 새 직원의 SSO 로그인 화면

6.2 라이선스 만료와 갱신

  1. 새 .lic 파일을 받아 위 명령으로 먼저 점검해요.
  2. Secret bizcoder-license(키 license.json)를 새 파일로 교체해요.
    kubectl -n bizcoder create secret generic bizcoder-license \
      --from-file=license.json=<새 라이선스 파일> --dry-run=client -o yaml | kubectl apply -f -
  3. 반영해요. values 에 license.hotReload: true 를 줬다면 재시작 없이 약 1분 안에 반영돼요. 아니면 파드를 다시 띄워요.
    kubectl -n bizcoder rollout restart deploy/bizcoder
  4. 조직 관리 → 라이선스에서 만료일과 좌석이 바뀌었는지 확인해요.

6.3 배포 정책과 승인

직원이 올린 사이트는 사내 주소로 열려요. 누가 올릴 수 있고 누가 볼 수 있는지는 조직 관리 → 정책 → 배포 통제 의 「배포 허용 범위」에서 정해요.

배포 허용 범위동작
관리자 승인 (승인제, 기본)직원이 올린 사이트는 올라가되, 승인 전에는 아무도 못 보게 잠겨요. 관리자가 승인하면 그때 열려요.
모두 허용 (자유)직원이 스스로 올리고, 승인 없이 바로 열려요.
금지배포를 허용하지 않아요.
조직 관리 → 정책 → 배포 통제. 「배포 허용 범위」를 모두 허용 / 관리자 승인 / 금지 중에서 골라요 (캡처는 「모두 허용」이 선택된 상태)
그림 26. 조직 관리 → 정책 → 배포 통제. 「배포 허용 범위」를 모두 허용 / 관리자 승인 / 금지 중에서 골라요 (캡처는 「모두 허용」이 선택된 상태)

부서 단위 공개 범위는 온프렘에서 지원하지 않고 「우리 회사」로 처리돼요. 정책과 별개로 관리자는 배포 사이트 탭에서 사이트별로 「범위 변경」을 할 수 있어요.

승인 처리 순서

1 직원 배포사이트가 올라가고 잠겨요
2 승인 대기관리자 화면에 표시
3 공개 승인공개 범위를 골라요
4 열림그 범위로 바로 열려요
  1. 조직 관리 → 배포 사이트 로 가요. 승인 대기가 있으면 「승인 대기 중」 칸이 주황색으로 바뀌고 왼쪽 메뉴에 건수 배지가 떠요. 이 화면에서 우리 회사 직원들이 올린 사이트와 공개 범위, Git 자동 배포(연결된 사이트·일시정지·마지막 배포 실패)도 한눈에 볼 수 있어요.
조직 관리 → 배포 사이트. 사이트별 공개 범위를 한눈에 보고 「범위 변경」을 할 수 있어요
그림 27. 조직 관리 → 배포 사이트. 사이트별 공개 범위를 한눈에 보고 「범위 변경」을 할 수 있어요
  1. 대기 중인 사이트 줄에 「관리자 승인 대기 — 아직 아무도 볼 수 없어요」가 붙고 「공개 승인」·「거절」 단추가 있어요. 주소를 열어 내용을 확인한 뒤 「공개 승인」을 눌러요.
승인 대기 1건 — 목록 맨 위 사이트에 「공개 승인」·「거절」 단추가 있어요
그림 28. 승인 대기 1건 — 목록 맨 위 사이트에 「공개 승인」·「거절」 단추가 있어요
  1. 공개 범위를 골라 「이 범위로 승인」을 눌러요. 선택지는 「요청대로 — 우리 회사 사람만」과 「주소를 아는 누구나」예요. 직원이 요청한 범위보다 넓히거나 좁혀도 돼요. 승인하면 그 범위로 바로 열려요.
「공개 승인」을 누르면 공개 범위를 고르는 창이 떠요
그림 29. 「공개 승인」을 누르면 공개 범위를 고르는 창이 떠요
  1. 승인이 끝나면 사이트에 「우리 회사 사람만」 표시가 붙고 「승인 대기 중」이 0 으로 돌아와요. 직원은 다시 올릴 필요 없이 곧바로 사이트를 열 수 있어요.
승인 뒤 — 사이트에 「우리 회사 사람만」이 표시되고 「승인 대기 중」이 0 이 돼요
그림 30. 승인 뒤 — 사이트에 「우리 회사 사람만」이 표시되고 「승인 대기 중」이 0 이 돼요
「주소를 아는 누구나」는 신중하게 이 범위는 로그인 없이 주소만 알면 열려요. 사내 자료를 다루는 사이트가 이 범위로 열려 있지 않은지 배포 사이트 화면의 「주소를 아는 누구나」 칸에서 수시로 확인하세요.

Git 자동 배포와 승인제 — 직원이 연결한 브랜치에 push 하면 사이트가 바로 바뀌지 않고 검토용 주소에 먼저 올라가요. 관리자가 승인(커밋 확인)하면 실제 사이트에 반영되고, 그동안 기존 사이트는 그대로예요(5.7절).

6.4 감사 로그

조직 관리 → 감사 로그 에는 작업·정책 변경·보안 플래그가 시간순으로 남아요. 위쪽 탭은 활동 · LLM 호출 로그 · 불변 감사 원장 · 전문 기록 이고, 활동 탭에서는 전체 · 작업 · 크레딧 · 변경 · 플래그로 걸러 볼 수 있어요. 작업 시작·종료, 사이트 배포, MR 생성(외부 전송), 정책 변경이 한 줄씩 기록돼요. 정책 화면 아래의 「정책 변경 이력」에서도 최근 변경을 볼 수 있어요.

조직 관리 → 감사 로그. 작업·배포·정책 변경이 시간순으로 남아요
그림 31. 조직 관리 → 감사 로그. 작업·배포·정책 변경이 시간순으로 남아요

7. 업그레이드 · 삭제 · Argo CD

7.1 업그레이드

새 번들을 받으면 이미지를 올리고 image.tag 만 바꿔 helm upgrade 해요. 앱은 시작할 때 DB 마이그레이션을 실행하므로 기본값을 replicas: 1, strategy: Recreate 로 두었어요(새·옛 버전이 같은 DB 를 동시에 만지지 않게). 그래서 교체되는 동안 잠시 접속이 안 될 수 있으니 직원이 적은 시간대에 하세요.

  1. 새 번들의 체크섬을 확인하고 이미지를 올려요(3.2절).
  2. 샌드박스 이미지가 바뀐 번들이면 scripts/provision.sh 를 같은 옵션으로 다시 실행해요. 새 샌드박스 이미지가 만들어지고, onpod.sandbox.image 별칭을 새 값으로 갱신해요(기존 Secret 은 유지돼요).
  3. my-values.yaml 의 image.tag 를 새 번들 bundle.env 의 APP_TAG 로 바꾸고 3.5절의 helm upgrade --install 을 다시 실행해요.
  4. kubectl -n bizcoder rollout status deploy/bizcoder 로 끝났는지 보고, preflight.sh(3.6절)를 다시 돌려요.
레플리카를 늘리기 전에 레플리카를 늘리면 새 버전이 올라가는 동안 서로 다른 버전이 같은 DB 를 만지게 돼요. 늘리기 전에 이 업그레이드 절차를 먼저 확인하세요. RollingUpdate 로 바꾸면 새·옛 파드가 잠깐 같이 떠서 마이그레이션이 겹칠 수 있어요.

기존 Secret 의 내용만 바뀌었을 때는 파드가 자동으로 다시 뜨지 않아요. kubectl -n bizcoder rollout restart deploy/bizcoder 를 하거나 values 의 secretsRevision 을 아무 문자열로 바꿔 반영해요.

7.2 삭제

helm uninstall bizcoder -n bizcoder

실수 방지를 위해 번들 DB 의 데이터(PVC data-bizcoder-postgres-0)와 provision.sh 가 만든 Secret 은 남아요. 완전히 지우려면 직접 삭제하세요.

kubectl -n bizcoder delete pvc data-bizcoder-postgres-0
kubectl -n bizcoder delete secret bizcoder-onpod bizcoder-app bizcoder-db bizcoder-azure bizcoder-license bizcoder-ca bizcoder-dev-login

서비스 키(이름 bizcoder-service)는 onpod 콘솔의 API 키 화면에서 회수해요.

7.3 Argo CD 로 배포하기

차트는 Argo CD 로도 배포할 수 있게 설계했어요. 비밀값을 무작위로 만들지 않고, 설치 순서 훅이 없고, lookup 같은 함수를 쓰지 않아서 같은 입력은 항상 같은 결과를 내요(렌더 결과가 같은지는 시험했어요. 다만 실제 Argo CD 로 동기화해 본 시험은 아직 하지 않았으니, 처음 적용할 때는 Argo CD 의 Diff 화면으로 변경 내용을 먼저 확인해 주세요). 번들의 argocd/ 에 application.yaml.example(Application + AppProject), externalsecret.yaml.example, sealedsecret.md 가 있어요.

준비

Application 예시 (argocd/application.yaml.example 발췌)

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: bizcoder
  namespace: argocd
spec:
  project: bizcoder
  source:
    repoURL: https://gitlab.corp.example/platform/bizcoder-deploy.git
    targetRevision: main
    path: helm/bizcoder
    helm:
      releaseName: bizcoder
      valueFiles:
        - ../../envs/prod/values.yaml      # source.path 기준 상대 경로 (같은 저장소 안)
  destination:
    server: https://kubernetes.default.svc
    namespace: bizcoder
  syncPolicy:
    automated:
      prune: false          # 비밀·DB 가 걸린 앱이라 prune 은 끈 채로 시작해요
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
      - ServerSideApply=true
      - PruneLast=true
      - PrunePropagationPolicy=foreground
    # retry 등 나머지는 번들의 application.yaml.example 참고

알아둘 점

8. 보안 구성

8.1 컨테이너와 클러스터

8.2 비밀과 신뢰 경계

정보어디에 있나요샌드박스에 전달되나요
LLM(Azure) 키Secret bizcoder-azure → BizCoder 서버아니요
직원의 GitLab 토큰BizCoder 서버에 암호화 저장아니요
onpod 서비스 키Secret bizcoder-onpod아니요
소스 파일GitLab 저장소 (클론·푸시·MR 은 BizCoder 가 대신해요)소스 파일만 전달돼요

샌드박스에는 비밀키가 하나도 없고, 클러스터 안에서 BizCoder :8077 만 불러요.

8.3 사내 CA

onpod.caSecret 로 준 CA 는 컨테이너 기본 CA 목록과 합쳐져서(시작 시 initContainer) onpod·GitLab·Azure 호출 모두에 쓰여요. caBundle.mergeSystemRoots: false 로 끄면 사내 CA 만 신뢰해요. 이때는 공인 인증서를 쓰는 엔드포인트(예: Azure OpenAI)에 연결이 안 돼요. GitLab 웹훅(자동 재배포)은 GitLab 이 BizCoder 의 인증서를 신뢰해야 동작해요(ALB 인증서의 발급 CA 를 GitLab 에 등록).

8.4 설치본의 제한과 알아둘 점

8.5 샌드박스 송신 제한 (선택, 기본 꺼짐)

sandbox.networkPolicy.enabled 는 샌드박스 Pod 의 송신을 「BizCoder 8077 + 클러스터 DNS」로만 좁혀요. 다만 onpod 는 앱·빌더·샌드박스 Pod 에 같은 라벨(app.kubernetes.io/managed-by=onpod 등)만 붙여서 이 정책으로 샌드박스만 골라낼 수 없어요. 그래서 샌드박스 전용 네임스페이스(별도 onpod 에이전트)에서만 켜도록 confirmSandboxOnlyNamespace 확인을 요구해요.

sandbox:
  namespace: <샌드박스 전용 네임스페이스>
  networkPolicy:
    enabled: true
    confirmSandboxOnlyNamespace: true     # 이 네임스페이스에는 샌드박스 Pod 만 뜬다는 걸 확인했어요
    dnsCidrs: []                          # NodeLocal DNSCache 면 [169.254.20.10/32]
    extraEgress: []                       # NetworkPolicy egress 규칙 원문 (예: 사내 npm 미러)
공유 네임스페이스에서는 켜지 마세요 앱·빌드가 함께 뜨는 공유 네임스페이스에서 켜면 고객 앱·빌드의 통신까지 막혀요. 켠 뒤에는 preflight.sh --smoke-sandbox --netpol-probe 1.1.1.1:443 으로 실제로 막히는지 확인하세요(CNI 가 NetworkPolicy 를 집행해야 해요).

9. 문제 해결

먼저 scripts/preflight.sh --from-release bizcoder/bizcoder --smoke-sandbox 의 PASS/FAIL 표를 보세요. 대부분의 설치·연동 문제는 FAIL 항목으로 바로 드러나요.

9.1 설치 · 기동

증상원인 · 해결
helm install 이 BizCoder 차트 값 검증 실패 로 멈춤출력된 항목이 채우지 않은 필수 값이에요. 그대로 채우세요.
provision.sh: 샌드박스 API 꺼짐(501)onpod 컨트롤플레인에 ONPOD_SANDBOX_API_ENABLED=1 을 켜세요(onpod 차트 controlplane.extraEnv 후 재시작). 출력된 명령을 따르세요(3.3절).
provision.sh: 조직에 속해 있지 않음콘솔에서 회사 조직을 만들거나 --create-org "회사 이름" 을 주세요.
provision.sh: 같은 이름의 서비스 키가 이미 있음--org-key-name 으로 다른 이름을 주거나 --rotate-key 로 기존 키를 회수하고 새로 발급하세요.
파드 CrashLoopBackOff, 로그에 WRKS_SECRET_KEY 오류Secret bizcoder-app 의 값이 Fernet 형식이 아니에요. python3 -c 'from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())' 로 만든 값이어야 해요.
파드가 Pending번들 DB 의 PVC 가 바인딩되지 않았거나(kubectl get sc) 리소스가 부족해요.
ImagePullBackOffimage.repository/tag 와 레지스트리 접근(imagePullSecrets)을 확인하세요.
ALB 502/504, 대상 그룹이 unhealthy헬스체크 경로를 /api/auth/mode 로, 대상 유형(target-type: ip/instance)과 service.type 을 맞추세요. 스트리밍이 끊기면 ALB 유휴 시간 제한을 늘리세요.
파드가 Secret 변경을 모름secretsRevision 값을 바꾸거나 kubectl -n bizcoder rollout restart deploy/bizcoder 를 하세요.

9.2 로그인 · 라이선스

증상원인 · 해결
접속은 되는데 로그인이 안 됨/?dev=1 주소로 들어갔는지, auth.devLogin.allowlist 의 이메일과 접근 코드(Secret bizcoder-dev-login)가 맞는지 확인하세요. publicBaseUrl 이 https 인지도 확인하세요.
SSO 로그인 뒤 ?sso_error=license_seats좌석이 가득 찼어요. 좌석을 비우거나 라이선스를 늘리세요(6.1절).
?sso_error=oidc_domain_mismatch로그인한 이메일의 도메인이 SSO 설정의 회사 이메일 도메인과 달라요(4.4절).
?sso_error=oidc_not_configured회사 SSO 가 설정되지 않았어요. 조직 관리 → 정책 → 회사 SSO 를 먼저 설정하세요.
라이선스 오류preflight.sh --license 파일 로 서명·만료·좌석을 오프라인으로 확인하세요(6.2절).

9.3 작업 · GitLab · LLM

증상원인 · 해결
「작업을 마치지 못했어요」가 시작 직후 반복preflight.sh --smoke-sandbox 의 「샌드박스 CLI 실행」(CPU 의 AVX2)과 「샌드박스 도구」를 확인하세요. 샌드박스 이미지 별칭, 샌드박스 → BizCoder 도달, LLM 호출을 한 번에 점검해 줘요.
작업이 오래 대기하거나 no_capacityonpod 의 샌드박스 슬롯이 부족해요. 용량 산정(2.3절)을 다시 보고, 배포 앱 크기(deploy.appShape)도 확인하세요.
푸시했는데 MR 이 안 열림직원의 GitLab 토큰 권한(api)과 사내 CA 신뢰(onpod.caSecret)를 확인하세요.
GitLab 푸시 x509: certificate signed by unknown authorityonpod.caSecret 에 GitLab 인증서를 발급한 CA 가 들어 있는지 확인하세요.
Azure 401키 또는 인증 방식이 맞지 않아요. llm.azure.auth 를 bearer 또는 both 로 바꿔 보세요.
Azure 404 DeploymentNotFound모델 id 와 Azure 배포 이름이 다르면 llm.modelMap 으로 매핑하세요.
「단가를 찾지 못했어요」로 작업이 거부됨llm.prices 에 모델 단가를 넣거나 llm.priceOptional: true 를 쓰세요.

9.4 배포

증상원인 · 해결
배포가 「승인 전에 잠글 수 없어」 로 되돌려짐서비스 키에 org:read·org:write 스코프가 없어요. provision.sh --rotate-key 로 키를 다시 발급하세요(--without-site-access 를 쓰지 않았는지도 확인).
동적 앱(Node·Python) 빌드가 실패함빌드가 npm/PyPI 에 닿지 못하는 경우예요. 사내 미러를 build.npmRegistry·build.pipIndexUrl 로 지정하세요(8.4절).
push 해도 자동 배포가 안 됨GitLab 이 BizCoder 주소의 인증서를 신뢰하는지, 사내 IP 로의 웹훅이면 GitLab 관리자 설정의 「로컬 네트워크 요청 허용」이 켜져 있는지 확인하세요(5.7절).
사이트가 승인 대기 상태로 잠겨 있음배포 정책이 승인제예요. 관리자가 조직 관리 → 배포 사이트에서 「공개 승인」을 하면 열려요(6.3절).

부록

A. values 요약표 (주요 항목)

전체 목록과 설명은 helm/bizcoder/values.yaml 의 주석이고, 형식 검사는 values.schema.json 이에요(알 수 없는 키·잘못된 값은 거절돼요).

키기본설명
image.repository / tag / digest(필수)앱 이미지. 사내 레지스트리 주소로 바꾸세요. digest 를 주면 tag 대신 고정해요.
publicBaseUrl(필수)직원이 접속하는 HTTPS 주소. 끝에 / 없이.
sandboxBaseUrl서비스 DNS샌드박스가 BizCoder 를 부르는 클러스터 안 주소
replicas / strategy.type1 / Recreate마이그레이션 때문에 1 권장
onpod.apiUrl(필수)사내 onpod API 주소
onpod.tokenSecret.{name,key}– / token서비스용 org API 키가 든 Secret
onpod.caSecret / caConfigMap / caPem–사내 CA (셋 중 하나)
onpod.sandbox.image / class(필수) / smallonpod://bizcoder-sandbox:<버전> / nano · micro · small · medium
onpod.deployDefaultScopeorg배포물 공개 범위: public · org · dept
build.npmRegistry / pipIndexUrl–생성된 앱의 빌드가 쓸 사내 미러
deploy.enabled / appShapetrue / cpu_2c_4g배포 기능 스위치 / 배포 앱 기본 크기
llm.kindopenaiopenai(OpenAI 호환 게이트웨이) 또는 azure
llm.azure.{endpoint,apiVersion,auth,existingSecret,keyKey}– / v1 / api-keyAzure OpenAI. apiVersion 이 날짜면 배포 이름 기반 클래식 주소
llm.openai.{baseUrl,existingSecret}–OpenAI 호환 게이트웨이
llm.models.{main,fallback,curated[]}(main·curated 필수)사용자에게 보이는 모델 id
llm.modelMap{}모델 id → Azure 배포 이름
llm.prices / priceOptional / priceMarkup{} / false / 1.0단가표(KRW/1M 토큰) · 미등록 모델 허용 · 배수
llm.sidecallModel–제목·요약 등 보조 호출 모델
llm.extraHeaders.{existingSecret,key}–APIM 등이 요구하는 추가 헤더(JSON, Secret)
secretKey.{existingSecret,key}– / WRKS_SECRET_KEYFernet 키 Secret (필수)
license.{existingSecret,key,hotReload}– / license.json / false라이선스 Secret (필수). hotReload: true 면 재시작 없이 갱신
postgres.enabled + postgres.persistence.*true / 20Gi번들 PostgreSQL. 운영은 사내 DB 권장
database.urlSecret.{name,key}–외부 DB 접속 문자열(postgres.enabled=false 일 때)
auth.devLogin.{enabled,allowlist,secretRef}true첫 관리자 로그인(이메일 + 접근 코드)
auth.superadminEmails[]슈퍼관리자 이메일
ingress.{enabled,className,annotations,host,tls}trueALB 어노테이션은 annotations 로
service.{type,port}ClusterIP / 8077ALB target-type: instance 면 NodePort
sandbox.namespace / sandbox.networkPolicy.*onpod-apps / 꺼짐8.5절 참고
caBundle.mergeSystemRootstrue사내 CA 를 기본 CA 목록과 합칠지 (8.3절)
pdb.* · resources · nodeSelector · tolerations · affinity · extraEnv · extraEnvFrom · extraVolumes · extraVolumeMounts일반 스케줄링 옵션 · 그 밖의 환경변수·볼륨
secretsRevision · secretAnnotations기존 Secret 변경 시 롤링 신호 / 차트가 만든 Secret 의 어노테이션

B. 자주 쓰는 명령

kubectl -n bizcoder rollout status deploy/bizcoder           # 기동·업그레이드 확인
kubectl -n bizcoder logs deploy/bizcoder --tail=50           # 로그
curl -sS https://bizcoder.corp.example/api/auth/mode         # 응답 확인 (JSON)
kubectl -n bizcoder get secret bizcoder-dev-login \
  -o jsonpath='{.data.code}' | base64 --decode; echo        # 첫 관리자 접근 코드
scripts/preflight.sh --from-release bizcoder/bizcoder --smoke-sandbox     # 점검 표
scripts/provision.sh --dry-run --onpod-url https://api.onpod.corp.example # 변경 없이 계획만 확인
helm get values bizcoder -n bizcoder                         # 적용된 values

C. 지원 문의

설치·운영 중 막히면 support@onpod.ai 로 문의해 주세요. 아래를 함께 보내 주시면 빨리 확인할 수 있어요.

보내면 안 되는 것 — API 키·GitLab 토큰·로그인 접근 코드·라이선스 파일·Secret 의 값은 메일에 넣지 마세요.