<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>jennieee.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Sat, 03 Oct 2026 10:07:04 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>jennieee.log</title>
            <url>https://velog.velcdn.com/images/jennie-infra/profile/aed1eb13-9d01-4475-bdeb-aae6741a9334/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. jennieee.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/jennie-infra" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[REST API와 웹 기술]]></title>
            <link>https://velog.io/@jennie-infra/REST-API%EC%99%80-%EC%9B%B9-%EA%B8%B0%EC%88%A0</link>
            <guid>https://velog.io/@jennie-infra/REST-API%EC%99%80-%EC%9B%B9-%EA%B8%B0%EC%88%A0</guid>
            <pubDate>Sat, 03 Oct 2026 10:07:04 GMT</pubDate>
            <description><![CDATA[<h2 id="rest-api란">REST API란</h2>
<p>API는 다른 소프트웨어와 통신할 때 따라야 하는 규칙이다. 웹 API는 웹에 있는 클라이언트와 리소스 사이의 관문이다. 클라이언트는 정보를 얻으려는 사용자나 프로그램이고, 리소스는 서버가 제공하는 이미지/텍스트/숫자 같은 모든 종류의 데이터다. <strong><span style='background-color: #fff3b0'>REST(Representational State Transfer)</span></strong>는 API가 어떻게 동작해야 하는지 조건을 정한 소프트웨어 아키텍처다. REST 방식을 따르는 API가 REST API이고, REST API와 RESTful API는 같은 뜻으로 쓴다. HTTP 위에서 REST API를 구현하는 경우가 많다.</p>
<h2 id="rest의-원칙">REST의 원칙</h2>
<table>
<thead>
<tr>
<th>원칙</th>
<th>내용</th>
</tr>
</thead>
<tbody><tr>
<td>균일한 인터페이스</td>
<td>요청은 URI로 리소스를 식별하고, 서버는 표준 형식(표현)으로 정보를 전달한다. 서버는 자기 설명적인 메시지와 하이퍼링크도 함께 보낸다</td>
</tr>
<tr>
<td>무상태(stateless)</td>
<td>서버가 모든 요청을 이전 요청과 상관없이 독립적으로 처리한다</td>
</tr>
<tr>
<td>계층형 시스템</td>
<td>클라이언트와 서버 사이에 중간 계층이 있어도 클라이언트에게는 보이지 않는다</td>
</tr>
<tr>
<td>캐시 가능성</td>
<td>응답이 스스로 캐시 가능 여부를 정의하고, 캐시 가능한 응답은 클라이언트나 중간 계층에 저장된다</td>
</tr>
<tr>
<td>주문형 코드</td>
<td>서버가 코드를 클라이언트에 보내 기능을 확장한다(예: 입력 오류 표시)</td>
</tr>
</tbody></table>
<p>이 원칙의 장점을 AWS는 세 가지로 설명한다. 무상태라서 서버가 이전 요청 정보를 기억할 필요가 없어 서버 부하가 줄고 <strong><span style='background-color: #fff3b0'>확장성</span></strong>이 좋아진다. 클라이언트와 서버를 완전히 분리해서 각 부분이 독립적으로 발전할 수 있어 <strong><span style='background-color: #fff3b0'>유연성</span></strong>이 높아진다. 클라이언트와 서버를 서로 다른 언어로 만들어도 API 설계에 영향이 없어 기술에 <strong><span style='background-color: #fff3b0'>독립적</span></strong>이다. 전에 HTTP 자체가 상태를 저장하지 않는다고 했는데 REST의 무상태 원칙은 이 성질을 API 설계 규칙으로 가져온 것이다.</p>
<h2 id="요청의-구성">요청의 구성</h2>
<p>REST API 요청에는 아래 요소가 들어간다.</p>
<table>
<thead>
<tr>
<th>구성</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>리소스 식별자</td>
<td>보통 URL을 쓰고, 요청 엔드포인트라고도 부른다</td>
</tr>
<tr>
<td>메서드</td>
<td>서버가 리소스에 무엇을 해야 하는지 알려 주는 HTTP 메서드</td>
</tr>
<tr>
<td>헤더</td>
<td>요청과 응답의 형식 같은 메타데이터</td>
</tr>
<tr>
<td>데이터</td>
<td>POST/PUT 같은 메서드에서 보내는 본문</td>
</tr>
<tr>
<td>파라미터</td>
<td>경로 파라미터(URL 상세), 쿼리 파라미터(리소스 추가 정보), 쿠키 파라미터(빠른 인증)</td>
</tr>
</tbody></table>
<h2 id="http-메서드">HTTP 메서드</h2>
<p>AWS 문서가 REST에서 흔히 쓰는 네 가지로 GET/POST/PUT/DELETE를 꼽고, MDN은 PATCH를 포함해 각 메서드의 특성을 정리한다. 다섯 가지를 비교하면 이렇다.</p>
<table>
<thead>
<tr>
<th>메서드</th>
<th>하는 일</th>
<th>안전(safe)</th>
<th>멱등(idempotent)</th>
</tr>
</thead>
<tbody><tr>
<td>GET</td>
<td>리소스를 조회하고, 본문은 없어야 한다</td>
<td>예</td>
<td>예</td>
</tr>
<tr>
<td>POST</td>
<td>데이터를 제출해 서버에 변화를 일으킨다</td>
<td>아니오</td>
<td>아니오</td>
</tr>
<tr>
<td>PUT</td>
<td>대상 리소스의 표현을 요청 내용으로 모두 교체한다</td>
<td>아니오</td>
<td>예</td>
</tr>
<tr>
<td>PATCH</td>
<td>리소스의 일부만 수정한다</td>
<td>아니오</td>
<td>아니오</td>
</tr>
<tr>
<td>DELETE</td>
<td>리소스를 삭제한다</td>
<td>아니오</td>
<td>예</td>
</tr>
</tbody></table>
<p>멱등은 같은 요청을 여러 번 보내도 결과가 같다는 뜻이다. AWS 문서의 설명대로 같은 POST를 여러 번 보내면 같은 리소스가 여러 개 만들어지는 부작용이 생기고, 같은 PUT을 여러 번 보내면 결과가 같다. 그래서 네트워크 오류로 재시도해야 할 때 PUT은 안전하게 다시 보낼 수 있지만 POST는 중복 생성을 조심해야 한다.</p>
<p>아래는 이 메서드로 사용자 리소스를 설계한 예시다. </p>
<table>
<thead>
<tr>
<th>요청</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td>GET /users/42</td>
<td>42번 사용자 조회</td>
</tr>
<tr>
<td>POST /users</td>
<td>새 사용자 생성(성공 시 201)</td>
</tr>
<tr>
<td>PUT /users/42</td>
<td>42번 사용자 정보 전체 교체</td>
</tr>
<tr>
<td>PATCH /users/42</td>
<td>42번 사용자 정보 일부 수정</td>
</tr>
<tr>
<td>DELETE /users/42</td>
<td>42번 사용자 삭제</td>
</tr>
</tbody></table>
<p>URL에는 동사 대신 리소스 이름을 두고 하려는 동작은 메서드가 나타낸다는 점이 포인트라고 이해했다.</p>
<h2 id="상태-코드">상태 코드</h2>
<p>응답의 상태 코드는 다섯 부류로 나뉜다.</p>
<table>
<thead>
<tr>
<th>범위</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td>1xx</td>
<td>정보 응답</td>
</tr>
<tr>
<td>2xx</td>
<td>성공</td>
</tr>
<tr>
<td>3xx</td>
<td>리다이렉션</td>
</tr>
<tr>
<td>4xx</td>
<td>클라이언트 오류</td>
</tr>
<tr>
<td>5xx</td>
<td>서버 오류</td>
</tr>
</tbody></table>
<p>API를 만들고 운영할 때 자주 마주치는 코드는 아래와 같다.</p>
<table>
<thead>
<tr>
<th>코드</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td>201</td>
<td>요청이 성공해 새 리소스가 만들어짐, 보통 POST 뒤에 보낸다</td>
</tr>
<tr>
<td>400</td>
<td>클라이언트 오류로 판단되는 잘못된 요청</td>
</tr>
<tr>
<td>401</td>
<td>이름은 unauthorized지만 의미는 인증되지 않음, 인증이 필요하다</td>
</tr>
<tr>
<td>403</td>
<td>접근 권한이 없음, 401과 달리 서버가 클라이언트의 신원을 안다</td>
</tr>
<tr>
<td>404</td>
<td>리소스를 찾을 수 없음, API에서는 엔드포인트는 맞지만 리소스가 없다는 뜻일 수도 있다</td>
</tr>
<tr>
<td>429</td>
<td>짧은 시간에 요청을 너무 많이 보냄(속도 제한)</td>
</tr>
<tr>
<td>500</td>
<td>서버가 처리 방법을 모르는 상황, 일반적인 서버 오류</td>
</tr>
<tr>
<td>502</td>
<td>게이트웨이로 동작하던 서버가 유효하지 않은 응답을 받음</td>
</tr>
<tr>
<td>503</td>
<td>서버가 요청을 처리할 준비가 안 됨, 점검이나 과부하 같은 일시적 상태</td>
</tr>
<tr>
<td>504</td>
<td>게이트웨이로 동작하던 서버가 제때 응답을 받지 못함</td>
</tr>
</tbody></table>
<p>502/503/504는 중간에 게이트웨이나 프록시가 있는 구조에서 나온다는 점이 눈에 띈다. 프록시와 이어 보면 이런 코드는 요청이 서버 앞단의 중간 계층에서 막혔는지 확인할 때 단서가 된다.</p>
<h2 id="인증-방식">인증 방식</h2>
<p>REST API는 응답을 보내기 전에 요청을 인증해야 한다. AWS 문서가 설명하는 흔한 방식은 네 가지다.</p>
<table>
<thead>
<tr>
<th>방식</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>HTTP 기본 인증</td>
<td>사용자 이름과 비밀번호를 base64로 인코딩해 요청 헤더에 담아 보낸다</td>
</tr>
<tr>
<td>베어러 인증</td>
<td>로그인 요청에 대한 응답으로 서버가 만든 토큰을 헤더에 담아 보낸다</td>
</tr>
<tr>
<td>API 키</td>
<td>서버가 처음 온 클라이언트에게 고유한 값을 주고, 이후 요청마다 그 값으로 신원을 증명한다. 키를 전송해야 해서 네트워크에서 탈취될 수 있어 상대적으로 덜 안전하다</td>
</tr>
<tr>
<td>OAuth</td>
<td>비밀번호와 토큰을 결합하고, 토큰은 범위와 유효 기간을 지정해 확인할 수 있다</td>
</tr>
</tbody></table>
<p>AWS의 Amazon API Gateway는 API를 만들고 게시/관리/모니터링/보호하는 완전 관리형 서비스다. IAM과 Cognito로 접근 권한을 제어하고, 같은 API의 여러 버전을 동시에 운영하며, 호출 수/지연 시간/오류율 같은 지표를 볼 수 있다고 한다.</p>
<h2 id="응답의-구성">응답의 구성</h2>
<p>REST 원칙에 따르면 응답에는 세 가지가 들어간다. 상태 줄에는 세 자리 상태 코드가 있고 본문에는 리소스의 표현이 들어간다. 클라이언트는 요청 헤더로 XML이나 JSON 형식을 요청할 수 있고 서버는 이를 보고 적절한 형식으로 응답한다. 헤더에는 서버/인코딩/날짜/콘텐츠 유형 같은 응답의 메타데이터가 들어간다.</p>
<h2 id="그-외-웹-기술과-프로토콜">그 외 웹 기술과 프로토콜</h2>
<p>HTTP 요청과 응답만으로는 부족한 상황을 위한 기술이 따로 있다.</p>
<table>
<thead>
<tr>
<th>기술</th>
<th>방향</th>
<th>특징</th>
</tr>
</thead>
<tbody><tr>
<td>HTTP/2</td>
<td>요청/응답</td>
<td>메시지를 이진 프레임에 담아 헤더를 압축하고 한 연결에서 여러 메시지를 동시에 주고받는다(멀티플렉싱). 메시지의 의미는 HTTP/1.1과 같다</td>
</tr>
<tr>
<td>Fetch API</td>
<td>요청/응답</td>
<td>자바스크립트에서 HTTP 요청을 보내는 API로, XMLHttpRequest를 대체했다</td>
</tr>
<tr>
<td>서버 전송 이벤트(SSE)</td>
<td>서버에서 클라이언트로 단방향</td>
<td>HTTP를 전송 수단으로 쓰고, 클라이언트가 EventSource로 연결을 열어 이벤트를 받는다</td>
</tr>
<tr>
<td>WebSocket</td>
<td>양방향</td>
<td>브라우저와 서버 사이에 양방향 대화 세션을 열어 폴링 없이 메시지를 주고받는다</td>
</tr>
</tbody></table>
<p><strong><span style='background-color: #fff3b0'>WebSocket</span></strong>은 HTTP 요청/응답과 달리 한 번 연결하면 서버도 먼저 메시지를 보낼 수 있다. 시작은 HTTP 요청으로 하고, Sec-WebSocket-Key/Sec-WebSocket-Accept 같은 헤더로 서버가 연결을 WebSocket으로 업그레이드하겠다고 알리는 핸드셰이크를 거친다. MDN은 WebSocket 인터페이스가 안정적이고 브라우저와 서버 지원이 좋다고 하면서 많은 용도에서 WebTransport가 WebSocket을 대체할 것으로 예상된다고 덧붙인다. WebTransport는 단방향 스트림/순서 없는 전달/데이터그램을 지원하지만 더 복잡하고 브라우저 지원이 덜하다. 일반적인 양방향 연결이면 WebSocket으로 빠르게 시작하고, 특수한 요구가 있을 때 WebTransport를 고려한다고 이해했다.</p>
<h2 id="핵심-복습">핵심 복습</h2>
<table>
<thead>
<tr>
<th>키워드</th>
<th>한 줄 정리</th>
</tr>
</thead>
<tbody><tr>
<td>REST</td>
<td>API가 따를 아키텍처 규칙, 균일한 인터페이스/무상태/계층형/캐시 가능</td>
</tr>
<tr>
<td>무상태</td>
<td>서버가 각 요청을 독립적으로 처리해 확장성이 좋음</td>
</tr>
<tr>
<td>요청 구성</td>
<td>URL + 메서드 + 헤더 + 데이터 + 파라미터</td>
</tr>
<tr>
<td>메서드</td>
<td>GET 조회, POST 생성/제출, PUT 전체 교체, PATCH 일부 수정, DELETE 삭제</td>
</tr>
<tr>
<td>멱등</td>
<td>GET/PUT/DELETE는 여러 번 보내도 결과가 같음, POST/PATCH는 아님</td>
</tr>
<tr>
<td>상태 코드</td>
<td>2xx 성공, 3xx 이동, 4xx 클라이언트 오류, 5xx 서버 오류</td>
</tr>
<tr>
<td>401과 403</td>
<td>인증 안 됨 vs 신원은 알지만 권한 없음</td>
</tr>
<tr>
<td>인증</td>
<td>기본 인증, 베어러 토큰, API 키, OAuth</td>
</tr>
<tr>
<td>WebSocket</td>
<td>한 번 연결해 양방향으로 메시지를 주고받는 기술</td>
</tr>
</tbody></table>
<h2 id="📍-참고-자료">📍 참고 자료</h2>
<p>확인일: 2026-10-03</p>
<ul>
<li><a href="https://aws.amazon.com/what-is/restful-api/">AWS - What is a RESTful API?</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Methods">MDN - HTTP request methods</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status">MDN - HTTP response status codes</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API">MDN - WebSocket API</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[서버 운영 프로토콜: 텔넷/SSH/FTP/NTP]]></title>
            <link>https://velog.io/@jennie-infra/%EC%84%9C%EB%B2%84-%EC%9A%B4%EC%98%81-%ED%94%84%EB%A1%9C%ED%86%A0%EC%BD%9C-%ED%85%94%EB%84%B7SSHFTPNTP</link>
            <guid>https://velog.io/@jennie-infra/%EC%84%9C%EB%B2%84-%EC%9A%B4%EC%98%81-%ED%94%84%EB%A1%9C%ED%86%A0%EC%BD%9C-%ED%85%94%EB%84%B7SSHFTPNTP</guid>
            <pubDate>Sat, 03 Oct 2026 10:03:41 GMT</pubDate>
            <description><![CDATA[<h2 id="서버를-운영하며-쓰는-네-가지-프로토콜">서버를 운영하며 쓰는 네 가지 프로토콜</h2>
<p>서버를 운영할 때는 원격으로 접속하고, 파일을 주고받고, 시계를 맞추는 일이 반복된다. 이 글의 네 프로토콜은 모두 응용 계층 프로토콜이고 역할이 이렇게 나뉜다.</p>
<table>
<thead>
<tr>
<th>프로토콜</th>
<th>하는 일</th>
<th>기본 포트(3편 표 기준)</th>
</tr>
</thead>
<tbody><tr>
<td>텔넷</td>
<td>원격으로 서버에 명령을 보냄(암호화 없음)</td>
<td>--</td>
</tr>
<tr>
<td>SSH</td>
<td>암호화된 연결로 원격 접속과 파일 전송</td>
<td>22</td>
</tr>
<tr>
<td>FTP</td>
<td>클라이언트와 서버 사이 파일 전송</td>
<td>20/21</td>
</tr>
<tr>
<td>NTP</td>
<td>컴퓨터 시계 동기화</td>
<td>123</td>
</tr>
</tbody></table>
<h2 id="텔넷에서-ssh로">텔넷에서 SSH로</h2>
<p>원격 서버를 관리하는 오래된 프로토콜인 텔넷은 관리자의 명령을 누구나 볼 수 있는 형태로 보냈다. 텔넷은 평문으로 데이터를 보내고, <strong><span style='background-color: #fff3b0'>SSH가 텔넷을 사실상 대체</span></strong>했다고 볼 수 있다. SSH(Secure Shell)는 신뢰할 수 없는 네트워크 위에서 컴퓨터에 안전하게 명령을 보내는 방법이다. 암호화와 인증으로 연결을 보호하기 때문에 중간에서 가로채도 의미 없는 데이터만 보인다.</p>
<p>SSH가 안전한 이유는 공개키 암호화로 인증하고 암호화하기 때문이다. 키는 서로 짝인 두 개로 이루어지는데 공개키는 누구나 쓸 수 있고 개인키는 소유자만 갖는다. SSH 연결에서는 양쪽이 모두 키 쌍을 갖고 서로를 인증하며 협상을 마친 뒤에는 둘이 공유하는 대칭키로 데이터를 암호화해서 주고받는다. 서버 쪽 신원만 확인하는 일반적인 HTTPS와 다른 점이다. 그다음 사용자 본인 인증으로 사용자 이름과 비밀번호를 요구하는 경우가 많고 인증이 끝나면 원격 컴퓨터에서 로컬처럼 명령을 실행할 수 있다.</p>
<table>
<thead>
<tr>
<th>비교</th>
<th>텔넷</th>
<th>SSH</th>
</tr>
</thead>
<tbody><tr>
<td>데이터</td>
<td>평문으로 전송</td>
<td>암호화해서 전송</td>
</tr>
<tr>
<td>인증</td>
<td>이 글의 문서에서 확인하지 못함</td>
<td>공개키 암호화 + 사용자 인증</td>
</tr>
<tr>
<td>현재 위상</td>
<td>오래된 프로토콜</td>
<td>원격 서버 접속의 표준</td>
</tr>
</tbody></table>
<p>SSH는 TCP/IP 위에서 동작하고 기본 포트는 22번이다. 리눅스와 맥에는 기본으로 들어 있고 윈도에는 클라이언트 설치가 필요할 수 있다. 원격 서버 관리, 파일의 안전한 전송, 개인 네트워크 안의 서비스 접속이 대표적인 용도다. SSH는 터널링(포트 포워딩)도 지원해서 외부에 열린 서버를 거쳐 사설 네트워크 안의 서버에 접속할 수 있다.</p>
<h2 id="ssh의-보안-위험">SSH의 보안 위험</h2>
<p>SSH 접속은 서버에 프로그램을 설치하거나 데이터를 지우고 빼내는 높은 권한이 따라온다. 그래서 공격자 손에 들어가면 위험하다고 경고한다. 특히 두 가지를 짚는다. 많은 방화벽이 22번 포트를 열어 두기 때문에 공격자가 이를 타고 내부 네트워크로 들어올 수 있고 SSH 키는 명시적으로 폐기하기 전까지 만료되지 않아서 도난당하면 몇 달에서 몇 년 동안 접근이 유지될 수 있다. 서버가 많은 조직에서는 키 관리가 큰 보안 과제라고도 한다. 클라우드 서버를 운영할 때 가장 먼저 점검할 부분이다.</p>
<h2 id="ftp와-안전한-대안">FTP와 안전한 대안</h2>
<p>FTP는 클라이언트와 서버 사이에서 파일을 주고받는 프로토콜이다. Cloudfare 문서는 SSH가 FTP 같은 암호화되지 않은 프로토콜보다 안전하다고 설명한다. FTP의 보안 대안으로는 아래 둘이 있다고 AWS 문서에서 확인했다.</p>
<table>
<thead>
<tr>
<th>프로토콜</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>SFTP</td>
<td>SSH 파일 전송 프로토콜(SSH File Transfer Protocol), SSH 위에서 동작</td>
</tr>
<tr>
<td>FTPS</td>
<td>FTP에 보안을 더한 프로토콜(File Transfer Protocol Secure)</td>
</tr>
</tbody></table>
<p>AWS는 이 프로토콜들을 서비스로도 제공한다. AWS Transfer Family는 SFTP/FTPS/FTP/AS2와 웹 브라우저 기반 전송으로 S3나 EFS에 파일을 주고받게 해 주는 완전 관리형 서비스다. 사용자는 OpenSSH, WinSCP, Cyberduck, FileZilla 같은 기존 클라이언트를 그대로 쓸 수 있고 서버 인프라를 직접 운영할 필요가 없다. FTP와 FTPS의 데이터 연결에는 8192~8200 포트 범위를 쓴다고 문서에 나와 있어서 방화벽 규칙을 만들 때 이 범위를 확인해야 한다.</p>
<h2 id="ntp">NTP</h2>
<p>NTP(Network Time Protocol)는 컴퓨터 시계를 서로 맞추는 프로토콜이고 기본 포트는 123번이다. 시계 동기화는 암호화에도 필수적이다. AWS 문서는 서버 시간이 왜 중요한지를 구체적으로 보여 준다. 시스템 로그의 타임스탬프로 문제가 언제 생겼고 사건이 어떤 순서로 일어났는지 파악하고 AWS CLI나 SDK가 요청에 서명할 때도 시간을 쓴다. 인스턴스의 날짜와 시간이 틀리면 서명 시각과 요청 시각이 어긋나서 AWS가 요청을 거부할 수 있다.</p>
<p>그래서 AWS는 모든 EC2 인스턴스에서 쓸 수 있는 Amazon Time Sync Service를 제공한다. 이 서비스는 각 리전의 위성 연결 시계와 원자시계로 협정 세계시(UTC)를 정확하게 제공하고 윤초를 시간에 걸쳐 나눠 반영(smearing)한다. 인스턴스에서는 로컬 Amazon Time Sync Service를 쓰는 것을 권장하고 백업이나 EC2 밖의 리소스에는 <code>time.aws.com</code>의 공개 서비스를 쓸 수 있다.</p>
<h2 id="핵심-복습">핵심 복습</h2>
<table>
<thead>
<tr>
<th>키워드</th>
<th>한 줄 정리</th>
</tr>
</thead>
<tbody><tr>
<td>텔넷</td>
<td>평문으로 원격 명령을 보내던 오래된 프로토콜</td>
</tr>
<tr>
<td>SSH</td>
<td>공개키 암호화로 인증/암호화하는 원격 접속 표준, 포트 22</td>
</tr>
<tr>
<td>SSH 위험</td>
<td>22번 포트가 열려 있고 키가 만료되지 않아 도난 시 장기간 접근 가능</td>
</tr>
<tr>
<td>FTP</td>
<td>파일 전송 프로토콜, 암호화되지 않음</td>
</tr>
<tr>
<td>SFTP/FTPS</td>
<td>FTP의 안전한 대안, SFTP는 SSH 기반</td>
</tr>
<tr>
<td>AWS Transfer Family</td>
<td>SFTP/FTPS/FTP로 S3/EFS에 파일을 주고받는 관리형 서비스</td>
</tr>
<tr>
<td>NTP</td>
<td>시계 동기화 프로토콜, 포트 123</td>
</tr>
<tr>
<td>Amazon Time Sync Service</td>
<td>EC2에서 쓰는 UTC 기준 시간 동기화 서비스</td>
</tr>
</tbody></table>
<h2 id="📍-참고-자료">📍 참고 자료</h2>
<p>확인일: 2026-10-03</p>
<ul>
<li><a href="https://www.cloudflare.com/learning/access-management/what-is-ssh/">Cloudflare Learning Center - What is SSH?</a></li>
<li><a href="https://docs.aws.amazon.com/transfer/latest/userguide/what-is-aws-transfer-family.html">AWS Docs - What is AWS Transfer Family?</a></li>
<li><a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/set-time.html">AWS Docs - Precision clock and time synchronization on your EC2 instance</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[DNS]]></title>
            <link>https://velog.io/@jennie-infra/DNS</link>
            <guid>https://velog.io/@jennie-infra/DNS</guid>
            <pubDate>Sat, 03 Oct 2026 10:01:23 GMT</pubDate>
            <description><![CDATA[<h2 id="dns가-필요한-이유">DNS가 필요한 이유</h2>
<p>인터넷의 모든 컴퓨터는 IP 주소라는 숫자로 서로 통신한다. 사람은 example.com 같은 도메인 이름을 쓰고 브라우저는 IP 주소로 통신하기 때문에, 둘 사이를 연결해 주는 것이 <strong><span style='background-color: #fff3b0'>DNS(Domain Name System)</span></strong>다. DNS는 도메인 이름을 IP 주소로 바꿔 줘서 브라우저가 서버를 찾아 접속하게 한다. 웹 접속 흐름에서 1단계로 나온 바로 그 과정이다. DNS는 53번 포트이다.</p>
<h2 id="조회에-참여하는-서버">조회에 참여하는 서버</h2>
<p>웹 페이지 하나를 불러오는 데 DNS 서버 네 종류가 관여한다.</p>
<table>
<thead>
<tr>
<th>서버</th>
<th>하는 일</th>
</tr>
</thead>
<tbody><tr>
<td>재귀 리졸버(recursor)</td>
<td>클라이언트의 질의를 받아서 답을 찾아올 때까지 추가 질의를 대신 보낸다</td>
</tr>
<tr>
<td>루트 네임서버</td>
<td>이름을 IP로 바꾸는 첫 단계, 더 구체적인 TLD 서버의 위치를 알려 준다</td>
</tr>
<tr>
<td>TLD 네임서버</td>
<td>호스트 이름의 마지막 부분(.com 등)을 담당하고, 해당 도메인의 네임서버를 알려 준다</td>
</tr>
<tr>
<td>권한 있는(authoritative) 네임서버</td>
<td>레코드를 실제로 갖고 있는 마지막 서버, 요청한 호스트의 IP를 돌려준다</td>
</tr>
</tbody></table>
<p>재귀 리졸버는 조회의 시작점에, 권한 있는 네임서버는 끝에 있다고 이해하면 된다.</p>
<h2 id="조회-과정">조회 과정</h2>
<p>캐시에 아무것도 없을 때 example.com을 조회하는 과정은 8단계다.</p>
<table>
<thead>
<tr>
<th>단계</th>
<th>일어나는 일</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>사용자가 브라우저에 example.com을 입력하고, 질의가 재귀 리졸버에 도착한다</td>
</tr>
<tr>
<td>2</td>
<td>리졸버가 루트 네임서버에 묻는다</td>
</tr>
<tr>
<td>3</td>
<td>루트 서버가 .com TLD 서버의 주소를 알려 준다</td>
</tr>
<tr>
<td>4</td>
<td>리졸버가 .com TLD 서버에 묻는다</td>
</tr>
<tr>
<td>5</td>
<td>TLD 서버가 example.com의 네임서버 주소를 알려 준다</td>
</tr>
<tr>
<td>6</td>
<td>리졸버가 example.com의 네임서버에 묻는다</td>
</tr>
<tr>
<td>7</td>
<td>네임서버가 example.com의 IP 주소를 리졸버에 돌려준다</td>
</tr>
<tr>
<td>8</td>
<td>리졸버가 브라우저에 IP 주소를 알려 주고, 브라우저는 그 IP로 HTTP 요청을 보낸다</td>
</tr>
</tbody></table>
<p>AWS 문서는 같은 과정을 Route 53 기준으로 설명한다. 리졸버는 보통 ISP가 관리하고, TLD 서버는 해당 도메인에 연결된 Route 53 네임서버 네 개의 이름을 알려 준다. 리졸버는 이 네임서버 정보를 캐시하기 때문에 다음에 같은 도메인을 조회할 때는 루트/TLD 단계를 건너뛰고, 이 정보는 보통 이틀 정도 캐시된다. 이후 Route 53 네임서버가 호스티드 존에서 <a href="http://www.example.com">www.example.com</a> 레코드를 찾아 값(예: 웹 서버의 IP)을 돌려준다.</p>
<h2 id="질의의-종류">질의의 종류</h2>
<p>실제 조회에서는 아래 세 가지 질의가 섞여 쓰인다.</p>
<table>
<thead>
<tr>
<th>질의</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>재귀 질의</td>
<td>클라이언트가 리졸버에게 최종 답(또는 오류)을 달라고 요구한다</td>
</tr>
<tr>
<td>반복 질의</td>
<td>서버가 아는 만큼의 최선의 답을 주고, 모르면 더 아래 단계 서버를 알려 주는 참조(referral)를 돌려준다. 클라이언트가 그 서버에 다시 묻는다</td>
</tr>
<tr>
<td>비재귀 질의</td>
<td>서버가 자기 권한 데이터나 캐시로 바로 답할 수 있을 때</td>
</tr>
</tbody></table>
<p>캐시되지 않은 일반적인 조회에는 재귀 질의와 반복 질의가 함께 쓰인다. 사용자 기기가 리졸버에게 보내는 것이 재귀 질의이고, 리졸버가 루트/TLD/권한 서버를 차례로 찾아가는 것이 반복 질의이다.</p>
<h2 id="캐시">캐시</h2>
<p>DNS 결과는 여러 곳에 임시로 저장돼서 조회 단계를 줄인다. 각 레코드는 TTL(time-to-live)이 정한 시간 동안만 캐시된다. 질의가 나가는 순서는 이렇다.</p>
<table>
<thead>
<tr>
<th>순서</th>
<th>위치</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>브라우저 캐시</td>
<td>DNS 레코드를 요청할 때 가장 먼저 확인하는 곳</td>
</tr>
<tr>
<td>2</td>
<td>운영체제 캐시</td>
<td>스텁 리졸버(DNS 클라이언트)가 자기 캐시를 확인한 뒤 없으면 ISP의 재귀 리졸버로 질의한다</td>
</tr>
<tr>
<td>3</td>
<td>재귀 리졸버 캐시</td>
<td>저장된 레코드 종류에 따라 단계를 건너뛴다</td>
</tr>
</tbody></table>
<p>재귀 리졸버가 A 레코드는 없어도 권한 네임서버의 NS 레코드를 갖고 있으면 그 서버에 바로 묻고 NS 레코드가 없으면 TLD 서버부터, 그것도 없으면 루트 서버부터 묻는다. 캐시가 비워진 직후에만 루트 서버까지 가는 일이 생긴다고 한다.</p>
<h2 id="dns-레코드">DNS 레코드</h2>
<p>DNS 레코드는 권한 있는 DNS 서버에 저장된, 도메인에 대한 정보(어느 IP와 연결되는지, 요청을 어떻게 처리할지)를 담은 지침이다. 모든 레코드에는 TTL이 있어서 DNS 서버가 그 레코드를 얼마나 자주 갱신하는지 나타낸다.</p>
<table>
<thead>
<tr>
<th>레코드</th>
<th>역할</th>
</tr>
</thead>
<tbody><tr>
<td>A</td>
<td>도메인의 IPv4 주소</td>
</tr>
<tr>
<td>AAAA</td>
<td>도메인의 IPv6 주소</td>
</tr>
<tr>
<td>CNAME</td>
<td>한 도메인을 다른 도메인으로 연결, IP 주소는 제공하지 않음</td>
</tr>
<tr>
<td>MX</td>
<td>메일을 메일 서버로 보냄</td>
</tr>
<tr>
<td>NS</td>
<td>해당 도메인의 네임서버</td>
</tr>
<tr>
<td>TXT</td>
<td>텍스트 메모, 이메일 보안에 자주 사용</td>
</tr>
<tr>
<td>SOA</td>
<td>도메인의 관리 정보</td>
</tr>
<tr>
<td>PTR</td>
<td>역방향 조회에서 도메인 이름 제공</td>
</tr>
</tbody></table>
<p>AWS 문서는 레코드를 이름/유형/값 세 가지로 설명한다. 이름은 도메인이나 서브도메인(<a href="http://www.example.com">www.example.com</a> 등), 유형은 트래픽을 보낼 리소스의 종류(메일 서버면 MX, IPv4 웹 서버면 A), 값은 유형에 맞는 내용(MX면 메일 서버 이름, A면 IPv4 주소)이다. Route 53에는 S3 버킷이나 CloudFront 같은 AWS 리소스로 트래픽을 보내는 별칭(alias) 레코드라는 특수 레코드도 있다. 도메인을 등록하면 같은 이름의 퍼블릭 호스티드 존이 자동으로 만들어지고 그 안에 레코드를 만들어 라우팅을 정한다.</p>
<h2 id="운영에서-자주-마주치는-상황">운영에서 자주 마주치는 상황</h2>
<p>동적 IP가 바뀌면 DNS 질의가 실패해 서비스가 내려갈 수 있다고 했는데 서버에는 고정 주소나 도메인 레코드 관리가 필요하다는 뜻이다. 또 캐시 때문에 레코드 값을 바꿔도 이전 값을 캐시한 쪽은 TTL이 지날 때까지 이전 값을 쓸 수 있다. (이 부분은 TTL과 캐시 설명에서 이해한 내용)</p>
<h2 id="핵심-복습">핵심 복습</h2>
<table>
<thead>
<tr>
<th>키워드</th>
<th>한 줄 정리</th>
</tr>
</thead>
<tbody><tr>
<td>DNS</td>
<td>도메인 이름을 IP 주소로 바꿔 주는 시스템</td>
</tr>
<tr>
<td>서버 4종</td>
<td>재귀 리졸버, 루트, TLD, 권한 있는 네임서버</td>
</tr>
<tr>
<td>조회 순서</td>
<td>리졸버 → 루트 → TLD → 권한 네임서버 → IP 반환</td>
</tr>
<tr>
<td>재귀/반복 질의</td>
<td>최종 답을 요구하는 질의 vs 참조를 따라가는 질의</td>
</tr>
<tr>
<td>캐시</td>
<td>브라우저 → OS → 재귀 리졸버 순으로 확인, TTL 동안만 유지</td>
</tr>
<tr>
<td>주요 레코드</td>
<td>A/AAAA는 IP, CNAME은 별칭, MX는 메일, NS는 네임서버</td>
</tr>
<tr>
<td>Route 53</td>
<td>호스티드 존에 레코드를 만들어 트래픽 라우팅, alias로 AWS 리소스 연결</td>
</tr>
</tbody></table>
<h2 id="📍-참고-자료">📍 참고 자료</h2>
<p>확인일: 2026-10-03</p>
<ul>
<li><a href="https://www.cloudflare.com/learning/dns/what-is-dns/">Cloudflare Learning Center - What is DNS?</a></li>
<li><a href="https://www.cloudflare.com/learning/dns/dns-records/">Cloudflare Learning Center - DNS records</a></li>
<li><a href="https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/welcome-dns-service.html">AWS Docs - How internet traffic is routed to your website or web application (Route 53)</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[웹은 어떻게 통신하는가]]></title>
            <link>https://velog.io/@jennie-infra/%EC%9B%B9%EC%9D%80-%EC%96%B4%EB%96%BB%EA%B2%8C-%ED%86%B5%EC%8B%A0%ED%95%98%EB%8A%94%EA%B0%80</link>
            <guid>https://velog.io/@jennie-infra/%EC%9B%B9%EC%9D%80-%EC%96%B4%EB%96%BB%EA%B2%8C-%ED%86%B5%EC%8B%A0%ED%95%98%EB%8A%94%EA%B0%80</guid>
            <pubDate>Sat, 03 Oct 2026 09:59:16 GMT</pubDate>
            <description><![CDATA[<h2 id="웹-통신에-쓰이는-프로토콜">웹 통신에 쓰이는 프로토콜</h2>
<p>브라우저로 웹 페이지를 열 때는 앞선 편에서 정리한 프로토콜이 한꺼번에 동작한다. </p>
<table>
<thead>
<tr>
<th>구성</th>
<th>하는 일</th>
<th>계층(2편 기준)</th>
</tr>
</thead>
<tbody><tr>
<td>DNS</td>
<td>도메인 이름으로 서버의 IP 주소를 찾는다</td>
<td>응용</td>
</tr>
<tr>
<td>HTTP/HTTPS</td>
<td>클라이언트와 서버가 요청과 응답으로 대화하는 규칙</td>
<td>응용</td>
</tr>
<tr>
<td>TCP/IP</td>
<td>데이터가 인터넷을 오가는 방식을 정한다</td>
<td>전송/인터넷</td>
</tr>
</tbody></table>
<p>HTTP는 응용 계층 프로토콜이고 TCP 위에서, 또는 TLS로 암호화한 TCP 위에서 전달된다. HTTPS는 HTTP를 암호화한 안전한 버전이다. 데이터는 한 덩어리가 아니라 작은 <strong><span style='background-color: #fff3b0'>패킷</span></strong> 여러 개로 나뉘어 오가고 각 패킷의 헤더에는 서버와 클라이언트의 IP 주소, 패킷 번호, 전체 패킷 수 같은 정보가 들어 있다. 패킷은 서로 다른 경로로 갈 수 있어서 순서가 뒤바뀌어 도착해도 헤더 정보로 올바른 순서로 다시 맞춘다. 일부가 유실되면 파일 전체가 아니라 빠진 패킷만 다시 요청하면 된다.</p>
<h2 id="클라이언트와-서버">클라이언트와 서버</h2>
<p>인터넷에 연결된 컴퓨터는 클라이언트와 서버로 나뉜다. 클라이언트는 사용자의 기기와 그 위의 웹 접속 소프트웨어(보통 브라우저)이고 서버는 웹 페이지나 앱을 저장한 컴퓨터다. HTTP는 클라이언트-서버 프로토콜이라서 <strong><span style='background-color: #fff3b0'>요청은 항상 클라이언트(브라우저)가 시작</span></strong>한다. 서버가 먼저 요청을 보내지는 않는다.</p>
<p>서버는 겉으로는 한 대처럼 보이지만 실제로는 부하를 나눠 맡는 여러 서버(로드 밸런싱)이거나, 문서를 그때그때 만들어 내는 캐시/데이터베이스 같은 다른 소프트웨어일 수도 있다. 한 서버 머신에서 여러 서버 프로그램이 돌 수 있고 HTTP/1.1의 Host 헤더 덕분에 같은 IP 주소를 공유할 수도 있다. 브라우저와 서버 사이에는 요청을 중계하는 프록시도 있다. 프록시는 캐싱/필터링/로드 밸런싱/인증/로깅 같은 일을 한다. 이렇게 보면 서브넷이나 라우터도 이 요청이 지나가는 길목이다.</p>
<h2 id="url과-uri">URL과 URI</h2>
<p>웹 주소를 정확히 부르면 URL이다. <strong><span style='background-color: #fff3b0'>URI</span></strong>는 웹의 리소스를 식별하는 이름이고, 가장 흔한 URI의 종류가 웹 주소로 알려진 <strong><span style='background-color: #fff3b0'>URL</span></strong>이다. 정리하면 URL은 URI의 한 종류다. 다음 예시로 구성 요소를 나눠 보면 (예시는 직접 만든 주소)</p>
<pre><code class="language-text">https://www.example.com:443/docs/page?lang=ko&amp;sort=new#intro</code></pre>
<table>
<thead>
<tr>
<th>구성</th>
<th>예시</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>스킴(프로토콜)</td>
<td>https</td>
<td>리소스를 요청할 때 브라우저가 쓸 프로토콜</td>
</tr>
<tr>
<td>권한(도메인 + 포트)</td>
<td><a href="http://www.example.com:443">www.example.com:443</a></td>
<td>어느 서버인지와 접속할 포트. HTTP 80/HTTPS 443이면 생략 가능</td>
</tr>
<tr>
<td>경로</td>
<td>/docs/page</td>
<td>서버에서 리소스의 위치. 지금은 실제 파일 위치가 아닌 추상화된 경로가 많다</td>
</tr>
<tr>
<td>쿼리</td>
<td>?lang=ko&amp;sort=new</td>
<td>서버에 추가로 전달하는 키/값 쌍, &amp;로 구분</td>
</tr>
<tr>
<td>프래그먼트</td>
<td>#intro</td>
<td>리소스 안의 특정 위치. 서버로는 전송되지 않는다</td>
</tr>
</tbody></table>
<p>도메인 대신 IP 주소를 쓸 수도 있지만 훨씬 불편해서 드물다. 이 도메인이 IP로 바뀌는 과정이 DNS의 주제다. 문서 안의 링크에는 일부가 생략된 상대 URL도 쓰이는데 브라우저가 현재 문서의 URL로 빠진 부분을 채운다.</p>
<h2 id="요청과-응답의-구조">요청과 응답의 구조</h2>
<p>HTTP 메시지는 요청과 응답 두 종류이고, 사람이 읽을 수 있게 설계됐다. 요청의 구성은 이렇다.</p>
<table>
<thead>
<tr>
<th>요청 구성</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>메서드</td>
<td>하려는 동작. 리소스를 가져오는 GET, 폼 값을 보내는 POST 등</td>
</tr>
<tr>
<td>경로</td>
<td>가져올 리소스의 경로(URL에서 스킴/도메인/포트를 뺀 부분)</td>
</tr>
<tr>
<td>HTTP 버전</td>
<td>사용하는 프로토콜 버전</td>
</tr>
<tr>
<td>헤더(선택)</td>
<td>서버에 전달하는 추가 정보</td>
</tr>
<tr>
<td>본문(선택)</td>
<td>POST처럼 보낼 데이터가 있을 때</td>
</tr>
</tbody></table>
<p>응답은 HTTP 버전, 상태 코드와 상태 메시지, 헤더, 그리고 가져온 리소스를 담은 본문(선택)으로 이루어진다. 자주 보는 상태 코드는 아래와 같다.</p>
<table>
<thead>
<tr>
<th>코드</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td>200</td>
<td>요청 성공</td>
</tr>
<tr>
<td>301</td>
<td>리소스가 영구적으로 새 위치로 이동(응답에 새 위치가 포함)</td>
</tr>
<tr>
<td>400</td>
<td>요청 형식이 잘못되어 서버가 처리할 수 없음</td>
</tr>
<tr>
<td>403</td>
<td>서버가 접근을 허용하지 않음(누군지는 알지만 권한이 없는 경우)</td>
</tr>
<tr>
<td>404</td>
<td>요청한 리소스를 찾을 수 없음</td>
</tr>
<tr>
<td>503</td>
<td>서버 쪽 문제로 처리할 수 없음(점검 중처럼 일시적인 경우가 많음)</td>
</tr>
</tbody></table>
<p>HTTP 자체는 <strong><span style='background-color: #fff3b0'>상태를 저장하지 않는(stateless)</span></strong> 프로토콜이라 연속된 두 요청 사이에 연결 고리가 없다. 그래서 쇼핑몰 장바구니처럼 맥락이 필요한 서비스는 쿠키로 세션을 만든다. HTTP가 상태가 없다는 것과 세션이 없다는 것은 다르다.</p>
<h2 id="한-번의-웹-접속-흐름">한 번의 웹 접속 흐름</h2>
<p>주소를 입력하고 페이지가 뜨기까지를 순서대로 정리하면 이렇다.</p>
<table>
<thead>
<tr>
<th>단계</th>
<th>일어나는 일</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>브라우저가 DNS로 서버의 실제 IP 주소를 찾는다</td>
</tr>
<tr>
<td>2</td>
<td>브라우저가 서버와 TCP 연결을 맺는다(왕복이 여러 번 필요)</td>
</tr>
<tr>
<td>3</td>
<td>브라우저가 HTTP 요청 메시지를 보내고, 이 메시지는 TCP/IP로 전달된다</td>
</tr>
<tr>
<td>4</td>
<td>서버가 요청을 승인하면 200 상태 코드와 함께 파일을 작은 패킷으로 나눠 보낸다</td>
</tr>
<tr>
<td>5</td>
<td>브라우저가 패킷을 모아 페이지를 완성해 보여 준다</td>
</tr>
<tr>
<td>6</td>
<td>연결을 닫거나 다음 요청에 재사용한다</td>
</tr>
</tbody></table>
<p>HTTP/1.0은 요청마다 TCP 연결을 새로 열어서 비효율적이었고, HTTP/1.1이 연결을 재사용하는 지속 연결을 도입했다. HTTP/2는 한 연결에서 메시지를 동시에 여러 개 주고받는 멀티플렉싱으로 더 효율을 높였다. 페이지 하나는 HTML뿐 아니라 CSS/JavaScript/이미지 같은 여러 리소스로 이루어져서 브라우저는 HTML을 받은 뒤 필요한 리소스를 추가로 요청한다.</p>
<h2 id="핵심-복습">핵심 복습</h2>
<table>
<thead>
<tr>
<th>키워드</th>
<th>한 줄 정리</th>
</tr>
</thead>
<tbody><tr>
<td>클라이언트/서버</td>
<td>요청은 항상 브라우저(클라이언트)가 시작</td>
</tr>
<tr>
<td>프록시</td>
<td>브라우저와 서버 사이에서 캐싱/필터링/로드 밸런싱 등을 수행</td>
</tr>
<tr>
<td>URI/URL</td>
<td>URI는 리소스 식별자, URL은 그중 웹 주소</td>
</tr>
<tr>
<td>URL 구성</td>
<td>스킴/도메인/포트/경로/쿼리/프래그먼트</td>
</tr>
<tr>
<td>HTTP 메시지</td>
<td>요청은 메서드+경로+버전+헤더, 응답은 버전+상태 코드+헤더+본문</td>
</tr>
<tr>
<td>상태 코드</td>
<td>200 성공, 301 이동, 403 권한 없음, 404 없음, 503 서버 문제</td>
</tr>
<tr>
<td>stateless</td>
<td>HTTP는 상태를 저장하지 않고 쿠키로 세션을 보완</td>
</tr>
<tr>
<td>접속 흐름</td>
<td>DNS 조회 → TCP 연결 → HTTP 요청 → 응답(패킷) → 페이지 완성</td>
</tr>
</tbody></table>
<h2 id="📍-참고-자료">📍 참고 자료</h2>
<p>확인일: 2026-10-03</p>
<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Learn_web_development/Getting_started/Web_standards/How_the_web_works">MDN - How the web works</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Learn_web_development/Howto/Web_mechanics/What_is_a_URL">MDN - What is a URL?</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Overview">MDN - Overview of HTTP</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/URI">MDN - URIs</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[라우터/라우팅과 ICMP]]></title>
            <link>https://velog.io/@jennie-infra/%EB%9D%BC%EC%9A%B0%ED%84%B0%EB%9D%BC%EC%9A%B0%ED%8C%85%EA%B3%BC-ICMP</link>
            <guid>https://velog.io/@jennie-infra/%EB%9D%BC%EC%9A%B0%ED%84%B0%EB%9D%BC%EC%9A%B0%ED%8C%85%EA%B3%BC-ICMP</guid>
            <pubDate>Sat, 03 Oct 2026 09:57:08 GMT</pubDate>
            <description><![CDATA[<h2 id="라우터가-하는-일">라우터가 하는 일</h2>
<p>라우터는 <strong><span style='background-color: #fff3b0'>둘 이상의 IP 네트워크를 연결하고 그 사이로 패킷을 전달하는 네트워크 장비</span></strong>다. 집이나 사무실에서 로컬 네트워크를 만드는 데도 쓰이고 더 강력한 라우터는 인터넷 곳곳에서 패킷이 목적지에 닿도록 돕는다. 전에 정리한 대로 스위치가 같은 네트워크 안의 장치를 연결한다면 라우터는 서로 다른 네트워크를 이어 준다.</p>
<p>라우터는 패킷의 헤더에서 목적지를 읽고 <strong><span style='background-color: #fff3b0'>라우팅 테이블</span></strong>을 보고 어느 경로로 보낼지 정한다. 라우팅 테이블은 라우터가 맡은 모든 목적지에 대해 패킷이 가야 할 경로를 적어 둔 표다. 패킷이 목적지에 가는 동안 서로 다른 라우터를 여러 번 거칠 수 있고, 그때마다 이 과정이 반복된다.</p>
<h2 id="클라우드에서의-라우팅-테이블">클라우드에서의 라우팅 테이블</h2>
<p>AWS VPC에서는 이 개념이 라우팅 테이블로 그대로 나타난다. 라우팅 테이블은 서브넷이나 게이트웨이에서 나가는 트래픽이 어디로 향할지 정하는 규칙(라우트)의 모음이다. 각 라우트는 목적지(CIDR 블록)와 대상(인터넷 게이트웨이, NAT 게이트웨이, VPC 피어링, VPN 연결 등)으로 이루어지고, 트래픽은 목적지 IP를 기준으로 대상에 보내진다. VPC를 만들면 기본 라우팅 테이블이 함께 만들어진다. 서브넷이 퍼블릭인지 프라이빗인지가 라우팅으로 정해지는데 그 규칙이 바로 이 라우팅 테이블에 있다.</p>
<p>아래는 이 구조를 이해하려고 직접 만든 예시다. (이해한 내용을 바탕으로 만든 예시)</p>
<table>
<thead>
<tr>
<th>목적지</th>
<th>대상</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td>10.0.0.0/16</td>
<td>local</td>
<td>VPC 안의 다른 서브넷으로 가는 트래픽</td>
</tr>
<tr>
<td>0.0.0.0/0</td>
<td>인터넷 게이트웨이</td>
<td>그 밖의 모든 트래픽은 인터넷으로(퍼블릭 서브넷)</td>
</tr>
</tbody></table>
<p>프라이빗 서브넷은 마지막 줄의 대상이 인터넷 게이트웨이가 아니라 NAT 게이트웨이가 되거나 아예 없다. 라우트가 겹칠 때의 우선순위는 AWS 문서의 Route priority 항목에서 따로 확인해야 하는 부분이라 이 글에서는 다루지 않았다.</p>
<h2 id="라우팅">라우팅</h2>
<p>라우팅은 <strong><span style='background-color: #fff3b0'>하나 이상의 네트워크를 가로지르는 경로를 고르는 과정</span></strong>이고 인터넷 같은 패킷 교환 네트워크에서는 IP 패킷이 출발지에서 목적지까지 갈 경로를 정한다. 라우팅 테이블을 만드는 방식은 둘로 나뉜다.</p>
<table>
<thead>
<tr>
<th>구분</th>
<th>방식</th>
<th>특징</th>
</tr>
</thead>
<tbody><tr>
<td>정적 라우팅</td>
<td>관리자가 경로를 직접 적는다</td>
<td>관리자가 바꾸기 전까지 경로가 고정되고, 작은 네트워크에서 쓴다</td>
</tr>
<tr>
<td>동적 라우팅</td>
<td>라우팅 프로토콜로 경로를 자동 갱신한다</td>
<td>계산량이 더 필요하지만 중대형 네트워크에서 훨씬 효율적이다</td>
</tr>
</tbody></table>
<p>동적 라우팅에 쓰이는 라우팅 프로토콜은 어디까지 적용되는지로 나뉜다.</p>
<table>
<thead>
<tr>
<th>프로토콜</th>
<th>범위</th>
<th>하는 일</th>
</tr>
</thead>
<tbody><tr>
<td>BGP</td>
<td>자율 시스템(AS) 사이</td>
<td>어느 네트워크가 어느 IP를 갖고 있고 어떤 네트워크끼리 연결됐는지 알린다</td>
</tr>
<tr>
<td>OSPF</td>
<td>하나의 AS 안</td>
<td>가장 빠르고 짧은 경로를 동적으로 찾는다</td>
</tr>
<tr>
<td>RIP</td>
<td>하나의 AS 안</td>
<td>거치는 라우터 수(홉 수)로 가장 짧은 경로를 찾는다</td>
</tr>
</tbody></table>
<p>인터넷은 이렇게 AS라 불리는 큰 네트워크들이 BGP로 서로를 알리며 이어진 구조라고 볼 수 있다. 집이나 사무실의 라우터는 그 가장자리에서 내부 네트워크를 인터넷에 이어 준다.</p>
<h2 id="라우터를-지날-때-주소는-어떻게-되는가">라우터를 지날 때 주소는 어떻게 되는가</h2>
<p>라우터는 패킷 헤더의 목적지 IP를 읽고 라우팅 테이블에 따라 다음 네트워크로 보낸다. MAC 주소는 IP 패킷 헤더에 들어가지 않고 같은 네트워크 안에서만 쓰인다. 그래서 패킷이 라우터를 지날 때 목적지 IP는 그대로이고 링크 계층의 MAC 주소는 구간마다 다음 장치의 것으로 바뀐다고 이해했다. </p>
<h2 id="icmp">ICMP</h2>
<p>ICMP는 네트워크 장치가 통신 문제를 진단하려고 쓰는 <strong><span style='background-color: #fff3b0'>네트워크 계층 프로토콜</span></strong>이다. 데이터가 목적지에 제때 닿는지를 확인하는 것이 주된 용도이고 라우터 같은 장치에서 흔히 쓰인다. 가장 기본적인 용도는 오류 보고다. 예를 들어 패킷이 라우터가 처리하기에 너무 크면 라우터는 그 패킷을 버리고 원래 출발지로 ICMP 메시지를 보낸다.</p>
<p>두 번째 용도는 진단이고, <code>ping</code>과 <code>traceroute</code>가 모두 ICMP로 동작한다. ping은 ICMP echo-request/echo-reply 메시지로 패킷이 목적지까지 갔다 오는 시간을 알려 주고, traceroute는 두 장치 사이의 경로와 홉마다 걸린 시간을 보여 줘서 지연이 어디서 생기는지 찾을 때 쓴다.</p>
<p>ICMP는 TCP나 UDP 같은 전송 계층 프로토콜과 묶이지 않는 비연결형이라 연결을 맺지 않고 바로 보낸다. ICMP 패킷은 일반 IP 헤더 뒤에 ICMP 헤더가 붙은 구조이고 오류 메시지의 본문에는 오류를 일으킨 패킷의 IP 헤더 사본이 들어간다. 또 ICMP로는 특정 포트를 지정할 수 없다. 그래서 ping이 성공해도 그 서버의 특정 서비스(포트)가 정상이라는 뜻은 아니라고 봐야 한다.</p>
<p>TTL은 ICMP를 이해하는 열쇠다. RFC 1122에 따르면 IP 헤더의 TTL(Time-to-Live) 필드는 라우팅 루프를 끝내는 역할을 하고 라우터는 패킷을 전달할 때마다 TTL을 최소 1씩 줄인다. TTL이 만료되면 라우터는 패킷을 버리고 ICMP Time Exceeded 메시지로 알린다. TTL은 일부 진단 도구로도 쓰인다. 이 두 가지를 이어서 traceroute가 TTL을 1부터 늘려 가며 보내고 각 홉이 돌려주는 Time Exceeded로 경로를 알아낸다. </p>
<table>
<thead>
<tr>
<th>ICMP 메시지</th>
<th>상황</th>
<th>쓰임</th>
</tr>
</thead>
<tbody><tr>
<td>Echo Request/Reply</td>
<td>상대가 살아 있는지 확인</td>
<td>ping</td>
</tr>
<tr>
<td>Time Exceeded</td>
<td>TTL이 0이 돼 패킷이 버려짐</td>
<td>경로 추적(traceroute), 루프 탐지</td>
</tr>
<tr>
<td>Destination Unreachable</td>
<td>목적지에 닿을 수 없음</td>
<td>오류 알림</td>
</tr>
</tbody></table>
<p>ICMP는 보안에서도 등장한다. 공격자가 echo-request를 대량으로 보내 대상의 자원을 소진시키는 ICMP flood 같은 공격이 있다. 이런 네트워크 계층(L3) DDoS가 웹 서비스가 아니라 네트워크 장비와 인프라를 노린다. 계층 번호로 위치를 말하는 것도 있는데 이런 공격을 L3 공격이라고 부르는 것도 같은 맥락이라고 볼 수 있다.</p>
<h2 id="핵심-복습">핵심 복습</h2>
<table>
<thead>
<tr>
<th>키워드</th>
<th>한 줄 정리</th>
</tr>
</thead>
<tbody><tr>
<td>라우터</td>
<td>서로 다른 IP 네트워크를 연결하고 패킷을 전달</td>
</tr>
<tr>
<td>라우팅 테이블</td>
<td>목적지별로 패킷이 갈 경로를 적은 표</td>
</tr>
<tr>
<td>정적/동적 라우팅</td>
<td>관리자가 직접 적음 vs 프로토콜로 자동 갱신</td>
</tr>
<tr>
<td>BGP/OSPF/RIP</td>
<td>BGP는 AS 사이, OSPF/RIP는 AS 안의 라우팅 프로토콜</td>
</tr>
<tr>
<td>AWS 라우팅 테이블</td>
<td>목적지 CIDR과 대상으로 이루어진 라우트의 모음</td>
</tr>
<tr>
<td>ICMP</td>
<td>네트워크 문제를 진단하는 L3 프로토콜, 포트 개념이 없음</td>
</tr>
<tr>
<td>ping/traceroute</td>
<td>왕복 시간 측정 vs 경로와 홉별 시간 확인</td>
</tr>
<tr>
<td>TTL</td>
<td>라우터를 지날 때마다 줄어들어 라우팅 루프를 끊는 값</td>
</tr>
</tbody></table>
<h2 id="📍-참고-자료">📍 참고 자료</h2>
<p>확인일: 2026-10-03</p>
<ul>
<li><a href="https://www.cloudflare.com/learning/network-layer/what-is-routing/">Cloudflare Learning Center - What is routing?</a></li>
<li><a href="https://www.cloudflare.com/learning/ddos/glossary/internet-control-message-protocol-icmp/">Cloudflare Learning Center - What is ICMP?</a></li>
<li><a href="https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Route_Tables.html">AWS Docs - Configure route tables</a></li>
<li><a href="https://www.rfc-editor.org/rfc/rfc1122">RFC 1122 - Requirements for Internet Hosts, Communication Layers</a> (TTL과 Time Exceeded 부분)</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[허브/스위치와 케이블]]></title>
            <link>https://velog.io/@jennie-infra/%ED%97%88%EB%B8%8C%EC%8A%A4%EC%9C%84%EC%B9%98%EC%99%80-%EC%BC%80%EC%9D%B4%EB%B8%94</link>
            <guid>https://velog.io/@jennie-infra/%ED%97%88%EB%B8%8C%EC%8A%A4%EC%9C%84%EC%B9%98%EC%99%80-%EC%BC%80%EC%9D%B4%EB%B8%94</guid>
            <pubDate>Sat, 03 Oct 2026 09:53:33 GMT</pubDate>
            <description><![CDATA[<h2 id="허브와-스위치는-어느-계층의-장비인가">허브와 스위치는 어느 계층의 장비인가</h2>
<p>계층에 장비를 대응시키면 이렇다. LAN은 OSI 1계층과 2계층의 장비를 쓴다. 허브/중계기 같은 1계층 장비는 데이터를 물리적으로 전달하고, 스위치/브리지 같은 2계층 장비는 같은 네트워크 구간에 있는 장치끼리 통신을 설정하고 유지한다. 서로 다른 네트워크 사이로 데이터를 보내는 3계층 장비가 라우터이고 이는 라우팅에서 다룬다.</p>
<table>
<thead>
<tr>
<th>장비</th>
<th>계층</th>
<th>보는 주소</th>
<th>하는 일</th>
</tr>
</thead>
<tbody><tr>
<td>허브</td>
<td>L1</td>
<td>주소를 보지 않음</td>
<td>들어온 신호를 물리적으로 전달</td>
</tr>
<tr>
<td>스위치</td>
<td>L2</td>
<td>MAC 주소</td>
<td>같은 네트워크 안에서 목적지 장치로 프레임 전달</td>
</tr>
<tr>
<td>라우터</td>
<td>L3</td>
<td>IP 주소</td>
<td>서로 다른 네트워크 사이의 경로 선택</td>
</tr>
</tbody></table>
<h2 id="허브">허브</h2>
<p>허브는 <strong><span style='background-color: #fff3b0'>1계층 장비</span></strong>라서 MAC 주소 같은 주소 정보를 읽지 않는다. 그래서 허브는 어느 포트로 들어온 신호든 다른 포트로 그대로 내보낸다. 주소를 보고 필요한 곳에만 보내는 장비가 필요해서 나온 것이 스위치다.</p>
<h2 id="스위치스위칭-허브">스위치(스위칭 허브)</h2>
<p>스위치는 같은 네트워크 안의 장치를 연결하고 패킷을 목적지 장치로만 전달하는 장비다. Cloudflare 문서는 스위치가 네트워크가 아닌 <strong><span style='background-color: #fff3b0'>단일 장치</span></strong>를 향해 데이터를 보낸다는 점에서 라우터와 다르다고 설명한다. 2계층 스위치는 목적지 MAC 주소를 보고 전달하고 3계층 스위치는 목적지 IP 주소를 보고 전달하며 둘 다 되는 스위치도 있다. 대부분은 2계층 스위치다.</p>
<p>스위치는 <strong><span style='background-color: #fff3b0'>MAC 주소 테이블</span></strong>(CAM 테이블)을 메모리에 두고 어느 MAC 주소가 어느 포트에 연결돼 있는지 기록한다. 테이블이 비어 있을 때 컴퓨터 A가 B에게 보내는 상황이 학습 과정을 보여 준다.</p>
<table>
<thead>
<tr>
<th>단계</th>
<th>스위치가 하는 일</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>A의 MAC 주소와 메시지가 들어온 포트를 테이블에 기록한다</td>
</tr>
<tr>
<td>2</td>
<td>B가 어느 포트인지 모르니 A를 제외한 모든 포트로 메시지를 보낸다(플러딩)</td>
</tr>
<tr>
<td>3</td>
<td>B가 응답하면 B의 MAC 주소와 포트도 테이블에 기록한다</td>
</tr>
<tr>
<td>4</td>
<td>이후 A와 B 사이 트래픽은 테이블을 보고 해당 포트로만 보낸다</td>
</tr>
</tbody></table>
<p>테이블은 메모리에 있어서 스위치 전원이 꺼지면 사라지고, 다시 켜면 처음부터 학습해야 한다. 전에 ARP 요청이 같은 네트워크의 모든 장치에게 브로드캐스트된다고 했는데 그 전달을 같은 네트워크 안에서 스위치가 해 준다.</p>
<p>스위치는 관리 기능에 따라 나뉜다. 비관리형 스위치는 LAN에 이더넷 포트를 늘려 주는 용도로 MAC 주소 기준으로 전달만 하고 관리형 스위치는 더 큰 네트워크에서 트래픽 우선순위를 정하거나 VLAN으로 로컬 네트워크를 더 작게 나누는 관리 기능을 제공한다. 집이나 작은 사무실은 인터넷 연결에 라우터만 있으면 되고 이더넷 포트가 많이 필요할 때만 스위치를 쓰지만 컴퓨터가 수십~수백 대인 큰 사무실이나 데이터센터에는 보통 스위치가 필요하다고 한다.</p>
<h2 id="케이블">케이블</h2>
<p>장치를 잇는 링크에는 유선과 무선이 있다. 유선 연결에는 동축/광섬유/트위스트 페어 기술로 만든 이더넷 케이블을 쓰고, 무선은 3G/4G/5G 같은 전파로 노드를 연결한다. 이 글은 유선 중 이더넷에서 흔히 쓰는 것을 정리한다.</p>
<p><strong>트위스트 페어 케이블</strong>은 구리선 쌍을 꼬아서 인접한 쌍에서 생기는 전자기 잡음(누화)을 줄인 케이블이다. 차폐가 없으면 UTP, 호일/편조로 감싸면 차폐형이다. 카테고리(CAT5e/CAT6/CAT6A)에 따라 지원하는 속도와 최대 거리가 다르다.</p>
<table>
<thead>
<tr>
<th>규격</th>
<th>CAT5e</th>
<th>CAT6</th>
<th>CAT6A</th>
</tr>
</thead>
<tbody><tr>
<td>1000BASE-T(1Gbps)</td>
<td>100 m</td>
<td>100 m</td>
<td>100 m</td>
</tr>
<tr>
<td>2.5GBASE-T</td>
<td>100 m</td>
<td>100 m</td>
<td>100 m</td>
</tr>
<tr>
<td>5GBASE-T</td>
<td>지원 안 함</td>
<td>100 m</td>
<td>100 m</td>
</tr>
<tr>
<td>10GBASE-T</td>
<td>지원 안 함</td>
<td>55 m</td>
<td>100 m</td>
</tr>
</tbody></table>
<p>높은 카테고리의 케이블은 하위 카테고리와 호환되지만 더 비싸고 덜 유연하다. 1Gbps라면 CAT5e로도 100 m까지 가능하고, 10Gbps를 100 m 가려면 CAT6A가 필요하다는 식으로 읽으면 된다.</p>
<p><strong>광케이블</strong>은 더 높은 속도와 긴 거리가 필요할 때 쓴다. 멀티모드 광섬유(MMF)는 코어가 굵어 여러 빛 경로를 전달하고 주로 짧은 거리의 백본에 쓰며 송수신기가 상대적으로 저렴하다. 단일 모드 광섬유(SMF)는 빛 하나만 전달해서 먼 거리에서도 신호가 잘 유지된다. 대신 SMF용 송수신기는 MMF보다 비싸고 복잡하다. </p>
<p>데이터센터 안에서는 광케이블 외에 아래 두 가지도 쓴다. 이 두 가지는 케이블 끝에 송수신기가 붙어 있는 형태다.</p>
<table>
<thead>
<tr>
<th>종류</th>
<th>매체</th>
<th>거리</th>
<th>쓰는 곳</th>
</tr>
</thead>
<tbody><tr>
<td>DAC(다이렉트 어태치)</td>
<td>구리(송수신기 내장)</td>
<td>패시브 SFP+는 최대 7 m, 액티브는 15 m</td>
<td>서버와 스위치 사이 짧은 구간</td>
</tr>
<tr>
<td>AOC(액티브 광케이블)</td>
<td>광섬유(송수신기 내장)</td>
<td>최대 100 m</td>
<td>랙 사이 또는 건물 안 연결</td>
</tr>
</tbody></table>
<h2 id="커넥터">커넥터</h2>
<p>트위스트 페어 케이블 끝에 달리는 것이 <strong><span style='background-color: #fff3b0'>RJ45 커넥터</span></strong>다. 원래 전화용으로 개발된 모듈러 커넥터에서 시작했고 이더넷용은 8핀 8접점(8P8C)이라서 업계에서 RJ45로 부른다. 케이블 카테고리가 바뀌어도 커넥터 모양은 그대로라서 높은 속도로 업그레이드하기 쉽다.</p>
<p>광케이블이나 구리 케이블을 스위치/어댑터에 연결할 때는 <strong><span style='background-color: #fff3b0'>SFP 같은 송수신기 모듈</span></strong>을 쓴다. 이 모듈은 꽂았다 뺄 수 있고 전기 신호를 광 신호로 바꿔 준다. SFP는 RJ45 구리 케이블, MMF/SMF 광케이블, DAC를 연결할 수 있고 같은 포트(케이지)에 다른 송수신기를 바꿔 끼워 쓸 수 있다.</p>
<table>
<thead>
<tr>
<th>송수신기</th>
<th>대표 속도</th>
</tr>
</thead>
<tbody><tr>
<td>SFP</td>
<td>1GbE</td>
</tr>
<tr>
<td>SFP+</td>
<td>10GbE</td>
</tr>
<tr>
<td>SFP28</td>
<td>25GbE</td>
</tr>
<tr>
<td>QSFP</td>
<td>40GbE</td>
</tr>
<tr>
<td>QSFP28</td>
<td>100GbE</td>
</tr>
</tbody></table>
<h2 id="핵심-복습">핵심 복습</h2>
<table>
<thead>
<tr>
<th>키워드</th>
<th>한 줄 정리</th>
</tr>
</thead>
<tbody><tr>
<td>허브</td>
<td>1계층 장비, 주소를 보지 않고 물리적으로 전달</td>
</tr>
<tr>
<td>스위치</td>
<td>2계층 장비, MAC 주소 테이블을 보고 목적지 포트로만 전달</td>
</tr>
<tr>
<td>플러딩</td>
<td>목적지 포트를 모르면 들어온 포트를 뺀 모든 포트로 전달</td>
</tr>
<tr>
<td>스위치와 라우터</td>
<td>스위치는 같은 네트워크 안의 장치, 라우터는 네트워크 사이를 연결</td>
</tr>
<tr>
<td>트위스트 페어</td>
<td>구리선 쌍을 꼬아 잡음을 줄임, 1Gbps는 CAT5e로 100 m</td>
</tr>
<tr>
<td>광케이블</td>
<td>MMF는 짧은 거리, SMF는 먼 거리, 송수신기는 SMF가 더 비쌈</td>
</tr>
<tr>
<td>RJ45</td>
<td>이더넷 트위스트 페어용 8핀 커넥터, 카테고리가 바뀌어도 모양 동일</td>
</tr>
<tr>
<td>SFP</td>
<td>케이블 종류를 바꿔 끼울 수 있는 송수신기 모듈</td>
</tr>
</tbody></table>
<h2 id="📍-참고-자료">📍 참고 자료</h2>
<p>확인일: 2026-10-02</p>
<ul>
<li><a href="https://www.cloudflare.com/learning/network-layer/what-is-a-network-switch/">Cloudflare Learning Center - What is a network switch?</a></li>
<li><a href="https://aws.amazon.com/ko/compare/the-difference-between-lan-and-wan/">AWS - LAN과 WAN의 차이점은 무엇인가요?</a></li>
<li><a href="https://cdrdv2-public.intel.com/639302/ethernet%20cables%20and%20transceivers%20tech%20guide.pdf">Intel - Ethernet Cables and Transceivers Overview (Technology Guide)</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[서브넷 구성과 해석]]></title>
            <link>https://velog.io/@jennie-infra/%EC%84%9C%EB%B8%8C%EB%84%B7-%EA%B5%AC%EC%84%B1%EA%B3%BC-%ED%95%B4%EC%84%9D</link>
            <guid>https://velog.io/@jennie-infra/%EC%84%9C%EB%B8%8C%EB%84%B7-%EA%B5%AC%EC%84%B1%EA%B3%BC-%ED%95%B4%EC%84%9D</guid>
            <pubDate>Sat, 03 Oct 2026 09:51:34 GMT</pubDate>
            <description><![CDATA[<h2 id="서브넷은-왜-나누는가">서브넷은 왜 나누는가</h2>
<p>서브넷은 <strong><span style='background-color: #fff3b0'>네트워크 안의 더 작은 네트워크</span></strong>다. 서브넷으로 나누면 트래픽이 불필요한 라우터를 거치지 않고 더 짧은 경로로 목적지에 간다. 큰 네트워크 하나에 장치가 수백만 대 있으면 데이터가 올바른 장치를 찾는 데 시간이 걸리기 때문에 주소를 일정한 범위로 좁혀 주는 것이 서브넷의 역할이다.</p>
<p>클라우드에서는 이 개념이 설계로 이어진다. AWS VPC에서 서브넷은 VPC 안의 IP 주소 범위이고 서브넷 하나는 가용 영역(AZ) 하나 안에만 있어야 하며 여러 AZ에 걸칠 수 없다. 그래서 가용 영역별로 서브넷을 따로 만들어 한 AZ가 장애가 나도 다른 AZ의 서비스는 유지되게 한다.</p>
<h2 id="ip-주소에서-네트워크와-호스트를-나누는-법">IP 주소에서 네트워크와 호스트를 나누는 법</h2>
<p>IPv4 주소는 두 부분으로 이루어진다. 앞부분은 어느 네트워크인지를, 뒷부분은 그 네트워크 안의 어느 장치(호스트)인지를 가리킨다. 문제는 앞부분이 어디까지인지가 주소만으로는 안 보인다는 점이고 그 경계를 알려 주는 것이 <strong><span style='background-color: #fff3b0'>서브넷 마스크</span></strong>다. Cloudflare 문서는 192.0.2.15를 예로 들어, 서브넷 마스크 255.255.255.0으로 계산하면 앞의 192.0.2가 네트워크이고 15가 장치 번호라고 보여 준다. 이 네트워크는 192.0.2.0/24로 표기한다.</p>
<p>서브넷 마스크는 패킷에 담겨 인터넷을 건너가지 않는다. 패킷에는 목적지 IP만 있고 네트워크 안의 라우터가 그 IP를 자기 서브넷 마스크와 맞춰 보고 어느 서브넷으로 보낼지 정한다고 한다.</p>
<h2 id="서브넷-마스크와-cidr-표기">서브넷 마스크와 CIDR 표기</h2>
<p>마스크는 2진수로 쓰면 앞쪽 1이 쭉 이어지고 뒤쪽이 0이다. 255.255.255.0은 <code>11111111.11111111.11111111.00000000</code>이고 여기서 1의 개수가 24개라서 <code>/24</code>로 줄여 쓴다. 이 표기가 <strong><span style='background-color: #fff3b0'>CIDR 표기</span></strong>이고, <code>/</code> 뒤의 숫자가 네트워크 부분의 비트 수다. Cloudflare 문서는 클래스(A/B/C) 개념으로 설명하지만, AWS VPC 문서는 서브넷 주소를 CIDR 표기로 쓴다. 클라우드 실무에서는 CIDR 위주로 읽으면 된다.</p>
<table>
<thead>
<tr>
<th>CIDR</th>
<th>서브넷 마스크</th>
<th>호스트 비트</th>
<th>전체 주소 수</th>
<th>AWS에서 사용 가능한 수</th>
</tr>
</thead>
<tbody><tr>
<td>/16</td>
<td>255.255.0.0</td>
<td>16</td>
<td>65,536</td>
<td>65,531</td>
</tr>
<tr>
<td>/20</td>
<td>255.255.240.0</td>
<td>12</td>
<td>4,096</td>
<td>4,091</td>
</tr>
<tr>
<td>/24</td>
<td>255.255.255.0</td>
<td>8</td>
<td>256</td>
<td>251</td>
</tr>
<tr>
<td>/25</td>
<td>255.255.255.128</td>
<td>7</td>
<td>128</td>
<td>123</td>
</tr>
<tr>
<td>/26</td>
<td>255.255.255.192</td>
<td>6</td>
<td>64</td>
<td>59</td>
</tr>
<tr>
<td>/27</td>
<td>255.255.255.224</td>
<td>5</td>
<td>32</td>
<td>27</td>
</tr>
<tr>
<td>/28</td>
<td>255.255.255.240</td>
<td>4</td>
<td>16</td>
<td>11</td>
</tr>
</tbody></table>
<p>AWS는 서브넷 크기를 /28에서 /16 사이로 허용하고 각 서브넷에서 앞의 4개와 마지막 1개, 총 5개 주소를 못 쓰게 예약한다. 표의 마지막 열은 전체 주소 수에서 이 5개를 뺀 값이다. 예약되는 5개는 /24 기준으로 이렇게 쓰인다.</p>
<table>
<thead>
<tr>
<th>주소</th>
<th>용도</th>
</tr>
</thead>
<tbody><tr>
<td>10.0.0.0</td>
<td>네트워크 주소</td>
</tr>
<tr>
<td>10.0.0.1</td>
<td>VPC 라우터용으로 AWS가 예약</td>
</tr>
<tr>
<td>10.0.0.2</td>
<td>AWS 예약(DNS 서버 주소 규칙)</td>
</tr>
<tr>
<td>10.0.0.3</td>
<td>향후 사용을 위해 AWS가 예약</td>
</tr>
<tr>
<td>10.0.0.255</td>
<td>브로드캐스트 주소(VPC는 브로드캐스트를 지원하지 않아 예약)</td>
</tr>
</tbody></table>
<h2 id="주소-개수-계산하는-법">주소 개수 계산하는 법</h2>
<p>계산은 세 줄이면 된다. 호스트 비트는 <code>32 - 프리픽스 길이</code>이고 전체 주소 수는 <code>2의 호스트 비트 제곱</code>이다. 마지막 옥텟에서 끊기는 /25~/30 구간은 <code>256 - 마스크의 마지막 숫자</code>가 블록 크기(주소 간격)가 된다. 예를 들어 /26은 마스크 마지막 숫자가 192라서 256 - 192 = 64이고, 서브넷이 64 간격으로 0/64/128/192에서 시작한다.</p>
<h2 id="범위-해석-연습">범위 해석 연습</h2>
<p><strong>연습 1. AWS 문서 예제.</strong> VPC가 10.0.0.0/24이면 256개 주소를 지원하고 이를 두 서브넷으로 쪼개면 각각 128개다. 10.0.0.0/25는 10.0.0.0 ~ 10.0.0.127이고, 10.0.0.128/25는 10.0.0.128 ~ 10.0.0.255다. 그러면 10.0.0.200은 어느 서브넷일까. 200은 128 ~ 255 구간에 있으니 10.0.0.128/25다.</p>
<p><strong>연습 2. 직접 계산한 예제.</strong> 192.168.10.100/26이 속한 범위를 구해 보자.</p>
<table>
<thead>
<tr>
<th>단계</th>
<th>계산</th>
</tr>
</thead>
<tbody><tr>
<td>블록 크기</td>
<td>256 - 192 = 64</td>
</tr>
<tr>
<td>네트워크 시작</td>
<td>100은 64 ~ 127 구간이므로 192.168.10.64</td>
</tr>
<tr>
<td>범위</td>
<td>192.168.10.64 ~ 192.168.10.127</td>
</tr>
<tr>
<td>마지막 주소</td>
<td>192.168.10.127(일반 네트워크에서는 브로드캐스트)</td>
</tr>
</tbody></table>
<p>정리하면 서브넷 해석은 <code>블록 크기 구하기 → 내 주소가 들어가는 구간 찾기 → 시작/끝 주소 읽기</code> 순서다.</p>
<h2 id="aws에서-서브넷은-어떻게-설계하는가">AWS에서 서브넷은 어떻게 설계하는가</h2>
<p>AWS 문서 기준으로 서브넷 CIDR은 VPC CIDR과 같거나 그 안의 일부여야 하고 한 VPC의 서브넷끼리는 범위가 겹치면 안 된다. 서브넷의 종류는 라우팅으로 정해진다. 인터넷 게이트웨이로 가는 직접 경로가 있으면 <strong><span style='background-color: #fff3b0'>퍼블릭 서브넷</span></strong>, 없으면 <strong><span style='background-color: #fff3b0'>프라이빗 서브넷</span></strong>이고, 프라이빗 서브넷의 리소스가 인터넷에 나가려면 NAT 장치가 필요하다. AWS는 리소스를 보호하기 위해 프라이빗 서브넷을 쓰라고 권장한다.</p>
<p>아래는 이 규칙을 적용해 직접 짜 본 예시 설계다. </p>
<table>
<thead>
<tr>
<th>서브넷</th>
<th>CIDR</th>
<th>AZ</th>
<th>용도</th>
</tr>
</thead>
<tbody><tr>
<td>public-a</td>
<td>10.0.0.0/24</td>
<td>a</td>
<td>로드밸런서/NAT</td>
</tr>
<tr>
<td>public-b</td>
<td>10.0.1.0/24</td>
<td>b</td>
<td>로드밸런서/NAT</td>
</tr>
<tr>
<td>private-a</td>
<td>10.0.10.0/24</td>
<td>a</td>
<td>웹/앱 서버</td>
</tr>
<tr>
<td>private-b</td>
<td>10.0.11.0/24</td>
<td>b</td>
<td>웹/앱 서버</td>
</tr>
</tbody></table>
<p>VPC는 10.0.0.0/16으로 잡으면 위 네 서브넷이 모두 그 안에 들어가고 서로 겹치지 않는다. 가용 영역별로 퍼블릭/프라이빗을 나눈 구조라고 이해했다. 서브넷 단위 보안은 네트워크 ACL이, 리소스 단위 보안은 보안 그룹이 맡고, 대부분은 보안 그룹으로 충분하다.</p>
<h2 id="핵심-복습">핵심 복습</h2>
<table>
<thead>
<tr>
<th>키워드</th>
<th>한 줄 정리</th>
</tr>
</thead>
<tbody><tr>
<td>서브넷</td>
<td>네트워크 안의 더 작은 네트워크, 불필요한 라우터 경유를 줄임</td>
</tr>
<tr>
<td>서브넷 마스크</td>
<td>주소의 네트워크/호스트 경계, 라우터가 서브넷을 구분할 때 씀</td>
</tr>
<tr>
<td>CIDR</td>
<td>마스크의 1 개수를 /n으로 표기(/24 = 255.255.255.0)</td>
</tr>
<tr>
<td>주소 수 계산</td>
<td>2의 (32 - n)제곱, AWS는 그중 5개 예약</td>
</tr>
<tr>
<td>범위 해석</td>
<td>블록 크기 구하기 → 구간 찾기 → 시작/끝 읽기</td>
</tr>
<tr>
<td>퍼블릭/프라이빗</td>
<td>인터넷 게이트웨이로 가는 직접 경로 유무로 구분</td>
</tr>
<tr>
<td>설계 규칙</td>
<td>서브넷 CIDR은 VPC 안에 들어가고 서로 겹치지 않음, 서브넷 1개는 AZ 1개</td>
</tr>
</tbody></table>
<h2 id="📍-참고-자료">📍 참고 자료</h2>
<p>확인일: 2026-10-02</p>
<ul>
<li><a href="https://www.cloudflare.com/learning/network-layer/what-is-a-subnet/">Cloudflare Learning Center - What is a subnet?</a></li>
<li><a href="https://docs.aws.amazon.com/vpc/latest/userguide/subnet-sizing.html">AWS Docs - Subnet CIDR blocks</a></li>
<li><a href="https://docs.aws.amazon.com/vpc/latest/userguide/configure-subnets.html">AWS Docs - Subnets for your VPC</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[IP/MAC 주소와 ARP, 포트 번호]]></title>
            <link>https://velog.io/@jennie-infra/IPMAC-%EC%A3%BC%EC%86%8C%EC%99%80-ARP-%ED%8F%AC%ED%8A%B8-%EB%B2%88%ED%98%B8</link>
            <guid>https://velog.io/@jennie-infra/IPMAC-%EC%A3%BC%EC%86%8C%EC%99%80-ARP-%ED%8F%AC%ED%8A%B8-%EB%B2%88%ED%98%B8</guid>
            <pubDate>Sat, 03 Oct 2026 09:49:24 GMT</pubDate>
            <description><![CDATA[<h2 id="주소가-세-종류나-필요한-이유">주소가 세 종류나 필요한 이유</h2>
<p>통신 한 번에는 서로 다른 세 가지 식별자가 쓰인다. 같은 서버에 접속하더라도 어느 네트워크의 어느 장치인지(IP), 같은 네트워크 안에서 어느 인터페이스인지(MAC), 그 장치 안의 어느 프로그램인지(포트)를 따로 가리켜야 하기 때문이다. 계층 모델로 보면 이렇게 나뉜다.</p>
<table>
<thead>
<tr>
<th>식별자</th>
<th>계층</th>
<th>가리키는 대상</th>
<th>형태</th>
</tr>
</thead>
<tbody><tr>
<td>IP 주소</td>
<td>인터넷(L3)</td>
<td>네트워크에 연결된 장치</td>
<td>IPv4는 32비트, 점으로 구분한 숫자 네 묶음</td>
</tr>
<tr>
<td>MAC 주소</td>
<td>링크(L2)</td>
<td>같은 네트워크 안의 네트워크 인터페이스</td>
<td>48비트</td>
</tr>
<tr>
<td>포트 번호</td>
<td>전송(L4)</td>
<td>장치 안에서 동작하는 프로그램/서비스</td>
<td>숫자(총 65,535개)</td>
</tr>
</tbody></table>
<h2 id="ip-주소">IP 주소</h2>
<p>IP 주소는 인터넷 프로토콜이 장치마다 부여하는 <strong><span style='background-color: #fff3b0'>고유한 식별 번호</span></strong>다. 브라우저가 서버에 요청을 보낼 때 요청에 출발지 IP가 들어 있어야 서버가 응답을 돌려보낼 곳을 안다. 도메인 이름을 IP로 바꿔 주는 것은 DNS가 한다.</p>
<p>IPv4는 <code>192.0.2.1</code>처럼 점으로 구분한 숫자 네 묶음이고 32비트라서 약 43억 개의 주소를 만들 수 있다. 기기가 늘면서 부족해져 128비트 형식의 IPv6가 나왔고, 지금은 두 버전이 함께 쓰인다. 할당 방식은 <strong><span style='background-color: #fff3b0'>동적 IP</span></strong>와 <strong><span style='background-color: #fff3b0'>고정 IP</span></strong>로 나뉜다. 대부분의 장치는 ISP가 공유 풀에서 임시로 나눠 주는 동적 IP를 쓴다. 그런데 직접 운영하는 웹 서버나 API 서버가 동적 IP를 쓰면 IP가 바뀔 때 DNS 질의가 실패해서 서비스가 사실상 내려갈 수도 있다. 그래서 서버에는 고정 주소가 필요하다.</p>
<h2 id="mac-주소와-ip-주소의-차이">MAC 주소와 IP 주소의 차이</h2>
<p>이더넷은 케이블 위에서 48비트 주소를 요구하는데 IP처럼 상위 프로토콜의 주소는 길이도 값도 이더넷 주소와 맞지 않는다. 그래서 둘을 연결하는 변환이 필요해진 것이다. 이더넷 프레임에는 목적지와 출발지 48비트 주소가 들어가고 이 주소는 고유하고 고정된 값이어야 하는 것으로 정해져 있다.</p>
<table>
<thead>
<tr>
<th>비교</th>
<th>IP 주소</th>
<th>MAC 주소</th>
</tr>
</thead>
<tbody><tr>
<td>길이</td>
<td>32비트(IPv4)</td>
<td>48비트</td>
</tr>
<tr>
<td>성격</td>
<td>할당/변경 가능(동적 할당이 흔함)</td>
<td>인터페이스에 고유하고 고정</td>
</tr>
<tr>
<td>쓰이는 범위</td>
<td>네트워크 사이를 넘어 전달</td>
<td>같은 네트워크(같은 케이블) 안에서 전달</td>
</tr>
<tr>
<td>계층</td>
<td>인터넷(L3)</td>
<td>링크(L2)</td>
</tr>
</tbody></table>
<p>정리하면 <strong><span style='background-color: #fff3b0'>IP는 네트워크를 넘어 목적지를 찾는 주소</span></strong>이고, <strong><span style='background-color: #fff3b0'>MAC은 같은 네트워크 안에서 다음 장치에 프레임을 넘기는 주소</span></strong>다.</p>
<h2 id="arp">ARP</h2>
<p>IP 주소는 알지만 MAC 주소를 모를 때 쓰는 것이 ARP(Address Resolution Protocol)다. <strong><span style='background-color: #fff3b0'>ARP는 IP 주소를 MAC 주소로 바꿔 주는 프로토콜</span></strong>이다. 같은 케이블 위의 두 장치 X와 Y가 통신하는 과정을 정리하면 이렇다.</p>
<table>
<thead>
<tr>
<th>단계</th>
<th>일어나는 일</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>X가 Y의 IP로 보내려는데 변환 표에 MAC 주소가 없으면, 보내려던 패킷은 일단 버리고(상위 계층이 다시 보낸다고 가정) ARP 요청을 만든다</td>
</tr>
<tr>
<td>2</td>
<td>요청에는 X 자신의 MAC/IP와 찾으려는 Y의 IP가 들어가고, 찾는 MAC 칸은 비워 둔다</td>
</tr>
<tr>
<td>3</td>
<td>요청은 같은 케이블의 모든 장치에게 브로드캐스트로 전달된다</td>
</tr>
<tr>
<td>4</td>
<td>자기 IP가 맞는 Y만 요청을 받아들이고, 자기 MAC을 채워 X에게 직접(브로드캐스트 아님) 응답한다</td>
</tr>
<tr>
<td>5</td>
<td>X는 응답으로 Y의 MAC을 변환 표에 기록하고, 이후 같은 목적지는 표를 보고 바로 보낸다</td>
</tr>
</tbody></table>
<p>통신은 보통 양방향이라고 보기 때문에 Y도 X의 요청을 받으면서 X의 MAC/IP를 표에 기록한다. 이렇게 필요할 때만 물어보는 방식이라 모든 장치가 주기적으로 주소를 방송할 때보다 트래픽이 적다. </p>
<h2 id="포트-번호">포트 번호</h2>
<p>IP가 장치를 찾았으면 그 장치 안에서 어느 프로그램에 데이터를 줄지는 <strong><span style='background-color: #fff3b0'>포트 번호</span></strong>가 정한다. 포트는 운영체제가 관리하는 가상의 접점이고 프로그램/서비스마다 연결된다. 메일과 웹 페이지가 같은 네트워크 연결로 들어와도 서로 다른 포트로 구분해서 처리한다. 하나의 웹 서버에서 HTTPS(443)와 SSH(22)가 동시에 동작할 수 있는 이유가 이것이다.</p>
<p>포트는 전송 계층(L4) 개념이다. TCP/UDP 헤더에 포트 번호를 적는 자리가 있고 IP 헤더에는 목적지 IP만 있고 포트 자리가 없다. 포트는 총 65,535개가 있고 많이 쓰는 것은 아래와 같다.</p>
<table>
<thead>
<tr>
<th>포트</th>
<th>프로토콜</th>
<th>용도</th>
</tr>
</thead>
<tbody><tr>
<td>21</td>
<td>FTP</td>
<td>파일 전송</td>
</tr>
<tr>
<td>22</td>
<td>SSH</td>
<td>원격 접속(보안 연결)</td>
</tr>
<tr>
<td>25</td>
<td>SMTP</td>
<td>메일 전송</td>
</tr>
<tr>
<td>53</td>
<td>DNS</td>
<td>도메인 이름을 IP로 변환</td>
</tr>
<tr>
<td>80</td>
<td>HTTP</td>
<td>웹</td>
</tr>
<tr>
<td>123</td>
<td>NTP</td>
<td>시간 동기화</td>
</tr>
<tr>
<td>443</td>
<td>HTTPS</td>
<td>암호화된 웹</td>
</tr>
<tr>
<td>3389</td>
<td>RDP</td>
<td>원격 데스크톱</td>
</tr>
</tbody></table>
<p>번호별 전체 목록은 IANA가 관리한다고 한다. 포트는 보안과도 직접 연결된다. 방화벽은 보통 모든 포트를 기본으로 막고, 25/80/443처럼 꼭 필요한 포트만 열어 둔다. </p>
<h2 id="한-번의-웹-접속에서-세-주소의-위치">한 번의 웹 접속에서 세 주소의 위치</h2>
<p>웹 접속 흐름에 대응시키면 전송 계층 헤더에는 서버 프로그램을 가리키는 목적지 포트(HTTPS는 443)가, 인터넷 계층 헤더에는 서버의 IP가, 링크 계층 헤더에는 같은 네트워크의 다음 장치 MAC이 들어간다. 이 중 IP와 포트는 목적지까지 그대로 유지되고, MAC은 구간마다 달라진다. </p>
<h2 id="핵심-복습">핵심 복습</h2>
<table>
<thead>
<tr>
<th>키워드</th>
<th>한 줄 정리</th>
</tr>
</thead>
<tbody><tr>
<td>IP 주소</td>
<td>네트워크 안의 장치를 가리키는 주소, IPv4는 32비트 네 묶음</td>
</tr>
<tr>
<td>동적/고정 IP</td>
<td>대부분 임시 할당, 서버는 고정이 필요</td>
</tr>
<tr>
<td>MAC 주소</td>
<td>같은 네트워크 안에서 인터페이스를 가리키는 48비트 주소</td>
</tr>
<tr>
<td>IP와 MAC의 차이</td>
<td>IP는 네트워크를 넘는 주소, MAC은 같은 네트워크 안의 주소</td>
</tr>
<tr>
<td>ARP</td>
<td>IP를 MAC으로 바꿔 줌, 요청은 브로드캐스트/응답은 직접 전달</td>
</tr>
<tr>
<td>다른 네트워크로 보낼 때</td>
<td>ARP가 찾는 것은 다음 홉(게이트웨이)의 MAC</td>
</tr>
<tr>
<td>포트 번호</td>
<td>장치 안의 프로그램을 가리키는 L4 번호, 총 65,535개</td>
</tr>
</tbody></table>
<h2 id="📍-참고-자료">📍 참고 자료</h2>
<p>확인일: 2026-10-02</p>
<ul>
<li><a href="https://www.cloudflare.com/learning/dns/glossary/what-is-my-ip-address/">Cloudflare Learning Center - What is my IP address?</a></li>
<li><a href="https://www.cloudflare.com/learning/network-layer/what-is-a-computer-port/">Cloudflare Learning Center - What is a computer port?</a></li>
<li><a href="https://www.rfc-editor.org/rfc/rfc826">RFC 826 - An Ethernet Address Resolution Protocol</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[OSI와 TCP/IP 모델]]></title>
            <link>https://velog.io/@jennie-infra/OSI%EC%99%80-TCPIP-%EB%AA%A8%EB%8D%B8</link>
            <guid>https://velog.io/@jennie-infra/OSI%EC%99%80-TCPIP-%EB%AA%A8%EB%8D%B8</guid>
            <pubDate>Sat, 03 Oct 2026 09:45:29 GMT</pubDate>
            <description><![CDATA[<h2 id="왜-모델이-두-개인가">왜 모델이 두 개인가</h2>
<p>통신은 계층으로 나누어 지는데 나누는 방식으로 가장 많이 언급되는 것이 OSI 7계층과 TCP/IP 4계층이다. <strong><span style='background-color: #fff3b0'>OSI</span></strong>는 ISO가 만든 개념 모델이고, <strong><span style='background-color: #fff3b0'>TCP/IP</span></strong>는 실제 인터넷이 쓰는 프로토콜 구조를 계층으로 정리한 모델이다. 현대 인터넷은 OSI를 엄격하게 따르지는 않고 더 단순한 인터넷 프로토콜 모음에 가깝다. 그래도 OSI는 문제가 어느 계층에서 생겼는지 좁혀 갈 때 유용해서 여전히 공용어처럼 쓰인다.</p>
<h2 id="osi-7계층">OSI 7계층</h2>
<table>
<thead>
<tr>
<th>계층</th>
<th>이름</th>
<th>하는 일</th>
<th>대표 예시</th>
<th>데이터 단위</th>
</tr>
</thead>
<tbody><tr>
<td>L7</td>
<td>응용</td>
<td>브라우저/메일 프로그램이 쓰는 프로토콜과 데이터 처리</td>
<td>HTTP/HTTPS, SMTP</td>
<td>데이터</td>
</tr>
<tr>
<td>L6</td>
<td>표현</td>
<td>인코딩 변환/암호화/압축</td>
<td>JSON/CSV 같은 데이터 형식</td>
<td>데이터</td>
</tr>
<tr>
<td>L5</td>
<td>세션</td>
<td>통신 세션의 시작/유지/종료</td>
<td>NFS/SMB</td>
<td>데이터</td>
</tr>
<tr>
<td>L4</td>
<td>전송</td>
<td>장치 끝과 끝 사이의 통신, 흐름/오류 제어</td>
<td>TCP/UDP</td>
<td>세그먼트</td>
</tr>
<tr>
<td>L3</td>
<td>네트워크</td>
<td>서로 다른 네트워크 사이의 전달과 경로 선택</td>
<td>IP/ICMP</td>
<td>패킷</td>
</tr>
<tr>
<td>L2</td>
<td>데이터 링크</td>
<td>같은 네트워크 안의 장치 간 전달</td>
<td>이더넷</td>
<td>프레임</td>
</tr>
<tr>
<td>L1</td>
<td>물리</td>
<td>케이블 같은 매체로 신호 전송</td>
<td>구리/광섬유 케이블</td>
<td>비트</td>
</tr>
</tbody></table>
<p>위에서부터 응용/표현/세션/전송/네트워크/데이터 링크/물리이다. 보내는 쪽은 L7에서 L1로 내려가며 계층마다 헤더를 붙이고 받는 쪽은 L1에서 L7로 올라가며 <strong><span style='background-color: #fff3b0'>헤더를 하나씩 벗긴다</span></strong>. 다만 OSI를 쓰는 모든 시스템이 7개 계층을 전부 구현하는 것은 아니다.</p>
<h2 id="tcpip-4계층">TCP/IP 4계층</h2>
<table>
<thead>
<tr>
<th>TCP/IP 계층</th>
<th>대응하는 OSI</th>
<th>대표 프로토콜</th>
<th>데이터 단위</th>
</tr>
</thead>
<tbody><tr>
<td>응용</td>
<td>응용 중심(표현/세션 기능 포함)</td>
<td>HTTPS, SMTP, FTP</td>
<td>데이터</td>
</tr>
<tr>
<td>전송</td>
<td>L4</td>
<td>TCP, UDP</td>
<td>세그먼트</td>
</tr>
<tr>
<td>인터넷</td>
<td>L3</td>
<td>IP, ICMP</td>
<td>패킷</td>
</tr>
<tr>
<td>링크(네트워크 접근)</td>
<td>L1/L2</td>
<td>이더넷, Wi-Fi</td>
<td>프레임</td>
</tr>
</tbody></table>
<p>AWS 영문 TCP/IP 문서는 TCP/IP의 일부 계층이 OSI의 여러 계층을 합친 것이라고 설명하고 특히 <strong><span style='background-color: #fff3b0'>링크 계층은 OSI의 데이터 링크와 물리 계층을 합친 것</span></strong>이라고 밝힌다. 응용 계층 쪽이 OSI의 어느 계층까지 합치는지는 문서마다 설명이 달라서 표현/세션 기능을 응용 계층에 포함해 본다고 생각했다. AWS 한국어 OSI 문서는 두 모델이 직접 일대일로 매핑되는 것은 아니고 TCP/IP가 실제 인터넷 구조에 더 가깝다고 말한다.</p>
<p>계층 수도 문서마다 다르게 나오는데 AWS 영문 TCP/IP 문서는 4계층으로 설명하는 반면, AWS 한국어 OSI 문서는 TCP/IP를 물리/데이터 링크/네트워크/전송/응용의 5계층으로 소개한다. 같은 모델을 아래쪽에서 어디까지 쪼개 보느냐의 차이라서 4계층을 기본으로 말하고 5계층 표기도 있다고 덧붙이면 될 것 같다.</p>
<h2 id="한-번의-웹-접속에서-계층은-어떻게-쓰이는가">한 번의 웹 접속에서 계층은 어떻게 쓰이는가</h2>
<p>노트북 브라우저에서 HTTPS 사이트에 접속하는 흐름으로 보면 이해가 쉽다. </p>
<table>
<thead>
<tr>
<th>계층</th>
<th>이 접속에서 하는 일</th>
<th>헤더에 들어가는 값</th>
</tr>
</thead>
<tbody><tr>
<td>응용</td>
<td>HTTP 요청을 만든다</td>
<td>요청 내용</td>
</tr>
<tr>
<td>전송</td>
<td>서버의 어느 프로그램인지 지정한다</td>
<td>출발/목적지 포트(HTTPS는 보통 443)</td>
</tr>
<tr>
<td>인터넷</td>
<td>서버를 지정한다</td>
<td>출발/목적지 IP 주소</td>
</tr>
<tr>
<td>링크</td>
<td>같은 네트워크의 다음 장치를 지정한다</td>
<td>출발/목적지 MAC 주소</td>
</tr>
</tbody></table>
<p>여기서 가장 헷갈리기 쉬운 것이 MAC 주소다. 서버가 다른 네트워크에 있으면 프레임의 목적지 MAC은 서버가 아니라 <strong><span style='background-color: #fff3b0'>같은 네트워크의 다음 장치(게이트웨이/라우터)</span></strong>가 된다. </p>
<p>데이터 단위 이름은 전송 계층이 데이터를 쪼갠 것이 세그먼트, 네트워크 계층이 세그먼트를 더 작게 나눈 것이 패킷, 데이터 링크 계층이 패킷을 쪼갠 것이 프레임이다.</p>
<h2 id="현업에서는-어떻게-쓰이는가">현업에서는 어떻게 쓰이는가</h2>
<p>계층 번호는 대화 속에서 위치를 가리키는 말로 자주 쓰인다. Cloudflare 문서는 DDoS 공격을 설명하면서 애플리케이션 계층(L7)을 노리는 공격과 3/4 계층을 노리는 프로토콜 계층 공격으로 나눠 부른다. 이처럼 어느 계층이 영향을 받는지에 따라 원인과 대응이 달라지기 때문에 계층 모델은 장애와 보안 이슈를 같은 말로 소통하는 도구라고 볼 수 있다.</p>
<h2 id="핵심-복습">핵심 복습</h2>
<table>
<thead>
<tr>
<th>키워드</th>
<th>한 줄 정리</th>
</tr>
</thead>
<tbody><tr>
<td>OSI 7계층</td>
<td>통신을 7단계로 나눈 개념 모델, 문제 위치를 말할 때 쓰는 공용어</td>
</tr>
<tr>
<td>TCP/IP 4계층</td>
<td>실제 인터넷 구조, 응용/전송/인터넷/링크</td>
</tr>
<tr>
<td>대응 관계</td>
<td>L4는 전송, L3는 인터넷, L1/L2는 링크, 위쪽은 응용</td>
</tr>
<tr>
<td>4계층 vs 5계층</td>
<td>하위 계층을 하나로 보면 4계층, 물리/데이터 링크로 쪼개면 5계층</td>
</tr>
<tr>
<td>데이터 단위</td>
<td>세그먼트(L4), 패킷(L3), 프레임(L2)</td>
</tr>
<tr>
<td>주소 사용</td>
<td>같은 네트워크는 MAC, 다른 네트워크는 IP + 다음 홉 라우터(뒤에서 확인)</td>
</tr>
</tbody></table>
<h2 id="📍-참고-자료">📍 참고 자료</h2>
<p>확인일: 2026-10-02</p>
<ul>
<li><a href="https://aws.amazon.com/ko/what-is/osi-model/">AWS - OSI 모델이란 무엇인가요?</a></li>
<li><a href="https://aws.amazon.com/what-is/tcp-ip/">AWS - What is TCP/IP?</a></li>
<li><a href="https://www.cloudflare.com/learning/ddos/glossary/open-systems-interconnection-model-osi/">Cloudflare Learning Center - What is the OSI Model?</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[네트워크와 프로토콜]]></title>
            <link>https://velog.io/@jennie-infra/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC%EC%99%80-%ED%94%84%EB%A1%9C%ED%86%A0%EC%BD%9C</link>
            <guid>https://velog.io/@jennie-infra/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC%EC%99%80-%ED%94%84%EB%A1%9C%ED%86%A0%EC%BD%9C</guid>
            <pubDate>Sat, 03 Oct 2026 09:41:17 GMT</pubDate>
            <description><![CDATA[<h2 id="네트워크란">네트워크란</h2>
<p>네트워크는 <strong><span style='background-color: #fff3b0'>노드와 링크로 이루어진 구조</span></strong>이고 만들려면 노드가 두 개 이상 필요하다. 노드는 컴퓨터/프린터 같은 단말이나 허브/스위치 같은 통신 장비이고 링크는 노드 사이를 잇는 전송 매체로 이더넷 케이블 같은 유선과 전파를 쓰는 무선이 있다. 노트북 브라우저가 웹 서버와 통신하는 것도, 본사와 지사가 통신하는 것도 같은 구조라고 이해할 수 있다.</p>
<p>규모에 따라 LAN과 WAN으로 나눠 부른다.</p>
<table>
<thead>
<tr>
<th>구분</th>
<th>연결 대상</th>
<th>연결 방식</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td>LAN</td>
<td>한 건물/캠퍼스처럼 물리적으로 가까운 장치</td>
<td>이더넷 케이블/무선 액세스 포인트, 스위치/라우터</td>
<td>사무실 안 파일 교환</td>
</tr>
<tr>
<td>WAN</td>
<td>멀리 떨어진 여러 LAN</td>
<td>임대 회선/MPLS/VPN/클라우드 연결</td>
<td>지사 간 통신, 클라우드 서비스 연결</td>
</tr>
</tbody></table>
<p>WAN은 <strong><span style='background-color: #fff3b0'>여러 LAN을 장거리로 연결한 네트워크</span></strong>다. WAN 연결은 공용 인터넷 위의 가상 연결인 경우가 많아서 LAN보다 지연이 길고 속도가 느린 편이라고 한다.</p>
<p>네트워크에서 데이터는 통째로 보내지 않는다. TCP가 데이터를 작은 <strong><span style='background-color: #fff3b0'>패킷</span></strong>으로 쪼개 보내고 도착지에서 다시 합치며 IP는 각 패킷이 올바른 목적지 주소로 가게 한다.</p>
<h2 id="프로토콜이란">프로토콜이란</h2>
<p>프로토콜은 <strong><span style='background-color: #fff3b0'>연결된 장치 사이의 데이터 전송을 관리하는 규칙 세트</span></strong>다. LAN/WAN 모두 프로토콜을 쓰고 가장 일반적인 것이 TCP/IP이며 UDP/ICMP 같은 프로토콜도 있다. 규칙에 무엇이 들어가는지는 TCP 연결 과정으로 보면 이해가 쉽다. </p>
<table>
<thead>
<tr>
<th>구성</th>
<th>TCP 연결에서의 예</th>
</tr>
</thead>
<tbody><tr>
<td>형식</td>
<td>헤더에 출발/목적지 포트, 체크섬, 시퀀스 번호 같은 필드를 정해진 자리에 넣는다</td>
</tr>
<tr>
<td>의미</td>
<td>ACK는 데이터를 잘 받았다는 표시이고, FIN은 연결을 끝내겠다는 표시다</td>
</tr>
<tr>
<td>순서</td>
<td>클라이언트가 SYN으로 요청하고, 서버가 응답하고, 클라이언트가 ACK로 확인한 뒤 데이터를 보낸다</td>
</tr>
</tbody></table>
<p>이 규칙 모음인 TCP/IP 프로토콜은 지금 IETF가 관리한다.</p>
<h2 id="프로토콜의-종류">프로토콜의 종류</h2>
<p>프로토콜은 하는 일을 기준으로 나눠서 보면 정리가 쉽다. </p>
<table>
<thead>
<tr>
<th>역할</th>
<th>대표 프로토콜</th>
<th>하는 일</th>
</tr>
</thead>
<tbody><tr>
<td>응용</td>
<td>HTTPS, SMTP, FTP</td>
<td>웹/메일/파일 전송 같은 서비스의 규칙</td>
</tr>
<tr>
<td>전송</td>
<td>TCP, UDP</td>
<td>컴퓨터 사이의 데이터 전달 방식</td>
</tr>
<tr>
<td>인터넷</td>
<td>IP, ICMP</td>
<td>IP는 주소로 패킷을 전달, ICMP는 통신 문제 진단</td>
</tr>
<tr>
<td>링크</td>
<td>이더넷, Wi-Fi</td>
<td>네트워크 카드/케이블/무선으로 실제 송수신</td>
</tr>
</tbody></table>
<p>전송 계층에서 자주 비교되는 두 프로토콜이 <strong><span style='background-color: #fff3b0'>TCP</span></strong>와 <strong><span style='background-color: #fff3b0'>UDP</span></strong>다. TCP는 연결을 맺고 체크섬/타이머/재전송으로 데이터가 빠짐없이 도착하게 하기 때문에 파일 공유처럼 손상이 없어야 하는 통신에 쓴다. UDP는 연결 과정 없이 보내서 빠르지만 순서를 추적하지 않아 신뢰성은 보장하지 않으므로 비디오 스트리밍처럼 일부 패킷이 유실돼도 덜 치명적인 곳에 쓴다.</p>
<h2 id="왜-계층으로-나누는가">왜 계층으로 나누는가</h2>
<p>계층별로 맡은 기능이 있고 상위 계층의 기술은 하위 계층의 구현 세부 사항을 몰라도 하위 기술을 쓸 수 있다고 한다. 각 계층은 독립적이고 위/아래 계층과 주고받는 인터페이스만 안다. 그래서 <strong><span style='background-color: #fff3b0'>한 계층을 바꿔도 다른 계층에 영향이 적다</span></strong>. 같은 HTTPS 통신이 유선 이더넷 위에서 돌든 Wi-Fi 위에서 돌든 응용 계층 쪽은 바꿀 것이 없다.</p>
<p>데이터가 내려갈 때는 각 계층이 자기 헤더를 덧붙이고, 받는 쪽은 올라가며 헤더를 벗긴다. 이 과정이 <strong><span style='background-color: #fff3b0'>캡슐화</span></strong>다.</p>
<table>
<thead>
<tr>
<th>단계</th>
<th>덧붙는 정보</th>
<th>데이터 단위</th>
</tr>
</thead>
<tbody><tr>
<td>응용</td>
<td>HTTPS/SMTP 같은 응용 프로토콜의 데이터</td>
<td>데이터</td>
</tr>
<tr>
<td>전송</td>
<td>TCP 헤더(출발/목적지 포트)</td>
<td>세그먼트</td>
</tr>
<tr>
<td>인터넷</td>
<td>IP 헤더(출발/목적지 IP 주소)</td>
<td>패킷</td>
</tr>
<tr>
<td>링크</td>
<td>링크 계층 헤더</td>
<td>프레임</td>
</tr>
</tbody></table>
<p>이 구조는 장애를 좁혀 갈 때도 쓸모가 있다. 예를 들어 웹 서버에서 DB(3306/TCP)에 접속이 안 되면 두 서버 사이에 IP로 도달이 되는지(인터넷 계층), 3306 포트가 열려 있는지(전송 계층), DB 프로세스가 응답하는지(응용 계층) 순서로 범위를 좁힐 수 있다.</p>
<h2 id="핵심-복습">핵심 복습</h2>
<table>
<thead>
<tr>
<th>키워드</th>
<th>한 줄 정리</th>
</tr>
</thead>
<tbody><tr>
<td>네트워크</td>
<td>노드를 링크로 연결해 데이터를 주고받는 구조</td>
</tr>
<tr>
<td>LAN/WAN</td>
<td>LAN은 가까운 장치끼리, WAN은 멀리 떨어진 LAN을 연결</td>
</tr>
<tr>
<td>패킷</td>
<td>데이터를 쪼갠 조각, 도착지에서 다시 합쳐진다</td>
</tr>
<tr>
<td>프로토콜</td>
<td>장치 사이 데이터 전송을 관리하는 규칙(형식/의미/순서)</td>
</tr>
<tr>
<td>TCP/UDP</td>
<td>빠짐없이 전달하는 연결형 vs 빠르지만 보장하지 않는 비연결형</td>
</tr>
<tr>
<td>계층화/캡슐화</td>
<td>계층별로 헤더를 덧붙여 내려가고, 받는 쪽은 벗겨 올라감</td>
</tr>
</tbody></table>
<h2 id="📍-참고-자료">📍 참고 자료</h2>
<p>확인일: 2026-10-02</p>
<ul>
<li><a href="https://aws.amazon.com/ko/compare/the-difference-between-lan-and-wan/">AWS - LAN과 WAN의 차이점은 무엇인가요?</a></li>
<li><a href="https://aws.amazon.com/what-is/tcp-ip/">AWS - What is TCP/IP?</a></li>
<li><a href="https://aws.amazon.com/ko/what-is/osi-model/">AWS - OSI 모델이란 무엇인가요?</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Amazon RDS]]></title>
            <link>https://velog.io/@jennie-infra/Amazon-RDS</link>
            <guid>https://velog.io/@jennie-infra/Amazon-RDS</guid>
            <pubDate>Thu, 01 Oct 2026 07:54:56 GMT</pubDate>
            <description><![CDATA[<h2 id="데이터베이스">데이터베이스</h2>
<p>데이터베이스는 데이터를 체계적으로 저장하고 필요할 때 검색/수정/삭제할 수 있도록 구조화해둔 데이터의 집합이다. 단순히 파일에 텍스트를 쌓아두는 것과 달리 데이터 간의 관계나 규칙을 정의해두고 일관된 방식으로 접근할 수 있게 만든 체계이다.</p>
<hr>
<h2 id="dbms">DBMS</h2>
<p>DBMS(Database Management System)는 데이터베이스를 생성/관리/운영하는 소프트웨어다. 사용자가 직접 파일을 다루는 대신 DBMS를 통해 데이터를 저장하고 질의(쿼리)하면 DBMS가 내부적으로 저장 구조/동시 접근 제어/백업 같은 걸 처리해준다. MySQL, PostgreSQL, Oracle, SQL Server 같은 관계형 DBMS(RDBMS)와 MongoDB, DynamoDB 같은 NoSQL DBMS로 크게 나뉜다.</p>
<hr>
<h2 id="rds">RDS</h2>
<p>RDS(Relational Database Service)는 AWS가 제공하는 <span style='background-color: #fff3b0'>완전관리형 관계형 데이터베이스 서비스</span>다. MySQL, PostgreSQL, MariaDB, Oracle, SQL Server, Amazon Aurora 중 원하는 엔진을 선택해서 쓸 수 있고 서버 프로비저닝/OS 패치/백업/장애 복구 같은 운영 작업을 AWS가 대신 처리해준다. 직접 EC2에 데이터베이스를 설치해서 운영하는 것과 비교하면 인프라 관리 부담 없이 데이터베이스 자체에만 집중할 수 있다는 차이가 있다.</p>
<hr>
<h2 id="rds-서비스-기능">RDS 서비스 기능</h2>
<ul>
<li>자동 백업: 설정한 보존 기간 동안 매일 자동으로 백업을 수행하고 특정 시점으로 복구(Point-in-Time Recovery)할 수 있다.</li>
<li>다중 AZ 배포: 기본 인스턴스와 별도로 다른 가용 영역에 대기 인스턴스를 동기 복제해두고, 장애 발생 시 자동으로 전환(Failover)한다.</li>
<li>읽기 전용 복제본(Read Replica): 읽기 트래픽을 분산하기 위해 복제본을 추가로 둘 수 있다. 쓰기는 기본 인스턴스에서만 처리하고 읽기는 복제본으로 분산하는 구조다.</li>
<li>자동 소프트웨어 패치: 데이터베이스 엔진의 보안 패치/마이너 버전 업데이트를 자동으로 적용한다.</li>
<li>모니터링: CloudWatch와 연동해서 CPU/메모리/스토리지/연결 수 같은 지표를 실시간으로 확인할 수 있다.</li>
<li>암호화: 저장 데이터와 전송 중 데이터를 암호화할 수 있다.</li>
</ul>
<hr>
<h2 id="rds-인스턴스-클래스">RDS 인스턴스 클래스</h2>
<p>RDS 인스턴스는 용도에 따라 몇 가지 계열로 나뉜다.</p>
<ul>
<li>범용(General Purpose, T/M 계열): 컴퓨팅/메모리/네트워크 자원이 균형 잡혀 있어 대부분의 워크로드에 적합하다.</li>
<li>메모리 최적화(Memory Optimized, R/X 계열): 메모리 대비 가격 효율이 높아서 대용량 데이터셋을 다루거나 메모리 집약적인 애플리케이션에 적합하다.</li>
<li>버스터블 성능(T 계열): 평소에는 기본 성능으로 돌다가 필요할 때 크레딧을 사용해서 순간적으로 성능을 끌어올리는 방식이다. 상시 고성능이 필요하지 않은 소규모 워크로드에 비용 효율적이다.</li>
</ul>
<p>인스턴스 클래스를 고를 때는 EC2와 마찬가지로 워크로드의 성격(상시 고부하인지, 간헐적인지)에 따라 계열을 먼저 정하고, 그 안에서 크기를 조정하는 방식으로 접근하면 된다.</p>
<hr>
<h2 id="rds-장단점">RDS 장단점</h2>
<p>장점</p>
<ul>
<li>서버 프로비저닝/패치/백업 같은 운영 부담이 줄어든다.</li>
<li>다중 AZ와 읽기 전용 복제본으로 가용성과 확장성을 비교적 쉽게 확보할 수 있다.</li>
<li>여러 데이터베이스 엔진 중 필요한 것을 선택할 수 있다.</li>
</ul>
<p>단점</p>
<ul>
<li>기본 운영체제나 데이터베이스 엔진 내부 설정에 대한 접근 권한이 제한적이라 세밀한 커스터마이징이 어렵다.</li>
<li>특정 확장 기능이나 플러그인은 지원되지 않을 수 있다.</li>
<li>직접 EC2에 설치하는 것보다 비용이 더 들 수 있다.</li>
</ul>
<hr>
<h2 id="rds-사용절차">RDS 사용절차</h2>
<p>RDS를 쓰는 기본 흐름은 이렇다.</p>
<pre><code>데이터베이스 엔진 선택 → 인스턴스 클래스/스토리지 설정 → 네트워크(VPC/서브넷 그룹)와 보안 그룹 구성 → 인스턴스 생성 → 엔드포인트로 애플리케이션에서 접속</code></pre><p>생성 시 다중 AZ 여부, 백업 보존 기간, 퍼블릭 접근 허용 여부도 함께 설정한다. 생성이 끝나면 RDS가 발급하는 엔드포인트(DNS 주소)로 애플리케이션에서 접속하면 되고, 이후 필요에 따라 읽기 전용 복제본을 추가하거나 인스턴스 크기를 조정할 수 있다.</p>
<hr>
<h2 id="키밸류-데이터베이스">키밸류 데이터베이스</h2>
<p>관계형 데이터베이스와 달리, 키와 값의 쌍으로 데이터를 저장하는 NoSQL 방식도 있다. AWS에서는 대표적으로 두 가지를 제공한다.</p>
<p>DynamoDB는 완전관리형 키밸류/문서 데이터베이스다. 스키마를 미리 엄격하게 정의하지 않아도 되고, 트래픽에 따라 자동으로 확장되며, 응답 속도가 한 자릿수 밀리초 단위로 빠른 게 특징이다. 세션 정보, 사용자 프로필, 게임 리더보드처럼 빠른 조회가 중요하고 데이터 구조가 유연해야 하는 경우에 적합하다.</p>
<p>ElastiCache는 완전관리형 인메모리 캐싱 서비스로, Redis나 Memcached 엔진을 지원한다. 데이터를 디스크가 아니라 메모리에 두기 때문에 조회 속도가 매우 빠르고, 보통 RDS나 DynamoDB 앞단에 캐시 레이어로 두어 자주 조회되는 데이터를 미리 담아두는 용도로 쓴다. 매번 데이터베이스까지 가지 않고 캐시에서 먼저 응답하게 해서 데이터베이스 부하를 줄이고 응답 속도를 높이는 구조다.</p>
<p>관계형 데이터베이스(RDS)가 데이터 간의 관계와 트랜잭션 일관성이 중요한 경우에 적합하다면, 키밸류 데이터베이스는 단순한 구조의 데이터를 빠르게 읽고 쓰는 데 최적화되어 있다는 차이가 있다.</p>
<hr>
<p>📍 참고 자료: AWS 공식 문서, 패스트캠퍼스 강의 &lt;실전 DevOps의 모든 것&gt;, 책 &lt;그림으로 이해하는 AWS 구조와 기술&gt;</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Amazon S3 총정리]]></title>
            <link>https://velog.io/@jennie-infra/Amazon-S3-%EC%B4%9D%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@jennie-infra/Amazon-S3-%EC%B4%9D%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Thu, 01 Oct 2026 07:44:36 GMT</pubDate>
            <description><![CDATA[<h2 id="s3란">S3란</h2>
<p>S3(Simple Storage Service)는 AWS가 제공하는 <span style='background-color: #fff3b0'>완전관리형 오브젝트 스토리지 서비스</span>다. 파일을 <strong>객체(Object) 단위로 저장하고, 그 객체들을 버킷(Bucket)이라는 컨테이너에 담아 관리</strong>한다. 디스크처럼 블록 단위로 쪼개서 쓰는 EBS나 폴더 구조로 여러 서버가 공유하는 EFS와 달리 S3는 파일 하나를 통째로 키(key)라는 이름에 매핑해서 저장하는 구조다.</p>
<hr>
<h2 id="특징">특징</h2>
<ul>
<li><strong>확장성</strong>: 저장 용량에 사실상 제한이 없다. 몇 개의 파일이든 몇 페타바이트든 별도로 용량을 미리 할당하거나 늘릴 필요 없이 그대로 저장된다.</li>
<li><strong>내구성</strong>: S3 Standard 기준으로 <span style='background-color: #fff3b0'>99.999999999%(11 9&#39;s)의 내구성</span>을 설계 목표로 한다. 객체를 여러 가용 영역(AZ)에 자동으로 복제해서 저장하기 때문에, 특정 AZ 하나가 통째로 사라져도 데이터가 보존되도록 설계되어 있다.</li>
<li><strong>가용성</strong>: 스토리지 클래스별로 다르지만 Standard 기준 99.99% 가용성을 목표로 한다. 내구성(데이터가 안 사라지는 것)과 가용성(원할 때 접근 가능한 것)은 별개의 지표라는 점이 헷갈리기 쉬운 부분이다.</li>
<li><strong>신뢰성(일관성)</strong>: 객체를 쓰면 바로 그다음 읽기 요청에서 최신 값이 보장되는 강한 읽기-후-쓰기 일관성(strong read-after-write consistency)을 제공한다. 과거에는 최종 일관성 모델이었지만 지금은 업데이트되어 이 부분을 신경 쓸 필요가 줄었다.</li>
<li><strong>관리 기능</strong>: 버저닝(같은 키에 여러 버전 보관), 수명주기 정책(일정 기간 후 다른 스토리지 클래스로 전환하거나 삭제), 복제(다른 버킷·리전으로 자동 복사) 등을 지원한다.</li>
</ul>
<hr>
<h2 id="서비스-기능-한눈에-보기">서비스 기능 한눈에 보기</h2>
<p>S3는 다음 기능들을 기본으로 제공한다.</p>
<ul>
<li><strong>스토리지 클래스</strong>: Standard(자주 접근), Standard-IA/One Zone-IA(가끔 접근), Glacier 계열(장기 보관/아카이브), Intelligent-Tiering(자동 전환) 등 접근 빈도에 따라 비용과 검색 속도가 다른 클래스를 선택할 수 있다.</li>
<li><strong>버저닝</strong>: 같은 객체를 덮어쓰거나 삭제해도 이전 버전이 남아서 복구할 수 있다. 실수로 덮어쓴 파일을 되돌릴 때 유용하다.</li>
<li><strong>수명주기 정책</strong>: 30일 지나면 Standard-IA로, 90일 지나면 Glacier로, 365일 지나면 삭제와 같은 규칙을 자동으로 적용한다.</li>
<li><strong>복제(Replication)</strong>: 같은 리전(SRR) 또는 다른 리전(CRR)의 버킷으로 객체를 자동 복사한다. 재해 복구나 지리적으로 가까운 곳에 데이터를 두고 싶을 때 쓴다.</li>
<li><strong>암호화</strong>: 저장 시 암호화(SSE-S3, SSE-KMS, SSE-C)를 기본적으로 지원한다.</li>
</ul>
<hr>
<h2 id="객체와-버킷">객체와 버킷</h2>
<ul>
<li><strong>버킷(Bucket)</strong>: 객체를 담는 최상위 컨테이너다. 버킷 이름은 전 세계적으로 유일해야 하고 리전을 지정해서 생성한다.</li>
<li><strong>객체(Object)</strong>: 실제 저장되는 파일 단위다. 객체는 키(파일 경로처럼 보이는 문자열), 값(실제 데이터), 메타데이터로 구성된다. S3는 폴더 구조가 실제로 존재하는 게 아니라, <code>images/2026/photo.jpg</code>처럼 키 이름 자체에 <code>/</code>가 포함된 것뿐이고 콘솔에서 폴더처럼 보여주는 것이다.</li>
</ul>
<hr>
<h2 id="버킷-정책-vs-사용자-정책">버킷 정책 vs 사용자 정책</h2>
<p>접근 권한을 거는 방법이 두 가지라 헷갈리기 쉽다.</p>
<ul>
<li><strong>버킷 정책(Bucket Policy)</strong>: 버킷에 직접 붙이는 리소스 기반 정책이다. 이 버킷에는 어떤 계정/사용자가 접근 가능한지를 버킷 쪽에서 정의한다. JSON으로 작성하고 퍼블릭 액세스 허용처럼 버킷 전체에 적용되는 규칙을 걸 때 쓴다.</li>
<li><strong>사용자 정책(IAM Policy)</strong>: IAM 사용자나 역할에 붙이는 자격 증명 기반 정책이다. 사용자가 어떤 버킷/객체에 접근 가능한지를 사용자 쪽에서 정의한다.</li>
</ul>
<p><span style='background-color: #fff3b0'>둘 다 허용해야 실제로 접근이 가능하다</span>는 점이 핵심이다. 버킷 정책이 허용해도 IAM 정책이 막고 있으면 접근이 안 되고, 반대도 마찬가지다. 저번에 IAM Role/액세스 키를 정리하면서 봤던 <strong>권한은 여러 레이어에서 동시에 평가된다</strong>는 개념이 S3에도 그대로 적용된다. 여기에 더해 버킷 단위로 퍼블릭 접근 자체를 원천 차단하는 퍼블릭 액세스 차단(Block Public Access) 설정도 있는데 이게 켜져 있으면 버킷 정책에서 퍼블릭을 허용해도 무시된다.</p>
<hr>
<h2 id="사용-절차">사용 절차</h2>
<p>S3를 쓰는 기본 흐름은 단순하다.</p>
<pre><code>버킷 생성(이름/리전 지정) → 객체 업로드 → 접근 권한 설정(버킷 정책/IAM 정책) → 애플리케이션/사용자가 접근</code></pre><p>버킷을 만들 때 퍼블릭 액세스 차단 여부, 버저닝 사용 여부, 암호화 방식을 함께 설정하고 이후 필요에 따라 수명주기 정책이나 복제 규칙을 추가하는 식으로 운영한다.</p>
<hr>
<h2 id="웹사이트-호스팅">웹사이트 호스팅</h2>
<p>S3는 정적 웹사이트 호스팅 기능을 내장하고 있다. 버킷에서 정적 웹사이트 호스팅을 활성화하고 인덱스 문서(<code>index.html</code>)와 오류 문서(<code>error.html</code>)를 지정하면, S3가 발급하는 웹사이트 엔드포인트로 HTML/CSS/JS 같은 정적 파일을 바로 서비스할 수 있다. HTML/이미지처럼 서버 사이드 처리가 필요 없는 정적 콘텐츠에 적합하고 서버를 띄울 필요가 없어서 비용이 저렴하다.</p>
<p>다만 이 방식은 HTTPS를 직접 지원하지 않고 접근 속도도 버킷이 있는 리전 하나에 고정된다는 한계가 있다. 그래서 실무에서는 S3를 정적 호스팅 origin으로 두고 앞단에 CloudFront를 붙이는 구성이 일반적이다(아래에서 다시 다룸).</p>
<hr>
<h2 id="다양한-파일-업로드-방법">다양한 파일 업로드 방법</h2>
<ul>
<li><strong>콘솔</strong>: AWS 웹 콘솔에서 드래그 앤 드롭으로 업로드. 소량의 파일을 수동으로 올릴 때 적합하다.</li>
<li><strong>AWS CLI</strong>: <code>aws s3 cp</code> 또는 <code>aws s3 sync</code> 명령으로 업로드/동기화한다. 스크립트에 넣어 자동화하기 좋다.</li>
<li><strong>SDK</strong>: Python(boto3), Node.js 등 각 언어의 SDK를 통해 애플리케이션 코드 안에서 업로드한다.</li>
<li><strong>멀티파트 업로드(Multipart Upload)</strong>: 큰 파일(보통 100MB 이상 권장, 5GB 이상은 필수)을 여러 조각으로 나눠 병렬로 업로드한 뒤 합치는 방식이다. 네트워크가 끊겨도 실패한 조각만 다시 올리면 되고 전체 업로드 속도도 빨라진다.</li>
<li><strong>Presigned URL</strong>: S3 자격 증명이 없는 클라이언트(예: 사용자의 브라우저)에게 제한된 시간 동안만 유효한 업로드/다운로드 URL을 발급해주는 방식이다. 서버를 거치지 않고 클라이언트가 직접 S3에 업로드할 수 있어서 파일 업로드가 많은 웹 서비스에서 서버 부하를 줄이는 데 쓰인다.</li>
<li><strong>Transfer Acceleration</strong>: CloudFront의 엣지 로케이션을 거쳐 S3로 더 빠르게 전송하는 기능이다. 사용자와 버킷 리전이 지리적으로 먼 경우에 효과가 크다.</li>
</ul>
<hr>
<h2 id="부정한-액세스-감지">부정한 액세스 감지</h2>
<p>S3에 대한 비정상적인 접근을 감지하는 방법도 여러 겹으로 구성할 수 있다.</p>
<ul>
<li><strong>서버 액세스 로깅</strong>: 버킷에 대한 모든 요청(누가, 언제, 어떤 객체에 접근했는지)을 로그 파일로 남겨 다른 버킷에 저장한다.</li>
<li><strong>CloudTrail 데이터 이벤트</strong>: 저번에 정리했던 CloudTrail을 S3의 객체 단위 작업(GetObject, PutObject 등)까지 기록하도록 설정하면 어떤 객체에 누가 접근했는지 API 호출 단위로 추적할 수 있다.</li>
<li><strong>GuardDuty S3 Protection</strong>: CloudTrail 데이터 이벤트를 분석해서 비정상적인 접근 패턴(예: 평소와 다른 위치에서의 대량 다운로드)을 탐지하고 자동으로 경고한다.</li>
<li><strong>IAM Access Analyzer</strong>: 버킷이 의도치 않게 조직 외부나 퍼블릭에 노출되어 있는지 분석해서 알려준다. 설정 실수로 버킷이 퍼블릭으로 열려 있는 경우를 사전에 잡아내는 데 유용하다.</li>
<li><strong>Macie</strong>: 버킷 안의 객체를 스캔해서 주민등록번호, 카드번호 같은 민감 정보가 포함된 파일이 있는지, 그 파일이 퍼블릭하게 노출돼 있는지를 탐지한다.</li>
</ul>
<p><span style='background-color: #fff3b0'>로깅(기록)과 탐지(분석/경고)가 분리되어 있다는 점</span>이 저번에 CloudTrail/EventBridge를 정리할 때 봤던 구조와 비슷하다. 서버 액세스 로깅,CloudTrail이 기록을 남기면 GuardDuty/Access Analyzer/Macie가 그 기록을 분석해서 문제를 찾아내는 역할을 나눠 맡는다.</p>
<hr>
<h2 id="cloudfront와의-조합">CloudFront와의 조합</h2>
<p>저번에 CloudFront를 정리할 때 S3가 오리진으로 등장했는데 이 조합을 쓰는 이유를 다시 정리하면 이렇다.</p>
<pre><code>사용자 ──▶ CloudFront(엣지 캐싱) ──(캐시 없을 때만)──▶ S3 버킷(오리진)</code></pre><p>S3를 바로 공개하는 대신 CloudFront를 앞에 두면 첫째로 전 세계 엣지 로케이션에서 캐싱되어 지연 시간이 줄고 둘째로 CloudFront가 HTTPS를 지원해서 S3 정적 호스팅의 한계(HTTPS 미지원)를 보완할 수 있다. 셋째로 보안 측면에서 <span style='background-color: #fff3b0'>Origin Access Control(OAC)을 설정하면 S3 버킷 자체는 퍼블릭으로 열어두지 않고 CloudFront를 통한 요청만 허용</span>하도록 제한할 수 있다. 즉 버킷을 완전히 비공개로 유지하면서도 CloudFront를 통해서만 콘텐츠를 서비스하는 구조가 가능해진다.</p>
<hr>
<p>📍 참고 자료: AWS 공식 문서, 패스트캠퍼스 강의 &lt;실전 DevOps의 모든 것&gt;, 책 &lt;그림으로 이해하는 AWS 구조와 기술&gt;</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Claude Code와 Claude.ai 활용법]]></title>
            <link>https://velog.io/@jennie-infra/Claude-Code%EC%99%80-Claude.ai-%ED%99%9C%EC%9A%A9%EB%B2%95</link>
            <guid>https://velog.io/@jennie-infra/Claude-Code%EC%99%80-Claude.ai-%ED%99%9C%EC%9A%A9%EB%B2%95</guid>
            <pubDate>Wed, 30 Sep 2026 09:39:09 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>요즘 매일 블로그 정리를 Claude Code/Claude와 같이 하다 보니 정작 이 도구들을 상황에 맞게 제대로 쓰고 있는지 궁금해졌다. Claude 아카데미 교육 자료를 보면서 기능별로 상황에 맞는 사용법을 정리해봤다. 개발 쪽(Claude Code)과 일반 업무 쪽(Claude.ai)을 나눠서 실제로 뭘 하려고 할 때 어떤 기능을 꺼내야 하는지 위주로 적는다.</p>
</blockquote>
<h2 id="claude-code-설치부터-첫-대화까지">Claude Code 설치부터 첫 대화까지</h2>
<p>Claude Code는 터미널, IDE(VS Code/JetBrains), 데스크톱 앱, 웹(claude.ai/code) 중 어디서든 쓸 수 있다. <span style='background-color: #fff3b0'>새 기능은 항상 터미널에 가장 먼저 나오기 때문에, 최신 상태를 유지하고 싶으면 터미널이 제일 유리</span>하고, 평소 쓰던 에디터에 붙여서 쓰고 싶으면 IDE 통합, 다른 작업을 하면서 백그라운드로 돌리고 싶으면 데스크톱, GitHub 저장소를 원격으로 다루거나 여러 세션을 동시에 돌리고 싶으면 웹이 낫다.</p>
<p>프롬프트를 입력할 때는 파일 변경을 자동으로 승인할지(Auto Accept), 매번 확인받을지를 Shift+Tab으로 전환할 수 있다. 이 메뉴 안에 Plan Mode도 있는데, <strong>이건 파일을 읽기만 하고 편집은 하지 않은 채로 구현 방법을 조사해서 계획만 돌려준다</strong>. 복잡한 기능을 구현하거나 안전하게 코드 리뷰를 하고 싶을 때 특히 유용하다.</p>
<h2 id="탐색-→-계획-→-코드-작성-→-커밋">탐색 → 계획 → 코드 작성 → 커밋</h2>
<p>Claude Code에서 딱 하나만 기억해야 한다면 이 흐름이다.</p>
<pre><code>탐색(코드베이스 파악) → 계획(Plan Mode로 실행 계획 수립) → 코드 작성(승인 후 구현) → 커밋(리뷰 후 푸시)</code></pre><p>이 순서를 생략하고 곧바로 코드를 짜는 것부터 시작하면 나중에 수정할 일이 더 많아진다는 게 요지다. Plan Mode에서는 아직 코드가 하나도 작성되지 않은 상태라 방향을 수정하기 가장 좋은 시점이고 계획이 만족스러우면 승인해서 실제 구현으로 넘어가면 된다. 커밋 전에는 서브에이전트로 코드 리뷰를 한 번 돌리고 Claude에게 커밋 메시지까지 맡기는 흐름을 권장하고 있었다.</p>
<h2 id="컨텍스트는-유한한-작업-메모리다">컨텍스트는 유한한 작업 메모리다</h2>
<p>Claude가 읽는 파일, 실행하는 명령, 주고받는 메시지가 전부 컨텍스트 윈도우를 채운다. 한도에 가까워지면 자동으로 압축(compaction)되는데 이 과정에서 예전 대화의 세부 사항이 날아갈 수 있다. </p>
<ul>
<li><strong>같은 기능을 계속 작업 중인데 컨텍스트가 부족할 때</strong> → <code>/compact</code>로 수동 압축(맥락은 유지한 채 공간만 확보)</li>
<li><strong>완전히 새 기능을 시작할 때</strong> → <code>/clear</code>로 이전 대화 기억을 완전히 비움(이전 작업이 새 작업에 편향을 주지 않도록)</li>
<li><strong>다른 세션에서도 계속 기억해야 할 내용</strong> → CLAUDE.md에 저장</li>
</ul>
<p>또 프롬프트를 짧게 쓰는 게 오히려 장기적으로 더 많은 컨텍스트를 잡아먹는다. 지시가 불명확하면 Claude가 코드베이스를 더 많이 뒤지면서 스스로 알아내야 하기 때문이다. <span style='background-color: #fff3b0'>안 쓰는 MCP 서버는 꺼두고 반복되는 절차는 스킬로 옮기는 것도 컨텍스트를 아끼는 방법</span>이라는 점도 눈에 띄었다.</p>
<h2 id="claudemd--프로젝트의-온보딩-스크립트">CLAUDE.md — 프로젝트의 온보딩 스크립트</h2>
<p>CLAUDE.md 파일이 없으면 Claude Code는 세션을 열 때마다 코드베이스를 처음부터 다시 탐색해야 한다. <strong>CLAUDE.md는 프로젝트 루트에 두는 마크다운 파일로 세션 시작 시 자동으로 읽힌다</strong>. <code>/init</code> 명령으로 코드베이스 기반 초안을 만들 수 있고 여기에 명령어/코드 스타일/디렉터리 구조 같은 걸 적어두면 매번 같은 설명을 반복할 필요가 없다.</p>
<p>계층 구조도 있는데 프로젝트 루트의 CLAUDE.md는 팀 전체가 공유하고 설정 폴더의 사용자 수준 CLAUDE.md는 나만을 위한 개인 선호(코드 주석 스타일 등)를 담는다. 실전 팁으로는 처음엔 CLAUDE.md 없이 시작해서 Claude를 계속 고쳐야 하는 지점이 어딘지 확인한 다음 그 부분만 채워 넣으라는 조언이 있었다 — (파일을 간결하게 유지하기 위해서)</p>
<h2 id="컨텍스트-윈도우를-나누는-서브에이전트">컨텍스트 윈도우를 나누는 서브에이전트</h2>
<p>서브에이전트는 각자 독립된 컨텍스트 윈도우를 가지고 작업한 뒤 메인 스레드에는 요약만 돌려준다. <span style='background-color: #fff3b0'>과정은 필요 없고 결과만 필요한 조사 작업</span>에 특히 유용하다. 서브에이전트 없이 직접 하면 15개 파일을 읽고 여러 번 검색해야 할 일도 서브에이전트에게 맡기면 메인 컨텍스트는 깨끗하게 유지한 채 답만 받을 수 있다. 대신 <strong>서브에이전트가 어떻게 그 결론에 도달했는지에 대한 가시성은 잃는다</strong>는 트레이드오프가 있다.</p>
<h2 id="스킬--반복-설명을-없애는-방법">스킬 — 반복 설명을 없애는 방법</h2>
<p>같은 코딩 표준, 같은 PR 리뷰 형식, 같은 커밋 메시지 스타일을 매번 설명하고 있다면 스킬로 만들 차례다. 스킬은 SKILL.md 하나로 구성되고 필요해지기 전까지는 이름과 설명만 컨텍스트에 로드되기 때문에 컨텍스트 비용이 거의 들지 않는다. 개인 스킬(<code>~/.claude/skills</code>)은 모든 프로젝트를 따라다니고 프로젝트 스킬(저장소 안 <code>.claude/skills</code>)은 그 저장소를 쓰는 모두가 자동으로 받는다.</p>
<p>CLAUDE.md와 차이는 <strong>CLAUDE.md는 모든 대화에 항상 로드되는 반면 스킬은 요청과 일치할 때만 필요에 따라 로드된다는 점</strong>이다. 디버깅 중에는 PR 리뷰 체크리스트가 컨텍스트에 있을 필요가 없는데 스킬이면 실제로 리뷰를 요청할 때만 로드된다.</p>
<h2 id="mcp--외부-도구데이터에-연결하기">MCP — 외부 도구/데이터에 연결하기</h2>
<p>MCP(Model Context Protocol)는 Claude Code를 데이터베이스나 프로젝트 관리 툴 같은 외부 소스에 연결하는 개방형 표준이다. <code>claude mcp add</code>로 추가하고, <code>/mcp</code>로 연결 상태를 확인·관리한다. 범위는 local(나 혼자, 현재 프로젝트만) / user(나, 모든 프로젝트) / project(팀 전체, <code>.mcp.json</code>으로 버전 관리) 세 가지로 나뉜다.</p>
<p>주의할 점은 <span style='background-color: #fff3b0'>MCP 서버는 쓰지 않을 때도 도구 정의 자체가 컨텍스트 윈도우를 차지</span>한다는 것이다. 그래서 적극적으로 안 쓰는 서버는 비활성화하는 게 좋고 GitHub의 <code>gh</code>처럼 CLI가 있는 도구는 CLI를 쓰는 게 컨텍스트 면에서 더 효율적이라고 한다.</p>
<h2 id="hooks--규칙을-가끔이-아니라-항상으로">Hooks — 규칙을 가끔이 아니라 항상으로</h2>
<p>CLAUDE.md에 적어두면 대부분은 지켜지지만 가끔 빠뜨릴 수 있다. Hooks는 이 차이를 없앤다 — 조건에 맞으면 예외 없이 매번 실행된다. 상황별로 쓰는 이벤트가 다르다.</p>
<ul>
<li><strong>파일 편집 후 자동 포맷팅/린트</strong> → PostToolUse</li>
<li><strong>위험한 작업(main 브랜치 커밋, 프로덕션 설정 수정 등) 차단</strong> → PreToolUse (종료 코드 2로 차단, 0은 통과)</li>
<li><strong>Claude가 끝냈다고 판단해도 조건이 안 맞으면 계속 시키기</strong> → Stop</li>
<li><strong>압축 후에도 작업 맥락을 잃지 않게 하기</strong> → SessionStart(compact 매처)</li>
</ul>
<p>PreToolUse는 단순히 막는 것 외에도 <code>updatedInput</code>으로 호출 자체를 다시 써서 넘길 수도 있다. 예를 들어 명령어에 포함된 비밀 키를 자리표시자로 바꿔치기하면서도 명령은 그대로 실행되게 만드는 식이다. 차단이 아니라 안전하게 걸러서 통과시키는 방식이다.</p>
<h2 id="코드-리뷰는-diff부터">코드 리뷰는 diff부터</h2>
<p>Claude가 만든 요약만 믿지 말고 실제 diff를 직접 읽는 게 첫 번째 원칙이었다. <code>/code-review</code>로 깨끗한 컨텍스트에서 두 번째 의견을 구하고 각 발견 사항은 지금 수정 / 이유 묻기 / 그대로 두기 중 하나로 처리한다. <span style='background-color: #fff3b0'>같은 문제가 계속 지적된다면 그걸 CLAUDE.md에 규칙으로 적어두는 게 다음 세션부터 반복을 줄이는 방법</span>이라는 조언도 있었다.</p>
<p>감독 없이 돌아가는 실행(auto 모드, 무인 파이프라인)일수록 검증은 더 엄격해야 한다는 게 핵심이다: diff를 직접 읽고 테스트를 부탁이 아니라 stop hook 같은 게이트로 만들고, 새 세션에서 아무 배경지식 없는 상태로 다시 검토(두 번째 의견)를 받는 식이다.</p>
<h2 id="자동화-어디까지-올릴까">자동화, 어디까지 올릴까</h2>
<p>반복 작업을 자동화하려 할 때 선택지가 네 가지 있는데 필요한 통제 수준에 따라 고르면 된다.</p>
<pre><code>루틴(클라우드 저장 프롬프트) → 헤드리스 모드(-p, 내 파이프라인 필요) → --bare(CI용 결정론적 실행) → Agent SDK(내 제품 안에 내장)</code></pre><ul>
<li><strong>매일 아침 의존성 감사, PR 들어올 때 자동 분류처럼 반복되는 트리거 + 같은 프롬프트</strong> → 루틴. 인프라도 Anthropic 것이라 내가 유지보수할 서버가 없음.</li>
<li><strong>내 파이프라인에서 스크립트로 결과를 가공해야 할 때</strong> → 헤드리스 모드(<code>-p</code>). 다만 이 모드는 훅/스킬/MCP/CLAUDE.md를 자동으로 안 읽으니 내가 명시적으로 허용한 것만 쓰임.</li>
<li><strong>CI에서 실행마다 똑같은 결과가 보장돼야 할 때</strong> → --bare</li>
<li><strong>내 제품 자체에 Claude Code를 내장해야 할 때</strong> → Agent SDK</li>
</ul>
<h2 id="pr-리뷰-관리형-vs-직접">PR 리뷰, 관리형 VS 직접</h2>
<ul>
<li><strong>PR이 열릴 때마다 자동으로 인라인 코멘트만 받고 싶다</strong> → Code Review (Claude GitHub 앱, Anthropic 호스팅). PR을 승인/차단하지는 않고 발견 사항만 게시한다. 로컬에서 <code>/code-review --fix</code>로 적용은 내가 한다.</li>
<li><strong>리뷰를 넘어서 댓글에서 바로 구현까지 하거나 예약 보고서를 돌리고 싶다</strong> → GitHub Action (<code>anthropics/claude-code-action@v1</code>). <code>/install-github-app</code>으로 설정하고, <code>claude_args</code>에서 <code>--max-turns</code> 같은 세부 조정을 한다.</li>
</ul>
<h2 id="플러그인--세팅을-패키징해서-공유하기">플러그인 — 세팅을 패키징해서 공유하기</h2>
<p>잘 만든 <code>.claude</code> 디렉터리(스킬, 서브에이전트, 훅, MCP 설정)를 팀원들에게 일일이 복사해서 붙여넣게 하는 대신 플러그인으로 묶어서 배포할 수 있다. <code>/plugin marketplace add</code>로 팀 마켓플레이스를 추가해두면 이후 설치가 그곳을 통해 해결된다.</p>
<p><span style='background-color: #fff3b0'>여기서 제일 신경 써야 할 부분은 <strong>설치 전에 먼저 읽어야 한다</strong>는 것</span>이었다. 플러그인은 내 권한으로 내 기기에서 코드를 실행하고 훅은 일치하는 모든 도구 호출에서 실행된다. 스킬 때문에 설치했더라도 그 플러그인의 PreToolUse나 Stop 훅까지 같이 딸려온다는 뜻으로  Anthropic이 서드파티 플러그인 내부를 다 통제하지는 않기 때문에 신뢰할 수 있는 출처인지 확인하고 실제로 뭘 하는 플러그인인지 살펴본 뒤 설치하는 게 맞다.</p>
<hr>
<h2 id="claudeai--데스크톱에서의-세-가지-작업-형태">Claude.ai — 데스크톱에서의 세 가지 작업 형태</h2>
<p>Claude Code가 개발자를 위한 것이라면 Claude.ai 쪽은 일반 업무를 세 가지 형태로 나눠서 본다.</p>
<ul>
<li><strong>Chat — 주고받으며 작업하기</strong>: 질문 하나, 브레인스토밍, 초안 편집처럼 매 턴의 판단이 핵심이고 결과물이 한 번에 안 나오는 경우. 즉흥적인 질문에 적합하다.</li>
<li><strong>Cowork — 작업 맡기기</strong>: 완성된 결과물, 여러 도구에 걸친 작업, 일정에 따라 반복 실행되는 작업. 로컬 폴더 접근, 예약 작업, 서브에이전트, 브라우저/컴퓨터 사용까지 지원한다.</li>
<li><strong>Code 탭 — 소프트웨어 구축</strong>: 코드베이스에서 직접 읽고 쓰고 테스트하는, 사실상 Claude Code를 데스크톱 안에서 쓰는 것과 같다.</li>
</ul>
<p><span style='background-color: #fff3b0'>지금 하려는 일의 성격을 먼저 파악하면 탭은 자연스럽게 정해진다</span>. </p>
<h2 id="프로젝트--지식을-저장하는-곳">프로젝트 — 지식을 저장하는 곳</h2>
<p>프로젝트는 관련 문서를 업로드해두고 프로젝트 지침을 설정해서 그 프로젝트 안의 모든 대화에 일관되게 적용되도록 하는 공간이다. 권한은 볼 수 있음/편집할 수 있음/생성자 세 단계로 나뉘고 정보가 많아지면 자동으로 RAG 모드로 전환돼서 컨텍스트 한도를 넘지 않도록 처리된다.</p>
<h2 id="아티팩트--결과물이-머무는-곳">아티팩트 — 결과물이 머무는 곳</h2>
<p>아티팩트는 문서/프레젠테이션/디자인/대시보드처럼 <strong>한 번 읽고 끝나는 게 아니라 계속 편집하거나 공유하고 싶은 것</strong>을 만들 때 쓴다. 유료 플랜에서는 대화와 별개로 아티팩트 탭에 저장되어서 나중에 다시 열어 편집할 수 있다. 다운로드 파일 생성(.docx, .xlsx, .pptx)과는 다른데 아티팩트는 Claude 안에서 바로 열리고 업데이트되며 링크로 공유되는 반면 파일 생성은 다운로드해서 다른 앱에서 여는 용도다. 준비가 되면 아티팩트도 내보내기를 통해 파일로 전환할 수 있다.</p>
<h2 id="스킬과-프로젝트-뭐가-다른지">스킬과 프로젝트, 뭐가 다른지</h2>
<p><span style='background-color: #fff3b0'>프로젝트는 지식(무엇을)을 저장하고, 스킬은 프로세스(어떻게)를 저장한다.</span> 프로젝트는 참고 자료/회의록/리서치 문서를 담아두는 지식 허브고 스킬은 반복 가능한 워크플로우를 인코딩한다. 둘은 서로 참조할 수도 있다.</p>
<h2 id="커넥터--실제-데이터에-접근하기">커넥터 — 실제 데이터에 접근하기</h2>
<p>커넥터는 Google Drive, Slack, Notion 같은 서비스에 Claude를 연결해서 실제 정보를 읽고(권한에 따라) 작업까지 하게 해준다. 웹 커넥터(클라우드 서비스)와 데스크톱 확장 프로그램(로컬 파일/네이티브 앱)으로 나뉘고 <code>claude.ai/directory</code>에서 찾아 연결할 수 있다. <span style='background-color: #fff3b0'>중요한 원칙은 Claude는 내가 보는 것만 본다</span>는 것 — 업무 이메일을 연결해도 내 받은 편지함만 접근 가능하고 남의 것은 볼 수 없다.</p>
<h2 id="enterprise-search--리서치-언제-쓸까">Enterprise Search / 리서치, 언제 쓸까</h2>
<ul>
<li><strong>회사 내부 정책, 지난주 회의 결정, 사내 문서/Slack/이메일을 통합해서 찾아야 할 때</strong> → Enterprise Search</li>
<li><strong>경쟁사 비교, 시장 분석처럼 여러 출처를 종합한 포괄적 보고서가 필요할 때</strong> → 리서치(웹 검색 활성화 필요, 몇 분 이상 소요)</li>
<li><strong>오늘 주가처럼 빠르고 구체적인 사실 하나만 필요할 때</strong> → 그냥 웹 검색</li>
<li><strong>외부 정보 없이 수학/디버깅/논리적 분석 같은 깊은 추론이 필요할 때</strong> → 확장 사고</li>
</ul>
<hr>
<p>📍 참고 자료: Anthropic Claude 아카데미의 「Claude Code 101」, 「Claude Code 실전 활용」, 「Claude.ai 101」 교육 자료를 참고해 정리함</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SNS 팬아웃 구조와 DLQ]]></title>
            <link>https://velog.io/@jennie-infra/SNS-%ED%8C%AC%EC%95%84%EC%9B%83-%EA%B5%AC%EC%A1%B0%EC%99%80-DLQ</link>
            <guid>https://velog.io/@jennie-infra/SNS-%ED%8C%AC%EC%95%84%EC%9B%83-%EA%B5%AC%EC%A1%B0%EC%99%80-DLQ</guid>
            <pubDate>Tue, 29 Sep 2026 01:43:48 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>SNS를 정리하면서 하나의 메시지를 여러 구독자에게 동시에 전달하는 팬아웃(fan-out) 구조를 다뤘는데 구독자가 여러 개로 늘어났을 때 그중 하나가 계속 메시지를 받지 못하는 상황은 어떻게 처리되는지는 짚지 않았다. 이번 글에서는 SNS 구독자 중 일부가 실패했을 때 발생하는 문제와 DLQ(Dead Letter Queue)가 왜 필요한지 정리한다.</p>
</blockquote>
<h2 id="sns는-구독자마다-독립적으로-메시지를-전달한다">SNS는 구독자마다 독립적으로 메시지를 전달한다</h2>
<p>SNS는 하나의 주제(Topic)에 메시지를 발행하면 그 주제를 구독하고 있는 모든 엔드포인트(Lambda, SQS, 이메일 등)로 각각 전달한다. 이때 구독자 각각에 대한 전달은 서로 독립적으로 이루어진다. 즉 구독자 A에게 전달이 실패했다고 해서 구독자 B, C로의 전달이 함께 실패하는 것은 아니다.</p>
<pre><code>Publisher ──▶ SNS Topic ──▶ 구독자 A (성공)
                        ├─▶ 구독자 B (실패 → 재시도)
                        └─▶ 구독자 C (성공)</code></pre><h2 id="실패한-구독자는-어떻게-되는가">실패한 구독자는 어떻게 되는가</h2>
<p>전달에 실패한 구독자에 대해서는 SNS가 일정 정책에 따라 재시도를 수행한다. 하지만 재시도 횟수에는 한계가 있고, 그 한계를 넘어서도 계속 실패하는 경우 해당 메시지는 결국 폐기될 수 있다. 예를 들어 구독하고 있는 Lambda 함수에 일시적인 오류가 있거나 처리량 한도를 초과해 지속적으로 실패를 반환하는 상황이라면 그 메시지는 재시도가 끝난 뒤 아무 기록 없이 사라질 수 있다는 뜻이다.</p>
<p>저번에 정리했던 CloudWatch → SNS → Lambda → Slack 흐름을 생각해보면 만약 Slack 웹훅 호출을 담당하는 Lambda 함수가 일시적으로 오류를 내고 있었다면 그 사이에 발생한 알림 메시지들이 재시도 끝에 조용히 유실될 수 있었다는 것이 된다. 알림이 오지 않았다는 사실 자체도 알아차리기 어려운 상황이 되는 것이다.</p>
<h2 id="dlq가-필요한-이유">DLQ가 필요한 이유</h2>
<p>이런 메시지 유실을 막기 위해 사용하는 것이 DLQ(Dead Letter Queue)다. 재시도가 모두 실패한 메시지를 그냥 폐기하는 대신에 별도로 지정한 큐(DLQ)로 보내서 보관하는 방식이다.</p>
<pre><code>SNS ──▶ 구독자(Lambda) ──재시도 모두 실패──▶ DLQ(SQS 큐)에 보관
                                              └─▶ 이후 별도 확인·재처리 가능</code></pre><p>DLQ에 쌓인 메시지를 통해 어떤 메시지가, 언제, 왜 전달에 실패했는지 사후에 확인할 수 있고 필요하다면 원인을 해결한 뒤 재처리할 수도 있다. 즉 DLQ는 실패를 막아주는 장치가 아니라 <span style='background-color: #fff3b0'>실패했다는 사실 자체를 조용히 사라지지 않게 남겨두는 장치</span>에 가깝다.</p>
<h2 id="정리">정리</h2>
<p>SNS의 팬아웃 구조는 구독자마다 독립적으로 전달이 이루어지기 때문에 특정 구독자 하나의 장애가 전체 알림 흐름을 막지는 않는다. 다만 그 구독자로의 전달이 재시도 끝에 실패하면 메시지가 유실될 수 있고 알림 시스템에서는 이 유실 자체를 인지하기 어렵다는 문제가 있다. DLQ를 구성해두면 이런 실패 메시지를 남겨서 사후에 확인하고 대응할 수 있다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Amazon SQS와 SNS 정리]]></title>
            <link>https://velog.io/@jennie-infra/Amazon-SQS%EC%99%80-SNS-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@jennie-infra/Amazon-SQS%EC%99%80-SNS-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Sun, 27 Sep 2026 15:33:00 GMT</pubDate>
            <description><![CDATA[<h2 id="sqssimple-queue-service">SQS(Simple Queue Service)</h2>
<p>SQS는 AWS가 제공하는 <span style='background-color: #fff3b0'>완전관리형 메시지 큐</span>다. 메시지를 큐에 넣어두면, 소비자(Consumer)가 필요할 때 하나씩 꺼내서 처리하는 구조다.</p>
<pre><code>Producer 1 ─┐
Producer 2 ─┼─(Message)─▶ SQS 큐 ─(Trigger)─▶ Consumer(1곳만) → 처리 후 큐에서 제거
Producer 3 ─┘</code></pre><p>여러 발신자가 메시지를 큐에 쌓아두면 그걸 처리하는 쪽은 보통 한 곳(또는 같은 그룹의 워커들)이고, 처리된 메시지는 큐에서 사라진다. FIFO 큐를 쓰면 순서 보장도 가능하다.</p>
<h2 id="snssimple-notification-service">SNS(Simple Notification Service)</h2>
<p>SNS는 <span style='background-color: #fff3b0'>발행/구독(Pub/Sub) 모델</span>로 동작하는 완전관리형 알림 서비스다. 하나의 주제(Topic)에 메시지를 발행하면 그 주제를 구독하고 있는 모든 엔드포인트로 동시에 전달된다.</p>
<pre><code>Publisher ─(Publish)─▶ SNS Topic ─(Subscribe)─┬─▶ Lambda
                                                ├─▶ SQS
                                                ├─▶ Email
                                                └─▶ EventBridge</code></pre><p>저번에 만들었던 CloudWatch → SNS → Lambda → Slack 흐름이 바로 이 구조였다. <span style='background-color: #fff3b0'>이상 상황 하나를 여러 구독자(Lambda 등)에게 동시에 뿌려야 하는 상황</span>이라 SNS가 맞는 선택이다.</p>
<h2 id="sqs와-sns-뭐가-다를까">SQS와 SNS, 뭐가 다를까</h2>
<ul>
<li><strong>모델</strong>: SQS는 큐 기반(Point-to-Point), SNS는 발행/구독(Pub/Sub)</li>
<li><strong>메시지 전달</strong>: SQS는 큐에 저장되었다가 소비자가 꺼내가면 사라지고, SNS는 발행 즉시 모든 구독자에게 전달</li>
<li><strong>용도</strong>: SQS는 비동기 작업 처리/워커 큐, SNS는 실시간 알림/이벤트 브로드캐스트</li>
</ul>
<p><span style='background-color: #fff3b0'>SQS는 <strong>한 번 처리하면 끝나는 작업을 순서대로 안전하게 넘기는</strong> 용도</span>이고, <span style='background-color: #fff3b0'>SNS는 <strong>하나의 이벤트를 여러 곳에 동시에 알려야 하는</strong> 용도</span>라는 게 가장 큰 차이였다. 만약 그때 만들었던 알림 함수가 &#39;Slack에도 보내고 별도 로그 큐에도 쌓아야 한다&#39;는 요구사항이었다면 SNS 하나에 Lambda와 SQS를 동시에 구독시켜서 양쪽에 다 전달할 수 있었겠다는 생각이 들었다.</p>
<h2 id="둘을-같이-쓰는-경우">둘을 같이 쓰는 경우</h2>
<p>SQS와 SNS는 종종 함께 쓰이는데 Producer가 SQS에 메시지를 쌓고 그 SQS가 Lambda를 트리거하면 Lambda가 처리 결과를 다시 SNS로 발행해서 Slack 등 여러 곳에 알리는 식이다.</p>
<pre><code>Producer ──▶ SQS(작업 큐) ──Trigger──▶ Lambda(처리) ──▶ SNS(결과 알림) ──▶ Slack / 다른 구독자</code></pre><p><span style='background-color: #fff3b0'>SQS는 <strong>처리 대기열</strong>을, SNS는 <strong>처리 결과 전파</strong>를 맡는 역할 분담</span>이다. 하나의 이벤트가 쌓였다가 처리되는 단계와 처리 후 여러 곳에 알려지는 단계로 나뉠 때 각 단계에 맞는 서비스를 골라 쓰는 것 같다.</p>
<hr>
<p>📍 출처: 패스트캠퍼스 강의 - 실전 DevOps의 모든 것</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Amazon CloudFront와 CDN 정리]]></title>
            <link>https://velog.io/@jennie-infra/Amazon-CloudFront%EC%99%80-CDN-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@jennie-infra/Amazon-CloudFront%EC%99%80-CDN-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Sun, 27 Sep 2026 15:29:03 GMT</pubDate>
            <description><![CDATA[<h2 id="cdn">CDN</h2>
<p>CDN(Content Delivery Network)은 <span style='background-color: #fff3b0'>콘텐츠를 효율적으로 전달하기 위해 여러 지역에 분산된 노드(엣지 로케이션)에 데이터를 캐싱해두는 네트워크</span>다. 사용자가 요청할 때마다 매번 본래 서버(오리진)까지 갔다 오는 게 아닌 사용자와 가장 가까운 엣지 로케이션에 미리 저장해둔 데이터를 빠르게 내려주는 방식이다.</p>
<pre><code>[CDN 없이]
사용자(한국) ──────(먼 거리)──────▶ 오리진 서버(미국)

[CDN 사용]
사용자(한국) ──(가까움)──▶ 엣지 로케이션(한국 인근) ──(캐시 없을 때만)──▶ 오리진 서버(미국)</code></pre><h2 id="amazon-cloudfront란">Amazon CloudFront란</h2>
<p>CloudFront는 AWS가 제공하는 CDN 서비스로 <span style='background-color: #fff3b0'>짧은 지연 시간과 빠른 전송 속도로 데이터/동영상/API를 전 세계 사용자에게 전달</span>한다. 오리진으로 S3 버킷(정적 콘텐츠), EC2/ELB(동적 콘텐츠), 심지어 AWS 외부의 HTTP 서버까지 지정할 수 있다.</p>
<p>EX) <span style='background-color: #fff3b0'>S3에 정적 파일을 저장해두고 그 앞단에 CloudFront를 붙이면 전 세계 어디서 접속해도 가까운 엣지 로케이션에서 빠르게 받아볼 수 있는 구조</span>가 되는 것이다.</p>
<h2 id="작동-방식">작동 방식</h2>
<p>요청 처리 흐름</p>
<pre><code>Client ──요청──▶ EdgeServer ──캐시 여부 확인──┬─[캐시 있음]──▶ 바로 응답
                                              └─[캐시 없음]──▶ OriginServer에 요청 포워딩
                                                              ──데이터 획득──▶ 캐싱 후 응답</code></pre><p>첫 요청이 들어오면 엣지 로케이션에 캐시가 있는지 먼저 확인하고 없으면 그때서야 오리진 서버까지 가서 데이터를 받아와 캐싱한 뒤 응답한다. 그 다음부터 같은 콘텐츠를 요청하는 사용자는 오리진까지 갈 필요 없이 엣지에 저장된 캐시로 바로 응답받는다.</p>
<h2 id="캐시-무효화invalidation">캐시 무효화(Invalidation)</h2>
<p>CloudFront는 캐시된 콘텐츠를 TTL(Time to Live) 동안 유지하는데 TTL을 길게 설정해두면 오리진의 콘텐츠가 바뀌어도 그 변경이 사용자에게 바로 반영되지 않는다. 이럴 때 <span style='background-color: #fff3b0'>무효화(Invalidation)를 통해 특정 파일이나 경로의 캐시를 강제로 삭제</span>하면 다음 요청부터는 캐시가 없는 상태이므로 오리진에서 최신 콘텐츠를 다시 가져와 캐싱한다.</p>
<pre><code>S3에 새 이미지 업로드 → CloudFront에 Invalidation 요청 → 기존 캐시 삭제 → 다음 요청 시 최신 이미지로 재캐싱</code></pre><p>캐싱을 오래 유지할수록 속도는 빨라지지만 최신 데이터 반영은 늦어지고 반대로 TTL을 짧게 잡거나 자주 무효화하면 최신성은 확보되지만 캐싱의 이점이 줄어드는 균형점을 찾아야 하는 것 같다.</p>
<h2 id="다른-서비스와의-관계">다른 서비스와의 관계</h2>
<p>CloudFront는 통합 보안 기능(AWS Shield, WAF, SSL/TLS)도 제공하고, CloudWatch와 연동한 로그/모니터링도 지원한다고 한다. 저번에 정리했던 ELB와 비교해보면 <span style='background-color: #fff3b0'>ELB는 여러 백엔드 서버 사이의 부하를 분산하는 서비스고, CloudFront는 사용자와 가까운 곳에 콘텐츠 자체를 캐싱해서 오리진까지 가는 요청 자체를 줄여주는 서비스</span>라는 차이가 있다. 트래픽을 다루는 위치가 서로 다른 것. (ELB는 오리진 쪽(서버들 사이)에서, CloudFront는 사용자와 가장 가까운 엣지 쪽에서 트래픽을 처리)</p>
<hr>
<p>📍 출처: 패스트캠퍼스 강의 - 실전 DevOps의 모든 것</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[컨테이너 오케스트레이션과 AWS ECS 정리]]></title>
            <link>https://velog.io/@jennie-infra/%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88-%EC%98%A4%EC%BC%80%EC%8A%A4%ED%8A%B8%EB%A0%88%EC%9D%B4%EC%85%98%EA%B3%BC-AWS-ECS-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@jennie-infra/%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88-%EC%98%A4%EC%BC%80%EC%8A%A4%ED%8A%B8%EB%A0%88%EC%9D%B4%EC%85%98%EA%B3%BC-AWS-ECS-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Sat, 26 Sep 2026 06:39:40 GMT</pubDate>
            <description><![CDATA[<h2 id="컨테이너-오케스트레이션이-뭘까">컨테이너 오케스트레이션이 뭘까</h2>
<p>컨테이너 오케스트레이션은 <span style='background-color: #fff3b0'>다수의 컨테이너를 자동으로 배포, 관리, 스케일링(확장 및 축소)하는 것</span>을 말한다. 컨테이너 몇 개 정도는 직접 하나씩 띄우고 내릴 수 있지만 컨테이너가 수십, 수백 개로 늘어나면 사람이 일일이 관리하기 어려워지는데 이걸 대신 자동으로 해주는 게 오케스트레이션 도구(컨트롤러)의 역할이다.</p>
<pre><code>개발자 ──명령──▶ 컨트롤러(ECS/EKS) ──자동 배포·관리──▶ 컨테이너 1, 2, 3 ... N</code></pre><h2 id="aws-ecs가-뭘까">AWS ECS가 뭘까</h2>
<p>ECS(Amazon Elastic Container Service)는 AWS의 관리형 컨테이너 오케스트레이션 서비스다. <span style='background-color: #fff3b0'>인프라 관리 부담 없이 컨테이너화된 애플리케이션을 배포/관리/확장</span>할 수 있고 IAM/CloudWatch/로드밸런서 같은 AWS 서비스들과 긴밀하게 통합돼 있다.</p>
<p>ECS는 런치 타입을 두 가지로 지원한다.</p>
<ul>
<li><strong>EC2 런치 타입</strong>: 내가 직접 관리하는 EC2 인스턴스 위에서 컨테이너를 실행한다.</li>
<li><strong>Fargate 런치 타입</strong>: 서버리스 방식으로 AWS가 관리하는 자원 풀에서 컨테이너를 실행한다. 인스턴스를 직접 프로비저닝하거나 관리할 필요가 없다.</li>
</ul>
<h2 id="구성요소">구성요소</h2>
<ul>
<li><strong>클러스터(Cluster)</strong>: ECS의 기본 논리적 단위로, 컨테이너를 실행할 수 있는 CPU나 메모리 같은 자원을 모아둔 집합이다.</li>
<li><strong>작업 정의(Task Definition)</strong>: 컨테이너 실행에 필요한 설정(이미지, CPU, 메모리, 포트 매핑, 환경 변수 등)을 담은 명세서다.</li>
<li><strong>작업(Task)</strong>: 작업 정의에 따라 실제로 실행되는 컨테이너 인스턴스다.</li>
<li><strong>서비스(Service)</strong>: 원하는 개수의 작업이 항상 실행되도록 보장하고, 배포/업데이트/자동 복구까지 관리한다.</li>
</ul>
<p>이 구조를 보면서 EKS의 Pod/Deployment 개념과 자연스레 연관지어 <span style='background-color: #fff3b0'>Task Definition은 Pod 스펙, Task는 실제 실행 중인 Pod, Service는 Deployment</span>와 각각 비슷한 역할을 한다고 이해했다. 결국 이름과 세부 구현은 다르지만 실행할 스펙을 정의하고 → 그 스펙대로 실제 컨테이너를 띄우고 → 원하는 개수를 계속 유지시켜주는 3단 구조 자체는 ECS든 EKS든 똑같았다.</p>
<h3 id="iam-role이-두-종류인-이유">IAM Role이 두 종류인 이유</h3>
<p>ECS 작업에는 IAM 역할이 두 가지 필요하다.</p>
<ul>
<li><strong>작업 역할(Task Role)</strong>: 컨테이너 안에서 실행되는 애플리케이션 코드가 다른 AWS 서비스(S3, DynamoDB 등)에 접근할 때 쓰는 권한이다.</li>
<li><strong>작업 실행 역할(Task Execution Role)</strong>: 작업을 실행하는 과정 자체에 필요한 권한이다. 예를 들어 ECR에서 컨테이너 이미지를 가져오거나 S3에서 환경 변수 파일을 읽어오는 데 쓰인다.</li>
</ul>
<p><span style='background-color: #fff3b0'>&#39;컨테이너를 실행시키는 데 필요한 권한&#39;과 &#39;컨테이너 안의 애플리케이션이 실행 중에 필요한 권한&#39;이 서로 다른 시점, 다른 주체의 권한이라서 분리된 것</span>이라고 이해하기.</p>
<h2 id="네트워크-awsvpc-모드-vs-브릿지-모드">네트워크: awsvpc 모드 vs 브릿지 모드</h2>
<p>ECS에서 작업을 실행할 때는 네트워크 모드를 선택해야 하는데 크게 두 가지로 나뉜다.</p>
<pre><code>[awsvpc 모드]
Task 1 ──ENI 1(172.31.16.1)──▶ Container (독립된 IP, 독립된 보안 그룹)
Task 2 ──ENI 2(172.31.16.2)──▶ Container (독립된 IP, 독립된 보안 그룹)

[브릿지 모드]
              ┌─ Container (Port 3000)
EC2 ENI 1 ────┤   (단일 ENI를 여러 컨테이너가 공유, 보안 그룹은 인스턴스 단위)
              └─ Container (Port 3000)</code></pre><p>awsvpc 모드는 각 작업(Task)마다 ENI를 따로 생성해서 독립된 프라이빗 IP를 할당하기 때문에 Task 단위로 보안 그룹을 따로 적용할 수 있고 IP 충돌 걱정도 없다. 반면 브릿지 모드는 하나의 EC2 ENI를 여러 컨테이너가 공유하는 방식이라 컨테이너별로 보안 그룹을 따로 줄 수 없고 호스트 포트를 매핑할 때도 포트 충돌을 신경 써야 한다.</p>
<p><span style='background-color: #fff3b0'>ECS가 각 Task에 별도의 ENI를 붙여주는 awsvpc 모드</span>를 보면서 이 방식은 Task 하나당 ENI 하나가 필요해서 인스턴스당 실행 가능한 Task 수가 ENI 개수 제한에 영향을 받을 수 있겠다는 생각도 들었다.</p>
<h2 id="ecs-애플리케이션-라이프사이클">ECS 애플리케이션 라이프사이클</h2>
<p>실제 배포 흐름은 이랬다.</p>
<pre><code>ECR 이미지 준비 → Task Definition 작성(작업 정의) → ECS Task/Service로 배포 → 모니터링
                                                      (EC2 or Fargate 자원 위에서 실행)</code></pre><p>컨테이너 이미지를 ECR에 올려두고 그 이미지를 어떻게 실행할지 Task Definition으로 정의한 다음, 이를 실제 Task나 Service로 배포하고, 이후엔 CloudWatch 같은 서비스로 계속 모니터링하는 흐름이다. </p>
<hr>
<p>📍 출처: 패스트캠퍼스 강의 - 실전 DevOps의 모든 것</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[서버리스 컴퓨팅과 AWS Lambda 정리]]></title>
            <link>https://velog.io/@jennie-infra/%EC%84%9C%EB%B2%84%EB%A6%AC%EC%8A%A4-%EC%BB%B4%ED%93%A8%ED%8C%85%EA%B3%BC-AWS-Lambda-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@jennie-infra/%EC%84%9C%EB%B2%84%EB%A6%AC%EC%8A%A4-%EC%BB%B4%ED%93%A8%ED%8C%85%EA%B3%BC-AWS-Lambda-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Fri, 25 Sep 2026 08:44:43 GMT</pubDate>
            <description><![CDATA[<h2 id="서버리스serverless가-뭘까">서버리스(Serverless)가 뭘까</h2>
<p>서버리스는 <span style='background-color: #fff3b0'>서버 인프라를 직접 관리하지 않고도 애플리케이션을 구축·실행할 수 있는 모델</span>이다. 서버를 AWS가 대신 관리해준다는 뜻이다. 이 서버리스의 한 형태가 FaaS(Function as a Service)인데 EC2와 비교해보면 이렇다.</p>
<pre><code>[EC2 방식]
서버 기동 ──────────────────계속 켜둠─────────────────→ 계속 과금
           (트래픽 없어도 켜져있는 동안 요금 발생)

[Lambda 방식]
이벤트 발생 → 함수 실행 → 실행 끝나면 즉시 종료
              (실행된 시간만큼만 과금, 평소엔 요금 없음)</code></pre><h2 id="부트캠프에서-만들었던-lambda">부트캠프에서 만들었던 Lambda</h2>
<p>그 프로젝트에서 구성했던 흐름을 보면</p>
<pre><code>CloudWatch ──(이상 지표 감지)──▶ SNS Topic ──(구독)──▶ Lambda 함수 ──(Webhook)──▶ Slack 채널
 (EKS/EFK 클러스터 모니터링)      (알림 발행)          (메시지 가공)              (알림 수신)</code></pre><p>당시엔 <strong>Lambda = SNS랑 Slack 사이를 이어주는 코드</strong> 정도로만 이해했는데 <span style='background-color: #fff3b0'>이 함수가 서버리스 컴퓨팅의 전형적인 사용 사례</span>로서 서버가 SNS 메시지를 계속 지켜보고 있을 필요 없이 메시지가 도착하는 순간에만 함수가 켜졌다 꺼지는 구조임을 알게 되었다.</p>
<h2 id="실제-경험에-비춰본-lambda-특징">실제 경험에 비춰본 Lambda 특징</h2>
<table>
<thead>
<tr>
<th>특징</th>
<th>개념</th>
<th>그때 겪었던 것</th>
</tr>
</thead>
<tbody><tr>
<td>실행 시간/메모리 제한</td>
<td>최대 15분, 메모리 최대 10,240MB까지 설정 가능</td>
<td>알림 함수는 1초 안팎이라 기본값(가장 작은 설정)만으로 충분했음</td>
</tr>
<tr>
<td>IAM Role</td>
<td>코드에 액세스 키 없이 역할로 임시 자격 증명 자동 획득</td>
<td>실습 가이드대로 역할만 붙였는데, 이게 EC2/IMDS와 같은 구조였다는 걸 이번에 알게 됨</td>
</tr>
<tr>
<td><span style='background-color: #fff3b0'>콜드 스타트</span></td>
<td>한동안 호출 안 되면 환경이 내려가 있다가, 재호출 시 재기동 지연 발생</td>
<td>알림이 몇 초 늦게 온 적이 있었는데, 이 때문이었을 가능성이 있음</td>
</tr>
<tr>
<td>무상태성(Stateless)</td>
<td>호출 간 데이터 유지 불가, 상태는 외부 저장소(DynamoDB 등)에 저장해야 함</td>
<td>&quot;메시지 하나 받아 하나 전송&quot;이라 문제없었지만, &quot;누적해서 한 번에 발송&quot; 같은 요구였다면 별도 저장소가 필요했을 것</td>
</tr>
<tr>
<td>벤더 종속성</td>
<td>트리거 연동 코드가 특정 클라우드 이벤트 형식에 종속</td>
<td>SNS 이벤트 형식에 맞춘 코드라 다른 클라우드로 옮기려면 재작성 필요</td>
</tr>
</tbody></table>
<h2 id="트리거-종류">트리거 종류</h2>
<p>Lambda는 다양한 AWS 서비스를 트리거로 걸 수 있다.</p>
<pre><code>S3 (파일 업로드/삭제)     ─┐
DynamoDB (데이터 변경)   ─┤
API Gateway (HTTP 요청) ─┼──▶ Lambda 함수 실행
SNS (알림 발행)         ─┤
SQS (큐 메시지 도착)     ─┤
EventBridge (규칙 매칭) ─┘</code></pre><p>내가 겪은 건 이 중 SNS 트리거였고 강의에 나온 다른 사례는 EventBridge 트리거였다.</p>
<pre><code>CloudTrail ──(API 호출 기록)──▶ EventBridge ──(규칙 감지)──▶ Lambda ──▶ 자동 대응</code></pre><p>결국 트리거의 종류만 다를 뿐이지 <span style='background-color: #fff3b0'>무언가 감지되면 그 처리를 Lambda가 떠맡는다</span>는 패턴은 동일했다.</p>
<h2 id="활용-범위">활용 범위</h2>
<ul>
<li><strong>운영 자동화</strong> → CloudWatch Alarm 발생 시 Lambda로 알림/재시작 처리 <em>(← 내가 겪은 사례)</em></li>
<li><strong>웹 애플리케이션</strong> → API Gateway와 연결해 서버 없이 백엔드 API 구성</li>
<li><strong>배치 처리</strong> → 정해진 시간에 대량 데이터를 일괄 처리</li>
<li><strong>실시간 파일 처리</strong> → S3에 파일 업로드 시 썸네일 생성 등 후처리</li>
<li><strong>실시간 스트림 처리</strong> → Kinesis 등으로 들어오는 스트리밍 데이터 처리</li>
<li><strong>IoT 백엔드</strong> → IoT 디바이스에서 들어오는 이벤트 처리</li>
<li><strong>모바일 백엔드</strong> → 모바일 앱의 백엔드 로직 처리</li>
<li><strong>자동화된 보안 대응</strong> → CloudTrail 이벤트를 EventBridge로 받아 자동 대응</li>
</ul>
<hr>
<p>📍 출처: 패스트캠퍼스 강의 - 실전 DevOps의 모든 것</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[AWS CloudWatch, CloudTrail, EventBridge 정리]]></title>
            <link>https://velog.io/@jennie-infra/AWS-CloudWatch-CloudTrail-EventBridge-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@jennie-infra/AWS-CloudWatch-CloudTrail-EventBridge-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Fri, 25 Sep 2026 08:17:47 GMT</pubDate>
            <description><![CDATA[<h2 id="cloudwatch">CloudWatch</h2>
<h3 id="cloudwatch란">CloudWatch란</h3>
<p>CloudWatch는 AWS 리소스와 애플리케이션을 모니터링하고 관리할 수 있는 <span style='background-color: #fff3b0'>완전관리형 서비스</span>다. AWS 서비스의 성능과 운영 상태를 실시간으로 파악하는 데 쓰인다.</p>
<h3 id="주요-특징">주요 특징</h3>
<ul>
<li><strong>지표 수집 및 모니터링</strong>: AWS 리소스의 지표(Metrics) 데이터를 수집하고 모니터링한다. 예를 들어 EC2의 CPU 사용률, 네트워크 트래픽 같은 수치들이 여기 해당한다.</li>
<li><strong>로그 관리</strong>: 애플리케이션 로그를 중앙에서 수집하고 분석할 수 있다.</li>
<li><strong>알림 설정</strong>: 특정 조건이 충족되면 알람을 발생시키고 이메일이나 SMS로 알림을 보낼 수 있다.</li>
</ul>
<p>강의 자료에서는 AWS 리소스나 커스텀 데이터가 CloudWatch로 들어가서 Metrics/APM/Logs 세 가지 형태로 쌓이고 거기서 조건에 맞으면 Alarm이 발생해서 Lambda/SNS/Auto Scaling Group 같은 곳으로 전달되는 구조였다. 그리고 Grafana 같은 외부 대시보드 도구가 CloudWatch에 쌓인 데이터를 가져다가 시각화하는 데 쓰이기도 한다. <span style='background-color: #fff3b0'>CloudWatch 자체는 데이터를 모으고 조건을 감시하는 역할이고, 실제로 뭔가 조치를 취하는 건 Alarm이 트리거하는 Lambda나 Auto Scaling 같은 다른 서비스가 담당</span>하는 구조이다.  이 흐름은 전에 했던 aws eks 프로젝트 아키텍처를 정리할 때 나왔던 CloudWatch → SNS → Lambda로 이어지는 알림 파이프라인과 정확히 같은 구조이다.</p>
<h2 id="cloudtrail">CloudTrail</h2>
<h3 id="cloudtrail란">CloudTrail란</h3>
<p>CloudTrail은 AWS 계정에서 발생하는 <span style='background-color: #fff3b0'>모든 API 호출과 활동을 기록하고 모니터링</span>하는 서비스다. AWS Management Console에서 클릭한 것이든, SDK로 코드에서 호출한 것이든, CLI로 명령어를 친 것이든 상관없이 AWS 안에서 벌어지는 API 호출은 다 CloudTrail에 기록된다. EX) VPC, EC2, RDS, EBS, IAM, STS와 같은 다양한 서비스에 대한 호출 기록이 CloudTrail을 거쳐서 지정된 S3 버킷에 로그 파일로 쌓이고 필요하면 SNS Topic으로 알림도 보낼 수 있는 구조이다. </p>
<h3 id="cloudwatch와-뭐가-다른가">CloudWatch와 뭐가 다른가</h3>
<p>여기서 CloudWatch와 CloudTrail이 뭐가 다른지 짚어보면 <span style='background-color: #fff3b0'>CloudWatch는 <strong>리소스가 지금 어떤 상태인가</strong>(CPU 사용률, 로그 내용 등)를 보는 성능/운영 모니터링이고, CloudTrail은 <strong>누가 언제 무엇을 했는가</strong>를 기록하는 감사(Audit) 로그</span>라는 차이가 있었다.EX) EC2 인스턴스의 CPU가 갑자기 튀었다면 CloudWatch로 확인해야 하고 그 인스턴스의 보안 그룹 설정을 누가 언제 바꿨는지 추적하려면 CloudTrail을 봐야 하는 식인 것.</p>
<h2 id="eventbridge">EventBridge</h2>
<h3 id="eventbridge란">EventBridge란</h3>
<p>EventBridge는 <span style='background-color: #fff3b0'>다양한 소스에서 발생하는 이벤트를 수집</span>해서 원하는 대상으로 전달해주는 서비스다. AWS 리소스는 CloudTrail에 기록되는 API 호출 이벤트 말고도 서비스마다 자체적인 이벤트를 발생시키기도 하는데(EX. EC2 인스턴스 상태 변경) 이런 것들까지 다 EventBridge가 받아서 처리할 수 있다.</p>
<h3 id="기능">기능</h3>
<ul>
<li><strong>이벤트 수집</strong>: AWS 서비스, SaaS 애플리케이션, 사용자 애플리케이션 등에서 발생하는 이벤트를 수집한다.</li>
<li><strong>규칙 기반 라우팅</strong>: 이벤트 패턴을 정의해서 특정 이벤트가 발생했을 때 원하는 대상에게 전달한다.</li>
<li><strong>다양한 대상 지원</strong>: Lambda 함수, SQS 큐, SNS 토픽, Kinesis 스트림 등 다양한 AWS 서비스와 통합된다.</li>
<li><strong>스케줄링 지원</strong>: 일정에 따라 이벤트를 트리거해서 정기적인 작업을 수행할 수 있다.</li>
</ul>
<h3 id="cloudtrail과-eventbridge를-같이-쓰면">CloudTrail과 EventBridge를 같이 쓰면</h3>
<p>IAM 사용자가 삭제되는 API 호출이 발생하면 그 호출이 먼저 CloudTrail에 기록되고 EventBridge가 이 이벤트를 감지해서 <strong>IAM User 삭제 시 Lambda로 이벤트 전송</strong>이라는 규칙에 따라 Lambda 함수를 실행시킨다. 이렇게 하면 <span style='background-color: #fff3b0'>단순히 로그를 남기는 걸 넘어서 특정 API 호출이 발생했을 때 자동으로 후속 조치(알림 발송, 자동 대응 등)까지 이어지는 파이프라인</span>을 만들 수 있다.
정리하자면 <span style='background-color: #fff3b0'>CloudTrail은 기록을 남기는 것까지가 역할이고, 그 기록을 실시간으로 감지해서 다른 서비스로 연결해주는 건 EventBridge의 역할</span>인 것이다. 이런 이벤트 기반 자동화를 미리 구성해두면 실수가 발생했을 때 바로 알림을 받거나 자동으로 대응할 수 있겠다는 생각이 들었다.</p>
<h2 id="정리">정리</h2>
<p>CloudWatch는 상태/성능 모니터링, CloudTrail은 API 호출 기록(감사), EventBridge는 이벤트를 감지해서 다른 곳으로 연결하는 역할</p>
<hr>
<p>📍 출처: 패스트캠퍼스 강의 - 실전 DevOps의 모든 것</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Route53 레코드 관리와 IaC 전환]]></title>
            <link>https://velog.io/@jennie-infra/Route53-%EB%A0%88%EC%BD%94%EB%93%9C-%EA%B4%80%EB%A6%AC%EC%99%80-IaC-%EC%A0%84%ED%99%98</link>
            <guid>https://velog.io/@jennie-infra/Route53-%EB%A0%88%EC%BD%94%EB%93%9C-%EA%B4%80%EB%A6%AC%EC%99%80-IaC-%EC%A0%84%ED%99%98</guid>
            <pubDate>Wed, 23 Sep 2026 06:37:34 GMT</pubDate>
            <description><![CDATA[<p>Route53을 정리하면서 호스팅 영역과 레코드 개념을 다뤘는데 실제로 도메인과 서비스 수가 늘어나는 상황을 가정하면 콘솔에서 레코드를 직접 관리하는 방식이 계속 유지 가능한지 의문이 생기게 된다. 레코드 관리 규모가 커질 때 발생하는 문제와 이를 코드로 관리하는 방식(Terraform)으로 전환해야 하는 이유에 관해 정리한 글이다.</p>
<h2 id="레코드-몇-개일-때는-콘솔로-충분함">레코드 몇 개일 때는 콘솔로 충분함</h2>
<p>서비스 초기 단계에서는 도메인 하나에 A 레코드 몇 개, CNAME 몇 개 정도만 관리하면 된다. 이 정도 규모라면 AWS 콘솔에서 직접 레코드를 추가하거나 수정하는 방식으로도 충분히 관리 가능하다. 변경 사항이 적기도 하고 담당자도 소수이기 때문에 어떤 레코드가 왜 존재하는지 파악하는 데 큰 어려움이 없다.</p>
<h2 id="도메인과-서비스가-늘어나면-발생하는-문제">도메인과 서비스가 늘어나면 발생하는 문제</h2>
<p>서비스가 여러 개로 늘어나고 도메인/서브도메인 수가 많아지면 다음과 같은 문제가 발생할 수 있다.</p>
<ul>
<li><strong>오래된 레코드 방치</strong>: 서비스가 종료되거나 인프라가 변경된 이후에도 관련 레코드가 삭제되지 않고 남아있는 경우가 생긴다. 시간이 지나면 이 레코드가 어떤 리소스를 가리키는지, 삭제해도 되는지 판단하기 어려워진다.</li>
<li><strong>중복 또는 충돌 설정</strong>: 여러 담당자가 각자 콘솔에서 레코드를 수정하다 보면 동일한 이름에 대해 서로 다른 값을 설정하거나 의도치 않게 기존 설정을 덮어쓰는 경우가 발생할 수 있다.</li>
<li><strong>변경 이력 추적 불가</strong>: 콘솔에서 이루어진 변경은 누가 언제 왜 수정했는지에 대한 기록이 체계적으로 남지 않는다. 문제가 발생했을 때 원인을 역추적하기 어렵다.</li>
<li><strong>환경 간 일관성 유지의 어려움</strong>: 개발/스테이징/운영 환경마다 유사한 레코드 구성을 반복해서 수동으로 만들어야 하는데, 이 과정에서 설정 차이가 발생하기 쉽다.</li>
</ul>
<h2 id="terraform으로-관리했을-때-해결되는-부분">Terraform으로 관리했을 때 해결되는 부분</h2>
<p>이런 문제에 대한 대안으로 흔히 언급되는 것이 Terraform과 같은 IaC(Infrastructure as Code) 도구다. </p>
<ul>
<li><strong>선언적 정의</strong>: 어떤 레코드가 어떤 값을 가져야 하는지를 코드로 명시적으로 정의한다. 코드 자체가 곧 현재 인프라의 스펙 문서가 된다.</li>
<li><strong>상태 파일(State) 기반 추적</strong>: Terraform은 실제 인프라의 현재 상태를 state 파일로 관리하기 때문에 코드에 정의된 상태와 실제 AWS 상의 상태가 다를 경우(드리프트) 이를 감지할 수 있다.</li>
<li><strong>적용 전 변경 사항 검토(plan)</strong>: 레코드를 실제로 변경하기 전에 <code>terraform plan</code>으로 어떤 항목이 추가/수정/삭제되는지 미리 확인할 수 있다. 콘솔에서 바로 수정하는 방식보다 실수를 줄일 수 있는 구조다.</li>
<li><strong>버전 관리와 이력 추적</strong>: 코드로 관리되므로 Git과 같은 버전 관리 시스템에 변경 이력이 그대로 남는다. 누가 언제 어떤 이유로 변경했는지 커밋 이력으로 확인할 수 있다.</li>
<li><strong>환경 간 재사용</strong>: 동일한 코드 구조를 변수만 바꿔서 여러 환경에 적용할 수 있어서 환경 간 설정 불일치 문제를 줄일 수 있다.</li>
</ul>
<h2 id="다만-전환에도-고려할-부분이-존재함">다만 전환에도 고려할 부분이 존재함</h2>
<p>Terraform 도입이 모든 상황에서 즉시 이점만 있는 것은 아니다.</p>
<ul>
<li><strong>기존 리소스의 편입 문제</strong>: 이미 콘솔에서 수동으로 생성해둔 레코드를 Terraform 관리 대상으로 가져오려면 <code>terraform import</code> 같은 작업이 필요하며, 이 과정에서 기존 설정과 코드 정의가 일치하지 않으면 예기치 않은 변경이 발생할 수 있다.</li>
<li><strong>state 파일 관리</strong>: state 파일을 로컬에만 두면 여러 사람이 동시에 작업할 때 충돌이 발생할 수 있어, 원격 백엔드(S3 등)와 잠금 메커니즘을 함께 구성해야 한다.</li>
<li><strong>학습 비용</strong>: 콘솔 조작에 비해 문법과 워크플로우를 익히는 데 별도의 학습이 필요하다.</li>
</ul>
<p>이런 부분들을 고려해봤을 때 레코드 수가 적고 담당자가 1-2명인 초기 단계에서는 굳이 Terraform을 도입할 필요가 없을 수도 있지만 반대로 서비스와 담당자가 늘어나 변경 이력 관리와 여러 명의 동시 작업이 필요해지는 시점부터는 IaC 전환을 고려하는 것이 합리적일 것 같다.</p>
<h2 id="정리">정리</h2>
<p>레코드 관리 방식의 선택 기준은 몇 개의 레코드를 몇 명이 관리하는가인 것 같다. 소규모에서는 콘솔 관리로 충분하지만 규모가 커지면 수동 관리 방식 자체가 오류의 원인이 되기 때문에 Terraform과 같은 코드 기반 관리로 전환하는 것이 필요하다.</p>
]]></description>
        </item>
    </channel>
</rss>