본문으로 건너뛰기
유동 IP와 스케일아웃 — Docker Hub로 배포하기

생성 수정

IBM * 레드햇 AX 과정 · 22강

유동 IP와 스케일아웃 — Docker Hub로 배포하기

2026년 7월 6일(월) ~ 7월 10일(금)

이 강의 문제풀이 — 배운 내용을 주관식 문답으로 확인해보세요.풀어보기 →

6. ⭐ 유동 IP 문제 — 이 주의 과제

여기가 이 주의 핵심 문제입니다.

6.1 다음날 아침의 절차

전날 원격 PC를 끄고 갔습니다. 다음날 아침에 이 순서를 밟습니다.

① 원격 PC로 가서 전원을 켠다
② sudo service ssh start
③ sudo service ssh status  →  active (running) 확인
④ 원격 PC의 파워쉘에서 ipconfig  →  192.x.x.x 확인
⑤ 접속PC에서 그 IP로 접속
# ② 서비스 시작과 ③ 상태 확인 — 이 줄이 뜨는지 눈으로 본다
sudo service ssh start
sudo service ssh status
#   ● ssh.service - OpenBSD Secure Shell server
#        Active: active (running) since ...
ipconfig      # ④ 원격 PC의 PowerShell에서 — IPv4 주소 . . . : 192.168.0.228
ssh desktop@192.168.0.228        # ⑤ 접속PC에서. 포트를 바꿨다면 -p 2222

6.2 왜 매일 service ssh start 를 쳐야 하는가

WSL은 완전한 리눅스 부팅 과정을 거치지 않기 때문입니다. 일반 리눅스 서버라면 부팅할 때 systemd가 등록된 서비스를 자동으로 켜줍니다. 그런데 WSL은 기본적으로 systemd 없이 최소한으로 뜨기 때문에 sshd가 자동으로 시작되지 않습니다. (sudo service ssh status 가 active (running) 이 아니라 inactive (dead) 로 나오는 상태입니다.)

⭐ status 로 눈으로 확인하는 절차를 절대 생략하지 마세요. start 명령이 성공한 것처럼 보여도 설정 오류로 곧바로 죽는 경우가 있습니다. "명령을 쳤다"와 "동작하고 있다"는 다른 사실입니다. 9주차에서 배운 센서의 개념입니다.

근본 해결 방향 — WSL에서 systemd를 켜면 자동 시작이 가능해집니다.

# /etc/wsl.conf
[boot]
systemd=true
sudo systemctl enable ssh      # 그 다음 부팅부터 자동 시작

(설정 후 PowerShell에서 wsl --shutdown 으로 완전히 종료했다가 다시 켜야 반영됩니다.)

6.3 그런데 IP가 바뀐다 ⭐

여기가 문제입니다.

전원이 새로 켜지면 IP 주소는 유동적으로 변합니다. 이 부분을 해결하는 것이 오늘의 과제입니다.

어제는 192.168.0.228 이었는데 오늘은 192.168.0.231 입니다. 어제 성공한 명령을 그대로 쳤는데 연결이 안 됩니다. 명령이 틀린 게 아니라 주소가 옮겨간 것입니다.

왜 바뀌는가 — DHCP 때문입니다.

DHCP(Dynamic Host Configuration Protocol, 동적 호스트 구성 프로토콜) — 공유기가 접속한 기기에게 IP를 자동으로 빌려주는 방식입니다. Dynamic 이라는 단어가 이미 답을 말하고 있습니다. 빌려주는 것이지 주는 것이 아닙니다.

개념뜻
임대(Lease)IP는 기간이 정해진 대여입니다
임대 만료기간이 끝나면 반납하고 다시 받습니다
재부팅껐다 켜면 다시 요청하고, 다른 번호를 받을 수 있습니다

6.4 축 2 — 고정 ↔ 유동

이 장의 두 번째 축이 여기서 이름을 얻습니다.

고정 (Static)유동 (Dynamic)
누가 정하는가사람이 지정DHCP 서버(공유기·ISP)가 배정
재부팅하면그대로바뀔 수 있음
관리 비용사람이 대장을 관리해야 함자동
서버로 쓰기✅ 적합❌ 부적합
예고정 공인 IP, AWS Elastic IP가정용 인터넷의 일반 IP

⭐ "서버는 주소가 변하면 안 된다." 이것이 이 축의 전부입니다. 클라이언트는 주소가 바뀌어도 괜찮습니다. 자기가 나가서 접속하니까요. 하지만 서버는 남이 찾아와야 하는 쪽입니다. 주소가 바뀌면 아무도 못 찾아옵니다. 축 5(접속하는가 받는가)와 축 2가 여기서 만납니다.

6.5 IP는 사실 세 층으로 되어 있다 ⭐

이 절을 이해하면 "무엇을 고정해야 하는가"라는 질문에 스스로 답할 수 있습니다.

[인터넷]
    │
    │  ① 공인 IP (Public IP)   예: 121.xxx.xxx.xxx
    ▼                          ISP가 우리 집 공유기에 배정
┌──────────── 공유기 ────────────┐
│                               │
│   ② LAN IP (사설 IP)   예: 192.168.0.228
│      공유기가 각 기기에 DHCP로 배정
│                               │
│   ┌──── 원격 PC (윈도우) ────┐  │
│   │                        │  │
│   │  ③ WSL 내부 IP  예: 172.30.174.137
│   │     WSL이 재시작할 때마다 새로 배정
│   │                        │  │
│   └────────────────────────┘  │
└───────────────────────────────┘
층주소누가 정하는가언제 바뀌는가밖에서 보이는가
① 공인 IP121.x.x.xISP(통신사)재접속·임대 만료 시✅ 인터넷 전체
② LAN IP192.168.x.x공유기 DHCPPC 재부팅 시❌ 같은 공유기 안에서만
③ WSL 내부 IP172.x.x.xWSL 가상 네트워크WSL 재시작 시❌ 그 PC 안에서만

⭐⭐ 이번 주에 우리가 겪은 문제는 사실 두 개입니다.

  • ②가 바뀌어서 → 접속할 IP를 매일 ipconfig 로 다시 찾아야 함
  • ③이 바뀌어서 → 포트포워딩 규칙의 connectaddress 가 어제 것과 달라져 규칙이 무용지물이 됨

"어제는 됐는데 오늘 안 된다"의 원인이 둘 중 어느 쪽인지 구분하지 못하면 계속 헤맵니다. ipconfig(②)와 ip addr(③)를 둘 다 확인하는 습관이 그래서 필요합니다.

6.6 해결 방향 — 어느 층을 고정할 것인가

문제를 층으로 나눠 놨으니, 해법도 "어느 층을 고정하는가" 로 분류됩니다.

