19์ฃผ์ฐจ(ํ ์คํธ ์ฌํ) ์ดํ Claude๊ฐ ์์๋ก ๊ตฌ์ฑํ ํ์ต ์ฌ์ ์ ์ต์ข ์ฃผ์ฐจ.
1~19์ฃผ์ฐจ์ ๋ชจ๋ ์ฝ๋๊ฐ ์ฌ์ฉ์์๊ฒ ์ ๋ฌ๋๊ณ ์ด์๋๋ ์์ญ ์ ์ ๋ณตํ๋ค.
- HTTP/๋คํธ์ํฌ ๊น์ด โ ๋ฐฑ์๋์ ํ ๋
- ์ปจํ ์ด๋์ Kubernetes โ ํ๋ ๋ฐฐํฌ์ ํ์ค
- CI/CD โ ์ฝ๋๋ฅผ ์ฌ์ฉ์์๊ฒ ์ ๋ฌํ๋ ๋ค๋ฆฌ
- Observability โ ์ด์ ์ค ์ผ์ด๋๋ ์ผ์ ๋ณด๋ ๋
4๋ ์ฐจ ํ์คํ ๊ฐ๋ฐ์๊ฐ ์๋์ด/๋ฆฌ๋ ๋ก ๊ฐ๋ ๋ง์ง๋ง ๊ด๋ฌธ.
1~19์ฃผ์ฐจ์ ์์น:
์ ์ด ์์ ์ ๊ฒฐ์ ์ ์ธ๊ฐ:
ILIC ๊ด์ :
[Part A โ ๋คํธ์ํฌ ๊ธฐ์ด (Day 1-2)]
[Phase 1] HTTP ๊น์ด (HTTP/1.1, HTTP/2, HTTP/3)
โ
[Phase 2] TCP/IP์ TLS โ ์ ์ 1
[Part B โ DevOps์ ์ปจํ
์ด๋ (Day 3-4)]
[Phase 3] Docker ๊น์ด
โ
[Phase 4] Kubernetes ํต์ฌ โ ์ ์ 2
[Part C โ CI/CD์ ์ด์ (Day 5-6)]
[Phase 5] CI/CD ํ์ดํ๋ผ์ธ
โ
[Phase 6] 12-Factor App๊ณผ ์ด์ ์์น
[Part D โ Observability (Day 7)]
[Phase 7] 3 Pillars (Logs, Metrics, Traces) โ ์ ์ 3
โ
[Phase 8] ์ฅ์ ๋์๊ณผ ์ฌ๊ณ ๋ถ์
์ด 8 Phase ร 28 Unit โ ์ ์ 3๊ฐ๋ฅผ ๊ฐ์ง ์์ถ ๋จ์ผ ์ฃผ์ฐจ.
| ์์ญ | ์ฃผ์ฐจ | ์๋ฏธ |
|---|---|---|
| Java ์ธ์ด | 1-3 | ๊ธฐ์ด |
| ๋์์ฑ | 4 | ๋จ์ผ JVM |
| Spring ์ํ๊ณ | 5-10 | ํ๋ ์์ํฌ |
| JPA | 11-12 | ์์์ฑ |
| DB | 13-14 | ๋ฐ์ดํฐ |
| Spring MVC | 15 | ์น ๊ณ์ธต |
| ๋ถ์ฐ ์์คํ | 16-17 | ์์คํ ํ์ฅ |
| Spring Security | 18 | ๋ณด์ |
| ํ ์คํธ | 19 | ๊ฒ์ฆ |
| HTTP/DevOps/Observability | 20 | ์ด์ |
โ ์๋์ด ๋ฐฑ์๋ ๊ฐ๋ฐ์๊ฐ ์์์ผ ํ ๊ฑฐ์ ๋ชจ๋ ์์ญ
| Day | Phase | ํ์ต ๋ชฉํ |
|---|---|---|
| 1์ผ์ฐจ | Phase 1 | HTTP ๊น์ด |
| 2์ผ์ฐจ | Phase 2 | TCP/IP + TLS (โ ) |
| 3์ผ์ฐจ | Phase 3 | Docker ๊น์ด |
| 4์ผ์ฐจ | Phase 4 | Kubernetes (โ ) |
| 5์ผ์ฐจ | Phase 5 + 6 | CI/CD + 12-Factor |
| 6์ผ์ฐจ | Phase 7 | Observability 3 Pillars (โ ) |
| 7์ผ์ฐจ | Phase 8 + ์ข ํฉ | ์ฅ์ ๋์ + ์๊ธฐ ์ ๊ฒ |
์ฌ์ ์ผ์ (14์ผ): ๊ฐ Part์ +1-2์ผ. ํนํ Phase 4, 7์ ์ง์ ์ค์ต ๊ถ์ฅ.
๋ชฉํ: ๋งค์ผ ์ฐ์ง๋ง ๊น์ด ๋ชจ๋ฅด๋ HTTP๋ฅผ ์ ํํ ์ดํดํ๋ค.
์ ์ ์ง์: 6์ฃผ์ฐจ Phase 7 (์น ์ธํ๋ผ), 15์ฃผ์ฐจ (Spring MVC)
HTTP (HyperText Transfer Protocol):
"TCP ์์ ํ ์คํธ ๊ธฐ๋ฐ ์์ฒญ-์๋ต ํ๋กํ ์ฝ"
ํต์ฌ ํน์ฑ โญ :
1. Stateless โ ๋งค ์์ฒญ ๋
๋ฆฝ
2. Request-Response โ ํด๋ผ์ด์ธํธ ์์
3. Text-based โ ์ฌ๋์ด ์ฝ์ ์ ์์ (HTTP/2 ์ ๊น์ง)
4. Connection-less โ ์๋ต ํ ์ฐ๊ฒฐ ์ข
๋ฃ (๊ธฐ๋ณธ)
HTTP ๋ฉ์์ง ๊ตฌ์กฐ:
Request:
GET /api/fares/1 HTTP/1.1 โ Start Line
Host: api.ilic.com โ Headers
Accept: application/json
Authorization: Bearer eyJ...
โ ๋น ์ค
โ Body (POST/PUT ์)
Response:
HTTP/1.1 200 OK โ Status Line
Content-Type: application/json โ Headers
Content-Length: 256
Cache-Control: max-age=60
โ ๋น ์ค
{"id": 1, "amount": 50000} โ Body
HTTP ๋ฉ์๋ ์๋ฏธ (15์ฃผ์ฐจ ๋ณต์ต + ์ฌํ):
| ๋ฉ์๋ | ์๋ฏธ | ๋ฉฑ๋ฑ์ฑ | ์์ ์ฑ | Body |
|---|---|---|---|---|
| GET | ์กฐํ | โ | โ | ๊ถ์ฅ X |
| POST | ์์ฑ | โ | โ | โ |
| PUT | ์ ์ฒด ์์ | โ | โ | โ |
| PATCH | ๋ถ๋ถ ์์ | โ* | โ | โ |
| DELETE | ์ญ์ | โ | โ | ์ต์ |
| HEAD | ๋ฉํ๋ฐ์ดํฐ๋ง | โ | โ | X |
| OPTIONS | ๋ฉ์๋ ํ์ธ | โ | โ | X |
์์ ์ฑ(Safe): ์๋ฒ ์ํ ๋ณ๊ฒฝ X
๋ฉฑ๋ฑ์ฑ(Idempotent): ์ฌ๋ฌ ๋ฒ ํธ์ถํด๋ ๊ฒฐ๊ณผ ๋์ผ
์์ฃผ ํท๊ฐ๋ฆฌ๋ ํค๋ โญ :
| ํค๋ | ์๋ฏธ |
|---|---|
| Content-Type | ์์ฒญ/์๋ต body์ ํ์ |
| Accept | ํด๋ผ์ด์ธํธ๊ฐ ๋ฐ์ ์ ์๋ ํ์ |
| Authorization | ์ธ์ฆ ์ ๋ณด |
| Cache-Control | ์บ์ฑ ์ ์ฑ |
| ETag | ๋ฆฌ์์ค ๋ฒ์ ์๋ณ |
| Content-Length | body ํฌ๊ธฐ |
| Connection | ์ฐ๊ฒฐ ์ ์ง (keep-alive) |
| Host | ๊ฐ์ ํธ์คํ ์ฉ |
| User-Agent | ํด๋ผ์ด์ธํธ ์ ๋ณด |
| Referer | ์ด์ ํ์ด์ง |
| Set-Cookie / Cookie | ์ฟ ํค ์ค์ /์ ์ก |
์๊ธฐ ์ ๊ฒ
์ ์ ์ง์: Unit 1.1, 15์ฃผ์ฐจ Phase 4
5๊ณ์ด โญ :
| ๊ณ์ด | ์๋ฏธ |
|---|---|
| 1xx | ์ ๋ณด (๋๋ฌผ๊ฒ ์ฌ์ฉ) |
| 2xx | ์ฑ๊ณต |
| 3xx | ๋ฆฌ๋ค์ด๋ ์ |
| 4xx | ํด๋ผ์ด์ธํธ ์ค๋ฅ |
| 5xx | ์๋ฒ ์ค๋ฅ |
์์ฃผ ์ฐ๋ ์ฝ๋ + ํํ ์คํด โญโญ :
ํํ ์คํด โ ๏ธ :
ํํ ์คํด:
ํํ ์คํด โ ๏ธ :
ILIC ์๋๋ฆฌ์ค โญ :
์ฌ์ฉ์: ์ด์ ๊ฒฌ์ ๋ฑ๋ก
โ
404 โ ์๋ชป๋ ID
401 โ ํ ํฐ ๋ง๋ฃ โ ์ฌ๋ก๊ทธ์ธ
403 โ ๊ถํ ๋ถ์กฑ
409 โ ์ด๋ฏธ ๋ฑ๋ก๋ ๊ฒฌ์
422 โ ํ์ ํ๋ ๋๋ฝ
429 โ API ํธ์ถ ํ๋ ์ด๊ณผ
500 โ ์๋ฒ ๋ด๋ถ ๋ฒ๊ทธ
502 โ ๊ฒฐ์ ์๋น์ค ๋ค์ด
504 โ DB ์ฟผ๋ฆฌ ํ์์์
์๊ธฐ ์ ๊ฒ
์ ์ ์ง์: Unit 1.2
์งํ ๊ณผ์ :
ํ๊ณ:
ํต์ฌ ๊ฐ์ :
"ํ ์ฐ๊ฒฐ์ ์ฌ๋ฌ ์์ฒญ/์๋ต์ ๋์์"
HTTP/1.1:
Connection 1: [Req A] โ [Res A]
Connection 2: [Req B] โ [Res B] (๋ณ๋ ์ฐ๊ฒฐ ํ์)
HTTP/2:
Connection 1: [Req A, Req B, Req C ๋์]
[Res A, Res B, Res C ์์ ๋ฌด๊ด]
โ HOL Blocking ํด๊ฒฐ (Application ๊ณ์ธต)
ํต์ฌ ๋ณํ:
HTTP/2์ ํ๊ณ (TCP ๋๋ฌธ):
HTTP/3 (QUIC):
์ฑํ ํํฉ:
๋น๊ต ๋งคํธ๋ฆญ์ค โญ :
| HTTP/1.1 | HTTP/2 | HTTP/3 | |
|---|---|---|---|
| ์ ์ก ๋ฐฉ์ | ํ ์คํธ | ๋ฐ์ด๋๋ฆฌ | ๋ฐ์ด๋๋ฆฌ |
| ๋ฉํฐํ๋ ์ฑ | X (HOL) | โ | โ |
| ํค๋ ์์ถ | X | HPACK | QPACK |
| ์ ์ก ๊ณ์ธต | TCP | TCP | QUIC (UDP) |
| TCP HOL | ์์ | ์์ | ํด๊ฒฐ |
| ํธ๋์ ฐ์ดํฌ | 1-2 RTT | 1-2 RTT | 0-1 RTT |
ILIC ์ ์ฉ:
server:
http2:
enabled: true
์๊ธฐ ์ ๊ฒ
๋ชฉํ: ๋ฉด์ ๋จ๊ณจ โ ๋คํธ์ํฌ ํ ๋๋ฅผ ๊น์ด ์ดํดํ๋ค.
์ ์ ์ง์: ์ปดํจํฐ ๊ธฐ์ด
OSI 7๊ณ์ธต (์ด๋ก ):
| ๊ณ์ธต | ์ด๋ฆ | ์ |
|---|---|---|
| 7 | Application | HTTP, FTP, SMTP |
| 6 | Presentation | TLS, SSL, JPEG |
| 5 | Session | NetBIOS |
| 4 | Transport | TCP, UDP โญ |
| 3 | Network | IP, ICMP โญ |
| 2 | Data Link | Ethernet, Wi-Fi |
| 1 | Physical | ์ผ์ด๋ธ, ๊ด์ฌ์ |
TCP/IP 4๊ณ์ธต (์ค์ ):
| ๊ณ์ธต | OSI ๋งคํ |
|---|---|
| Application | 7-5 |
| Transport | 4 |
| Internet | 3 |
| Network Access | 2-1 |
ํต์ฌ ์บก์ํ โญ :
[HTTP Request ๋ฐ์ดํฐ]
โ Application Layer
[HTTP + ๋ฐ์ดํฐ]
โ Transport Layer (TCP)
[TCP ํค๋ + HTTP + ๋ฐ์ดํฐ] = TCP ์ธ๊ทธ๋จผํธ
โ Internet Layer (IP)
[IP ํค๋ + TCP ์ธ๊ทธ๋จผํธ] = IP ํจํท
โ Network Access
[Ethernet ํค๋ + IP ํจํท] = Frame
โ
[์ ์ก]
์๊ธฐ ์ ๊ฒ
์ ์ ์ง์: Unit 2.1
TCP:
"์ฐ๊ฒฐ ์งํฅ์ , ์ ๋ขฐ์ฑ ์๋ ์ ์ก ํ๋กํ ์ฝ"
3-way Handshake โ ์ฐ๊ฒฐ ์๋ฆฝ โญ :
Client Server
| |
|โโโ SYN (seq=x) โโโโโโโโโโ| 1. "์ฐ๊ฒฐํ ๊ฒ"
| |
|โโโ SYN-ACK (seq=y, โโโโโ| 2. "OK, ๋๋ OK?"
| ack=x+1) |
| |
|โโโ ACK (ack=y+1) โโโโโโโโ| 3. "OK"
| |
|โโโ ์ฐ๊ฒฐ ์๋ฆฝ โโโโโโโโโโโ|
| |
|โโโ HTTP Request โโโโโโโโโ|
|โโโ HTTP Response โโโโโโโโ|
์ 3๋ฒ? โญ :
4-way Handshake โ ์ฐ๊ฒฐ ์ข ๋ฃ โญ :
Client Server
| |
|โโโ FIN โโโโโโโโโโโโโโโโโโ| 1. "๋๋ผ๊ฒ"
| |
|โโโ ACK โโโโโโโโโโโโโโโโโโ| 2. "OK"
| |
| (์๋ฒ ์์
๋ง๋ฌด๋ฆฌ) |
| |
|โโโ FIN โโโโโโโโโโโโโโโโโโ| 3. "๋๋ ๋"
| |
|โโโ ACK โโโโโโโโโโโโโโโโโโ| 4. "OK"
| |
|โโโ TIME_WAIT (Client) โโ|
TIME_WAIT โญ :
TIME_WAIT ํด๊ฒฐ:
SO_REUSEADDR ์ต์
TCP์ ์ ๋ขฐ์ฑ ๋ณด์ฅ ๋ฉ์ปค๋์ฆ โญ :
TCP vs UDP โญ :
| TCP | UDP | |
|---|---|---|
| ์ฐ๊ฒฐ | ์ฐ๊ฒฐ ์งํฅ | ๋น์ฐ๊ฒฐ |
| ์ ๋ขฐ์ฑ | โ | X |
| ์์ | ๋ณด์ฅ | ๋ณด์ฅ X |
| ์๋ | ๋๋ฆผ | ๋น ๋ฆ |
| Header | 20+ bytes | 8 bytes |
| ์ฉ๋ | HTTP, DB | DNS, ๊ฒ์, VoIP |
๋ฉด์ ๋ชจ์ ๋ต๋ณ โญ :
"TCP๋ ์ฐ๊ฒฐ ์งํฅ์ ์ด๊ณ ์ ๋ขฐ์ฑ ์๋ ์ ์ก ํ๋กํ ์ฝ์ ๋๋ค. ์ฐ๊ฒฐ ์๋ฆฝ ์ 3-way handshake๋ฅผ ๊ฑฐ์น๋๋ฐ, SYN, SYN-ACK, ACK ์ธ ๋ฒ์ ๋ฉ์์ง๋ก ์์ชฝ ๋ชจ๋์ ์ก์์ ๋ฅ๋ ฅ์ ํ์ธํฉ๋๋ค.
์ข ๋ฃ ์์๋ 4-way handshake๋ก, ์์ชฝ์ด ๊ฐ๊ฐ FIN๊ณผ ACK๋ฅผ ์ฃผ๊ณ ๋ฐ์ต๋๋ค. ์ด๋ ๋ง์ง๋ง ACK ์์ค์ ๋๋นํด TIME_WAIT ์ํ๋ก ์ผ์ ์๊ฐ ๋๊ธฐํ๋๋ฐ, ์ด๊ฒ ๋์ ๋๋ฉด ์์ผ ๊ณ ๊ฐ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ด SO_REUSEADDR ์ต์ ์ด๋ Connection Pool๋ก ํด๊ฒฐํฉ๋๋ค.
TCP๋ ์ ๋ขฐ์ฑ์ ์ํด Sequence Number, ACK, Checksum, Flow Control, Congestion Control์ ์ฌ์ฉํฉ๋๋ค. ์ด๋ฐ ๋ฉ์ปค๋์ฆ ๋๋ฌธ์ UDP๋ณด๋ค ๋๋ฆฌ์ง๋ง, ์ ํ์ฑ์ด ์ค์ํ HTTP, DB ํต์ ๋ฑ์ ์ฌ์ฉ๋ฉ๋๋ค."
์๊ธฐ ์ ๊ฒ
์ ์ ์ง์: Unit 2.2, 18์ฃผ์ฐจ (Security)
HTTPS:
"HTTP + TLS โ ์ํธํ๋ HTTP"
์ ํ์ํ๊ฐ:
TLS (Transport Layer Security):
TLS 1.2 Handshake (์ ํต):
Client Server
| |
|โโโ ClientHello โโโโโโโโโโโโโโโโโโ| ์ง์ ์ํธ ์๊ณ ๋ฆฌ์ฆ
| |
|โโโ ServerHello โโโโโโโโโโโโโโโโโโ| ์ ํํ ์๊ณ ๋ฆฌ์ฆ
|โโโ Certificate (์ธ์ฆ์) โโโโโโโโโ| ์๋ฒ ์ธ์ฆ์
|โโโ ServerHelloDone โโโโโโโโโโโโโโ|
| |
| [์ธ์ฆ์ ๊ฒ์ฆ] |
| |
|โโโ ClientKeyExchange โโโโโโโโโโโโ| Pre-Master Secret ์ ์ก
|โโโ ChangeCipherSpec โโโโโโโโโโโโโ|
|โโโ Finished โโโโโโโโโโโโโโโโโโโโโ|
| |
|โโโ ChangeCipherSpec โโโโโโโโโโโโโ|
|โโโ Finished โโโโโโโโโโโโโโโโโโโโโ|
| |
|โโโ ์ํธํ๋ ํต์ โโโโโโโโโโโโโโโโ|
RTT: 2 RTT (์๋ณต 2๋ฒ)
TLS 1.3 Handshake (2018) โญ :
Client Server
| |
|โโโ ClientHello + Key Share โโโโโโ|
| |
|โโโ ServerHello + Cert + Key + โโ|
| Finished |
| |
|โโโ Finished โโโโโโโโโโโโโโโโโโโโโ|
| |
|โโโ ์ํธํ๋ ํต์ โโโโโโโโโโโโโโโโ|
RTT: 1 RTT
0-RTT ๋ชจ๋: ์ด์ ์ธ์
์ฌ๊ฐ ์ ์ฆ์
๊ฐ์ ์ :
ํต์ฌ ์๋ฆฌ โญ :
์ ๋ ๋ค?:
์ธ์ฆ์ ์ฒด์ธ:
Root CA (๋ธ๋ผ์ฐ์ ์ ๋ด์ฅ)
โ ์๋ช
Intermediate CA
โ ์๋ช
Leaf Certificate (์ค์ ์ฌ์ดํธ)
Let's Encrypt:
HTTPS ๋น์ฉ โ ๏ธ :
ํ๋ ๊ฒฐ๋ก :
ILIC ์ ์ฉ:
์๊ธฐ ์ ๊ฒ
์ ์ ์ง์: Unit 2.3
DNS (Domain Name System):
"๋๋ฉ์ธ ์ด๋ฆ โ IP ์ฃผ์ ๋ณํ"
api.ilic.com โ 203.0.113.42
DNS ์กฐํ ํ๋ฆ:
1. Browser Cache ํ์ธ
2. OS Cache ํ์ธ
3. Router Cache ํ์ธ
4. ISP DNS ์๋ฒ ์กฐํ
5. Root โ TLD โ Authoritative DNS
DNS ๋ ์ฝ๋ ํ์ โญ :
| ํ์ | ์๋ฏธ |
|---|---|
| A | ๋๋ฉ์ธ โ IPv4 |
| AAAA | ๋๋ฉ์ธ โ IPv6 |
| CNAME | ๋๋ฉ์ธ โ ๋ค๋ฅธ ๋๋ฉ์ธ (๋ณ์นญ) |
| MX | ๋ฉ์ผ ์๋ฒ |
| TXT | ํ ์คํธ (SPF, DKIM, ์ธ์ฆ) |
| NS | ๋ค์์๋ฒ |
| SRV | ์๋น์ค (ํฌํธ ํฌํจ) |
Load Balancing โญ :
์ญํ :
์๊ณ ๋ฆฌ์ฆ:
| ์๊ณ ๋ฆฌ์ฆ | ํน์ง |
|---|---|
| Round Robin | ์์ฐจ ๋ถ๋ฐฐ |
| Least Connections | ์ฐ๊ฒฐ ์ ์ ์ ๊ณณ |
| IP Hash | ๊ฐ์ IP๋ ๊ฐ์ ์๋ฒ (Sticky) |
| Weighted | ๊ฐ์ค์น ๊ธฐ๋ฐ |
Layer 4 vs Layer 7 LB โญ :
| L4 (Transport) | L7 (Application) | |
|---|---|---|
| ๊ธฐ์ค | IP, Port | URL, Header, Cookie |
| ์๋ | ๋น ๋ฆ | ๋๋ฆผ |
| ๊ธฐ๋ฅ | ๋จ์ | ํ๋ถ (Path ๋ผ์ฐํ ๋ฑ) |
| ์ | AWS NLB | AWS ALB, Nginx |
ILIC ์๋๋ฆฌ์ค:
/api/* โ Spring Boot/static/* โ CDNSticky Session โ ๏ธ :
์๊ธฐ ์ ๊ฒ
๋ชฉํ: ILIC๊ฐ ์ด๋ฏธ ์ฌ์ฉ ์ค์ผ ๊ฐ๋ฅ์ฑ ๋์ง๋ง ๊น์ด ์ ๋ฆฌํ๋ค.
์ ์ ์ง์: ์ด์์ฒด์ ๊ธฐ์ด
์ ํต ๋ฐฐํฌ์ ๋ฌธ์ :
๊ฐ์ํ์ ์งํ:
[App A] [App B] [App C]
[Guest OS] [Guest OS] [Guest OS] โ ๋ฌด๊ฑฐ์
[Hypervisor]
[Host OS]
[Hardware]
[App A] [App B] [App C]
[Bin/Lib] [Bin/Lib] [Bin/Lib]
[Container Runtime (Docker)]
[Host OS] โ ๊ณต์
[Hardware]
ํต์ฌ ์ฐจ์ด:
Docker์ ํต์ฌ ๋ฉ์ปค๋์ฆ โญ :
3๊ฐ์ง ํต์ฌ ๊ฐ๋ โญ :
์๊ธฐ ์ ๊ฒ
์ ์ ์ง์: Unit 3.1
๊ธฐ๋ณธ Dockerfile (Spring Boot):
FROM openjdk:17-jdk-slim
WORKDIR /app
COPY target/ilic.jar app.jar
EXPOSE 8080
CMD ["java", "-jar", "app.jar"]
๋ฌธ์ :
Multi-stage Build โญ โ ๋น๋์ ์คํ ๋ถ๋ฆฌ:
# ๋น๋ ์คํ
์ด์ง
FROM gradle:8-jdk17 AS builder
WORKDIR /build
COPY . .
RUN gradle build -x test
# ์คํ ์คํ
์ด์ง
FROM openjdk:17-jre-slim
WORKDIR /app
COPY --from=builder /build/libs/ilic.jar app.jar
EXPOSE 8080
CMD ["java", "-jar", "app.jar"]
ํจ๊ณผ:
๋ ์ด์ด ์บ์ฑ ํ์ฉ โญ :
๋์ ์:
COPY . .
RUN gradle build # ์ฝ๋ 1์ค ๋ณ๊ฒฝํด๋ ์ฒ์๋ถํฐ
์ข์ ์ (Spring Boot ๊ถ์ฅ):
# ์์กด์ฑ๋ง ๋จผ์
COPY build.gradle settings.gradle ./
RUN gradle dependencies
# ๊ทธ ๋ค์ ์์ค
COPY src ./src
RUN gradle build
โ ์์กด์ฑ ๋ณ๊ฒฝ ์์ผ๋ฉด ์บ์ ํ์ฉ
Spring Boot Layered JAR โญ :
Spring Boot 2.3+๊ฐ ์ ๊ณตํ๋ ์ต์ ํ:
FROM openjdk:17-jre-slim
WORKDIR /app
ARG JAR_FILE=target/ilic.jar
COPY ${JAR_FILE} app.jar
RUN java -Djarmode=layertools -jar app.jar extract
FROM openjdk:17-jre-slim
WORKDIR /app
COPY --from=builder /app/dependencies/ ./
COPY --from=builder /app/spring-boot-loader/ ./
COPY --from=builder /app/snapshot-dependencies/ ./
COPY --from=builder /app/application/ ./
ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]
ํจ๊ณผ:
๋ณด์ ๋ชจ๋ฒ ์ฌ๋ก โญ :
RUN useradd -ms /bin/bash appuser
USER appuser
alpine ๋๋ slim ๋ณํdistroless (Google) โ ๋ ์์.git
.gradle
target
*.md
FROM openjdk:17.0.9-jre-slim # โ latest ๊ธ์ง
ILIC ์๋๋ฆฌ์ค:
์๊ธฐ ์ ๊ฒ
์ ์ ์ง์: Unit 3.2
๋ฌธ์ :
Docker Compose:
"์ฌ๋ฌ ์ปจํ ์ด๋๋ฅผ YAML๋ก ์ ์ + ํ ๋ฒ์ ์คํ"
version: '3.8'
services:
app:
build: .
ports:
- "8080:8080"
environment:
- SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/ilic
- SPRING_DATASOURCE_PASSWORD=${DB_PASSWORD}
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_started
networks:
- ilic-network
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
MYSQL_DATABASE: ilic
volumes:
- mysql-data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping"]
interval: 10s
timeout: 5s
retries: 5
networks:
- ilic-network
redis:
image: redis:7-alpine
networks:
- ilic-network
kafka:
image: confluentinc/cp-kafka:latest
networks:
- ilic-network
volumes:
mysql-data:
networks:
ilic-network:
์คํ:
docker-compose up -d
docker-compose down
docker-compose logs -f app
Compose vs Kubernetes:
ILIC ํ์ฉ:
์๊ธฐ ์ ๊ฒ
๋ชฉํ: ํ๋ ์ด์์ ํ์ค โ K8s์ ํต์ฌ ์ปจ์ ์ ๋ฉด์ ๋ต๋ณ ๊ฐ๋ฅ ์์ค์ผ๋ก.
์ ์ ์ง์: Phase 3
Docker๋ง์ผ๋ก์ ํ๊ณ:
Kubernetes (K8s):
"์ปจํ ์ด๋ ์ค์ผ์คํธ๋ ์ด์ ํ์ค"
ํต์ฌ ๊ธฐ๋ฅ โญ :
Cluster ๊ตฌ์กฐ โญ :
[Control Plane (Master)]
โโโ API Server โ ๋ชจ๋ ๋ช
๋ น์ ์
๊ตฌ
โโโ etcd โ ์ํ ์ ์ฅ (17์ฃผ์ฐจ ํฉ์ ์๊ณ ๋ฆฌ์ฆ)
โโโ Scheduler โ Pod ๋ฐฐ์น ๊ฒฐ์
โโโ Controller Manager โ ์ํ ์ ์ง
[Worker Nodes]
โโโ Node 1
โ โโโ kubelet โ ๋
ธ๋ ์์ด์ ํธ
โ โโโ kube-proxy โ ๋คํธ์ํฌ
โ โโโ Pods (containers)
โโโ Node 2
โโโ Node 3
์๊ธฐ ์ ๊ฒ
์ ์ ์ง์: Unit 4.1
3๊ฐ์ง ํต์ฌ ๋ฆฌ์์ค โญ :
apiVersion: v1
kind: Pod
metadata:
name: ilic-pod
spec:
containers:
- name: ilic-app
image: ilic:1.0.0
ports:
- containerPort: 8080
ํน์ง:
์ Pod์ธ๊ฐ (๊ทธ๋ฅ ์ปจํ ์ด๋ ์๋๊ณ ):
apiVersion: apps/v1
kind: Deployment
metadata:
name: ilic-deployment
spec:
replicas: 3 โ 3๊ฐ Pod
selector:
matchLabels:
app: ilic
template:
metadata:
labels:
app: ilic
spec:
containers:
- name: ilic-app
image: ilic:1.0.0
resources:
requests:
memory: "512Mi"
cpu: "500m"
limits:
memory: "1Gi"
cpu: "1000m"
์ญํ โญ :
Rolling Update ํ๋ฆ:
v1: [Pod1] [Pod2] [Pod3]
โ
v2 ์์: [Pod1] [Pod2] [Pod3] [Pod4(v2)]
โ
[Pod2] [Pod3] [Pod4(v2)] [Pod5(v2)] โ Pod1 ์ข
๋ฃ
โ
[Pod4(v2)] [Pod5(v2)] [Pod6(v2)]
๋ฌธ์ : Pod IP๋ ๋ณํจ โ ์ด๋ป๊ฒ ์ ๊ทผ?
Service:
"Pod ๊ทธ๋ฃน์ ์์ ์ ์ธ ์ ๊ทผ์ "
apiVersion: v1
kind: Service
metadata:
name: ilic-service
spec:
selector:
app: ilic โ ์ด ๋ผ๋ฒจ์ Pod ๋ฌถ์
ports:
- port: 80
targetPort: 8080
type: ClusterIP
Service Type โญ :
| Type | ์๋ฏธ |
|---|---|
| ClusterIP | ํด๋ฌ์คํฐ ๋ด๋ถ๋ง (๊ธฐ๋ณธ) |
| NodePort | ๋ ธ๋์ ํน์ ํฌํธ๋ก ๋ ธ์ถ |
| LoadBalancer | ์ธ๋ถ LB ์๋ ์์ฑ (AWS ELB ๋ฑ) |
| ExternalName | DNS CNAME |
Service Discovery (17์ฃผ์ฐจ ์๋ ํด๊ฒฐ):
http://ilic-service ์ผ๋ก ์ ๊ทผ โ K8s๊ฐ ์๋ ๋ผ์ฐํ
ILIC ์๋๋ฆฌ์ค:
# Backend
Deployment: ilic-app (replicas: 3)
Service: ilic-service (ClusterIP)
# Frontend
Deployment: ilic-vue (replicas: 2)
Service: ilic-vue-service
# Ingress (์ธ๋ถ ์ ๊ทผ)
Ingress:
- api.ilic.com โ ilic-service
- ilic.com โ ilic-vue-service
์๊ธฐ ์ ๊ฒ
์ ์ ์ง์: Unit 4.2
๋ฌธ์ : LoadBalancer Service๋ฅผ ๋๋ฉ์ธ๋ง๋ค ๋ง๋ค๋ฉด ๋น์ฉ โ
Ingress:
"HTTP/HTTPS L7 ๋ผ์ฐํ "
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ilic-ingress
annotations:
cert-manager.io/cluster-issuer: letsencrypt
spec:
tls:
- hosts:
- api.ilic.com
secretName: ilic-tls
rules:
- host: api.ilic.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: ilic-service
port:
number: 80
- path: /admin
pathType: Prefix
backend:
service:
name: ilic-admin-service
port:
number: 80
์ญํ :
apiVersion: v1
kind: ConfigMap
metadata:
name: ilic-config
data:
application.yml: |
spring:
profiles:
active: prod
server:
port: 8080
์ฌ์ฉ:
spec:
containers:
- name: ilic-app
volumeMounts:
- name: config
mountPath: /config
volumes:
- name: config
configMap:
name: ilic-config
apiVersion: v1
kind: Secret
metadata:
name: ilic-secret
type: Opaque
data:
db-password: cGFzc3dvcmQ= # Base64
์ฌ์ฉ:
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: ilic-secret
key: db-password
โ ๏ธ ์ฃผ์:
ILIC ์ ์ฉ:
์๊ธฐ ์ ๊ฒ
์ ์ ์ง์: Unit 4.2
3๊ฐ์ง Probe:
spec:
containers:
- name: ilic-app
livenessProbe: โ "์ด์์๋?"
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
failureThreshold: 3
readinessProbe: โ "ํธ๋ํฝ ๋ฐ์ ์ค๋น?"
httpGet:
path: /actuator/health/readiness
port: 8080
periodSeconds: 5
startupProbe: โ "์์ ์ค?"
httpGet:
path: /actuator/health
port: 8080
failureThreshold: 30
periodSeconds: 10
์ฐจ์ด์ โญ :
| Liveness | Readiness | Startup | |
|---|---|---|---|
| ์คํจ ์ | ์ฌ์์ | ํธ๋ํฝ ์ฐจ๋จ | ๋ค๋ฅธ Probe ์์ |
| ์ฉ๋ | Deadlock ๊ฐ์ง | ์ผ์์ ๋ถํ | ๋๋ฆฐ ์์ |
Spring Boot Actuator ํ์ฉ:
management:
endpoints:
web:
exposure:
include: health
endpoint:
health:
probes:
enabled: true
โ /actuator/health/liveness, /actuator/health/readiness ์๋ ์ ๊ณต
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: ilic-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: ilic-deployment
minReplicas: 3
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
ํจ๊ณผ:
ILIC ์๋๋ฆฌ์ค:
VPA (Vertical) vs HPA (Horizontal) โญ :
์๊ธฐ ์ ๊ฒ
๋ชฉํ: ์ฝ๋๋ฅผ ์ฌ์ฉ์์๊ฒ ์๋์ผ๋ก ์ ๋ฌํ๋ ๋ค๋ฆฌ๋ฅผ ์ดํดํ๋ค.
์ ์ ์ง์: Phase 4, 19์ฃผ์ฐจ (ํ ์คํธ)
CI (Continuous Integration):
"์์ฃผ ํตํฉ โ ๋น๋ + ํ ์คํธ ์๋ํ"
CD (Continuous Delivery / Deployment):
์ ํ์ ํ์ดํ๋ผ์ธ โญ :
[Code Push]
โ
[Build] โ Gradle build
โ
[Static Analysis] โ SonarQube, Checkstyle
โ
[Unit Test] โ JUnit (19์ฃผ์ฐจ)
โ
[Integration Test] โ Testcontainers (19์ฃผ์ฐจ)
โ
[Build Image] โ Docker
โ
[Push to Registry] โ ECR, GCR
โ
[Deploy to Dev] โ ์๋
โ
[E2E Test] โ ์๋
โ
[Deploy to Staging] โ ์๋
โ
[Manual Approval] โ ์ด์ ๋ฐฐํฌ ์
โ
[Deploy to Prod]
โ
[Smoke Test]
๊ฐ ๋จ๊ณ์ ์๋ฏธ โญ :
| ๋จ๊ณ | ๋ชฉ์ |
|---|---|
| Build | ์ฝ๋ โ ์คํ ๊ฐ๋ฅ ํํ |
| Static Analysis | ์ปดํ์ผ ์ ์ ์ก๊ธฐ (์ฝ๋ ์ค๋ฉ, ๋ณด์) |
| Unit Test | ๋น ๋ฅธ ํ๊ท ๊ฒ์ฆ |
| Integration Test | ํตํฉ ๊ฒ์ฆ |
| Build Image | ๋ฐฐํฌ ๋จ์ |
| Deploy to Dev | ๊ฐ๋ฐ์ ๊ฒ์ฆ |
| E2E Test | ์ ์ฒด ์๋๋ฆฌ์ค |
| Deploy to Staging | ์ด์๊ณผ ๋์ผ ํ๊ฒฝ |
| Manual Approval | ์ํ ํต์ |
| Deploy to Prod | ์ฌ์ฉ์ ๋ ธ์ถ |
์๊ธฐ ์ ๊ฒ
์ ์ ์ง์: Unit 5.1
GitHub Actions (๊ฐ์ฅ ๋ณดํธ):
.github/workflows/ci-cd.yml:
name: CI/CD
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
services:
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: test
MYSQL_DATABASE: test
ports:
- 3306:3306
steps:
- uses: actions/checkout@v4
- name: Setup JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Cache Gradle
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
- name: Run Tests
run: ./gradlew test
- name: Generate Coverage Report
run: ./gradlew jacocoTestReport
- name: Upload Coverage to Codecov
uses: codecov/codecov-action@v3
build-and-push:
needs: test
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build with Gradle
run: ./gradlew build -x test
- name: Build Docker Image
run: docker build -t ilic:${{ github.sha }} .
- name: Login to ECR
uses: aws-actions/amazon-ecr-login@v2
- name: Push Image
run: docker push ${{ env.ECR_REGISTRY }}/ilic:${{ github.sha }}
deploy:
needs: build-and-push
runs-on: ubuntu-latest
steps:
- name: Deploy to K8s
run: kubectl set image deployment/ilic ilic=ilic:${{ github.sha }}
ํต์ฌ ๊ฐ๋ :
needs๋ก ์์กด์ฑ์บ์ฑ โญ โ ์๋ ํฅ์:
์๊ธฐ ์ ๊ฒ
์ ์ ์ง์: Phase 4, Unit 5.2
3๊ฐ์ง ๋ฐฐํฌ ์ ๋ต โญ :
v1: [Pod] [Pod] [Pod]
โ 1๊ฐ์ฉ ๊ต์ฒด
v2: [Pod(v2)] [Pod(v1)] [Pod(v1)]
โ
v2: [Pod(v2)] [Pod(v2)] [Pod(v1)]
โ
v2: [Pod(v2)] [Pod(v2)] [Pod(v2)]
์ฅ์ : ๋จ์, ์์ ํจ์จ
๋จ์ : ๋กค๋ฐฑ ๋๋ฆผ, ๋ ๋ฒ์ ๊ณต์กด
Blue (์ด์): [Pod(v1)] [Pod(v1)] [Pod(v1)] โ ํธ๋ํฝ
Green (๋๊ธฐ): [Pod(v2)] [Pod(v2)] [Pod(v2)]
โ ํธ๋ํฝ ์ ํ
Blue (๋๊ธฐ): [Pod(v1)] [Pod(v1)] [Pod(v1)]
Green (์ด์): [Pod(v2)] [Pod(v2)] [Pod(v2)] โ ํธ๋ํฝ
์ฅ์ : ์ฆ์ ๋กค๋ฐฑ ๊ฐ๋ฅ, ๋ ๋ฒ์ ๊ณต์กด X
๋จ์ : ์์ 2๋ฐฐ
v1: [Pod] [Pod] [Pod] [Pod] [Pod] โ 95% ํธ๋ํฝ
v2: [Pod] โ 5% ํธ๋ํฝ
โ ์ ์ง์ ํ๋
v1: [Pod] [Pod] [Pod]
v2: [Pod] [Pod] โ 50% ํธ๋ํฝ
โ
v1:
v2: [Pod] [Pod] [Pod] [Pod] [Pod] โ 100% ํธ๋ํฝ
์ฅ์ : ์ ์ง์ ๊ฒ์ฆ, ์คํจ ์ ์ ์ ์ํฅ
๋จ์ : ๋ณต์ก
Argo Rollouts, Flagger ๋ฑ ๋๊ตฌ ํ์ฉ.
์ ํ ๊ฐ์ด๋ โญ :
| ์ํฉ | ์ถ์ฒ |
|---|---|
| ์ผ๋ฐ ๋ฐฐํฌ | Rolling |
| ๋น ๋ฅธ ๋กค๋ฐฑ ํ์ | Blue-Green |
| ์ํํ ๋ณ๊ฒฝ, ์ ์ง ๊ฒ์ฆ | Canary |
| ์์ ์ฌ์ ์ ์ | Rolling |
| ์์ ๊ฒฉ๋ฆฌ ํ์ | Blue-Green |
ILIC ์๋๋ฆฌ์ค:
์๊ธฐ ์ ๊ฒ
๋ชฉํ: ํด๋ผ์ฐ๋ ๋ค์ดํฐ๋ธ์ ํ์ค ์์น์ ์ ๋ฆฌํ๋ค.
์ ์ ์ง์: Phase 5
12-Factor:
"ํด๋ผ์ฐ๋ ๋ค์ดํฐ๋ธ ์ฑ์ 12๊ฐ์ง ์์น" (Heroku ๋ฐํ)
12๊ฐ์ง ์์น ์์ฝ โญ :
| # | ์์น | ์๋ฏธ |
|---|---|---|
| 1 | Codebase | ํ ์ฑ = ํ ์ ์ฅ์ |
| 2 | Dependencies | ๋ช ์์ ์ ์ธ (build.gradle) |
| 3 | Config | ํ๊ฒฝ๋ณ์๋ก ๋ถ๋ฆฌ |
| 4 | Backing Services | DB/Redis ๋ฑ = ์ธ๋ถ ์์ |
| 5 | Build/Release/Run | ๋จ๊ณ ๋ถ๋ฆฌ |
| 6 | Processes | Stateless |
| 7 | Port Binding | ์์ฒด ํฌํธ ๋ ธ์ถ |
| 8 | Concurrency | ํ๋ก์ธ์ค ๋จ์ ํ์ฅ |
| 9 | Disposability | ๋น ๋ฅธ ์์/์ข ๋ฃ (Graceful Shutdown) |
| 10 | Dev/Prod Parity | ํ๊ฒฝ ๋์ผ์ฑ |
| 11 | Logs | stdout์ผ๋ก ์ถ๋ ฅ (Phase 7) |
| 12 | Admin Processes | ์ผํ์ฑ ์์ ๋ถ๋ฆฌ |
ํต์ฌ ๊ฐ์กฐ โญ :
// Spring Boot
server:
shutdown: graceful
spring:
lifecycle:
timeout-per-shutdown-phase: 30s
โ SIGTERM ๋ฐ์ผ๋ฉด ์ ์์ฒญ ์ ๋ฐ๊ณ , ์งํ ์ค์ธ ์์ฒญ ์๋ฃ ํ ์ข ๋ฃ.
ILIC ์ ๊ฒ:
์๊ธฐ ์ ๊ฒ
๋ชฉํ: ์ด์ ์ค ์ผ์ด๋๋ ์ผ์ ๋ณด๋ ์ธ ๊ฐ์ง ๋์ ์ ๋ณตํ๋ค.
์ ์ ์ง์: Phase 5-6
Monitoring (์ ํต):
Observability (ํ๋):
๊ด๊ณ:
"Monitoring์ Observability์ ๋ถ๋ถ ์งํฉ"
3 Pillars โญโญโญ :
| Pillar | ๋ตํ๋ ์ง๋ฌธ | ๋๊ตฌ |
|---|---|---|
| Logs | ๋ฌด์จ ์ผ์ด ์ผ์ด๋ฌ๋๊ฐ? | ELK, Loki |
| Metrics | ์ผ๋ง๋ ์ผ์ด๋ฌ๋๊ฐ? | Prometheus, Grafana |
| Traces | ์ด๋ป๊ฒ ํ๋ ๋๊ฐ? | Zipkin, Jaeger |
โ 17์ฃผ์ฐจ Distributed Tracing์ด Traces.
์๊ธฐ ์ ๊ฒ
์ ์ ์ง์: Unit 7.1
๋์ ๋ก๊ทธ:
2024-05-04 10:00:00 - ์ด์ ์ฒ๋ฆฌ ์์
2024-05-04 10:00:05 - ์ ์ ์๋ ์ค๋ฅ ๋ฐ์
๋ฌธ์ :
๊ตฌ์กฐํ ๋ก๊น (JSON) โญ :
{
"timestamp": "2024-05-04T10:00:00Z",
"level": "ERROR",
"service": "ilic-fare-service",
"trace_id": "abc123",
"user_id": "42",
"fare_id": "100",
"error": "PaymentTimeout",
"duration_ms": 5000,
"message": "๊ฒฐ์ ์ฒ๋ฆฌ ์๊ฐ ์ด๊ณผ"
}
ํจ๊ณผ:
Spring Boot ๊ตฌ์กฐํ ๋ก๊น :
# logback-spring.xml
<configuration>
<appender name="JSON" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<providers>
<timestamp/>
<logLevel/>
<loggerName/>
<mdc/>
<message/>
</providers>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="JSON"/>
</root>
</configuration>
MDC (Mapped Diagnostic Context) โญ โ ์ปจํ ์คํธ ์ ํ:
@Component
public class TraceIdFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(...) {
String traceId = request.getHeader("X-Trace-Id");
if (traceId == null) traceId = UUID.randomUUID().toString();
MDC.put("trace_id", traceId);
try {
filterChain.doFilter(request, response);
} finally {
MDC.clear();
}
}
}
โ ๋ชจ๋ ๋ก๊ทธ์ trace_id ์๋ ํฌํจ
ELK Stack (์ ํต):
Grafana Loki (ํ๋):
ILIC ์ ์ฉ:
์๊ธฐ ์ ๊ฒ
์ ์ ์ง์: Unit 7.2
Metrics:
"์๊ณ์ด ์ซ์ ๋ฐ์ดํฐ โ ์ผ๋ง๋ ์ผ์ด๋ฌ๋๊ฐ"
์:
Prometheus โ ์ฌ์ค์ ํ์ค:
Pull ๋ชจ๋ธ:
/actuator/prometheus ๋
ธ์ถ# Spring Boot
management:
endpoints:
web:
exposure:
include: prometheus
โ /actuator/prometheus ์๋ ์ ๊ณต:
# HELP http_server_requests_seconds
# TYPE http_server_requests_seconds histogram
http_server_requests_seconds_count{method="GET",uri="/api/fares"} 1234
http_server_requests_seconds_sum{method="GET",uri="/api/fares"} 45.6
4๊ฐ์ง ๋ฉํธ๋ฆญ ํ์ โญ :
| ํ์ | ์๋ฏธ | ์ |
|---|---|---|
| Counter | ๋์ ์นด์ดํธ (๊ฐ์ X) | ์ด ์์ฒญ ์ |
| Gauge | ํ์ฌ ๊ฐ | ํ์ฌ ๋ฉ๋ชจ๋ฆฌ |
| Histogram | ๋ถํฌ (๋ฒํท) | ์๋ต ์๊ฐ ๋ถํฌ |
| Summary | Percentile | P95 ์๋ต ์๊ฐ |
Spring Boot Actuator + Micrometer โญ :
implementation 'io.micrometer:micrometer-registry-prometheus'
์๋ ๋ฉํธ๋ฆญ :
์ปค์คํ ๋ฉํธ๋ฆญ:
@Service
public class FareService {
private final MeterRegistry meterRegistry;
private final Counter fareCounter;
private final Timer fareTimer;
public FareService(MeterRegistry registry) {
this.fareCounter = registry.counter("fare.created.total");
this.fareTimer = registry.timer("fare.processing");
}
public Fare create(FareRequest request) {
return fareTimer.record(() -> {
Fare fare = ...;
fareCounter.increment();
return fare;
});
}
}
Grafana โ ์๊ฐํ:
SLI/SLO/SLA โญ โ ๋ฉด์ ๋จ๊ณจ:
| ์๋ฏธ | ์ | |
|---|---|---|
| SLI (Indicator) | ์ธก์ ์งํ | "์๋ฌ์จ" |
| SLO (Objective) | ๋ชฉํ | "์๋ฌ์จ < 0.1%" |
| SLA (Agreement) | ๊ณ์ฝ | "99.9% ๊ฐ์ฉ์ฑ, ๋ชป ์งํค๋ฉด ํ๋ถ" |
ILIC ๊ถ์ฅ:
์๊ธฐ ์ ๊ฒ
์ ์ ์ง์: Unit 7.3, 17์ฃผ์ฐจ Phase 9.4
๋ณต์ต (17์ฃผ์ฐจ):
OpenTelemetry (OTel) โญ :
"๊ด์ธก ๊ฐ๋ฅ์ฑ์ ํ์ค โ Logs/Metrics/Traces ํตํฉ"
์ฑํ ํํฉ:
Spring Boot ํตํฉ (Micrometer Tracing):
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'io.micrometer:micrometer-tracing-bridge-otel'
implementation 'io.opentelemetry:opentelemetry-exporter-otlp'
management:
tracing:
sampling:
probability: 0.1 # 10% ์ํ๋ง
otlp:
tracing:
endpoint: http://otel-collector:4317
โ ์๋์ผ๋ก ๋ชจ๋ HTTP ์์ฒญ, DB ์ฟผ๋ฆฌ, Redis ํธ์ถ ๋ฑ ์ถ์
3 Pillars ํตํฉ โญ โ ๊ฐ์ฅ ๊ฐ๋ ฅ:
// Log
{
"timestamp": "...",
"level": "ERROR",
"trace_id": "abc123", โ Trace์ ์ฐ๊ฒฐ
"span_id": "span456",
"message": "๊ฒฐ์ ์คํจ"
}
ํจ๊ณผ:
ILIC ์ ์ฉ:
์๊ธฐ ์ ๊ฒ
๋ชฉํ: ์๋์ด๊ฐ ์๋ 4๋ ์ฐจ์ ๊ฒฐ์ ์ ์ฐจ์ด ์์ญ.
์ ์ ์ง์: Phase 7
On-Call ๋ฌธํ:
์ข์ ์๋ฆผ ์์คํ โญ :
| ๋จ๊ณ | ์๋ฏธ |
|---|---|
| Info | ์ฐธ๊ณ ์ฉ (์ด๋ฉ์ผ) |
| Warning | ์ฃผ์ (Slack) |
| Critical | ์ฆ์ ๋์ (์ ํ/SMS) |
์๋ฆผ ํผ๋ก(Alert Fatigue) โ ๏ธ :
์ฅ์ ๋์ ํ๋ฆ โญ :
1. ๊ฐ์ง (Detection)
- ์๋ ์๋ฆผ
- ์ฌ์ฉ์ ์ ๊ณ
โ
2. ๋ถ๋ฅ (Triage)
- ์ฌ๊ฐ๋ ํ๋จ
- ์ํฅ ๋ฒ์
โ
3. ์ํ (Mitigation) โ ์ฐ์ !
- ๋น ๋ฅธ ํด๊ฒฐ (๋กค๋ฐฑ, ํธ๋ํฝ ์ฐจ๋จ)
- "์์ " ๋ณด๋ค "์ค๋จ" ์ด ์ฐ์
โ
4. ๋ณต๊ตฌ (Recovery)
- ์ ์ ์ํ๋ก
โ
5. ๋ถ์ (Post-mortem) โญ
- ์ฌํ ๋ถ์
- ๋น๋ X, ํ์ต โ
ํต์ฌ ์์น โญ :
"๊ทผ๋ณธ ์์ธ ์์ ์ ์ ์ํฅ ์ํ ์ฐ์ "
์: ๊ฒฐ์ ์์คํ ๋ค์ด โ ๋๋ฒ๊น X โ ์ฆ์ ๋กค๋ฐฑ
์์ฌ๊ฒฐ์ ํ๋ ์์ํฌ:
์๋์ด์ ์ฐจ๋ณํ:
์๊ธฐ ์ ๊ฒ
์ ์ ์ง์: Unit 8.1
Postmortem:
"์ฅ์ ํ ๊ณต์์ ์ธ ๋ถ์ + ํ์ต ๋ฌธ์"
ํต์ฌ ์์น โญ :
"Blameless (๋น๋ ์๋)"
Postmortem ํ ํ๋ฆฟ โญ :
# ์ฅ์ ๋ณด๊ณ ์ โ ์ด์ ์์คํ
๋ค์ด (2024-05-04)
## ์์ฝ
- ๋ฐ์: 2024-05-04 14:00 KST
- ๋ณต๊ตฌ: 2024-05-04 15:30 KST
- ์ํฅ ๋ฒ์: ์ ์ฒด ์ด์ ์์คํ
- ์ํฅ๋ฐ์ ์ฌ์ฉ์: ์ฝ 500๋ช
## Timeline
- 14:00 โ DB ๋ง์ด๊ทธ๋ ์ด์
์์
- 14:15 โ ๋ง์ด๊ทธ๋ ์ด์
์๋ฃ, but ์ธ๋ฑ์ค ๋๋ฝ
- 14:20 โ ์ด์ ๊ฒ์ API ์๋ต 30์ด โ Critical ์๋ฆผ
- 14:30 โ ์จ์ฝ ์ธ์ง
- 14:45 โ ๋ง์ด๊ทธ๋ ์ด์
๋กค๋ฐฑ ๊ฒฐ์
- 15:00 โ ๋กค๋ฐฑ ์์
- 15:30 โ ์ ์ ๋ณต๊ตฌ
## ๊ทผ๋ณธ ์์ธ (Root Cause)
- ๋ง์ด๊ทธ๋ ์ด์
์คํฌ๋ฆฝํธ์ ์ธ๋ฑ์ค ์์ฑ ๋๋ฝ
- Staging์์ ์ถฉ๋ถํ ๋ถํ ํ
์คํธ ์์์
- โ ๋จ์ผ ์์ธ X, ์ฌ๋ฌ ์์ธ์ ๊ฒฐํฉ
## ๋ฌด์์ด ์ ๋์๋
- ๋น ๋ฅธ ์๋ฆผ ๊ฐ์ง (5๋ถ)
- ์ ์ํ ๋กค๋ฐฑ ๊ฒฐ์
## ๋ฌด์์ด ์๋ชป๋์๋
- ๋ง์ด๊ทธ๋ ์ด์
๊ฒํ ๋ถ์ฌ
- Staging์ ๋ฐ์ดํฐ ์์ด ์ด์๊ณผ ๋ค๋ฆ
## Action Items
1. ๋ง์ด๊ทธ๋ ์ด์
PR ํ
ํ๋ฆฟ ๋์
(Owner: A, Due: 5/15)
2. Staging ๋ฐ์ดํฐ ์์ ์ด์์ 30%๋ก (Owner: B, Due: 5/30)
3. ๋ง์ด๊ทธ๋ ์ด์
์ ์๋ ๋ถํ ํ
์คํธ (Owner: C, Due: 6/15)
์ข์ Postmortem์ ํน์ง:
1. ์ฌ์ค ์์ฃผ โ ์ถ์ธก X
2. Blameless โ ์ฌ๋ ๋น๋ X
3. Action Items ๋ช
ํ โ ๋๊ฐ, ์ธ์ ๊น์ง
4. ๊ณต์ โ ํ ์ ์ฒด ํ์ต
ILIC ์ ์ฉ:
๋ฉด์ ์ง๋ฌธ ๋๋น โญ :
"์ง๊ธ๊น์ง ๊ฐ์ฅ ์ด๋ ค์ ๋ ์ฅ์ ๊ฒฝํ์?"
์ข์ ๋ต๋ณ ๊ตฌ์กฐ:
1. ์ํฉ (๊ฐ๋จ)
2. ๋ฌธ์ ๋ฐ๊ฒฌ ๊ณผ์
3. ์ํ ์๋
4. ๊ทผ๋ณธ ์์ธ
5. ํ์ต + ๊ฐ์
์๊ธฐ ์ ๊ฒ
โ โ โ ๋ฉด์ ๋จ๊ณจ (๋ฐ๋์):
โ โ ๋งค์ฐ ๊ถ์ฅ:
Phase 2 (TCP/TLS) โ ๋ฐฑ์๋์ ํ ๋. "TCP 3-way handshake ์ค๋ช ?" ๋ฉด์ 100%. ๋ฉด์ ๊ด์ด ๊น์ด ํ๊ณ ๋๋ ์ง๋ฌธ ์์ญ.
Phase 4 (Kubernetes) โ ํ๋ ์ด์์ ํ์ค. "K8s ์จ๋ณด์ จ๋์?" ์ Pod/Deployment/Service์ ์ฐจ์ด๋ฅผ 1๋ถ ์์ ๋ตํ ์ ์์ด์ผ ์ฐจ๋ณํ.
Phase 7 (Observability) โ ์๋์ด์ ๊ฒฐ์ ์ ์ฐจ๋ณํ. "์ฅ์ ๋ฅผ ์ด๋ป๊ฒ ์ฐพ์ผ์ธ์?" ๋ต๋ณ์ 3 Pillars + SLI/SLO ๋ค์ด๊ฐ๋ฉด ์๋์ด ๋ ๋ฒจ.
์ด์ ์๋์ด ๋ฐฑ์๋ ๊ฐ๋ฐ์๊ฐ ์์์ผ ํ ๊ฑฐ์ ๋ชจ๋ ์์ญ์ ํ์ตํ์ต๋๋ค:
| ์์ญ | ์ฃผ์ฐจ | ๊น์ด |
|---|---|---|
| Java ์ธ์ด | 1-3 | โ โ โ |
| ๋์์ฑ | 4 | โ โ โ |
| Spring Core | 5, 8-9 | โ โ โ |
| ํธ๋์ญ์ | 7, 10 | โ โ โ |
| JPA | 11-12 | โ โ โ |
| DB | 13-14 | โ โ โ |
| Spring MVC | 15 | โ โ โ |
| ๋ถ์ฐ ์์คํ | 16-17 | โ โ โ |
| Spring Security | 18 | โ โ โ |
| ํ ์คํธ | 19 | โ โ โ |
| HTTP/DevOps/Observability | 20 | โ โ โ |
โ 20์ฃผ์ ๊ฑธ์ณ ์๋ฐ ๋ฐฑ์๋ ์๋์ด ๊ฐ๋ฐ์์ ๊ฑฐ์ ๋ชจ๋ ์์ญ์ ์ ๋ณต
๊ฐ์ฅ ์ค์ํฉ๋๋ค. 20์ฃผ์ฐจ ๋ถ๋์ ์ด๋ก ์์:
์ด ์์ ์ด ์ด๋ก ์ ๋ฉด์ ํฉ๊ฒฉ์ผ๋ก ๋ณํ ํฉ๋๋ค.
1~20์ฃผ์ฐจ๋ฅผ ์์ ํ ์ฒดํํ๋ค๋ฉด:
ํ์ฌ์ ํ์ต์ผ๋ก ๋ถ์กฑํ ์์ญ (์๊ธฐ ํ์ต ๊ถ์ฅ):
๋ณด์ ํ์: