Files
distribution_erp/INFRA_MIGRATION.md
T
chpark 7d7b22f388 docs: 인프라 이관 가이드 추가 (집 PC → IDC)
운영 서비스 목록, 데이터 볼륨 위치, 노출 포트, 운영 중 적용한 hotfix(Mailu DNSSEC/MariaDB 11.8 등), Phase 별 이관 체크리스트.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 23:17:57 +09:00

12 KiB

인프라 이관 가이드 (집 PC → IDC)

작성: 2026-05-12 / 대상 호스트: chparkserver (183.99.177.40) 목적: 운영 중인 서비스 전부 IDC 서버로 옮길 때 필요한 정보와 절차 정리


1. 현재 호스트 사양 / 환경

항목
Hostname chparkserver
OS Ubuntu 24.04.4 LTS (kernel 6.8)
Docker 29.1.3
K3s v1.34.6+k3s1
디스크 / 116G / /data 916G (사용 121G)
외부 IP 183.99.177.40
접속 SSH (chpark@)

디스크 사용량 분포 (/data):

51G  containerd  (K3s container runtime)
31G  docker      (docker engine data-root)
56G  opt         (docker compose 운영 파일들)
544M transfer
490M dumps
303M k3s
90M  mailu
87M  backups     ← 이번 사고 대응으로 만든 백업

2. 운영 중인 서비스 전체 목록

2.1 Docker Compose 기반 (직접 운영)