#방법고정하는 층필요한 것장점단점
①공유기 DHCP 예약 (MAC ↔ IP 고정)② LAN IP공유기 관리자 페이지무료·간단·기기 설정 불필요같은 공유기 안에서만 유효
②정적 IP 수동 설정② LAN IPOS 네트워크 설정공유기 기능과 무관다른 기기와 충돌 위험, 대장 관리 필요
③WSL 미러 네트워킹③ WSL 내부 IP를 없앰Windows 11 + .wslconfig포트포워딩 자체가 불필요해짐OS 버전 제약
④DDNS (동적 DNS)① 공인 IP에 이름을 붙임DDNS 서비스·공유기 지원밖에서도 이름으로 접속공인 IP 필요, 포트 개방(보안 위험)
⑤터널 (Cloudflare Tunnel 등)주소 문제를 우회cloudflared, 도메인공인 IP·포트 개방 모두 불필요외부 서비스 의존
⑥메시 VPN (Tailscale·WireGuard)기기마다 가상 고정 IP각 기기에 설치NAT를 통과하고 주소가 안 바뀜네트워크 계층이 하나 더 생김
⑦클라우드 VM으로 이사 (EC2 + Elastic IP)① 진짜 고정 공인 IP요금가장 확실비용 발생, 내 PC가 아님

각 방법을 한 문단씩

① 공유기 DHCP 예약 — 가장 먼저 시도할 방법입니다. 공유기 관리자 화면에서 원격PC의 MAC 주소(랜카드에 새겨진 고유 번호라 바뀌지 않습니다)를 찾아 "이 기기에는 항상 192.168.0.228을 줘라"고 등록합니다. 설정은 공유기가 하므로 PC 쪽은 아무것도 안 건드려도 됩니다.

② 정적 IP 수동 설정 — PC 네트워크 설정에 IP를 직접 박습니다. 확실하지만 다른 기기가 그 번호를 DHCP로 받아가면 충돌하므로, 공유기의 DHCP 할당 범위 밖의 번호를 골라야 합니다.

③ WSL 미러 네트워킹 — Windows 11의 최신 WSL에는 네트워크를 호스트와 똑같이 보이게 하는 모드가 있습니다.

# %USERPROFILE%\.wslconfig
[wsl2]
networkingMode=mirrored

이걸 켜면 WSL 내부 IP(③층)가 따로 존재하지 않게 되어 포트포워딩이 필요 없어집니다. 5.8~5.10절에서 한 고생이 통째로 사라지는 셈입니다. ⚠️ 다만 OS·WSL 버전 요건이 있고, 도커 등 다른 도구와의 상호작용을 확인해야 합니다.

④ DDNS(Dynamic DNS) — "IP는 바뀌어도 좋으니, 이름은 늘 그대로이게 하자"는 발상입니다. 공유기(또는 PC의 클라이언트)가 IP가 바뀔 때마다 DDNS 서비스에 "나 이제 이 번호야"라고 알려주고, 서비스는 myhome.example.net 이라는 이름이 항상 최신 IP를 가리키도록 갱신합니다.

⭐ DDNS는 "고정 IP를 얻는 방법"이 아니라 "유동 IP를 견디는 방법"입니다. 문제를 없애는 게 아니라 이름이라는 한 겹을 덧대서 무해하게 만드는 것입니다. 10주차에서 배운 DNS = 이름 ↔ 주소 변환의 응용입니다.

⚠️ DDNS를 쓰려면 공유기에서 22(또는 2222)번 포트를 인터넷 쪽으로 열어야 합니다. 전 세계의 자동 스캔이 그 포트를 두드리게 된다는 뜻입니다. 비밀번호 인증을 끄고 키 인증만 남기는 것이 필수가 됩니다.

⑤ 터널(Cloudflare Tunnel) — 발상이 다릅니다. 밖에서 들어오게 하는 대신, 안에서 밖으로 나가서 붙습니다.

[기존] 인터넷 ──▶ 공유기(포트 열기) ──▶ 내 PC     : 들어오는 문을 뚫어야 함
[터널] 내 PC ──▶ (아웃바운드 연결) ──▶ Cloudflare ◀── 인터넷 : 문을 안 뚫어도 됨

내 PC에서 cloudflared 가 클라우드로 먼저 나가서 연결을 유지합니다. 외부 사용자는 Cloudflare에 접속하고, Cloudflare가 그 연결을 타고 내 PC로 전달합니다.

⭐ 공인 IP도, 포트 개방도, 고정 주소도 필요 없습니다. 주소 문제를 푸는 게 아니라 주소를 안 쓰는 쪽으로 우회한 것입니다.

앞에서 배웠습니다 — 10주차 12.11절에서 Cloudflare Zero Trust 터널로 로컬 서버를 열어봤습니다. 그때는 "편해서" 썼지만, 이번 주 문제를 겪고 나면 왜 그 도구가 존재하는지가 보입니다.

앞으로 다시 만납니다 — 14주차에서 터널이 컨테이너 이름으로 안쪽 서비스를 가리키는 방식까지 다룹니다.

⑥ 메시 VPN(Tailscale 등) — 참여한 기기들끼리 자기들만의 가상 네트워크를 만들고 각 기기에 바뀌지 않는 가상 IP를 줍니다. 공유기 설정도 포트 개방도 필요 없지만, 양쪽 PC에 모두 설치해야 합니다.

⑦ 클라우드 VM으로 이사 — 아예 남의 컴퓨터를 빌립니다. AWS EC2에 Elastic IP를 붙이면 진짜 고정 공인 IP가 생깁니다. 대신 켜 둔 시간만큼 요금이 나갑니다. 10주차의 AWS 요금 폭탄 사례가 그 이야기였습니다.

6.7 무엇부터 할 것인가

순서가 있습니다. 위에서부터 시도하세요.

순서상황선택
1같은 집·같은 사무실 안에서만 접속① DHCP 예약 (+ 가능하면 ③ 미러 네트워킹)
2밖에서도 접속해야 함, 공인 IP 있음④ DDNS + 키 인증 전용
3포트를 열고 싶지 않음⑤ 터널
4기기 몇 대만 서로 붙이면 됨⑥ 메시 VPN
524시간 켜져 있어야 하는 진짜 서비스⑦ 클라우드 VM

⚠️ 가장 흔한 실수는 1번을 건너뛰고 4~5번부터 시작하는 것입니다. LAN 안에서도 안정되지 않은 서버를 인터넷에 여는 것은 문제를 두 배로 만드는 일입니다. 안쪽부터 고정하고, 그 다음에 바깥으로 나갑니다.

6.8 임시방편 — 스크립트로 매번 다시 등록하기

# 관리자 PowerShell — 오늘의 WSL 내부 IP를 읽어 포트포워딩 규칙을 다시 만든다
$wslIp = (wsl hostname -I).Trim().Split(" ")[0]
netsh interface portproxy delete v4tov4 listenport=2222 listenaddress=0.0.0.0
netsh interface portproxy add    v4tov4 listenport=2222 listenaddress=0.0.0.0 connectport=2222 connectaddress=$wslIp
netsh interface portproxy show all

⚠️ 이건 해결이 아니라 자동화된 반복입니다. 원인(③층이 바뀌는 것)은 그대로 있습니다. 그래도 손으로 하던 일을 스크립트로 옮기는 것 자체는 좋은 습관입니다. 손으로 하는 일에는 반드시 오타가 섞입니다.


