#!/usr/bin/env bash # 배포 — 코드를 당기고, 지정한 서비스만 다시 빌드해 갈아끼운다. # # ./deploy.sh 전체 # ./deploy.sh solution-backend 그 서비스만 # ./deploy.sh solution-backend solution-worker 여럿 # # 서비스명 대신 컨테이너명(o2o-web4ai-solution-backend)으로 불러도 받는다. set -euo pipefail cd "$(dirname "$0")" PREFIX=o2o-web4ai # api·worker·api-admin 은 이미지 한 벌(o2o-web4ai-backend)을 나눠 쓴다. BACKEND_SVCS=(solution-backend solution-worker admin-backend) PULL=1 ONLY=0 TARGETS=() usage() { cat <<'USAGE' 사용법: ./deploy.sh [옵션] [서비스...] 옵션 --no-pull git pull 을 건너뛴다(디스크에 있는 코드 그대로 빌드) --only 백엔드 형제 서비스를 함께 갈아끼우지 않는다 (아래 ★ 참고) -h, --help 서비스: solution-backend · solution-worker · solution-frontend · solution-site admin-backend · admin-frontend (프로필 admin, 기본 기동에서 빠져 있다) o2o-web4ai-solution-backend 처럼 컨테이너명으로 적어도 된다 ★ solution-backend·solution-worker·admin-backend 는 이미지가 한 벌이다. 하나를 빌드하면 나머지도 새 이미지로 갈아끼워야 한다 — 안 그러면 옛 코드로 도는 컨테이너가 남는데, 셋 다 "살아 있음" 이라 화면상으로는 배포가 끝난 것처럼 보인다. --only 는 그걸 알고 건너뛸 때만 쓴다. USAGE } while [ $# -gt 0 ]; do case "$1" in --no-pull) PULL=0 ;; --only) ONLY=1 ;; -h|--help) usage; exit 0 ;; -*) echo "모르는 옵션: $1" >&2; usage >&2; exit 2 ;; *) TARGETS+=("${1#"$PREFIX"-}") ;; # 컨테이너명으로 불러도 받는다 esac shift done ALL_SVCS=$(docker compose config --services) for t in ${TARGETS+"${TARGETS[@]}"}; do grep -qx "$t" <<<"$ALL_SVCS" || { echo "그런 서비스가 없다: $t" >&2 echo "있는 것: $(tr '\n' ' ' <<<"$ALL_SVCS")" >&2 exit 2 } done # ── 코드 ──────────────────────────────────────────────────────────── if [ "$PULL" = 1 ]; then echo "▶ git pull" if ! git pull --ff-only 2>&1; then echo " ! 당기지 못했다 — 디스크에 있는 코드 그대로 간다." >&2 echo " (원격 인증이 없으면 밖에서 밀어넣고 --no-pull 로 돌린다)" >&2 fi fi echo "▶ 지금 코드: $(git log --oneline -1)" # ── 대상 정하기 ───────────────────────────────────────────────────── if [ ${#TARGETS[@]} -eq 0 ]; then SVCS=() # 빈 인자 = compose 가 전부로 해석한다 echo "▶ 대상: 전체" else SVCS=("${TARGETS[@]}") # 백엔드 하나를 건드리면 같은 이미지를 쓰는 형제도 함께 갈아끼운다. if [ "$ONLY" = 0 ]; then for t in "${TARGETS[@]}"; do for b in "${BACKEND_SVCS[@]}"; do [ "$t" = "$b" ] || continue for sib in "${BACKEND_SVCS[@]}"; do printf '%s\n' "${SVCS[@]}" | grep -qx "$sib" || { SVCS+=("$sib") echo " + $sib — 같은 이미지를 쓴다(옛 코드로 남지 않게 함께 간다)" } done done done fi echo "▶ 대상: ${SVCS[*]}" fi # ── 빌드 · 교체 ───────────────────────────────────────────────────── # build 절이 없는 서비스(node:24-alpine · nginx:alpine)는 build 가 조용히 건너뛴다. echo "▶ build" docker compose build ${SVCS+"${SVCS[@]}"} echo "▶ up -d" docker compose up -d --force-recreate ${SVCS+"${SVCS[@]}"} echo docker compose ps echo echo "로그: ./log.sh"