Project 경로 도메인/포트 비고
traefik /data/opt/docker/traefik/ 80, 443 HTTPS reverse proxy (Let's Encrypt). 모든 도메인 입구
mailufinal /data/mailu/ mail.coa-soft.com (25/110/143/465/587/993/995) Mailu 메일 서버 9개 컨테이너
nextcloudfinal /home/chpark/nextcloud/ cloud.junggomoa.com Nextcloud + MariaDB 11.8 + Redis
gitea2 /data/opt/docker/gitea/ git.junggomoa.com / 2222 (SSH) Gitea + PostgreSQL
mattermost2 /data/opt/docker/mattermost/ 8065 Mattermost + PostgreSQL
registry2 /data/opt/docker/registry/ localhost:5000 Docker registry (K3s 가 image pull 용)
source /home/chpark/momo-erp/source/ momotogether.com momo-erp
tradeing2 /home/chpark/tradeing/ (도메인 확인) Tradeing 서비스 + PostgreSQL
portainer /data/opt/docker/portainer/ 9000 (관리 UI) Docker 관리 UI

⚠️ stopped 상태로 남은 옛 프로젝트: gitea, mailu, mattermost, nextcloud, registry, tradeing — 이전 버전. 이관 시 무시.

2.2 K3s 위에서 운영 (kubectl 로 관리)

Namespace 서비스 도메인
invyone frontend / backend-spring / backend-node www.invyone.com / solution.invyone.com
invyone-homepage homepage (invyone homepage)
insurance api / web / postgres-0 (insurance 도메인)
kubernetes-dashboard dashboard / metrics-scraper (관리용)
portainer portainer-agent (관리용)
kube-system coredns / metrics-server / local-path-provisioner (인프라)

K3s manifests: /data/k8s-manifests/ 또는 Gitea 의 repo 확인.


3. 데이터 볼륨 (이관 시 반드시 옮길 것)

3.1 Docker Named Volumes

nextcloud_nextcloud_db        ← Nextcloud DB (MariaDB 11.8)
nextcloud_nextcloud_data      ← Nextcloud 사용자 파일
insurance_postgres_data       ← Insurance K3s PostgreSQL
insurance_uploads             ← Insurance 업로드 파일
invyone-db-data               ← Invyone PostgreSQL
source_momo_data_storage      ← Momo ERP 데이터

호스트 경로: /data/docker/volumes/<volume_name>/_data/

3.2 Bind Mount 경로

/data/mailu/             ← Mailu compose + env + 인증서
/mailu/                  ← Mailu data (메일함 실제 저장 위치, /mailu/data)
/data/opt/docker/        ← 각 서비스의 compose 디렉토리
/home/chpark/nextcloud/  ← Nextcloud compose
/home/chpark/momo-erp/   ← Momo ERP compose + source
/home/chpark/tradeing/   ← Tradeing compose

3.3 K3s/containerd

/data/containerd/        ← K3s container runtime data (이관 비추, K3s 새로 설치 + manifest 재배포 권장)
/data/k3s/               ← K3s state
/data/k8s-manifests/     ← K8s manifest 파일들 (직접 이관)

4. 외부 노출 포트 (방화벽 규칙)

포트 프로토콜 용도
80, 443 TCP Traefik (HTTPS 리버스 프록시)
25 TCP SMTP (메일 수신)
465 TCP SMTPS (메일 송신 TLS)
587 TCP SMTP Submission
993 TCP IMAPS
995 TCP POP3S
110, 143 TCP POP3/IMAP plain (보안상 disable 권장)
2222 TCP Gitea SSH
8065 TCP Mattermost
5432 TCP ⚠️ invyone-db PostgreSQL 외부 노출 — IDC 이관 시 내부 IP 만 허용하도록 변경 권장

5. 운영 중 적용된 Hotfix 내역 (이관 시 그대로 가져가야 함)

이관 시 단순히 compose 파일만 복사하면 안 됨. 아래는 컨테이너/네트워크 quirk 대응으로 추가한 패치.

5.1 Mailu (/data/mailu/docker-compose.yml)

  • admin / front / antispamentrypoint override:

    entrypoint:
      - /bin/sh
      - -c
      - |
        echo "nameserver 127.0.0.11" > /etc/resolv.conf
        echo "nameserver 192.168.203.2" >> /etc/resolv.conf
        echo "search ." >> /etc/resolv.conf
        echo "options edns0 trust-ad ndots:0" >> /etc/resolv.conf
        exec /start.py
    
  • admin / front / antispamextra_hosts (mailu 내부 service IP 직접 박음):

    extra_hosts:
      - "redis:192.168.203.4"
      - "imap:192.168.203.9"
      - "smtp:192.168.203.6"
      - "antispam:192.168.203.8"
      - "webmail:192.168.203.10"
      - "front:192.168.203.3"
      - "resolver:192.168.203.2"
    

    이유: docker user-defined bridge network 에서 admin 만 DNSSEC AD flag 강제. embedded DNS(127.0.0.11) 가 DNSSEC 안 함 → admin 시작 실패. mailu unbound resolver(192.168.203.2) 가 DNSSEC capable 이라 그쪽으로 박았고, internal service hostname 은 extra_hosts 로 박아 NXDOMAIN 방지.

  • resolver service 의 ipv4_address: 192.168.203.254 제거됨 (자동 할당).

    이유: 192.168.203.254 IP 가 packet drop 되는 docker bridge quirk 발견. 자동 할당으로 .2 받음.

  • /data/mailu/mailu.env 에 추가:

    WEBROOT_REDIRECT=/webmail/
    

    이유: 로그인 후 admin 계정이라 가끔 admin UI 로 redirect 됨. 항상 webmail 로 일관시킴.

5.2 Nextcloud (/home/chpark/nextcloud/docker-compose.yml)

  • DB 컨테이너 image: mariadb:10.5mariadb:11.8 (원본 데이터 버전 일치)
  • command: 라인 중복 제거 (이전엔 두 줄이라 첫 번째가 덮어써짐)
  • 백업 위치: /data/backups/nextcloud_db_20260512_080401.tgz (87MB)
  • 추가 mariadb-dump: /data/backups/nc_db_*.sql

5.3 Docker daemon (/etc/docker/daemon.json)

  • 사용자가 이전에 추가한 "dns": ["8.8.8.8", "1.1.1.1"] 가 모든 컨테이너 dns 옵션과 합쳐져 충돌. 이관 시 daemon.json 의 dns 키는 빼는 게 안전 (Mailu 가 의존하는 docker embedded DNS 만 사용하도록).

5.4 cron

*/5 * * * * /mailu/sync-certs.sh
0 4 * * * /usr/bin/docker builder prune -af --filter until=72h
5 4 * * * /usr/bin/docker image prune -af --filter until=168h

이관 시 root crontab 그대로 복사. sync-certs.sh 는 traefik 발급 인증서를 Mailu 형식으로 변환하는 스크립트.


6. 이관 절차 (체크리스트)

Phase 1 — 신규 IDC 호스트 준비

  • Ubuntu 24.04 LTS 설치 (현재와 동일 버전 권장)
  • Docker 29.x + Docker Compose v2 설치
  • K3s 설치 (curl -sfL https://get.k3s.io | sh -)
  • 디스크 파티션: / (시스템) + /data (운영 데이터, 916G 이상 권장)
  • systemd: docker, k3s, containerd 자동 시작 enable

Phase 2 — 데이터 백업 (현재 호스트)

# 1. 모든 docker compose 정지 (downtime 시작)
for proj in mailufinal nextcloudfinal gitea2 mattermost2 registry2 source tradeing2 traefik portainer; do
  docker compose -p $proj down
done

# 2. K3s 도 정지 (시작 시 컨테이너 자동 stop)
sudo systemctl stop k3s

# 3. volume + 운영 디렉토리 통째로 백업
sudo tar -czf /data/backups/all_volumes_$(date +%Y%m%d).tgz \
  /data/docker/volumes \
  /data/mailu \
  /data/opt \
  /data/k8s-manifests \
  /home/chpark/nextcloud \
  /home/chpark/momo-erp \
  /home/chpark/tradeing \
  /mailu

# 4. crontab 백업
sudo crontab -l > /data/backups/root_crontab.txt

# 5. daemon.json 백업
sudo cp /etc/docker/daemon.json /data/backups/daemon.json

Phase 3 — IDC 로 전송

# rsync 권장 (재시도 가능)
rsync -avzP --partial --append-verify \
  /data/backups/all_volumes_*.tgz \
  user@idc-host:/data/backups/

Phase 4 — IDC 에서 복원

cd /
sudo tar -xzf /data/backups/all_volumes_*.tgz

# crontab 복원
sudo crontab /data/backups/root_crontab.txt

# 각 서비스 기동
for path in /data/opt/docker/traefik /data/mailu /home/chpark/nextcloud /data/opt/docker/gitea /data/opt/docker/mattermost /data/opt/docker/registry /home/chpark/momo-erp/source /home/chpark/tradeing /data/opt/docker/portainer; do
  cd "$path" && docker compose up -d
done

# K3s manifest 재적용
kubectl apply -f /data/k8s-manifests/

Phase 5 — DNS 변경

  • 도메인 A 레코드를 새 IDC IP 로 변경 (TTL 짧게 미리 줄여놓으면 좋음)
    • mail.coa-soft.com
    • cloud.junggomoa.com
    • git.junggomoa.com
    • momotogether.com
    • www.invyone.com / solution.invyone.com
    • 기타
  • Mailu MX 레코드도 새 IP 로

Phase 6 — 검증

# 컨테이너 상태
docker ps --filter "name=mailufinal\|nextcloud\|traefik\|gitea" --format "{{.Names}} {{.Status}}"

# HTTP 확인
for url in https://mail.coa-soft.com/ https://cloud.junggomoa.com/ https://git.junggomoa.com/ https://momotogether.com/; do
  curl -ksS -o /dev/null -w "$url -> %{http_code}\n" "$url"
done

# SMTP banner
echo "QUIT" | nc -w 3 새IDC_IP 25

7. 이관 후 정리할 것 (선택)

  • 옛 compose project (gitea/mailu/mattermost/nextcloud/registry/tradeing) 삭제 — docker compose -p <이름> down --remove-orphans
  • dangling image 정리 — 이미 cron 으로 자동화됨
  • /data/backups/ 의 오래된 tarball 정리
  • daemon.json"dns" 키 제거 (Mailu admin DNS 충돌 방지)
  • Mailu admin/front/antispam 의 entrypoint override 가 더 이상 필요한지 재확인 (IDC 의 docker network 환경에서는 안 필요할 수도)

8. 핵심 비밀번호 / 인증 정보

⚠️ 이 문서에는 비밀번호 직접 안 박는다. 아래 위치에서 확인:

  • Mailu 계정: /data/mailu/mailu.env (SECRET_KEY, DB_PW 등)
  • Nextcloud DB: /home/chpark/nextcloud/docker-compose.yml (MYSQL_ROOT_PASSWORD)
  • 각 서비스 admin 계정: 해당 compose 의 environment 또는 env_file
  • Traefik basic auth: /data/opt/docker/traefik/ 안 설정
  • SSH 비밀번호: 운영 PC 관리자가 보관

이관 시 새 IDC 에서 비밀번호 모두 회전(rotation) 권장.


9. 알려진 이슈 / 주의사항

  1. Mailu resolver 192.168.203.254 IP 회피: 이번 사고에서 .254 IP 가 packet drop 되는 docker bridge quirk 발견. IDC 에서도 발생할 수 있으니 resolver 는 자동 할당으로 두는 게 안전.

  2. MariaDB 버전 일치: Nextcloud DB 는 11.8.x. 이관 시 절대 다운그레이드 금지 (이번에 10.5 로 갔다가 plugin load fail 로 사고남).

  3. K3s 와 docker 의 iptables/nftables 공존: K3s 의 kube-router 가 FORWARD chain 에 끼어들어서 docker bridge 통신에 영향을 줄 수 있음. mailu 의 192.168.203.0/24 subnet 이 다른 서비스의 K3s pod CIDR 와 안 겹치는지 확인.

  4. 메일 데이터 위치: 사용자 메일함 파일은 /mailu/data/ (호스트 root). /data/mailu/ 와 다른 위치. 이관 시 둘 다 옮겨야 함.

  5. 인증서: Let's Encrypt 인증서는 Traefik 이 자동 발급. 이관 후 도메인 가리키면 자동 재발급. 단 rate limit 주의 (도메인당 주 5건).


10. 빠른 참조 — 자주 쓰는 명령

# 전체 컨테이너 상태
docker ps --format "{{.Names}}\t{{.Status}}" | sort

# 특정 서비스 로그
docker logs --tail 50 mailufinal-admin-1

# 한 서비스만 재기동
cd /data/mailu && docker compose up -d --force-recreate admin

# Mailu 계정 추가 (admin 컨테이너 안)
docker exec mailufinal-admin-1 flask mailu user $USER $DOMAIN $PASSWORD

# Nextcloud occ
docker exec -u www-data nextcloud-app-new php occ status

# K3s pod 상태
kubectl get pods -A