7. 스케일아웃 — PC 두 대가 한 시스템이 되는 순간

7.1 스케일업과 스케일아웃

원격PC를 세운 진짜 목적이 여기 있습니다.

스케일업 (Scale-up)스케일아웃 (Scale-out)
방법한 대를 더 좋게 (CPU·RAM·GPU 업그레이드)여러 대로 늘림
한계물리적 상한이 있음이론상 계속 늘릴 수 있음
비용 곡선고사양일수록 급격히 비쌈대체로 선형
어려운 점없음 (그냥 꽂으면 됨)여러 대를 어떻게 같은 상태로 유지할 것인가
다른 이름수직 확장 (Vertical)수평 확장 (Horizontal)

앞에서 배운 것과 이어집니다 — 3주차 DB 비교표에 "NoSQL은 Scale-out이 쉽다 / RDBMS는 어렵다" 는 줄이 있었습니다. 그때는 DB의 성질로만 나왔지만, 여기서 그 단어의 실체를 손으로 만듭니다.

7.2 스케일아웃의 진짜 문제는 동기화다

PC를 두 대로 늘리는 것 자체는 쉽습니다. 어려운 것은 두 대가 같은 코드를 갖고 있게 만드는 일입니다. 그리고 그 문제는 이미 배운 도구로 풀립니다.

                    ┌─────────────┐
                    │   GitHub    │   ← 유일한 진실의 원천 (허브)
                    └─────────────┘
                     ▲           ▲
              push/pull         push/pull
                     │           │
        ┌────────────┘           └────────────┐
┌───────────────┐                    ┌───────────────┐
│  접속PC(laptop)│                    │ 원격PC(desktop)│
│  로컬 WSL      │                    │  SSH 서버      │
└───────────────┘                    └───────────────┘

⭐ 두 PC는 서로 직접 파일을 주고받지 않습니다. 반드시 GitHub를 거칩니다. 9주차에서 배운 스타 토폴로지(허브 앤 스포크) 가 그대로 인프라에 나타난 것입니다. GitHub가 허브, 두 PC가 스포크입니다. 스포크끼리 직접 통신하지 않는다는 규칙이 여기서도 지켜집니다.

7.3 브랜치 규칙

위치브랜치 이름
원격 SSH 서버desktop
로컬 WSL (접속PC)laptop

5.5절에서 우분투 사용자 이름을 이것과 맞춘 이유가 이제 분명해집니다. 터미널에 desktop@... 이 떠 있으면 desktop 브랜치를 만지면 된다는 뜻입니다. 눈으로 보이는 하네스입니다.

7.4 동기화

두 PC와 GitHub의 상태를 한 번에 맞추는 작업입니다. AI 에이전트에게 맡길 때는 이렇게 지시합니다.

깃허브에 푸시하고 모든 브랜치를 동기화하고,
desktop 브랜치는 ssh 서버에서 pull 해서 다 동기화해줘

수동으로 하면 이렇습니다.

# 접속PC(laptop)에서
git add .
git commit -m "작업 내용"
git push origin laptop

# main 에 반영
git checkout main
git merge laptop
git push origin main
# 원격PC(desktop)에 SSH로 들어가서
ssh -p 2222 desktop@192.168.0.228

git checkout desktop
git fetch origin
git merge origin/main

⚠️ git pull 은 fetch + merge 입니다. 두 PC를 오갈 때는 fetch 로 먼저 가져와서 확인하고 merge 하는 습관이 안전합니다. 한쪽에서 커밋한 걸 잊고 다른 쪽에서 작업하면 충돌이 납니다. 하루의 시작은 항상 fetch 입니다.

7.5 이것이 하네스 엔지니어링입니다

이 구조 전체에 이름이 있습니다. 스케일아웃 기반 하네스 엔지니어링입니다.

하네스의 요소이번 주의 구현
규격화된 통로GitHub를 유일한 경유지로 강제
가이드(규칙)PC 이름 = 사용자 이름 = 브랜치 이름
센서(검증)service ssh status 로 상태 확인, portproxy show all 로 규칙 확인
재현성두 PC가 같은 저장소·같은 이미지에서 출발

3주차에서 하네스를 처음 배울 때 "규격화된 통로를 만들어두는 일"이라고 했습니다. 그것이 코드 안에서는 libs/common 이었고, 아키텍처에서는 포트&어댑터였고, 인프라에서는 이 구조입니다. 같은 원리가 크기를 바꿔 반복됩니다. 프랙탈입니다.


8. 백엔드를 이미지로 만들어 도커허브로 ⭐

2장의 세 쌍이 하나의 파이프라인에서 전부 쓰이는 자리입니다.

8.1 왜 백엔드 폴더만 이미지로 만드는가

우리 프로젝트는 모듈러 모놀리식입니다. 하나의 저장소 안에 프론트와 백엔드가 같이 있습니다. 그런데 배포 경로는 서로 다릅니다.

프론트엔드백엔드
기술Next.jsFastAPI
배포처Vercel도커허브 → 원격 서버
배포 방식GitHub 푸시 시 자동 빌드이미지 빌드 → push → 서버에서 pull → run
상태정적 자산 + 서버리스계속 떠 있는 프로세스

⭐ "하나의 저장소"와 "하나의 배포"는 다른 축입니다. 3주차에서 모노레포 ≠ 모놀리식이라고 배운 것이 여기서 실물이 됩니다. 저장소는 하나(모노레포)지만 배포 대상은 둘입니다.

8.2 requirements.txt 와 Dockerfile

이미지 안에 무엇을 설치할지 정하는 목록입니다.

fastapi
uvicorn[standard]
sqlalchemy
asyncpg
python-dotenv
pydantic-settings

⚠️ 3.12절의 교훈을 기억하세요. 여기 있는 줄을 빌드 과정에서 grep -v 로 걸러내면 컨테이너 안에는 그 라이브러리가 없습니다. 용량을 줄이려다 기능을 지우는 실수가 이렇게 일어납니다.

FROM python:3.13-slim

WORKDIR /app

# ① 의존성 파일만 먼저 복사 — 캐시를 살리기 위해
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# ② 그 다음에 소스 복사
COPY . .

EXPOSE 8000

# ③ --host 0.0.0.0 이 반드시 필요하다
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
#무엇왜
①requirements.txt 를 먼저 복사소스만 바뀌면 의존성 설치 단계를 캐시에서 재사용합니다. 순서를 바꾸면 매번 전부 다시 설치
②EXPOSE 8000"이 이미지는 8000번을 쓴다"는 문서화. 실제 개방은 run 의 -p 가 합니다
③--host 0.0.0.0⭐ 기본값 127.0.0.1 로 두면 컨테이너 안에서만 접속 가능합니다

⭐ ③번은 이 장 전체에서 가장 자주 나오는 오류입니다. 127.0.0.1(localhost)은 "나 자신" 이고, 컨테이너 입장에서 자기 자신은 컨테이너 내부입니다. 0.0.0.0 은 "모든 랜카드에서 받겠다" 는 뜻으로, 5.8절 포트포워딩의 listenaddress=0.0.0.0 과 정확히 같은 의미입니다.

.dockerignore 도 같이 만듭니다.

.git
.venv
__pycache__
*.pyc
.env            # ⚠️ 절대 이미지에 넣지 않는다
node_modules

⚠️ .env 를 이미지에 넣으면 그 이미지를 받는 모든 사람이 내 API 키를 갖게 됩니다. 공개 저장소에 올렸다면 전 세계에 배포한 것입니다. 3주차의 개인정보 보호 종합대책 — 키가 새면 회사 대표가 책임진다는 이야기가 이 한 줄에 걸려 있습니다. 환경변수는 실행할 때 --env-file 로 주입합니다.

8.3 빌드하고 올리기 (push)

docker login
docker build -t myaccount/example-backend:0.1.0 .
docker tag  myaccount/example-backend:0.1.0 myaccount/example-backend:latest
docker push myaccount/example-backend:0.1.0
docker push myaccount/example-backend:latest

이름 규칙은 계정이름 / 저장소이름 : 태그(버전) 입니다. GitHub의 사용자/저장소 와 완전히 같은 형식입니다. 2.4절 표의 "이름 붙이는 단위" 줄이 이것입니다.

⚠️ :latest 만 쓰지 마세요. latest 는 "가장 최신"이라는 약속일 뿐 보증이 아닙니다. 문제가 생겼을 때 "어제 것으로 되돌리기"를 하려면 버전 태그(0.1.0)가 반드시 있어야 합니다. Git에서 커밋 없이 되돌릴 수 없는 것과 같은 이치입니다.

8.4 원격 PC에서 내려받아 띄우기 (pull)

ssh -p 2222 desktop@192.168.0.228          # 원격 PC로 들어간 뒤

docker pull myaccount/example-backend:latest
docker run -d --name backend -p 8000:8000 --env-file .env \
  --restart unless-stopped myaccount/example-backend:latest

docker ps
docker logs -f backend
옵션뜻
-d백그라운드로 실행(detached)
--name backend컨테이너 이름 지정 — 안 주면 랜덤 이름이 붙습니다
-p 8000:8000호스트 8000 → 컨테이너 8000. 5.8절 포트포워딩과 같은 개념
--env-file .env환경변수를 실행 시점에 주입
--restart unless-stopped재부팅해도 다시 뜸 — 6.2절 문제의 도커판 해법

⭐ --restart unless-stopped 를 보세요. 6.2절에서 "WSL은 sshd를 자동으로 안 켜준다"고 했습니다. 같은 문제를 도커는 옵션 하나로 해결합니다. "재부팅 후에도 살아 있는가" 는 서버를 다루는 내내 따라다니는 질문입니다.

8.5 전체 그림 — 세 쌍이 한 줄에 서다 ⭐

이번 주에 만든 것을 한 장으로 그리면 이렇습니다.

   [ 접속PC (laptop) ]                                 [ 클라우드 ]
   ┌────────────────┐    git push                ┌──────────────────┐
   │ 코드 작성       │ ─────────────────────────▶ │     GitHub       │
   │ Docker build   │                            └──────────────────┘
   │                │    docker push             ┌──────────────────┐
   │ 이미지 생성     │ ─────────────────────────▶ │   Docker Hub     │
   └────────────────┘                            └──────────────────┘
                                                 ┌──────────────────┐
                              from_pretrained()  │  Hugging Face    │
                          ◀───────────────────── │  (모델 가중치)    │
                                                 └──────────────────┘
            │  ssh                                        │
            ▼                                     git pull │ docker pull
   ┌──────────────────────────────────────────────────────▼──┐
   │              [ 원격PC (desktop) — 우분투 ]                │
   │   git pull   →  코드 동기화                               │
   │   docker pull →  이미지 내려받기                          │
   │   docker run →  백엔드 서버 가동 (:8000)                  │
   └──────────────────────────────────────────────────────────┘

⭐ 왼쪽이 엔진, 오른쪽이 유통망, 아래가 실행 현장입니다. 그리고 화살표에 적힌 단어는 전부 push 아니면 pull 입니다. 축 4가 그림 전체를 관통합니다.


9. 기획서 상호 평가 — 한계를 인정한 설계

이 주의 마지막 날은 코드가 아니라 문서를 다뤘습니다. 네 개 팀이 공모전 기획서를 서로 평가했습니다.

9.1 연합 포트폴리오 전략

각 팀이 자기 기획서를 다듬는 대신, 다른 팀의 기획서를 읽고 강점을 서로 이식했습니다. 팀 간 강점을 서로 이식하는 '연합 포트폴리오' 전략입니다.

왜 이게 효과가 있는가 — 자기 문서의 결함은 자기 눈에 안 보입니다. 이미 머릿속에서 보완해서 읽기 때문입니다. 9주차의 린터·pre-commit이 코드에 대해 한 일을, 서로의 눈이 문서에 대해 한 것입니다. 규칙을 사람이 지키게 하지 말고 장치가 강제하게 한다 — 여기서 그 장치가 동료입니다.

9.2 Human-in-the-Loop ⭐

문제 상황: 음식 사진(2D 이미지)으로 영양소를 정량 분석하려 합니다. 한계: 2D 이미지로는 체적(부피)을 측정할 수 없습니다. 사진의 밥 한 공기가 100g인지 200g인지 알 방법이 원리적으로 없습니다.

설계 결정: ① 시스템은 DB의 기준량(예: "밥 1공기 = 210g")을 우선 서빙하고, ② 사용자가 최종 정량(g)을 직접 확정하게 강제합니다.

Human-in-the-Loop(HITL, 사람이 루프 안에 있음) — [자동화 설계]인데, [최종 판단을 사람이 확정하도록 흐름 안에 사람을 넣는다]는 점에서 완전 자동화와 구별된다.

완전 자동화Human-in-the-Loop
최종 결정시스템사람
시스템의 역할답을 낸다좋은 초안을 낸다
틀렸을 때그대로 저장됨사람이 고침
언제 쓰는가답이 확실할 때원리적으로 불확실할 때

⭐ 핵심은 "AI가 부족해서"가 아닙니다. 2D 이미지에서 부피를 얻는 것은 모델을 아무리 키워도 안 되는 일입니다. 정보 자체가 없기 때문입니다. 없는 정보는 만들어낼 수 없다 — 이것을 인정하고 사람에게 넘긴 것이 이 설계입니다.

앞에서 배운 것과 이어집니다 — 10주차의 정책 기반(확률적) → 규칙 기반 가드레일 순서와 같은 구조입니다. 여기서는 마지막 가드레일이 사람입니다.

9.3 2단계 즉시 파기 정책

문제 상황: 사용자가 자연어로 제보하고, 동선 데이터가 함께 수집됩니다. 개인을 특정할 수 있는 정보입니다.

단계무엇을어떻게
1단계제보 자연어·동선 데이터 수집에이전트가 분석
2단계분석 직후 즉시 파기DB에 원문·이미지를 남기지 않음
표시위치건물명 대신 반경 단위 비식별 표시

⭐ "보관하지 않으면 유출될 수 없다." 가장 강력한 보안은 암호화가 아니라 애초에 갖고 있지 않는 것입니다. 3주차에서 다룬 개인정보 보호 종합대책(유출 시 CEO 책임 법제화, ISMS-P 의무화)이 설계 결정으로 내려온 사례입니다.

"반경 단위 비식별 표시" 도 같은 원리입니다. "○○아파트 101동"은 개인을 특정하지만, "이 지점 반경 300m 이내"는 통계적으로만 의미가 있습니다. 정밀도를 일부러 낮춰서 위험을 줄이는 것입니다.

9.4 기획서 결함 우선순위

상호 평가에서 나온 결함을 우선순위 순으로 정리했습니다. 순서 자체가 배울 점입니다.

순위결함바로잡기
①추진 일정이 뭉뚱그려져 있음M1~M5 형식(기간 + 마일스톤 + 산출물)으로 재작성 ⭐ 최우선
②제출 양식 미확정참가과제 택1 체크, 서약서 자필 서명 등 양식 확정
③통계에 출처 없음통계 2~3개에 출처 표기
④경쟁 비교가 모호함실명 비교표로 작성
⑤과장 표현정직화 + MVP 컷라인 선언
⑥오타교정

왜 일정이 1순위인가

⭐ 심사자가 가장 먼저 의심하는 것은 "이걸 정말 할 수 있느냐"입니다. 아이디어가 좋다는 것은 다들 주장합니다. 기간·마일스톤·산출물이 적힌 표는 주장할 수 없고 보여줘야 합니다.

M1~M5 형식의 예

|---|---|---|---| | M1 | 12주차 | 요구사항 확정 | 요구사항 명세서, 화면 정의서 | | M2 | 35주차 | 백엔드 API 구현 | API 문서, 테스트 리포트 | | M3 | 68주차 | 프론트 연동 | 동작하는 MVP | | M4 | 910주차 | 사용자 테스트 | 피드백 리포트, 수정 목록 | | M5 | 11~12주차 | 배포·발표 | 배포 URL, 발표자료 |

MVP 컷라인 선언이 ⑤번에 붙어 있는 것도 같은 맥락입니다. "이것도 하고 저것도 하겠다"보다 "MVP에는 여기까지만 넣고 나머지는 이후 과제로 둔다" 가 훨씬 신뢰를 줍니다. 할 수 있는 것을 정확히 말하는 것이 과장하지 않는 방법입니다.

9.5 AI 에이전트 오케스트레이션

오케스트레이션(Orchestration) — [조율 방식]인데, [중앙의 지휘자가 여러 구성요소의 실행 순서와 흐름을 통제한다]는 점에서 각자 알아서 반응하는 코레오그래피(Choreography)와 구별된다.

오케스트레이션코레오그래피
지휘자있음 (중앙 조율자)없음
흐름중앙이 순서를 정함각자 이벤트에 반응
추적쉬움어려움
토폴로지스타메시

앞에서 배운 것과 이어집니다 — 9주차의 스타 토폴로지 vs 메시가 에이전트 세계에서 그대로 반복됩니다. 여러 에이전트를 붙일 때 허브를 둘 것인가 각자 반응하게 할 것인가가 같은 선택입니다. 10주차에서 배운 에이전트 루프가 하나의 에이전트 이야기였다면, 오케스트레이션은 여러 에이전트를 조율하는 층입니다.


10. 실습 — 이번 주에 손으로 한 것

10.1 원격PC를 세우는 순서 (5장)

한 번만 하는 준비입니다. 순서를 바꾸면 뒤 단계에서 막힙니다.

#할 일명령 / 경로절
①WSL 설치 후 재부팅wsl --install (관리자 PowerShell)5.4
②윈도우 터미널 설치·기본 프로필 Ubuntuwinget install Microsoft.WindowsTerminal5.7
③OpenSSH 서버 설치 (클라이언트 아님)설정 > 선택적 기능 > [기능 보기] > openssh5.6
④우분투에 SSH 서버sudo apt update && sudo apt install -y openssh-server5.6
⑤작업용 사용자 (이름 = 브랜치 이름)adduser desktop → usermod -aG sudo desktop5.5
⑥기본 사용자 지정ubuntu config --default-user desktop5.5
⑦우분투 내부 IP 확인ip addr / hostname -I5.8
⑧포트포워딩 등록netsh interface portproxy add v4tov4 ...5.8
⑨방화벽 허용netsh advfirewall firewall add rule ...5.9
⑩sshd_config 설정 후 재시작Port 2222 외 3줄 → sudo service ssh restart5.11
⑪접속 테스트ssh -p 2222 desktop@192.168.0.2285.2

막혔을 때 점검 순서는 항상 안쪽 → 바깥쪽입니다. service ssh status → portproxy show all → 방화벽 규칙 → 주소.

10.2 매일 아침 루틴 (6.1~6.2절)

sudo service ssh start
sudo service ssh status        # active (running) 을 눈으로 확인
ipconfig                       # 오늘의 192.x.x.x 를 다시 확인
ssh -p 2222 desktop@192.168.0.228

자동 시작으로 바꾸기 — /etc/wsl.conf 에 [boot] / systemd=true 를 넣고, sudo systemctl enable ssh 등록 후 PowerShell에서 wsl --shutdown 으로 완전히 껐다 켭니다.

10.3 YOLO — 헬로월드와 파인튜닝 (3.9~3.11절)

pip install ultralytics
from ultralytics import YOLO

# ① 사전학습 가중치 로드 — 로컬에 없으면 자동으로 내려받습니다 (= pull)
model = YOLO("yolo11n.pt")

# ② 추론과 결과 확인
results = model("bus.jpg")
results[0].show()
for box in results[0].boxes:
    print(model.names[int(box.cls[0])], float(box.conf[0]))

# ③ 파인튜닝 — 반드시 Nano(n)로 시작
model.train(
    data="data.yaml",     # 데이터셋 설정 파일의 절대경로
    epochs=50,            # 전체 데이터를 몇 번 반복할지 (과적합 주의)
    batch=16,             # 한 번에 몇 장씩 (VRAM을 씁니다)
    imgsz=640,            # 입력 이미지 한 변의 픽셀
    device="cpu",         # GPU면 0, 맥은 "mps"
)

⚠️ device 를 지정하지 않아 CPU로 며칠 도는 사고가 흔합니다. 학습 시작 로그에서 장치를 확인하세요.

10.4 이미지 빌드 → 푸시 → 원격에서 실행 (8장)

# 접속PC에서
docker login
docker build -t myaccount/example-backend:0.1.0 .
docker tag  myaccount/example-backend:0.1.0 myaccount/example-backend:latest
docker push myaccount/example-backend:0.1.0
docker push myaccount/example-backend:latest
# 원격PC에서 (SSH 접속 후)
docker pull myaccount/example-backend:latest
docker run -d --name backend -p 8000:8000 --env-file .env \
  --restart unless-stopped myaccount/example-backend:latest
docker ps && docker logs -f backend

10.5 두 PC 동기화 (7.4절)

깃허브에 푸시하고 모든 브랜치를 동기화하고,
desktop 브랜치는 ssh 서버에서 pull 해서 다 동기화해줘
git add . && git commit -m "작업" && git push origin laptop   # 접속PC
git fetch origin && git merge origin/main                     # 원격PC

11. 이 주의 읽을거리와 그 맥락

11.1 ANN / DNN / CNN / RNN 개념 정리

🔗 https://ebbnflow.tistory.com/119

왜 이 주에 이게 나왔는가: 축 1의 왼쪽 세 번째 칸이 모델 파일이었고, 그 파일 안에 들어 있는 것이 신경망의 가중치입니다. YOLO를 조사하기 전에 CNN이 무엇인지를 먼저 잡아야 "왜 이미지에는 이 구조를 쓰는가"가 이해됩니다. (3.2절)

11.2 YOLO 조사 보고서 (컴퓨터비전)

🔗 https://share.evernote.com/note/76623b26-389b-4df6-9edb-15bc10421317

객체 검출의 역사, One-shot vs Two-shot, YOLO의 정의, Fast R-CNN과의 비교, v1~v5 발전과정, 조사 결과와 의견까지 여섯 개 목차로 이루어진 조사 보고서입니다.

왜 이 주에 이게 나왔는가: 이 주의 산출물은 다운로드 절차가 아니라 조사 보고서였습니다. 새 기술을 만났을 때 "설치법"이 아니라 "이것은 어떤 축의 어느 쪽에서 태어났는가" 를 먼저 조사하는 훈련입니다. One-shot/Two-shot 축을 잡고 나면 앞으로 나올 검출 모델 대부분이 자동으로 분류됩니다. (3.3~3.8절)

11.3 헤르메스 에이전트 가이드북

🔗 https://wikidocs.net/book/19414

왜 이 주에 이게 나왔는가: 이번 주에 세운 원격 우분투 서버는 사람이 매일 SSH로 들어가는 곳입니다. 그런데 그 자리는 결국 에이전트가 상주하는 자리가 됩니다. 서버를 세우는 이유가 "내가 원격으로 코딩하려고"에서 "에이전트를 24시간 돌리려고"로 옮겨가는 것입니다.

앞으로 다시 만납니다 — 14주차에서 이 우분투 위에 헤르메스 에이전트를 설치하고, 로컬 Ollama와 연결합니다. 그때 10주차의 SLM 온프레미스와 이번 주의 원격 서버가 한 자리에서 만납니다.

11.4 AI 에이전트 오케스트레이션

🔗 https://www.ibm.com/kr-ko/think/topics/ai-agent-orchestration

왜 이 주에 이게 나왔는가: 마지막 날 팀 기획서를 평가하면서, 여러 팀이 여러 에이전트를 붙이는 구조를 제안했습니다. 에이전트를 하나 만드는 것과 여럿을 조율하는 것은 다른 문제입니다. 9주차의 스타 토폴로지가 그 답의 뼈대이고, 이 글은 그것이 에이전트 세계에서 어떤 이름으로 불리는지를 알려줍니다. (9.5절)

11.5 AWS 요금과 EC2 — 이 주에 왜 다시 언급되는가

10주차에서 다룬 AWS EC2·RDS·S3와 요금 폭탄 사례가 이 주에 다시 의미를 갖습니다.

왜 이 주인가: 이번 주 내내 우리는 "고정 주소를 가진 서버가 필요하다" 는 문제와 싸웠습니다. 그리고 그 문제를 돈으로 즉시 해결하는 방법이 클라우드 VM입니다. 직접 원격PC를 세워보고 나면 "왜 사람들이 EC2에 돈을 내는가" 가 이해되고, 동시에 "왜 켜두기만 해도 요금이 나가는가" 도 이해됩니다. 24시간 켜져 있어야 서버니까요. (6.6절 ⑦)


부록 A. 용어 사전

용어영문상위 범주정의
로컬Local실행 위치내 컴퓨터. 연산이 실제로 일어나는 엔진 쪽
클라우드Cloud실행 위치남의 컴퓨터. 배포·협업이 일어나는 유통망 쪽
레지스트리Registry저장소 유형이름(태그)을 붙여 이미지를 등록해두는 곳
Docker Hub—레지스트리도커 이미지의 공용 등록소
Hugging Face—플랫폼AI 모델·데이터셋·데모를 공유하는 생태계
Spaces—Hugging Face 기능올린 모델로 데모 웹앱까지 호스팅해주는 기능
.safetensors—모델 파일 포맷코드 실행 없이 텐서만 안전하게 읽는 포맷
push—방향로컬 → 클라우드. 밀어 올림
pull—방향클라우드 → 로컬. 끌어 내림
ANNArtificial Neural Network신경망입력–은닉–출력층으로 된 인공신경망의 기본형
DNNDeep Neural Network신경망은닉층이 여러 겹인 심층신경망
CNNConvolutional Neural Network신경망필터로 지역 특징을 뽑아 공간을 보존
RNNRecurrent Neural Network신경망은닉 상태를 다음 시점에 넘겨 순서를 보존
객체 검출Object DetectionCV 과제무엇이 있는지 + 어디에 있는지를 함께 답하는 작업
Two-shot—검출 방식후보 영역을 먼저 뽑고 분류하는 2단계 방식 (R-CNN 계열)
One-shot—검출 방식한 번의 신경망 통과로 위치·종류를 동시 예측 (YOLO 등)
YOLOYou Only Look Once검출 모델2015년 Joseph Redmon이 고안한 One-shot 검출 모델
Segmentation—CV 과제픽셀 단위로 물체 영역을 칠하는 작업
Bilinear Interpolation—계산 기법주변 값을 거리 비율로 섞어 중간 값을 구하는 방법
PyTorch—프레임워크텐서 연산·자동미분·학습 루프를 제공하는 딥러닝 프레임워크
VGGFace2—데이터셋셀럽 9,131명·약 331만 장의 얼굴 데이터셋
NVIDIA Container Toolkit—도구컨테이너가 호스트 GPU에 접근하게 해주는 다리
FaceDatasetPort—아웃바운드 포트데이터셋 설정 파일의 절대경로를 요구하는 추상
resource_adapters—폴더 규칙아웃바운드 포트의 구현체(자원 어댑터)를 두는 폴더
SSHSecure Shell프로토콜암호화된 원격 접속 프로토콜. 기본 포트 22
접속PC—역할ssh 를 치는 쪽(클라이언트). OS 무관
원격PC—역할sshd 가 도는 쪽(서버). SSH 접속하려면 우분투
WSLWindows Subsystem for Linux실행 환경윈도우 안에서 리눅스를 돌리는 장치
~tilde경로 표기홈 디렉터리. /home/<사용자이름>
포트포워딩Port Forwarding네트워크 기법들어온 요청을 안쪽 주소·포트로 전달하는 것
0.0.0.0—주소 표기"모든 랜카드에서 받는다"는 뜻
127.0.0.1localhost주소 표기"나 자신". 컨테이너 안에서는 컨테이너 자신
DHCPDynamic Host Configuration Protocol프로토콜IP를 자동으로 임대해주는 방식
공인 IPPublic IP주소 층위인터넷 전체에서 보이는 주소
NATNetwork Address Translation네트워크 기법사설 주소를 공인 주소로 바꿔주는 변환
MAC 주소—하드웨어 식별자랜카드 고유 번호. DHCP 예약의 기준
DDNSDynamic DNS서비스바뀌는 IP에 고정된 이름을 붙여주는 방식
터널Tunnel연결 방식안에서 밖으로 나가 붙어 포트 개방 없이 노출하는 방식
Elastic IP—AWS 기능EC2에 붙이는 고정 공인 IP
스케일업Scale-up확장 전략한 대의 사양을 올림(수직 확장)
스케일아웃Scale-out확장 전략대수를 늘림(수평 확장)
Human-in-the-LoopHITL설계 원칙최종 판단을 사람이 확정하도록 흐름에 사람을 넣는 것
즉시 파기—보안 정책분석 직후 원문·이미지를 저장하지 않고 지우는 것
오케스트레이션Orchestration조율 방식중앙 조율자가 실행 순서를 통제하는 방식
MVP 컷라인—범위 결정최소 기능 제품에 무엇까지 넣을지 명시적으로 선언하는 것

부록 B. 스스로 확인하기

먼저 답해보고, 막히면 옆의 절을 펼치세요.

#질문답이 있는 곳
1세 쌍(Git·Docker·Model)의 왼쪽에는 공통적으로 무엇이 있는가?1.3, 2.4
2Hugging Face가 GitHub·Docker Hub와 다른 점 하나는?2.3
3.safetensors 가 .pt 보다 안전한 이유는?2.3
4"이건 축 1의 쌍인가"를 판별하는 한 문장 질문은?2.6
5CNN과 RNN을 가르는 축은 무엇인가?3.2
6Two-shot에서 두 번의 shot은 각각 무엇인가?3.4
7YOLOv4는 무엇을 주고 무엇을 얻었는가?3.7
8PyTorch와 YOLO는 왜 같은 줄에 놓고 비교할 수 없는가?3.9
9"도커라서 GPU를 못 쓴다"의 진짜 원인은 어디에 있었는가?3.12
10FaceDatasetPort 가 요구하는 것은 딱 하나인데, 그것은?4.2
11접속PC와 원격PC 중 OS 제약이 있는 쪽은?5.1
12OpenSSH 서버를 깔아야 하는 쪽은 어느 PC인가?5.6
13WSL에 SSH로 붙으려면 왜 포트포워딩이 필요한가?5.8
14포트를 2222로 바꿀 때 같이 바꿔야 하는 네 곳은?5.10
15매일 아침 sudo service ssh start 를 쳐야 하는 이유는?6.2
16IP의 세 층은 각각 무엇이고 언제 바뀌는가?6.5
17DDNS는 IP를 고정하는가?6.6 ④
18터널이 포트 개방 없이 동작하는 원리는?6.6 ⑤
19두 PC는 왜 서로 직접 파일을 주고받지 않는가?7.2
20--host 0.0.0.0 을 빼면 무슨 일이 생기는가?8.3
21.env 를 이미지에 넣으면 안 되는 이유는?8.3
22:latest 태그만 쓰면 안 되는 이유는?8.4
232D 이미지로 영양소 정량이 어려운 원리적 이유는?9.2
24기획서 결함 중 일정이 1순위인 이유는?9.4

부록 C. 자주 하는 실수

실수바로잡기
"Git과 GitHub는 같은 것"❌ 프로그램과 웹 서비스. Git이 먼저 있고 GitHub가 그 위에 지어졌습니다
"클라우드 = 인터넷"❌ 인터넷은 길, 클라우드는 그 끝의 남의 컴퓨터
"허깅페이스는 그냥 깃허브 같은 것"⚠️ Spaces로 실행까지 해줍니다. 보관과 실행은 다른 축
model.save() 를 업로드라고 생각❌ 그건 SAVE(디스크 기록)입니다. 인터넷이 필요한가로 구분하세요
"버전 숫자가 크면 더 좋은 YOLO"⚠️ v4·v5부터 저자와 계보가 갈라졌습니다
"YOLO는 PyTorch의 상위 개념"❌ PyTorch는 프레임워크, YOLO는 그 위의 모델
"도커라서 GPU를 못 쓴다"❌ Dockerfile이 torch를 빌드에서 제외한 것이 원인. pip list 부터 확인
큰 모델(x)로 파인튜닝을 시작⚠️ Nano(n)로 시작하세요. 에러인지 느린 건지 구분이 안 됩니다
device 를 지정하지 않고 학습 시작⚠️ CPU로 며칠 돕니다. 시작 로그에서 장치를 확인하세요
OpenSSH 클라이언트를 깔고 접속을 기다림❌ 원격PC에는 서버가 필요합니다
usermod -G sudo (a 없이)❌ 기존 그룹이 전부 날아갑니다. 반드시 -aG
포트포워딩만 하고 방화벽을 안 열음⚠️ 둘 다 필요합니다. 전달 규칙과 통과 허가는 다릅니다
PowerShell에서 netsh 가 안 먹음⚠️ .\netsh.exe 로 실제 실행파일을 지목하세요
포트를 2222로 바꾸고 한 곳만 수정⚠️ 네 곳(sshd_config·portproxy·방화벽·접속 명령)을 전부
sshd_config 고치고 재시작 안 함⚠️ 설정은 시작할 때 읽습니다. sudo service ssh restart
"어제 됐는데 오늘 안 됨 = 고장"❌ DHCP로 IP가 바뀐 것입니다. ipconfig 와 ip addr 를 둘 다 확인
WSL 내부 IP와 LAN IP를 혼동⚠️ 172.x(WSL 내부)와 192.168.x(LAN)는 다른 층입니다
DDNS를 "고정 IP 받는 법"으로 이해❌ 유동 IP를 견디는 법입니다. 이름 한 겹을 덧대는 것
LAN도 불안정한데 인터넷에 포트부터 개방⚠️ 안쪽부터 고정하고 바깥으로 나갑니다
인터넷에 22번을 열고 비밀번호 인증 유지⚠️ 열 거면 키 인증만 남기세요
--host 127.0.0.1 로 컨테이너 실행❌ 컨테이너 밖에서 절대 안 붙습니다. 0.0.0.0
.env 를 이미지에 COPY❌ 이미지를 받는 모두가 내 키를 갖게 됩니다. .dockerignore + --env-file
:latest 만 태깅⚠️ 되돌릴 수 없습니다. 버전 태그를 같이 붙이세요
두 PC 사이에서 파일을 직접 복사⚠️ GitHub를 거치세요. 허브 없는 동기화는 반드시 어긋납니다
아침에 fetch 없이 바로 작업 시작⚠️ 다른 PC의 커밋과 충돌합니다. 하루의 시작은 fetch
"AI가 좋아지면 사진으로 g을 알 수 있다"❌ 2D에는 부피 정보가 없습니다. 없는 정보는 만들 수 없습니다

부록 D. 날짜별 색인

이 장의 내용이 실제 수업에서 어느 날 다뤄졌는지입니다.

날짜다룬 내용이 장의 절
7/6 (월)ANN/DNN/CNN/RNN 정리, YOLO와 PyTorch의 차이, YOLO 헬로월드, YOLO 조사 보고서(객체 검출 역사·One-shot vs Two-shot·v1~v5), keras_vggface의 VGGFace(resnet50)와 VGGFace2, 클린 아키텍처에 YOLO 파인튜닝 데이터셋 연결(FaceDatasetPort·LocalYoloDatasetAdapter·S3DatasetAdapter), resource_adapters 폴더명 확정, Nano 모델과 학습 파라미터, "도커라서 GPU 못 쓴다"는 오해와 NVIDIA Container Toolkit3, 4, 10.10~10.13
7/7 (화)헤르메스 에이전트 가이드북, ipconfig, OpenSSH 서버 설치, Windows Terminal 설치와 기본 프로필, 우분투 서브유저 adduser·usermod -aG sudo·ubuntu config --default-user, PC별 유저 이름 = 브랜치 이름 규칙, 윈도우 포트포워딩 netsh portproxy, 방화벽 규칙, ip addr 로 내부 IP 확인5.45.9, 10.110.6, 11.3
7/8 (수)접속PC/원격PC 구성 완성, SSH·WSL·우분투 설치 후 깃허브로 두 PC 동기화 = 스케일아웃 기반 하네스 엔지니어링, 원격 우분투에 도커 설치, 꼬인 포트 규칙 초기화와 2222 재등록(.\netsh.exe), SSH 서버 재설치, sshd_config 설정값(Port 2222·PasswordAuthentication·AllowUsers·ChallengeResponseAuthentication)5.10~5.12, 7, 10.5, 10.7
7/9 (목)⭐ 로컬 ↔ 클라우드 3쌍 대칭(Git·Docker·Model), 로컬=엔진/클라우드=유통망, 원격 PC를 껐다 켠 다음날 절차, sudo service ssh start·status·active (running), ipconfig 로 IP 재확인, 접속 테스트, 접속PC OS 무관·원격PC는 우분투, 모듈러 모놀리식에서 프론트 Vercel / 백엔드 FastAPI 도커 이미지 빌드·도커허브 배포1, 2, 5.1, 6.16.2, 8, 10.8, 10.1410.15
7/10 (금)⭐ 전원을 새로 켜면 IP가 유동적으로 변하는 문제와 해결 과제, 리눅스 ~ = home, 네 팀 기획서 상호 평가와 연합 포트폴리오 전략, Human-in-the-Loop(2D 영양소 정량 한계), 2단계 즉시 파기 정책과 반경 단위 비식별, 기획서 결함 우선순위 6가지와 M1~M5, 브랜치 규칙(원격 SSH=desktop / 로컬 WSL=laptop), AI 에이전트 오케스트레이션5.3, 6.3~6.8, 7.3, 9, 11.4

부록 E. Gemini / NotebookLM 프롬프트

복습 문제 받기

이 11주차 교재만 근거로 8문제를 내줘. 비전공자 기준으로.
"로컬 ↔ 클라우드 세 쌍"과 "IP의 세 층"은 반드시 포함해줘.
답은 바로 주지 말고, 내가 답한 다음에 채점하고
틀린 이유를 교재의 어느 절을 근거로 설명해줘. 교재에 없는 내용은 꺼내지 마.

인포그래픽 ① — 이 장의 중심

「2. 세 쌍의 대칭」을 인포그래픽 1장으로 만들어줘.
- 가운데 세로줄 기준으로 왼쪽 = 로컬(엔진), 오른쪽 = 클라우드(유통망)
- 위에서 아래로 세 줄: Git↔GitHub / Docker↔Docker Hub / Model↔Hugging Face
- 세 줄 모두 가운데에 "push ▶" 와 "◀ pull" 화살표를 같은 모양으로
- 각 상자 안에 2.1~2.3 표의 '개념'과 '비유'를 한 줄씩
- 맨 아래에 "로컬 = 엔진 / 클라우드 = 유통망" 을 크게. 전문용어는 한글(영문) 병기

인포그래픽 ② — IP의 세 층과 유동 IP 문제

「6.5 IP는 사실 세 층으로 되어 있다」를 인포그래픽 1장으로 만들어줘.
- 바깥에서 안쪽으로 세 겹의 상자: 인터넷 → 공유기 → 원격PC → WSL
- 각 층에 IP 예시(121.x / 192.168.0.228 / 172.30.174.137)와
  "언제 바뀌는가"를 빨간 라벨로 표시
- 오른쪽에 6.6절 해결 방법 7가지를 "어느 층을 고정하는가" 기준으로 배치
- 아래에 "서버는 주소가 변하면 안 된다" 한 문장을 크게

인포그래픽 ③ — SSH 접속이 성립하는 네 조건

「5.2」의 네 조건과 「5.8~5.9」를 합쳐 세로 흐름도로 만들어줘.
- 접속PC → 공유기 → 원격PC(윈도우) → portproxy → WSL(우분투) → sshd
- 각 화살표 옆에 그 구간에서 막힐 수 있는 원인과 확인 명령
  (ipconfig / ip addr / netsh portproxy show all / service ssh status)
- 점검 순서를 "안쪽 → 바깥쪽" 번호로 표시

막힐 때

11주차에서 "___" 가 이해가 안 돼.
이 교재의 판별 축 5개(로컬/클라우드, 고정/유동, 엔진/유통망, push/pull, 접속PC/원격PC)만
써서 다시 설명해줘. 교재에 없는 새 비유는 만들지 마.

미국식 분류로 다시 정리하기

이 교재에 나온 비유(일기장, 밀폐 용기, 스팀 플랫폼, 신분증, 방)를 전부 걷어내고,
"이것은 무엇의 한 종류인가 / 형제 개념과 무엇으로 갈리는가" 형식으로만
Git·GitHub·Docker·Docker Hub·모델 파일·Hugging Face·SSH·포트포워딩·DHCP·DDNS·터널을
다시 정의해줘.

앞뒤 장 연결 확인

1주차의 "축 2 (내 컴퓨터 ↔ 남의 컴퓨터)"가 11주차에서 어떻게 완성되는지 표로 정리해줘.
컬럼: 1주차에서의 모습 / 11주차의 절 / 무엇이 추가되었는가 / 새로 생긴 문제.
그리고 "앞으로 다시 만납니다"라고 표시된 부분을 모두 찾아, 이번 장의 어떤 개념이
몇 주차에서 어떤 이름으로 다시 나오는지도 같은 표에 넣어줘.